Skip to content

Commit

Permalink
refactor(store-sync): move syncToZustand to new config (#2936)
Browse files Browse the repository at this point in the history
  • Loading branch information
holic authored Jul 11, 2024
1 parent 811049a commit 9e05278
Show file tree
Hide file tree
Showing 16 changed files with 208 additions and 89 deletions.
5 changes: 5 additions & 0 deletions .changeset/flat-swans-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/store-sync": patch
---

Refactored `syncToZustand` to use new Store config under the hood, removing compatibility layers and improving performance.
5 changes: 5 additions & 0 deletions .changeset/orange-beans-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/dev-tools": patch
---

Updated Zustand components after changes to `syncToZustand`.
4 changes: 4 additions & 0 deletions packages/config/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ export type Table = {
readonly schema: Schema;
readonly key: readonly string[];
};

export type Tables = {
readonly [label: string]: Table;
};
2 changes: 1 addition & 1 deletion packages/config/src/exports/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
* Be sure we're ready to commit to these being supported and changes made backward compatible!
*/

export type { AbiType, StaticAbiType, DynamicAbiType, Schema, Table } from "../common";
export type { AbiType, StaticAbiType, DynamicAbiType, Schema, Table, Tables } from "../common";
18 changes: 4 additions & 14 deletions packages/dev-tools/src/zustand/TableDataTable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Table } from "@latticexyz/store/internal";
import { useRecords } from "./useRecords";
import { FieldValue } from "./FieldValue";
import { Table } from "@latticexyz/store-sync/zustand";

// TODO: use react-table or similar for better perf with lots of logs

