Skip to content

Commit

Permalink
refactor(store-sync): remove remaining refs to old config (#2938)
Browse files Browse the repository at this point in the history
  • Loading branch information
holic authored Jul 12, 2024
1 parent 9e05278 commit b62cf9f
Show file tree
Hide file tree
Showing 38 changed files with 229 additions and 191 deletions.
2 changes: 1 addition & 1 deletion .changeset/flat-swans-turn.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"@latticexyz/store-sync": patch
---

Refactored `syncToZustand` to use new Store config under the hood, removing compatibility layers and improving performance.
Refactored package to use the new Store/World configs under the hood, removing compatibility layers and improving performance.
5 changes: 5 additions & 0 deletions .changeset/fluffy-experts-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/store-indexer": patch
---

Updated return values to match updated types in `@latticexyz/store-sync`.
5 changes: 0 additions & 5 deletions .changeset/real-pigs-work.md

This file was deleted.

1 change: 1 addition & 0 deletions packages/protocol-parser/src/exports/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export * from "../valueSchemaToHex";
export * from "../getKeySchema";
export * from "../getValueSchema";
export * from "../getSchemaTypes";
export * from "../getSchemaPrimitives";
10 changes: 6 additions & 4 deletions packages/protocol-parser/src/getKeySchema.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Table } from "@latticexyz/config";
import { Schema, Table } from "@latticexyz/config";

export type getKeySchema<table extends Table> = {
[fieldName in table["key"][number]]: table["schema"][fieldName];
};
export type getKeySchema<table extends Table> = Table extends table
? Schema
: {
readonly [fieldName in keyof table["schema"] & table["key"][number]]: table["schema"][fieldName];
};

export function getKeySchema<table extends Table>(table: table): getKeySchema<table> {
return Object.fromEntries(table.key.map((fieldName) => [fieldName, table.schema[fieldName]])) as getKeySchema<table>;
Expand Down
6 changes: 6 additions & 0 deletions packages/protocol-parser/src/getSchemaPrimitives.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Schema } from "@latticexyz/config";
import { SchemaAbiTypeToPrimitiveType } from "@latticexyz/schema-type/internal";

export type getSchemaPrimitives<schema extends Schema> = {
readonly [fieldName in keyof schema]: SchemaAbiTypeToPrimitiveType<schema[fieldName]["type"]>;
};
2 changes: 1 addition & 1 deletion packages/protocol-parser/src/getSchemaTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Schema } from "@latticexyz/config";
import { mapObject } from "@latticexyz/common/utils";

export type getSchemaTypes<schema extends Schema> = {
readonly [k in keyof schema]: schema[k]["type"];
readonly [fieldName in keyof schema]: schema[fieldName]["type"];
};

export function getSchemaTypes<schema extends Schema>(schema: schema): getSchemaTypes<schema> {
Expand Down
10 changes: 6 additions & 4 deletions packages/protocol-parser/src/getValueSchema.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Table } from "@latticexyz/config";
import { Schema, Table } from "@latticexyz/config";

export type getValueSchema<table extends Table> = {
[fieldName in Exclude<keyof table["schema"], table["key"][number]>]: table["schema"][fieldName];
};
export type getValueSchema<table extends Table> = Table extends table
? Schema
: {
readonly [fieldName in Exclude<keyof table["schema"], table["key"][number]>]: table["schema"][fieldName];
};

