Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(store-sync): remove remaining refs to old config #2938

Merged
merged 8 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading