diff --git a/packages/stash/src/actions/runQuery.test.ts b/packages/stash/src/actions/runQuery.test.ts index 123d7ee795..681021e6b2 100644 --- a/packages/stash/src/actions/runQuery.test.ts +++ b/packages/stash/src/actions/runQuery.test.ts @@ -5,7 +5,7 @@ import { runQuery } from "./runQuery"; import { defineStore } from "@latticexyz/store"; import { Stash, StoreRecords, getQueryConfig } from "../common"; import { setRecord } from "./setRecord"; -import { In, MatchRecord, NotIn, NotMatchRecord } from "../queryFragments"; +import { In, Matches, NotIn, NotMatches } from "../queryFragments"; import { Hex } from "viem"; describe("runQuery", () => { @@ -79,7 +79,7 @@ describe("runQuery", () => { }); it("should return all keys that have Position.x = 4 and are included in Health", () => { - const result = runQuery({ stash, query: [MatchRecord(Position, { x: 4 }), In(Health)] }); + const result = runQuery({ stash, query: [Matches(Position, { x: 4 }), In(Health)] }); attest(result).snap({ keys: { "0x4": { player: "0x4" } } }); }); @@ -95,7 +95,7 @@ describe("runQuery", () => { }); it("should return all keys that don't include a gold item in the Inventory table", () => { - const result = runQuery({ stash, query: [NotMatchRecord(Inventory, { item: "0xgold" })] }); + const result = runQuery({ stash, query: [NotMatches(Inventory, { item: "0xgold" })] }); attest(result).snap({ keys: { "0x0|0xsilver": { player: "0x0", item: "0xsilver" }, @@ -108,9 +108,9 @@ describe("runQuery", () => { }); it("should throw an error when tables with different key schemas are mixed", () => { - attest(() => - runQuery({ stash, query: [In(Position), MatchRecord(Inventory, { item: "0xgold", amount: 2 })] }), - ).throws("All tables in a query must share the same key schema"); + attest(() => runQuery({ stash, query: [In(Position), Matches(Inventory, { item: "0xgold", amount: 2 })] })).throws( + "All tables in a query must share the same key schema", + ); }); it("should include all matching records from the tables if includeRecords is set", () => { diff --git a/packages/stash/src/actions/runQuery.ts b/packages/stash/src/actions/runQuery.ts index 46cf77039f..8948455ea1 100644 --- a/packages/stash/src/actions/runQuery.ts +++ b/packages/stash/src/actions/runQuery.ts @@ -62,7 +62,7 @@ export function runQuery({ for (const fragment of query) { // TODO: this might be more efficient if we would use a Map() instead of an object for (const encodedKey of Object.keys(keys)) { - if (!fragment.match(stash, encodedKey)) { + if (!fragment.pass(stash, encodedKey)) { delete keys[encodedKey]; } } diff --git a/packages/stash/src/actions/subscribeQuery.test.ts b/packages/stash/src/actions/subscribeQuery.test.ts index 80ea8ff12c..67edd9051a 100644 --- a/packages/stash/src/actions/subscribeQuery.test.ts +++ b/packages/stash/src/actions/subscribeQuery.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, it, vi, expect } from "vitest"; import { QueryUpdate, subscribeQuery } from "./subscribeQuery"; import { attest } from "@arktype/attest"; import { defineStore } from "@latticexyz/store"; -import { In, MatchRecord } from "../queryFragments"; +import { In, Matches } from "../queryFragments"; import { deleteRecord } from "./deleteRecord"; import { setRecord } from "./setRecord"; import { Stash } from "../common"; @@ -66,7 +66,7 @@ describe("defineQuery", () => { it("should notify subscribers when a matching key is updated", () => { let lastUpdate: unknown; const subscriber = vi.fn((update: QueryUpdate) => (lastUpdate = update)); - const result = subscribeQuery({ stash, query: [MatchRecord(Position, { x: 4 }), In(Health)] }); + const result = subscribeQuery({ stash, query: [Matches(Position, { x: 4 }), In(Health)] }); result.subscribe(subscriber); setRecord({ stash, table: Position, key: { player: "0x4" }, record: { y: 2 } }); diff --git a/packages/stash/src/actions/subscribeQuery.ts b/packages/stash/src/actions/subscribeQuery.ts index 0d49f12259..2edb4bbf86 100644 --- a/packages/stash/src/actions/subscribeQuery.ts +++ b/packages/stash/src/actions/subscribeQuery.ts @@ -94,7 +94,7 @@ export function subscribeQuery({ update.keys[key] = matching[key]; // If the key matched before, check if the relevant fragments (accessing this table) still match const relevantFragments = query.filter((f) => f.table.namespace === namespaceLabel && f.table.label === label); - const match = relevantFragments.every((f) => f.match(stash, key)); + const match = relevantFragments.every((f) => f.pass(stash, key)); if (match) { // If all relevant fragments still match, the key still matches the query. update.types[key] = "update"; @@ -105,7 +105,7 @@ export function subscribeQuery({ } } else { // If this key didn't match the query before, check all fragments - const match = query.every((f) => f.match(stash, key)); + const match = query.every((f) => f.pass(stash, key)); if (match) { // Since the key schema of query fragments has to match, we can pick any fragment to decode they key const decodedKey = decodeKey({ stash, table: query[0].table, encodedKey: key }); diff --git a/packages/stash/src/queryFragments.ts b/packages/stash/src/queryFragments.ts index 77a712a233..50444d69ff 100644 --- a/packages/stash/src/queryFragments.ts +++ b/packages/stash/src/queryFragments.ts @@ -4,8 +4,6 @@ import { TableRecord } from "./common"; import { getRecords } from "./actions/getRecords"; import { getKeys } from "./actions/getKeys"; -// TODO: add more query fragments - ie GreaterThan, LessThan, Range, etc - /** * Compare two {@link TableRecord}s. * `a` can be a partial record, in which case only the keys present in `a` are compared to the corresponding keys in `b`. @@ -36,7 +34,7 @@ export type QueryFragment = { /** * Checking an individual table row for whether it matches the query fragment */ - match: (stash: Stash, encodedKey: string) => boolean; + pass: (stash: Stash, encodedKey: string) => boolean; /** * The keys that should be included in the query result if this is the first fragment in the query. * This is to avoid having to iterate over each key in the first table if there is a more efficient @@ -50,9 +48,9 @@ export type QueryFragment
= { * RECS equivalent: Has(Component) */ export function In
(table: table): QueryFragment
{ - const match = (stash: Stash, encodedKey: string) => encodedKey in getRecords({ stash, table }); + const pass = (stash: Stash, encodedKey: string) => encodedKey in getRecords({ stash, table }); const getInitialKeys = (stash: Stash) => getKeys({ stash, table }); - return { table, match, getInitialKeys }; + return { table, pass, getInitialKeys }; } /** @@ -60,9 +58,9 @@ export function In
(table: table): QueryFragment
{ * RECS equivalent: Not(Component) */ export function NotIn
(table: table): QueryFragment
{ - const match = (stash: Stash, encodedKey: string) => !(encodedKey in getRecords({ stash, table })); + const pass = (stash: Stash, encodedKey: string) => !(encodedKey in getRecords({ stash, table })); const getInitialKeys = () => ({}); - return { table, match, getInitialKeys }; + return { table, pass, getInitialKeys }; } /** @@ -70,18 +68,18 @@ export function NotIn
(table: table): QueryFragment
{ * This works for both value and key, since both are part of the record. * RECS equivalent (only for value match): HasValue(Component, value) */ -export function MatchRecord
( +export function Matches
( table: table, partialRecord: Partial>, ): QueryFragment
{ - const match = (stash: Stash, encodedKey: string) => { + const pass = (stash: Stash, encodedKey: string) => { const record = getRecords({ stash, table })[encodedKey]; return recordMatches(partialRecord, record); }; // TODO: this is a very naive and inefficient implementation for large tables, can be optimized via indexer tables const getInitialKeys = (stash: Stash) => - Object.fromEntries(Object.entries(getKeys({ stash, table })).filter(([key]) => match(stash, key))); - return { table, match, getInitialKeys }; + Object.fromEntries(Object.entries(getKeys({ stash, table })).filter(([key]) => pass(stash, key))); + return { table, pass, getInitialKeys }; } /** @@ -91,16 +89,16 @@ export function MatchRecord
( * @param table * @param partialRecord */ -export function NotMatchRecord
( +export function NotMatches
( table: table, partialRecord: Partial>, ): QueryFragment
{ - const match = (stash: Stash, encodedKey: string) => { + const pass = (stash: Stash, encodedKey: string) => { const record = getRecords({ stash, table })[encodedKey]; return !recordMatches(partialRecord, record); }; // TODO: this is a very naive and inefficient implementation for large tables, can be optimized via indexer tables const getInitialKeys = (stash: Stash) => - Object.fromEntries(Object.entries(getKeys({ stash, table })).filter(([key]) => match(stash, key))); - return { table, match, getInitialKeys }; + Object.fromEntries(Object.entries(getKeys({ stash, table })).filter(([key]) => pass(stash, key))); + return { table, pass, getInitialKeys }; }