export function getValueSchema<table extends Table>(table: table): getValueSchema<table> {
return Object.fromEntries(
Expand Down
4 changes: 2 additions & 2 deletions packages/store-indexer/src/postgres/apiRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Middleware } from "koa";
import Router from "@koa/router";
import compose from "koa-compose";
import { input } from "@latticexyz/store-sync/indexer-client";
import { storeTables } from "@latticexyz/store-sync";
import { schemasTable } from "@latticexyz/store-sync";
import { queryLogs } from "./queryLogs";
import { recordToLog } from "./recordToLog";
import { debug, error } from "../debug";
Expand All @@ -28,7 +28,7 @@ export function apiRoutes(database: Sql): Middleware {
}

try {
options.filters = options.filters.length > 0 ? [...options.filters, { tableId: storeTables.Tables.tableId }] : [];
options.filters = options.filters.length > 0 ? [...options.filters, { tableId: schemasTable.tableId }] : [];
const records = await queryLogs(database, options ?? {}).execute();
benchmark("query records");
const logs = records.map(recordToLog);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getAddress } from "viem";
import { PgDatabase } from "drizzle-orm/pg-core";
import { TableWithRecords, isTableRegistrationLog, logToTable, storeTables } from "@latticexyz/store-sync";
import { decodeKey, decodeValueArgs } from "@latticexyz/protocol-parser/internal";
import { TableWithRecords, isTableRegistrationLog, logToTable, schemasTable } from "@latticexyz/store-sync";
import { KeySchema, decodeKey, decodeValueArgs } from "@latticexyz/protocol-parser/internal";
import { QueryAdapter } from "@latticexyz/store-sync/trpc-indexer";
import { debug } from "../../debug";
import { getLogs } from "./getLogs";
Expand All @@ -25,19 +25,20 @@ export async function createQueryAdapter(database: PgDatabase<any>): Promise<Que
const { blockNumber, logs } = await getLogs(database, {
...opts,
// make sure we're always retrieving `store.Tables` table, so we can decode table values
filters: filters.length > 0 ? [...filters, { tableId: storeTables.Tables.tableId }] : [],
filters: filters.length > 0 ? [...filters, { tableId: schemasTable.tableId }] : [],
});

const tables = logs.filter(isTableRegistrationLog).map(logToTable);

const logsByTable = groupBy(logs, (log) => `${getAddress(log.address)}:${log.args.tableId}`);

const tablesWithRecords: TableWithRecords[] = tables.map((table) => {
const tablesWithRecords: readonly TableWithRecords[] = tables.map((table) => {
const tableLogs = logsByTable.get(`${getAddress(table.address)}:${table.tableId}`) ?? [];
const records = tableLogs.map((log) => ({
key: decodeKey(table.keySchema, log.args.keyTuple),
value: decodeValueArgs(table.valueSchema, log.args),
}));
const records = tableLogs.map((log) => {
const key = decodeKey(table.keySchema as KeySchema, log.args.keyTuple);
const value = decodeValueArgs(table.valueSchema, log.args);
return { key, value, fields: { ...key, ...value } };
});

return {
...table,
Expand Down
4 changes: 2 additions & 2 deletions packages/store-indexer/src/sqlite/apiRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Middleware } from "koa";
import Router from "@koa/router";
import compose from "koa-compose";
import { input } from "@latticexyz/store-sync/indexer-client";
import { storeTables, tablesWithRecordsToLogs } from "@latticexyz/store-sync";
import { schemasTable, tablesWithRecordsToLogs } from "@latticexyz/store-sync";
import { debug } from "../debug";
import { createBenchmark } from "@latticexyz/common";
import { compress } from "../koa-middleware/compress";
Expand All @@ -28,7 +28,7 @@ export function apiRoutes(database: BaseSQLiteDatabase<"sync", any>): Middleware
}

try {
options.filters = options.filters.length > 0 ? [...options.filters, { tableId: storeTables.Tables.tableId }] : [];
options.filters = options.filters.length > 0 ? [...options.filters, { tableId: schemasTable.tableId }] : [];
benchmark("parse config");
const { blockNumber, tables } = getTablesWithRecords(database, options);
benchmark("query tables with records");
Expand Down
19 changes: 13 additions & 6 deletions packages/store-indexer/src/sqlite/getTablesWithRecords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
import { buildTable, chainState, getTables } from "@latticexyz/store-sync/sqlite";
import { Hex, getAddress } from "viem";
import { decodeDynamicField } from "@latticexyz/protocol-parser/internal";
import { SyncFilter, TableWithRecords } from "@latticexyz/store-sync";
import { SyncFilter, TableRecord, TableWithRecords } from "@latticexyz/store-sync";
import { hexToResource } from "@latticexyz/common";
import { mapObject } from "@latticexyz/common/utils";

// TODO: refactor sqlite and replace this with getLogs to match postgres (https://github.com/latticexyz/mud/issues/1970)

Expand Down Expand Up @@ -60,13 +62,18 @@ export function getTablesWithRecords(
(filter.key1 == null || filter.key1 === keyTuple[1]),
);
});
const resource = hexToResource(table.tableId);
return {
...table,
records: filteredRecords.map((record) => ({
key: Object.fromEntries(Object.entries(table.keySchema).map(([name]) => [name, record[name]])),
value: Object.fromEntries(Object.entries(table.valueSchema).map(([name]) => [name, record[name]])),
})),
};
type: resource.type as never,
schema: mapObject({ ...table.keySchema, ...table.valueSchema }, (type) => ({ type, internalType: type })),
key: Object.keys(table.keySchema),
records: filteredRecords.map((record): TableRecord => {
const key = Object.fromEntries(Object.entries(table.keySchema).map(([name]) => [name, record[name]]));
const value = Object.fromEntries(Object.entries(table.valueSchema).map(([name]) => [name, record[name]]));
return { key, value, fields: { ...key, ...value } };
}),
} satisfies TableWithRecords;
});