Expand All @@ -15,12 +15,7 @@ export function TableDataTable({ table }: Props) {
<table className="w-full -mx-1">
<thead className="sticky top-0 z-10 bg-slate-800 text-left">
<tr className="text-amber-200/80 font-mono">
{Object.keys(table.keySchema).map((name) => (
<th key={name} className="px-1.5 pt-1.5 font-normal">
{name}
</th>
))}
{Object.keys(table.valueSchema).map((name) => (
{Object.keys(table.schema).map((name) => (
<th key={name} className="px-1.5 pt-1.5 font-normal">
{name}
</th>
Expand All @@ -31,14 +26,9 @@ export function TableDataTable({ table }: Props) {
{records.map((record) => {
return (
<tr key={record.id}>
{Object.keys(table.keySchema).map((name) => (
<td key={name} className="px-1.5 whitespace-nowrap overflow-hidden text-ellipsis">
<FieldValue value={record.key[name]} />
</td>
))}
{Object.keys(table.valueSchema).map((name) => (
{Object.keys(table.schema).map((name) => (
<td key={name} className="px-1.5 whitespace-nowrap overflow-hidden text-ellipsis">
<FieldValue value={record.value[name]} />
<FieldValue value={record.fields[name]} />
</td>
))}
</tr>
Expand Down
3 changes: 1 addition & 2 deletions packages/dev-tools/src/zustand/useRecords.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Table } from "@latticexyz/store/internal";
import { useDevToolsContext } from "../DevToolsContext";
import { useEffect, useState } from "react";
import { TableRecord } from "@latticexyz/store-sync/zustand";
import { Table, TableRecord } from "@latticexyz/store-sync/zustand";

export function useRecords<table extends Table>(table: table): TableRecord<table>[] {
const { useStore } = useDevToolsContext();
Expand Down
2 changes: 1 addition & 1 deletion packages/dev-tools/src/zustand/useTables.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Table } from "@latticexyz/store/internal";
import { useDevToolsContext } from "../DevToolsContext";
import { useEffect, useState } from "react";
import { Table } from "@latticexyz/store-sync/zustand";

export function useTables(): Table[] {
const { useStore } = useDevToolsContext();
Expand Down
1 change: 1 addition & 0 deletions packages/protocol-parser/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type KeySchema<userTypes extends UserTypes | undefined = undefined> = Rec
string,
userTypes extends UserTypes ? StaticAbiType | keyof userTypes : StaticAbiType
>;

export type ValueSchema<userTypes extends UserTypes | undefined = undefined> = Record<
string,
userTypes extends UserTypes ? SchemaAbiType | keyof userTypes : SchemaAbiType
Expand Down
10 changes: 7 additions & 3 deletions packages/store-sync/src/zustand/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Table, SchemaToPrimitives } from "@latticexyz/store/internal";
import { Table } from "@latticexyz/config";
import { SchemaToPrimitives, getKeySchema, getSchemaTypes, getValueSchema } from "@latticexyz/protocol-parser/internal";
import { Hex } from "viem";

export type RawRecord = {
Expand All @@ -16,6 +17,9 @@ export type TableRecord<table extends Table = Table> = {
readonly id: string;
readonly table: table;
readonly keyTuple: readonly Hex[];
readonly key: SchemaToPrimitives<table["keySchema"]>;
readonly value: SchemaToPrimitives<table["valueSchema"]>;
readonly key: SchemaToPrimitives<getSchemaTypes<getKeySchema<table>>>;
readonly value: SchemaToPrimitives<getSchemaTypes<getValueSchema<table>>>;
readonly fields: SchemaToPrimitives<getSchemaTypes<table["schema"]>>;
};

export type { Table };
114 changes: 89 additions & 25 deletions packages/store-sync/src/zustand/createStorageAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { beforeAll, describe, expect, it } from "vitest";
import { storeEventsAbi } from "@latticexyz/store";
import { createStorageAdapter } from "./createStorageAdapter";
import { createStore } from "./createStore";
import { config, deployMockGame } from "../../test/mockGame";
import { configV2 as config, deployMockGame } from "../../test/mockGame";
import { fetchAndStoreLogs } from "../fetchAndStoreLogs";
import { testClient } from "../../test/common";
import { getBlockNumber } from "viem/actions";
Expand Down Expand Up @@ -34,6 +34,11 @@ describe("createStorageAdapter", async () => {
expect(useStore.getState().getRecords(config.tables.Position)).toMatchInlineSnapshot(`
{
"0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000078cf0753dd50f7c56f20b3ae02719ea199be2eb": {
"fields": {
"player": "0x078cf0753dd50f7C56F20B3Ae02719EA199BE2eb",
"x": 3,
"y": 5,
},
"id": "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000078cf0753dd50f7c56f20b3ae02719ea199be2eb",
"key": {
"player": "0x078cf0753dd50f7C56F20B3Ae02719EA199BE2eb",
Expand All @@ -42,16 +47,25 @@ describe("createStorageAdapter", async () => {
"0x000000000000000000000000078cf0753dd50f7c56f20b3ae02719ea199be2eb",
],
"table": {
"keySchema": {
"codegen": {
"dataStruct": true,
"outputDirectory": "tables",
"storeArgument": false,
"tableIdArgument": false,
},
"deploy": {
"disabled": false,
},
"key": [
"player",
],
"name": "Position",
"namespace": "",
"schema": {
"player": {
"internalType": "address",
"type": "address",
},
},
"name": "Position",
"namespace": "",
"tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000",
"valueSchema": {
"x": {
"internalType": "int32",
"type": "int32",
Expand All @@ -61,13 +75,20 @@ describe("createStorageAdapter", async () => {
"type": "int32",
},
},
"tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000",
"type": "table",
},
"value": {
"x": 3,
"y": 5,
},
},
"0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e": {
"fields": {
"player": "0x1D96F2f6BeF1202E4Ce1Ff6Dad0c2CB002861d3e",
"x": 1,
"y": -1,
},
"id": "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
"key": {
"player": "0x1D96F2f6BeF1202E4Ce1Ff6Dad0c2CB002861d3e",
Expand All @@ -76,16 +97,25 @@ describe("createStorageAdapter", async () => {
"0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
],
"table": {
"keySchema": {
"codegen": {
"dataStruct": true,
"outputDirectory": "tables",
"storeArgument": false,
"tableIdArgument": false,
},
"deploy": {
"disabled": false,
},
"key": [
"player",
],
"name": "Position",
"namespace": "",
"schema": {
"player": {
"internalType": "address",
"type": "address",
},
},
"name": "Position",
"namespace": "",
"tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000",
"valueSchema": {
"x": {
"internalType": "int32",
"type": "int32",
Expand All @@ -95,13 +125,20 @@ describe("createStorageAdapter", async () => {
"type": "int32",
},
},
"tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000",
"type": "table",
},
"value": {
"x": 1,
"y": -1,
},
},
"0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6": {
"fields": {
"player": "0x328809Bc894f92807417D2dAD6b7C998c1aFdac6",
"x": 3,
"y": 5,
},
"id": "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6",
"key": {
"player": "0x328809Bc894f92807417D2dAD6b7C998c1aFdac6",
Expand All @@ -110,16 +147,25 @@ describe("createStorageAdapter", async () => {
"0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6",
],
"table": {
"keySchema": {
"codegen": {
"dataStruct": true,
"outputDirectory": "tables",
"storeArgument": false,
"tableIdArgument": false,
},
"deploy": {
"disabled": false,
},
"key": [
"player",
],
"name": "Position",
"namespace": "",
"schema": {
"player": {
"internalType": "address",
"type": "address",
},
},
"name": "Position",
"namespace": "",
"tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000",
"valueSchema": {
"x": {
"internalType": "int32",
"type": "int32",
Expand All @@ -129,13 +175,20 @@ describe("createStorageAdapter", async () => {
"type": "int32",
},
},
"tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000",
"type": "table",
},
"value": {
"x": 3,
"y": 5,
},
},
"0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000dba86119a787422c593cef119e40887f396024e2": {
"fields": {
"player": "0xdBa86119a787422C593ceF119E40887f396024E2",
"x": 100,
"y": 100,
},
"id": "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000dba86119a787422c593cef119e40887f396024e2",
"key": {
"player": "0xdBa86119a787422C593ceF119E40887f396024E2",
Expand All @@ -144,16 +197,25 @@ describe("createStorageAdapter", async () => {
"0x000000000000000000000000dba86119a787422c593cef119e40887f396024e2",
],
"table": {
"keySchema": {
"codegen": {
"dataStruct": true,
"outputDirectory": "tables",
"storeArgument": false,
"tableIdArgument": false,
},
"deploy": {
"disabled": false,
},
"key": [
"player",
],
"name": "Position",
"namespace": "",
"schema": {
"player": {
"internalType": "address",
"type": "address",
},
},
"name": "Position",
"namespace": "",
"tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000",
"valueSchema": {
"x": {
"internalType": "int32",
"type": "int32",
Expand All @@ -163,6 +225,8 @@ describe("createStorageAdapter", async () => {
"type": "int32",
},
},
"tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000",
"type": "table",
},
"value": {
"x": 100,
Expand Down
23 changes: 18 additions & 5 deletions packages/store-sync/src/zustand/createStorageAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { Tables } from "@latticexyz/store/internal";
import { StorageAdapter } from "../common";
import { RawRecord, TableRecord } from "./common";
import { ZustandStore } from "./createStore";
import { hexToResource, resourceToLabel, spliceHex } from "@latticexyz/common";
import { debug } from "./debug";
import { getId } from "./getId";
import { size } from "viem";
import { decodeKey, decodeValueArgs } from "@latticexyz/protocol-parser/internal";
import { flattenSchema } from "../flattenSchema";
import {
KeySchema,
decodeKey,
decodeValueArgs,
getKeySchema,
getSchemaTypes,
getValueSchema,
} from "@latticexyz/protocol-parser/internal";
import { isDefined } from "@latticexyz/common/utils";
import { Tables } from "@latticexyz/config";

export type CreateStorageAdapterOptions<tables extends Tables> = {
store: ZustandStore<tables>;
Expand Down Expand Up @@ -131,14 +137,21 @@ export function createStorageAdapter<tables extends Tables>({
return;
}
// TODO: warn if no table

// TODO: update decodeKey to use more recent types
const key = decodeKey(getSchemaTypes(getKeySchema(table)) as KeySchema, rawRecord.keyTuple);
// TODO: update decodeValueArgs to use more recent types
const value = decodeValueArgs(getSchemaTypes(getValueSchema(table)), rawRecord);

return [
id,
{
id,
table: store.getState().tables[rawRecord.tableId],
keyTuple: rawRecord.keyTuple,
key: decodeKey(flattenSchema(table.keySchema), rawRecord.keyTuple),
value: decodeValueArgs(flattenSchema(table.valueSchema), rawRecord),
key,
value,
fields: { ...key, ...value },
} satisfies TableRecord,
];
})
Expand Down
Loading

0 comments on commit 9e05278

Please sign in to comment.