return {
Expand Down
50 changes: 27 additions & 23 deletions packages/store-sync/src/common.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { Address, Block, Hex, Log, PublicClient, TransactionReceipt } from "viem";
import { StoreEventsAbiItem, StoreEventsAbi } from "@latticexyz/store";
import { resolveConfig } from "@latticexyz/store/internal";
import { Observable } from "rxjs";
import { UnionPick } from "@latticexyz/common/type-utils";
import { KeySchema, TableRecord, ValueSchema } from "@latticexyz/protocol-parser/internal";
import {
getKeySchema,
getSchemaPrimitives,
getSchemaTypes,
getValueSchema,
} from "@latticexyz/protocol-parser/internal";
import storeConfig from "@latticexyz/store/mud.config";
import worldConfig from "@latticexyz/world/mud.config";
import { flattenSchema } from "./flattenSchema";
import { Store as StoreConfig } from "@latticexyz/store";
import { storeToV1 } from "@latticexyz/store/config/v2";
import { Table as ConfigTable, Schema } from "@latticexyz/config";

/** @internal Temporary workaround until we redo our config parsing and can pull this directly from the config (https://github.com/latticexyz/mud/issues/1668) */
export const storeTables = resolveConfig(storeToV1(storeConfig)).tables;
/** @internal Temporary workaround until we redo our config parsing and can pull this directly from the config (https://github.com/latticexyz/mud/issues/1668) */
export const worldTables = resolveConfig(storeToV1(worldConfig)).tables;
export const storeTables = storeConfig.tables;
export type storeTables = typeof storeTables;

export const worldTables = worldConfig.tables;
export type worldTables = typeof worldTables;

export const internalTableIds = [...Object.values(storeTables), ...Object.values(worldTables)].map(
(table) => table.tableId,
Expand All @@ -22,19 +26,21 @@ export const internalTableIds = [...Object.values(storeTables), ...Object.values
export type ChainId = number;
export type WorldId = `${ChainId}:${Address}`;

export type TableNamespace = string;
export type TableName = string;
export type TableRecord<table extends ConfigTable = ConfigTable> = {
readonly key: getSchemaPrimitives<getKeySchema<table>>;
readonly value: getSchemaPrimitives<getValueSchema<table>>;
readonly fields: getSchemaPrimitives<table["schema"]>;
};

export type Table = {
address: Address;
tableId: Hex;
namespace: TableNamespace;
name: TableName;
keySchema: KeySchema;
valueSchema: ValueSchema;
export type Table<table extends ConfigTable = ConfigTable> = table & {
readonly address: Address;
readonly keySchema: getSchemaTypes<ConfigTable extends table ? Schema : getKeySchema<table>>;
readonly valueSchema: getSchemaTypes<ConfigTable extends table ? Schema : getValueSchema<table>>;
};

export type TableWithRecords = Table & { records: TableRecord[] };
export type TableWithRecords<table extends ConfigTable = ConfigTable> = Table<table> & {
readonly records: readonly TableRecord<table>[];
};

export type StoreEventsLog = Log<bigint, number, false, StoreEventsAbiItem, true, StoreEventsAbi>;
export type BlockLogs = { blockNumber: StoreEventsLog["blockNumber"]; logs: readonly StoreEventsLog[] };
Expand Down Expand Up @@ -127,10 +133,8 @@ export type StorageAdapterLog = Partial<StoreEventsLog> & UnionPick<StoreEventsL
export type StorageAdapterBlock = { blockNumber: BlockLogs["blockNumber"]; logs: readonly StorageAdapterLog[] };
export type StorageAdapter = (block: StorageAdapterBlock) => Promise<void>;

export const schemasTableId = storeTables.Tables.tableId;
export const schemasTable = {
...storeTables.Tables,
// TODO: remove once we've got everything using the new Table shape
keySchema: flattenSchema(storeTables.Tables.keySchema),
valueSchema: flattenSchema(storeTables.Tables.valueSchema),
...storeTables.store__Tables,
keySchema: getSchemaTypes(getKeySchema(storeTables.store__Tables)),
valueSchema: getSchemaTypes(getValueSchema(storeTables.store__Tables)),
};
8 changes: 0 additions & 8 deletions packages/store-sync/src/flattenSchema.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/store-sync/src/isTableRegistrationLog.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { StorageAdapterLog, storeTables } from "./common";
import { StorageAdapterLog, schemasTable } from "./common";

/**
* @internal
*/
export function isTableRegistrationLog(
log: StorageAdapterLog,
): log is StorageAdapterLog & { eventName: "Store_SetRecord" } {
return log.eventName === "Store_SetRecord" && log.args.tableId === storeTables.Tables.tableId;
return log.eventName === "Store_SetRecord" && log.args.tableId === schemasTable.tableId;
}
31 changes: 31 additions & 0 deletions packages/store-sync/src/logToTable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,43 @@ describe("logToTable", () => {
).toMatchInlineSnapshot(`
{
"address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
"key": [
"tableId",
],
"keySchema": {
"tableId": "bytes32",
},
"name": "Tables",
"namespace": "mudstore",
"resourceId": "0x74626d756473746f72650000000000005461626c657300000000000000000000",
"schema": {
"abiEncodedFieldNames": {
"internalType": "bytes",
"type": "bytes",
},
"abiEncodedKeyNames": {
"internalType": "bytes",
"type": "bytes",
},
"fieldLayout": {
"internalType": "bytes32",
"type": "bytes32",
},
"keySchema": {
"internalType": "bytes32",
"type": "bytes32",
},
"tableId": {
"internalType": "bytes32",
"type": "bytes32",
},
"valueSchema": {
"internalType": "bytes32",
"type": "bytes32",
},
},
"tableId": "0x74626d756473746f72650000000000005461626c657300000000000000000000",
"type": "table",
"valueSchema": {
"abiEncodedFieldNames": "bytes",
"abiEncodedKeyNames": "bytes",
Expand Down
42 changes: 22 additions & 20 deletions packages/store-sync/src/logToTable.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { hexToSchema, decodeValue, ValueSchema } from "@latticexyz/protocol-parser/internal";
import { Hex, concatHex, decodeAbiParameters, parseAbiParameters } from "viem";
import { hexToSchema, decodeValue, getSchemaTypes } from "@latticexyz/protocol-parser/internal";
import { concatHex, decodeAbiParameters, parseAbiParameters } from "viem";
import { StorageAdapterLog, Table, schemasTable } from "./common";
import { hexToResource } from "@latticexyz/common";
import { Schema } from "@latticexyz/config";

/**
* @internal
Expand All @@ -12,34 +13,35 @@ export function logToTable(log: StorageAdapterLog & { eventName: "Store_SetRecor
console.warn("registerSchema event is expected to have only one key in key tuple, but got multiple", log);
}

const table = hexToResource(tableId);
const resource = hexToResource(tableId);

const value = decodeValue(
// TODO: remove cast when we have strong types for user types
schemasTable.valueSchema as ValueSchema,
schemasTable.valueSchema,
concatHex([log.args.staticData, log.args.encodedLengths, log.args.dynamicData]),
);

// TODO: remove cast when we have strong types for user types
const keySchema = hexToSchema(value.keySchema as Hex);
const solidityKeySchema = hexToSchema(value.keySchema);
const solidityValueSchema = hexToSchema(value.valueSchema);
const keyNames = decodeAbiParameters(parseAbiParameters("string[]"), value.abiEncodedKeyNames)[0];
const fieldNames = decodeAbiParameters(parseAbiParameters("string[]"), value.abiEncodedFieldNames)[0];

// TODO: remove cast when we have strong types for user types
const valueSchema = hexToSchema(value.valueSchema as Hex);
const valueAbiTypes = [...solidityValueSchema.staticFields, ...solidityValueSchema.dynamicFields];

// TODO: remove cast when we have strong types for user types
const keyNames = decodeAbiParameters(parseAbiParameters("string[]"), value.abiEncodedKeyNames as Hex)[0];
const keySchema = Object.fromEntries(
solidityKeySchema.staticFields.map((abiType, i) => [keyNames[i], { type: abiType, internalType: abiType }]),
) satisfies Schema;

// TODO: remove cast when we have strong types for user types
const fieldNames = decodeAbiParameters(parseAbiParameters("string[]"), value.abiEncodedFieldNames as Hex)[0];

const valueAbiTypes = [...valueSchema.staticFields, ...valueSchema.dynamicFields];
const valueSchema = Object.fromEntries(
valueAbiTypes.map((abiType, i) => [fieldNames[i], { type: abiType, internalType: abiType }]),
) satisfies Schema;

return {
address: log.address,
...resource,
tableId,
namespace: table.namespace,
name: table.name,
keySchema: Object.fromEntries(keySchema.staticFields.map((abiType, i) => [keyNames[i], abiType])),
valueSchema: Object.fromEntries(valueAbiTypes.map((abiType, i) => [fieldNames[i], abiType])),
};
schema: { ...keySchema, ...valueSchema },
key: Object.keys(keySchema),
keySchema: getSchemaTypes(keySchema),
valueSchema: getSchemaTypes(valueSchema),
} as never;
}
Loading

0 comments on commit b62cf9f

Please sign in to comment.