@fragno-dev/lofi 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/adapters/in-memory/adapter.d.ts.map +1 -1
  2. package/dist/adapters/in-memory/adapter.js.map +1 -1
  3. package/dist/adapters/in-memory/query.js +1 -2
  4. package/dist/adapters/in-memory/query.js.map +1 -1
  5. package/dist/adapters/in-memory/store.d.ts.map +1 -1
  6. package/dist/adapters/in-memory/store.js +1 -1
  7. package/dist/adapters/in-memory/store.js.map +1 -1
  8. package/dist/adapters/stacked/adapter.d.ts.map +1 -1
  9. package/dist/adapters/stacked/adapter.js.map +1 -1
  10. package/dist/adapters/stacked/merge.js.map +1 -1
  11. package/dist/cli/client.js +1 -1
  12. package/dist/cli/client.js.map +1 -1
  13. package/dist/cli/index.d.ts.map +1 -1
  14. package/dist/cli/index.js +2 -2
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/scenario.js +1 -1
  17. package/dist/cli/scenario.js.map +1 -1
  18. package/dist/cli/server.js +1 -1
  19. package/dist/cli/server.js.map +1 -1
  20. package/dist/client/client.d.ts.map +1 -1
  21. package/dist/client/client.js.map +1 -1
  22. package/dist/indexeddb/adapter.d.ts.map +1 -1
  23. package/dist/indexeddb/adapter.js +1 -1
  24. package/dist/indexeddb/adapter.js.map +1 -1
  25. package/dist/optimistic/overlay-manager.d.ts.map +1 -1
  26. package/dist/optimistic/overlay-manager.js +0 -1
  27. package/dist/optimistic/overlay-manager.js.map +1 -1
  28. package/dist/outbox/decode.d.ts.map +1 -1
  29. package/dist/outbox/decode.js.map +1 -1
  30. package/dist/outbox/uow.d.ts.map +1 -1
  31. package/dist/outbox/uow.js.map +1 -1
  32. package/dist/query/conditions.d.ts +2 -1
  33. package/dist/query/conditions.d.ts.map +1 -1
  34. package/dist/query/conditions.js +2 -1
  35. package/dist/query/conditions.js.map +1 -1
  36. package/dist/query/engine.d.ts.map +1 -1
  37. package/dist/query/engine.js +1 -1
  38. package/dist/query/engine.js.map +1 -1
  39. package/dist/scenario.d.ts.map +1 -1
  40. package/dist/scenario.js.map +1 -1
  41. package/dist/submit/client.d.ts.map +1 -1
  42. package/dist/submit/client.js.map +1 -1
  43. package/dist/submit/local-handler-tx.d.ts.map +1 -1
  44. package/dist/submit/local-handler-tx.js.map +1 -1
  45. package/dist/submit/queue.js.map +1 -1
  46. package/dist/submit/rebase.d.ts.map +1 -1
  47. package/dist/submit/rebase.js.map +1 -1
  48. package/dist/types.d.ts.map +1 -1
  49. package/package.json +23 -26
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","names":[],"sources":["../../../src/adapters/in-memory/adapter.ts"],"sourcesContent":[],"mappings":";;;;;cAmBa,mBAAA,YAA+B,aAAa;;EAA5C,SAAA,OAAA,EAEO,SAFa,EAAA;EAEb,SAAA,KAAA,EACF,iBADE;EACF,iBAAA,SAAA;EAOK,iBAAA,QAAA;EAwCR,iBAAA,oBAAA;EACT,iBAAA,IAAA;EAuC4B,iBAAA,KAAA;EAAiB,WAAA,CAAA,OAAA,EAhF5B,0BAgF4B;EA6BrB,gBAAA,CAAA,OAAA,EAAA;IAIe,SAAA,EAAA,MAAA;IAIT,YAAA,EAAA,MAAA;IACxB,KAAA,EAAA,MAAA;IACE,SAAA,EA/EC,YA+ED,EAAA;EACU,CAAA,CAAA,EA/ElB,OA+EkB,CAAA;IAAnB,OAAA,EAAA,OAAA;EAlIuC,CAAA,CAAA;EAAa,cAAA,CAAA,SAAA,EA0FvB,YA1FuB,EAAA,CAAA,EA0FN,OA1FM,CAAA,IAAA,CAAA;EAAoB,OAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAuH/C,OAvH+C,CAAA,MAAA,GAAA,SAAA,CAAA;uCA2HhC;oCAIT,mBACxB,aACE,yBACT,mBAAmB"}
1
+ {"version":3,"file":"adapter.d.ts","names":[],"sources":["../../../src/adapters/in-memory/adapter.ts"],"sourcesContent":[],"mappings":";;;;;cAoBa,mBAAA,YAA+B,aAAa;;EAA5C,SAAA,OAAA,EAEO,SAFa,EAAA;EAEb,SAAA,KAAA,EACF,iBADE;EACF,iBAAA,SAAA;EAOK,iBAAA,QAAA;EAwCR,iBAAA,oBAAA;EACT,iBAAA,IAAA;EAuC4B,iBAAA,KAAA;EAAiB,WAAA,CAAA,OAAA,EAhF5B,0BAgF4B;EA6BrB,gBAAA,CAAA,OAAA,EAAA;IAIe,SAAA,EAAA,MAAA;IAIT,YAAA,EAAA,MAAA;IACxB,KAAA,EAAA,MAAA;IACE,SAAA,EA/EC,YA+ED,EAAA;EACU,CAAA,CAAA,EA/ElB,OA+EkB,CAAA;IAAnB,OAAA,EAAA,OAAA;EAlIuC,CAAA,CAAA;EAAa,cAAA,CAAA,SAAA,EA0FvB,YA1FuB,EAAA,CAAA,EA0FN,OA1FM,CAAA,IAAA,CAAA;EAAoB,OAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAuH/C,OAvH+C,CAAA,MAAA,GAAA,SAAA,CAAA;uCA2HhC;oCAIT,mBACxB,aACE,yBACT,mBAAmB"}
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","names":["knownMutations: LofiMutation[]"],"sources":["../../../src/adapters/in-memory/adapter.ts"],"sourcesContent":["import type { AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\nimport type {\n InMemoryLofiAdapterOptions,\n LofiAdapter,\n LofiMutation,\n LofiQueryEngineOptions,\n LofiQueryInterface,\n LofiQueryableAdapter,\n} from \"../../types\";\nimport { createInMemoryQueryEngine } from \"./query\";\nimport { InMemoryLofiStore } from \"./store\";\n\ntype InboxRow = {\n sourceKey: string;\n uowId: string;\n versionstamp: string;\n receivedAt: number;\n};\n\nexport class InMemoryLofiAdapter implements LofiAdapter, LofiQueryableAdapter {\n readonly endpointName: string;\n readonly schemas: AnySchema[];\n readonly store: InMemoryLofiStore;\n private readonly schemaMap: Map<string, AnySchema>;\n private readonly tableMap: Map<string, Map<string, AnyTable>>;\n private readonly ignoreUnknownSchemas: boolean;\n private readonly meta = new Map<string, string>();\n private readonly inbox = new Map<string, InboxRow>();\n\n constructor(options: InMemoryLofiAdapterOptions) {\n if (!options.endpointName || options.endpointName.trim().length === 0) {\n throw new Error(\"InMemoryLofiAdapter requires a non-empty endpointName.\");\n }\n\n const schemaMap = new Map<string, AnySchema>();\n const tableMap = new Map<string, Map<string, AnyTable>>();\n\n for (const schema of options.schemas) {\n if (!schema.name || schema.name.trim().length === 0) {\n throw new Error(\"InMemoryLofiAdapter schemas must have a non-empty name.\");\n }\n if (schemaMap.has(schema.name)) {\n throw new Error(`InMemoryLofiAdapter schema name must be unique: ${schema.name}`);\n }\n schemaMap.set(schema.name, schema);\n const tables = new Map<string, AnyTable>();\n for (const [tableName, table] of Object.entries(schema.tables)) {\n tables.set(tableName, table);\n }\n tableMap.set(schema.name, tables);\n }\n\n this.endpointName = options.endpointName;\n this.schemas = [...schemaMap.values()];\n this.schemaMap = schemaMap;\n this.tableMap = tableMap;\n this.ignoreUnknownSchemas = options.ignoreUnknownSchemas ?? false;\n this.store =\n options.store ??\n new InMemoryLofiStore({\n endpointName: this.endpointName,\n schemas: this.schemas,\n });\n }\n\n async applyOutboxEntry(options: {\n sourceKey: string;\n versionstamp: string;\n uowId: string;\n mutations: LofiMutation[];\n }): Promise<{ applied: boolean }> {\n const inboxKey = `${options.sourceKey}::${options.uowId}::${options.versionstamp}`;\n if (this.inbox.has(inboxKey)) {\n return { applied: false };\n }\n\n const knownMutations: LofiMutation[] = [];\n for (const mutation of options.mutations) {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown outbox schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown outbox table: ${mutation.schema}.${mutation.table}`);\n }\n knownMutations.push(mutation);\n }\n\n if (knownMutations.length > 0) {\n this.store.applyMutations(knownMutations);\n }\n\n this.inbox.set(inboxKey, {\n sourceKey: options.sourceKey,\n uowId: options.uowId,\n versionstamp: options.versionstamp,\n receivedAt: Date.now(),\n });\n\n return { applied: true };\n }\n\n async applyMutations(mutations: LofiMutation[]): Promise<void> {\n if (mutations.length === 0) {\n return;\n }\n\n const knownMutations: LofiMutation[] = [];\n for (const mutation of mutations) {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown mutation schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown mutation table: ${mutation.schema}.${mutation.table}`);\n }\n knownMutations.push(mutation);\n }\n\n if (knownMutations.length > 0) {\n this.store.applyMutations(knownMutations);\n }\n }\n\n async getMeta(key: string): Promise<string | undefined> {\n return this.meta.get(key);\n }\n\n async setMeta(key: string, value: string): Promise<void> {\n this.meta.set(key, value);\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n options?: LofiQueryEngineOptions,\n ): LofiQueryInterface<T> {\n return createInMemoryQueryEngine({\n schema,\n store: this.store,\n schemaName: options?.schemaName,\n });\n }\n\n clear(): void {\n this.store.clear();\n this.inbox.clear();\n }\n\n reset(): void {\n this.clear();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"adapter.js","names":["knownMutations: LofiMutation[]"],"sources":["../../../src/adapters/in-memory/adapter.ts"],"sourcesContent":["import type { AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\n\nimport type {\n InMemoryLofiAdapterOptions,\n LofiAdapter,\n LofiMutation,\n LofiQueryEngineOptions,\n LofiQueryInterface,\n LofiQueryableAdapter,\n} from \"../../types\";\nimport { createInMemoryQueryEngine } from \"./query\";\nimport { InMemoryLofiStore } from \"./store\";\n\ntype InboxRow = {\n sourceKey: string;\n uowId: string;\n versionstamp: string;\n receivedAt: number;\n};\n\nexport class InMemoryLofiAdapter implements LofiAdapter, LofiQueryableAdapter {\n readonly endpointName: string;\n readonly schemas: AnySchema[];\n readonly store: InMemoryLofiStore;\n private readonly schemaMap: Map<string, AnySchema>;\n private readonly tableMap: Map<string, Map<string, AnyTable>>;\n private readonly ignoreUnknownSchemas: boolean;\n private readonly meta = new Map<string, string>();\n private readonly inbox = new Map<string, InboxRow>();\n\n constructor(options: InMemoryLofiAdapterOptions) {\n if (!options.endpointName || options.endpointName.trim().length === 0) {\n throw new Error(\"InMemoryLofiAdapter requires a non-empty endpointName.\");\n }\n\n const schemaMap = new Map<string, AnySchema>();\n const tableMap = new Map<string, Map<string, AnyTable>>();\n\n for (const schema of options.schemas) {\n if (!schema.name || schema.name.trim().length === 0) {\n throw new Error(\"InMemoryLofiAdapter schemas must have a non-empty name.\");\n }\n if (schemaMap.has(schema.name)) {\n throw new Error(`InMemoryLofiAdapter schema name must be unique: ${schema.name}`);\n }\n schemaMap.set(schema.name, schema);\n const tables = new Map<string, AnyTable>();\n for (const [tableName, table] of Object.entries(schema.tables)) {\n tables.set(tableName, table);\n }\n tableMap.set(schema.name, tables);\n }\n\n this.endpointName = options.endpointName;\n this.schemas = [...schemaMap.values()];\n this.schemaMap = schemaMap;\n this.tableMap = tableMap;\n this.ignoreUnknownSchemas = options.ignoreUnknownSchemas ?? false;\n this.store =\n options.store ??\n new InMemoryLofiStore({\n endpointName: this.endpointName,\n schemas: this.schemas,\n });\n }\n\n async applyOutboxEntry(options: {\n sourceKey: string;\n versionstamp: string;\n uowId: string;\n mutations: LofiMutation[];\n }): Promise<{ applied: boolean }> {\n const inboxKey = `${options.sourceKey}::${options.uowId}::${options.versionstamp}`;\n if (this.inbox.has(inboxKey)) {\n return { applied: false };\n }\n\n const knownMutations: LofiMutation[] = [];\n for (const mutation of options.mutations) {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown outbox schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown outbox table: ${mutation.schema}.${mutation.table}`);\n }\n knownMutations.push(mutation);\n }\n\n if (knownMutations.length > 0) {\n this.store.applyMutations(knownMutations);\n }\n\n this.inbox.set(inboxKey, {\n sourceKey: options.sourceKey,\n uowId: options.uowId,\n versionstamp: options.versionstamp,\n receivedAt: Date.now(),\n });\n\n return { applied: true };\n }\n\n async applyMutations(mutations: LofiMutation[]): Promise<void> {\n if (mutations.length === 0) {\n return;\n }\n\n const knownMutations: LofiMutation[] = [];\n for (const mutation of mutations) {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown mutation schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n if (this.ignoreUnknownSchemas) {\n continue;\n }\n throw new Error(`Unknown mutation table: ${mutation.schema}.${mutation.table}`);\n }\n knownMutations.push(mutation);\n }\n\n if (knownMutations.length > 0) {\n this.store.applyMutations(knownMutations);\n }\n }\n\n async getMeta(key: string): Promise<string | undefined> {\n return this.meta.get(key);\n }\n\n async setMeta(key: string, value: string): Promise<void> {\n this.meta.set(key, value);\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n options?: LofiQueryEngineOptions,\n ): LofiQueryInterface<T> {\n return createInMemoryQueryEngine({\n schema,\n store: this.store,\n schemaName: options?.schemaName,\n });\n }\n\n clear(): void {\n this.store.clear();\n this.inbox.clear();\n }\n\n reset(): void {\n this.clear();\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
- import { normalizeValue } from "../../query/normalize.js";
2
1
  import { buildCondition } from "../../query/conditions.js";
2
+ import { normalizeValue } from "../../query/normalize.js";
3
3
  import { compareNormalizedValues } from "./value-comparison.js";
4
- import "./store.js";
5
4
  import { Column, FragnoId, FragnoReference } from "@fragno-dev/db/schema";
6
5
  import { Cursor, createCursorFromRecord, decodeCursor } from "@fragno-dev/db/cursor";
7
6
  import { FindBuilder } from "@fragno-dev/db/unit-of-work";
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","names":["selected: RowSelection","prefixed: RowSelection","output: Record<string, unknown>","columnValues: Record<string, unknown>","relationData: Record<string, Record<string, unknown>>","exhaustiveCheck: never","matches","matches: InMemoryLofiRow[]","outputs: RowSelection[]","nextOutputs: RowSelection[]","filtered: InMemoryLofiRow[]","results: RowSelection[]","resultSources: InMemoryLofiRow[]","cursor: Cursor | undefined","cursorRecord: Record<string, unknown>","context: QueryContext"],"sources":["../../../src/adapters/in-memory/query.ts"],"sourcesContent":["import type { AnyColumn, AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\nimport { Column, FragnoId, FragnoReference } from \"@fragno-dev/db/schema\";\nimport type { CursorResult } from \"@fragno-dev/db/cursor\";\nimport { Cursor, createCursorFromRecord, decodeCursor } from \"@fragno-dev/db/cursor\";\nimport { FindBuilder } from \"@fragno-dev/db/unit-of-work\";\nimport type { LofiQueryInterface } from \"../../types\";\nimport type { ReferenceTarget } from \"../../indexeddb/types\";\nimport { normalizeValue } from \"../../query/normalize\";\nimport { buildCondition, type Condition, type ConditionBuilder } from \"../../query/conditions\";\nimport { compareNormalizedValues } from \"./value-comparison\";\nimport type { InMemoryLofiRow } from \"./store\";\nimport { InMemoryLofiStore } from \"./store\";\n\nexport type InMemoryQueryContext = {\n endpointName: string;\n schemaName: string;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n};\n\ntype QueryContext = InMemoryQueryContext;\n\ntype RowSelection = Record<string, unknown>;\n\ntype CompiledJoin = {\n relation: { name: string; table: AnyTable; on: [string, string][] };\n options:\n | {\n select: unknown;\n where?: Condition;\n orderBy?: [AnyColumn, \"asc\" | \"desc\"][];\n join?: CompiledJoin[];\n limit?: number;\n }\n | false;\n};\n\nconst isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined;\n\nconst toByteArray = (value: unknown): Uint8Array | null => {\n if (value instanceof Uint8Array) {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n return null;\n};\n\nconst bytesToHex = (bytes: Uint8Array): string => {\n let hex = \"\";\n for (const byte of bytes) {\n hex += byte.toString(16).padStart(2, \"0\");\n }\n return hex;\n};\n\ntype DbNow = { tag: \"db-now\" };\n\nconst isDbNow = (value: unknown): value is DbNow =>\n typeof value === \"object\" && value !== null && (value as { tag?: string }).tag === \"db-now\";\n\nconst resolveFragnoIdValue = (value: unknown, col: AnyColumn): unknown => {\n if (value instanceof FragnoReference) {\n return value.internalId;\n }\n\n if (value instanceof FragnoId) {\n if (col.role === \"external-id\") {\n return value.externalId;\n }\n if (col.role === \"internal-id\") {\n if (value.internalId === undefined) {\n throw new Error(`FragnoId must have internalId for internal-id column ${col.name}`);\n }\n return value.internalId;\n }\n if (col.role === \"reference\") {\n return value.databaseId;\n }\n return value.externalId;\n }\n\n return value;\n};\n\nconst buildSelection = (\n table: AnyTable,\n select: undefined | true | readonly string[],\n): Set<string> => {\n const selection = new Set<string>();\n\n if (!select || select === true) {\n for (const columnName of Object.keys(table.columns)) {\n selection.add(columnName);\n }\n } else {\n for (const columnName of select) {\n selection.add(columnName);\n }\n }\n\n selection.add(\"_internalId\");\n selection.add(\"_version\");\n\n return selection;\n};\n\nconst getColumnValue = (row: InMemoryLofiRow, columnName: string, column: AnyColumn): unknown => {\n if (column.role === \"external-id\") {\n return row.id;\n }\n if (column.role === \"internal-id\") {\n return row._lofi.internalId;\n }\n if (column.role === \"version\") {\n return row._lofi.version;\n }\n\n return row.data[columnName];\n};\n\nconst selectRow = (\n row: InMemoryLofiRow,\n table: AnyTable,\n select: undefined | true | readonly string[],\n): RowSelection => {\n const selection = buildSelection(table, select);\n const selected: RowSelection = {};\n\n for (const columnName of selection) {\n if (columnName === \"_internalId\") {\n selected[columnName] = row._lofi.internalId;\n continue;\n }\n if (columnName === \"_version\") {\n selected[columnName] = row._lofi.version;\n continue;\n }\n\n const column = table.columns[columnName];\n if (!column) {\n continue;\n }\n\n if (column.role === \"reference\") {\n selected[columnName] = row._lofi.norm[columnName];\n continue;\n }\n\n selected[columnName] = getColumnValue(row, columnName, column);\n }\n\n return selected;\n};\n\nconst prefixSelection = (\n row: InMemoryLofiRow,\n table: AnyTable,\n select: undefined | true | readonly string[],\n prefix: string,\n): RowSelection => {\n const selected = selectRow(row, table, select);\n const prefixed: RowSelection = {};\n\n for (const key in selected) {\n prefixed[`${prefix}:${key}`] = selected[key];\n }\n\n return prefixed;\n};\n\nconst buildOutputValueForColumn = (row: InMemoryLofiRow, column: AnyColumn): unknown => {\n if (column.isHidden) {\n return undefined;\n }\n\n if (column.role === \"external-id\") {\n return new FragnoId({\n externalId: row.id,\n internalId: BigInt(row._lofi.internalId),\n version: row._lofi.version,\n });\n }\n\n if (column.role === \"reference\") {\n const value = row._lofi.norm[column.name];\n return value === null || value === undefined\n ? null\n : FragnoReference.fromInternal(BigInt(value as number));\n }\n\n if (column.role === \"internal-id\") {\n return BigInt(row._lofi.internalId);\n }\n\n if (column.role === \"version\") {\n return row._lofi.version;\n }\n\n return row.data[column.name];\n};\n\nconst decodeRow = (row: RowSelection, table: AnyTable): Record<string, unknown> => {\n const output: Record<string, unknown> = {};\n const columnValues: Record<string, unknown> = {};\n const relationData: Record<string, Record<string, unknown>> = {};\n\n for (const key in row) {\n const colonIndex = key.indexOf(\":\");\n if (colonIndex === -1) {\n if (table.columns[key]) {\n columnValues[key] = row[key];\n }\n continue;\n }\n\n const relationName = key.slice(0, colonIndex);\n const remainder = key.slice(colonIndex + 1);\n const relation = table.relations[relationName];\n if (!relation) {\n continue;\n }\n\n relationData[relationName] ??= {};\n relationData[relationName][remainder] = row[key];\n }\n\n for (const relationName in relationData) {\n const relation = table.relations[relationName];\n if (!relation) {\n continue;\n }\n output[relationName] = decodeRow(relationData[relationName], relation.table);\n }\n\n for (const key in columnValues) {\n const column = table.columns[key];\n if (!column || column.isHidden) {\n continue;\n }\n\n if (column.role === \"external-id\" && columnValues[\"_internalId\"] !== undefined) {\n output[key] = new FragnoId({\n externalId: columnValues[key] as string,\n internalId: BigInt(columnValues[\"_internalId\"] as number),\n version: columnValues[\"_version\"] as number,\n });\n continue;\n }\n\n if (column.role === \"reference\") {\n const value = columnValues[key];\n output[key] =\n value === null || value === undefined\n ? null\n : FragnoReference.fromInternal(BigInt(value as number));\n continue;\n }\n\n output[key] = columnValues[key];\n }\n\n return output;\n};\n\nconst coerceLocalInternalId = (value: unknown): number | unknown => {\n if (typeof value === \"bigint\") {\n const asNumber = Number(value);\n if (!Number.isSafeInteger(asNumber)) {\n throw new Error(`Local internalId is not a safe integer: ${value.toString()}`);\n }\n return asNumber;\n }\n return value;\n};\n\nconst resolveReferenceExternalId = (options: {\n value: string;\n schemaName: string;\n table: AnyTable;\n columnName: string;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): number | null => {\n const { value, schemaName, table, columnName, store, referenceTargets } = options;\n const target = referenceTargets.get(`${schemaName}::${table.name}::${columnName}`);\n if (!target) {\n return null;\n }\n const referenced = store.getRow(target.schema, target.table, value);\n if (!referenced) {\n return null;\n }\n return referenced._lofi.internalId;\n};\n\nconst resolveReferenceValue = (options: {\n value: unknown;\n column: AnyColumn;\n table: AnyTable;\n schemaName: string;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): unknown => {\n const { value, column, table, schemaName, store, referenceTargets } = options;\n\n if (value instanceof FragnoReference) {\n return coerceLocalInternalId(value.internalId);\n }\n\n if (value instanceof FragnoId) {\n if (value.internalId !== undefined) {\n return coerceLocalInternalId(value.internalId);\n }\n return resolveReferenceExternalId({\n value: value.externalId,\n schemaName,\n table,\n columnName: column.name,\n store,\n referenceTargets,\n });\n }\n\n if (typeof value === \"string\") {\n return resolveReferenceExternalId({\n value,\n schemaName,\n table,\n columnName: column.name,\n store,\n referenceTargets,\n });\n }\n\n return resolveFragnoIdValue(value, column);\n};\n\nconst resolveComparisonValue = (options: {\n value: unknown;\n column: AnyColumn;\n table: AnyTable;\n row: InMemoryLofiRow;\n schemaName: string;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): { value: unknown; column: AnyColumn } => {\n const { value, column, table, row, schemaName, store, referenceTargets } = options;\n\n if (value instanceof Column) {\n return { value: row._lofi.norm[value.name], column: value };\n }\n\n if (isDbNow(value)) {\n return { value: new Date(), column };\n }\n\n if (column.role === \"reference\") {\n const resolved = resolveReferenceValue({\n value,\n column,\n table,\n schemaName,\n store,\n referenceTargets,\n });\n return { value: resolved, column };\n }\n\n return { value: resolveFragnoIdValue(value, column), column };\n};\n\nconst normalizeLikeValue = (value: unknown, column: AnyColumn): string | null => {\n const normalized =\n column.role === \"reference\" || column.role === \"internal-id\"\n ? coerceLocalInternalId(value)\n : normalizeValue(value, column);\n if (normalized === null || normalized === undefined) {\n return null;\n }\n const bytes = toByteArray(normalized);\n if (bytes) {\n return bytesToHex(bytes);\n }\n return String(normalized);\n};\n\nconst evaluateCondition = async (\n condition: Condition | boolean,\n table: AnyTable,\n row: InMemoryLofiRow,\n context: QueryContext,\n): Promise<boolean> => {\n if (typeof condition === \"boolean\") {\n return condition;\n }\n\n switch (condition.type) {\n case \"and\": {\n for (const item of condition.items) {\n if (!(await evaluateCondition(item, table, row, context))) {\n return false;\n }\n }\n return true;\n }\n case \"or\": {\n for (const item of condition.items) {\n if (await evaluateCondition(item, table, row, context)) {\n return true;\n }\n }\n return false;\n }\n case \"not\":\n return !(await evaluateCondition(condition.item, table, row, context));\n case \"compare\":\n break;\n default: {\n const exhaustiveCheck: never = condition;\n throw new Error(`Unsupported condition type: ${JSON.stringify(exhaustiveCheck)}`);\n }\n }\n\n const leftColumn = condition.a;\n const leftValue = row._lofi.norm[leftColumn.name];\n const right = resolveComparisonValue({\n value: condition.b,\n column: leftColumn,\n table,\n row,\n schemaName: context.schemaName,\n store: context.store,\n referenceTargets: context.referenceTargets,\n });\n\n const op = condition.operator;\n const rightValue = right.value;\n\n if (op === \"is\" || op === \"is not\") {\n if (isNullish(rightValue)) {\n const matches = isNullish(leftValue);\n return op === \"is\" ? matches : !matches;\n }\n\n if (isNullish(leftValue)) {\n return op === \"is not\";\n }\n\n const leftNormalized = leftValue;\n const rightNormalized =\n right.column.role === \"reference\" || right.column.role === \"internal-id\"\n ? coerceLocalInternalId(rightValue)\n : normalizeValue(rightValue, right.column);\n const matches = compareNormalizedValues(leftNormalized, rightNormalized) === 0;\n return op === \"is\" ? matches : !matches;\n }\n\n if (isNullish(leftValue) || isNullish(rightValue)) {\n return false;\n }\n\n if (op === \"in\" || op === \"not in\") {\n if (!Array.isArray(rightValue)) {\n throw new Error(`Operator \"${op}\" expects an array value.`);\n }\n\n const leftNormalized = leftValue;\n let hasNull = false;\n let hasMatch = false;\n\n for (const item of rightValue) {\n const resolved = resolveComparisonValue({\n value: item,\n column: leftColumn,\n table,\n row,\n schemaName: context.schemaName,\n store: context.store,\n referenceTargets: context.referenceTargets,\n });\n if (isNullish(resolved.value)) {\n hasNull = true;\n continue;\n }\n\n const normalized =\n resolved.column.role === \"reference\" || resolved.column.role === \"internal-id\"\n ? coerceLocalInternalId(resolved.value)\n : normalizeValue(resolved.value, resolved.column);\n if (compareNormalizedValues(leftNormalized, normalized) === 0) {\n hasMatch = true;\n break;\n }\n }\n\n if (hasMatch) {\n return op === \"in\";\n }\n\n if (hasNull) {\n return false;\n }\n\n return op === \"not in\";\n }\n\n if (\n op === \"contains\" ||\n op === \"starts with\" ||\n op === \"ends with\" ||\n op === \"not contains\" ||\n op === \"not starts with\" ||\n op === \"not ends with\"\n ) {\n const leftLike = normalizeLikeValue(leftValue, leftColumn);\n const rightLike = normalizeLikeValue(rightValue, right.column);\n\n if (leftLike === null || rightLike === null) {\n return false;\n }\n\n const leftText = leftLike.toLowerCase();\n const rightText = rightLike.toLowerCase();\n let matches = false;\n\n if (op.includes(\"contains\")) {\n matches = leftText.includes(rightText);\n } else if (op.includes(\"starts with\")) {\n matches = leftText.startsWith(rightText);\n } else {\n matches = leftText.endsWith(rightText);\n }\n\n if (op.startsWith(\"not \")) {\n return !matches;\n }\n return matches;\n }\n\n const leftNormalized = leftValue;\n const rightNormalized =\n right.column.role === \"reference\" || right.column.role === \"internal-id\"\n ? coerceLocalInternalId(rightValue)\n : normalizeValue(rightValue, right.column);\n const comparison = compareNormalizedValues(leftNormalized, rightNormalized);\n\n switch (op) {\n case \"=\":\n return comparison === 0;\n case \"!=\":\n return comparison !== 0;\n case \">\":\n return comparison > 0;\n case \">=\":\n return comparison >= 0;\n case \"<\":\n return comparison < 0;\n case \"<=\":\n return comparison <= 0;\n default:\n throw new Error(`Unsupported operator \"${op}\".`);\n }\n};\n\nconst orderRows = (\n rows: InMemoryLofiRow[],\n orderBy: [AnyColumn, \"asc\" | \"desc\"][] | undefined,\n): InMemoryLofiRow[] => {\n if (!orderBy || orderBy.length === 0) {\n return rows;\n }\n\n return rows.slice().sort((left, right) => {\n for (const [column, direction] of orderBy) {\n const leftValue = left._lofi.norm[column.name];\n const rightValue = right._lofi.norm[column.name];\n const comparison = compareNormalizedValues(leftValue, rightValue);\n if (comparison !== 0) {\n return direction === \"asc\" ? comparison : -comparison;\n }\n }\n return 0;\n });\n};\n\nconst buildOrderColumns = (table: AnyTable, indexName: string): AnyColumn[] => {\n if (indexName === \"_primary\") {\n return [table.getIdColumn()];\n }\n\n const index = table.indexes[indexName];\n const columns = index ? [...index.columns] : [table.getIdColumn()];\n const idColumn = table.getIdColumn();\n if (!columns.some((col) => col.name === idColumn.name)) {\n columns.push(idColumn);\n }\n return columns;\n};\n\nconst getCursorValue = (value: unknown, column: AnyColumn): unknown => {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"externalId\" in value &&\n typeof (value as { externalId?: unknown }).externalId === \"string\"\n ) {\n const fragnoLike = value as { externalId: string; internalId?: string | number | bigint };\n if (column.role === \"external-id\") {\n return fragnoLike.externalId;\n }\n if ((column.role === \"internal-id\" || column.role === \"reference\") && fragnoLike.internalId) {\n return coerceLocalInternalId(\n typeof fragnoLike.internalId === \"string\"\n ? BigInt(fragnoLike.internalId)\n : fragnoLike.internalId,\n );\n }\n }\n\n if (value instanceof FragnoId) {\n if (column.role === \"external-id\") {\n return value.externalId;\n }\n if ((column.role === \"internal-id\" || column.role === \"reference\") && value.internalId) {\n return coerceLocalInternalId(value.internalId);\n }\n }\n\n if (value instanceof FragnoReference) {\n return coerceLocalInternalId(value.internalId);\n }\n\n return value;\n};\n\nconst buildCursorValues = (\n cursor: Cursor | string | undefined,\n columns: AnyColumn[],\n): readonly unknown[] | undefined => {\n if (!cursor) {\n return undefined;\n }\n\n const cursorObj = typeof cursor === \"string\" ? decodeCursor(cursor) : cursor;\n return columns.map((column) => {\n if (!(column.name in cursorObj.indexValues)) {\n throw new Error(`Cursor is missing index value for ${column.name}`);\n }\n const value = getCursorValue(cursorObj.indexValues[column.name], column);\n return column.role === \"reference\" || column.role === \"internal-id\"\n ? coerceLocalInternalId(value)\n : normalizeValue(value, column);\n });\n};\n\nconst compareRowToCursor = (\n row: InMemoryLofiRow,\n columns: AnyColumn[],\n cursorValues: readonly unknown[],\n): number => {\n for (let i = 0; i < columns.length; i += 1) {\n const column = columns[i];\n const leftValue = row._lofi.norm[column.name];\n const rightValue = cursorValues[i];\n const comparison = compareNormalizedValues(leftValue, rightValue);\n if (comparison !== 0) {\n return comparison;\n }\n }\n return 0;\n};\n\nconst collectRows = (options: { context: QueryContext; tableName: string }): InMemoryLofiRow[] => {\n const { context, tableName } = options;\n return context.store.getTableRows(context.schemaName, tableName);\n};\n\nconst findJoinMatches = async (options: {\n parentRow: InMemoryLofiRow;\n parentTable: AnyTable;\n join: CompiledJoin;\n rowsByTable: Map<string, InMemoryLofiRow[]>;\n context: QueryContext;\n}): Promise<InMemoryLofiRow[]> => {\n const { parentRow, parentTable, join, rowsByTable, context } = options;\n if (join.options === false) {\n return [];\n }\n\n const targetTable = join.relation.table;\n const cacheKey = `${context.schemaName}::${targetTable.name}`;\n let targetRows = rowsByTable.get(cacheKey);\n if (!targetRows) {\n targetRows = collectRows({\n context,\n tableName: targetTable.name,\n });\n rowsByTable.set(cacheKey, targetRows);\n }\n\n const matches: InMemoryLofiRow[] = [];\n\n for (const row of targetRows) {\n let matchesJoin = true;\n\n for (const [left, right] of join.relation.on) {\n const leftColumn = parentTable.columns[left];\n if (!leftColumn) {\n throw new Error(`Column \"${left}\" not found on table \"${parentTable.name}\".`);\n }\n\n const rightColumn = targetTable.columns[right];\n if (!rightColumn) {\n throw new Error(`Column \"${right}\" not found on table \"${targetTable.name}\".`);\n }\n\n const actualRight = rightColumn.role === \"external-id\" ? \"_internalId\" : right;\n const actualRightColumn = targetTable.columns[actualRight];\n if (!actualRightColumn) {\n throw new Error(`Column \"${actualRight}\" not found on table \"${targetTable.name}\".`);\n }\n\n const leftValue = parentRow._lofi.norm[leftColumn.name];\n const rightValue = row._lofi.norm[actualRightColumn.name];\n if (isNullish(leftValue) || isNullish(rightValue)) {\n matchesJoin = false;\n break;\n }\n if (compareNormalizedValues(leftValue, rightValue) !== 0) {\n matchesJoin = false;\n break;\n }\n }\n\n if (!matchesJoin) {\n continue;\n }\n\n if (join.options.where) {\n const matchesWhere = await evaluateCondition(join.options.where, targetTable, row, context);\n if (!matchesWhere) {\n continue;\n }\n }\n\n matches.push(row);\n }\n\n if (join.options.orderBy && join.options.orderBy.length > 0) {\n return orderRows(matches, join.options.orderBy as [AnyColumn, \"asc\" | \"desc\"][]);\n }\n\n return matches;\n};\n\nconst applyJoins = async (options: {\n baseOutput: RowSelection;\n parentRow: InMemoryLofiRow;\n parentTable: AnyTable;\n joins: CompiledJoin[];\n rowsByTable: Map<string, InMemoryLofiRow[]>;\n context: QueryContext;\n parentPath?: string;\n}): Promise<RowSelection[]> => {\n const { baseOutput, parentRow, parentTable, joins, rowsByTable, context, parentPath } = options;\n\n if (!joins || joins.length === 0) {\n return [baseOutput];\n }\n\n let outputs: RowSelection[] = [baseOutput];\n\n for (const join of joins) {\n if (join.options === false) {\n continue;\n }\n\n const relationPath = parentPath ? `${parentPath}:${join.relation.name}` : join.relation.name;\n const nextOutputs: RowSelection[] = [];\n\n for (const currentOutput of outputs) {\n const matches = await findJoinMatches({\n parentRow,\n parentTable,\n join,\n rowsByTable,\n context,\n });\n\n if (matches.length === 0) {\n nextOutputs.push(currentOutput);\n continue;\n }\n\n for (const matchRow of matches) {\n const prefixed = prefixSelection(\n matchRow,\n join.relation.table,\n join.options.select as undefined | true | readonly string[],\n relationPath,\n );\n const merged = { ...currentOutput, ...prefixed };\n\n if (join.options.join && join.options.join.length > 0) {\n nextOutputs.push(\n ...(await applyJoins({\n baseOutput: merged,\n parentRow: matchRow,\n parentTable: join.relation.table,\n joins: join.options.join,\n rowsByTable,\n context,\n parentPath: relationPath,\n })),\n );\n } else {\n nextOutputs.push(merged);\n }\n }\n }\n\n outputs = nextOutputs;\n }\n\n return outputs;\n};\n\nconst buildFindBuilder = <TTable extends AnyTable>(tableName: string, table: TTable) =>\n new FindBuilder<TTable>(tableName, table);\n\ntype OverlayFindOptions<TTable extends AnyTable = AnyTable> = {\n useIndex: string;\n select?: unknown;\n where?: ((builder: ConditionBuilder<TTable[\"columns\"]>) => Condition | boolean) | Condition;\n orderByIndex?: {\n indexName: string;\n direction: \"asc\" | \"desc\";\n };\n after?: Cursor | string;\n before?: Cursor | string;\n pageSize?: number;\n joins?: CompiledJoin[];\n};\n\ntype OverlayRetrievalOperation =\n | {\n type: \"find\";\n table: AnyTable;\n indexName: string;\n options: OverlayFindOptions;\n withCursor: boolean;\n }\n | {\n type: \"count\";\n table: AnyTable;\n indexName: string;\n options: Pick<OverlayFindOptions, \"where\">;\n };\n\nconst resolveFindCondition = <TTable extends AnyTable>(\n table: TTable,\n input: OverlayFindOptions<TTable>[\"where\"],\n): Condition | undefined | false => {\n if (!input) {\n return undefined;\n }\n if (typeof input === \"function\") {\n const built = buildCondition(table.columns, input);\n if (built === true) {\n return undefined;\n }\n return built;\n }\n return input;\n};\n\nconst applyCursorFilters = (options: {\n rows: InMemoryLofiRow[];\n orderColumns: AnyColumn[];\n direction: \"asc\" | \"desc\";\n after?: Cursor | string;\n before?: Cursor | string;\n}): InMemoryLofiRow[] => {\n const { rows, orderColumns, direction, after, before } = options;\n\n const afterValues = buildCursorValues(after, orderColumns);\n const beforeValues = buildCursorValues(before, orderColumns);\n\n return rows.filter((row) => {\n if (afterValues) {\n const comparison = compareRowToCursor(row, orderColumns, afterValues);\n if (direction === \"asc\" ? comparison <= 0 : comparison >= 0) {\n return false;\n }\n }\n\n if (beforeValues) {\n const comparison = compareRowToCursor(row, orderColumns, beforeValues);\n if (direction === \"asc\" ? comparison >= 0 : comparison <= 0) {\n return false;\n }\n }\n\n return true;\n });\n};\n\nexport const executeInMemoryRetrievalOperation = async (options: {\n operation: OverlayRetrievalOperation;\n context: QueryContext;\n}): Promise<Record<string, unknown>[] | CursorResult<Record<string, unknown>> | number> => {\n const { operation, context } = options;\n\n const rows = collectRows({\n context,\n tableName: operation.table.name,\n });\n\n const condition =\n operation.options.where !== undefined\n ? resolveFindCondition(operation.table, operation.options.where)\n : undefined;\n\n if (condition === false) {\n if (operation.type === \"count\") {\n return 0;\n }\n return operation.withCursor ? { items: [], hasNextPage: false } : [];\n }\n\n if (operation.type === \"count\") {\n let count = 0;\n for (const row of rows) {\n if (condition && !(await evaluateCondition(condition, operation.table, row, context))) {\n continue;\n }\n count += 1;\n }\n return count;\n }\n\n const filtered: InMemoryLofiRow[] = [];\n for (const row of rows) {\n if (condition && !(await evaluateCondition(condition, operation.table, row, context))) {\n continue;\n }\n filtered.push(row);\n }\n\n const orderIndexName = operation.options.orderByIndex?.indexName ?? operation.indexName;\n const direction = operation.options.orderByIndex?.direction ?? \"asc\";\n const orderColumns = buildOrderColumns(operation.table, orderIndexName);\n\n let ordered = orderRows(\n filtered,\n orderColumns.map((col) => [col, direction]),\n );\n ordered = applyCursorFilters({\n rows: ordered,\n orderColumns,\n direction,\n after: operation.options.after,\n before: operation.options.before,\n });\n\n const limit =\n operation.withCursor && operation.options.pageSize !== undefined\n ? operation.options.pageSize + 1\n : operation.options.pageSize;\n\n const results: RowSelection[] = [];\n const resultSources: InMemoryLofiRow[] = [];\n const rowsByTable = new Map<string, InMemoryLofiRow[]>();\n\n for (const row of ordered) {\n const select = operation.options.select as undefined | true | readonly string[];\n const baseOutput = selectRow(row, operation.table, select);\n\n if (operation.options.joins && operation.options.joins.length > 0) {\n const joined = await applyJoins({\n baseOutput,\n parentRow: row,\n parentTable: operation.table,\n joins: operation.options.joins,\n rowsByTable,\n context,\n });\n for (const joinedRow of joined) {\n results.push(joinedRow);\n resultSources.push(row);\n if (limit !== undefined && results.length >= limit) {\n break;\n }\n }\n } else {\n results.push(baseOutput);\n resultSources.push(row);\n }\n\n if (limit !== undefined && results.length >= limit) {\n break;\n }\n }\n\n const decoded = results.map((row) => decodeRow(row, operation.table));\n\n if (!operation.withCursor) {\n return decoded;\n }\n\n let cursor: Cursor | undefined;\n let hasNextPage = false;\n let items = decoded;\n\n if (\n operation.options.pageSize &&\n operation.options.pageSize > 0 &&\n decoded.length > operation.options.pageSize\n ) {\n hasNextPage = true;\n items = decoded.slice(0, operation.options.pageSize);\n\n const lastRow = items[items.length - 1];\n if (lastRow) {\n const cursorRecord: Record<string, unknown> = { ...lastRow };\n const sourceRow = resultSources[operation.options.pageSize - 1];\n for (const column of orderColumns) {\n if (cursorRecord[column.name] === undefined) {\n cursorRecord[column.name] = sourceRow\n ? buildOutputValueForColumn(sourceRow, column)\n : cursorRecord[column.name];\n }\n }\n\n cursor = createCursorFromRecord(cursorRecord, orderColumns, {\n indexName: orderIndexName,\n orderDirection: direction,\n pageSize: operation.options.pageSize,\n });\n }\n }\n\n return { items, cursor, hasNextPage };\n};\n\nexport const createInMemoryQueryEngine = <T extends AnySchema>(options: {\n schema: T;\n store: InMemoryLofiStore;\n schemaName?: string;\n}): LofiQueryInterface<T> => {\n const schemaName = options.schemaName ?? options.schema.name;\n const context: QueryContext = {\n endpointName: options.store.endpointName,\n schemaName,\n store: options.store,\n referenceTargets: options.store.referenceTargets,\n };\n\n const runFind = async (\n tableName: string,\n builderFn: ((builder: FindBuilder<AnyTable>) => unknown) | undefined,\n withCursor: boolean,\n ): Promise<Record<string, unknown>[] | CursorResult<Record<string, unknown>> | number> => {\n const tableMap = options.schema.tables as Record<string, AnyTable>;\n const table = tableMap[tableName];\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n\n const builder = buildFindBuilder(tableName, table);\n if (builderFn) {\n builderFn(builder);\n } else {\n builder.whereIndex(\"primary\");\n }\n\n const built = builder.build();\n if (built.type === \"count\") {\n return executeInMemoryRetrievalOperation({\n operation: {\n type: \"count\",\n table,\n indexName: built.indexName,\n options: { where: built.options.where },\n },\n context,\n });\n }\n\n return executeInMemoryRetrievalOperation({\n operation: {\n type: \"find\",\n table,\n indexName: built.indexName,\n options: built.options,\n withCursor,\n },\n context,\n });\n };\n\n const queryEngine = {\n async find(tableName, builderFn) {\n const result = await runFind(\n tableName,\n builderFn as unknown as (builder: FindBuilder<AnyTable>) => unknown,\n false,\n );\n return result as Record<string, unknown>[] | number;\n },\n\n async findWithCursor(tableName, builderFn) {\n const result = await runFind(\n tableName,\n builderFn as unknown as (builder: FindBuilder<AnyTable>) => unknown,\n true,\n );\n return result as CursorResult<Record<string, unknown>>;\n },\n\n async findFirst(tableName, builderFn) {\n const result = await runFind(\n tableName,\n builderFn\n ? (builder: FindBuilder<AnyTable>) => {\n (builderFn as unknown as (b: FindBuilder<AnyTable>) => unknown)(builder);\n builder.pageSize(1);\n return builder;\n }\n : (builder: FindBuilder<AnyTable>) => builder.whereIndex(\"primary\").pageSize(1),\n false,\n );\n\n if (typeof result === \"number\") {\n return null;\n }\n\n return (result as Record<string, unknown>[])[0] ?? null;\n },\n } as LofiQueryInterface<T>;\n\n return queryEngine;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"query.js","names":["selected: RowSelection","prefixed: RowSelection","output: Record<string, unknown>","columnValues: Record<string, unknown>","relationData: Record<string, Record<string, unknown>>","exhaustiveCheck: never","matches","matches: InMemoryLofiRow[]","outputs: RowSelection[]","nextOutputs: RowSelection[]","filtered: InMemoryLofiRow[]","results: RowSelection[]","resultSources: InMemoryLofiRow[]","cursor: Cursor | undefined","cursorRecord: Record<string, unknown>","context: QueryContext"],"sources":["../../../src/adapters/in-memory/query.ts"],"sourcesContent":["import type { CursorResult } from \"@fragno-dev/db/cursor\";\nimport { Cursor, createCursorFromRecord, decodeCursor } from \"@fragno-dev/db/cursor\";\nimport type { AnyColumn, AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\nimport { Column, FragnoId, FragnoReference } from \"@fragno-dev/db/schema\";\nimport { FindBuilder } from \"@fragno-dev/db/unit-of-work\";\n\nimport type { ReferenceTarget } from \"../../indexeddb/types\";\nimport { buildCondition, type Condition, type ConditionBuilder } from \"../../query/conditions\";\nimport { normalizeValue } from \"../../query/normalize\";\nimport type { LofiQueryInterface } from \"../../types\";\nimport type { InMemoryLofiRow } from \"./store\";\nimport { InMemoryLofiStore } from \"./store\";\nimport { compareNormalizedValues } from \"./value-comparison\";\n\nexport type InMemoryQueryContext = {\n endpointName: string;\n schemaName: string;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n};\n\ntype QueryContext = InMemoryQueryContext;\n\ntype RowSelection = Record<string, unknown>;\n\ntype CompiledJoin = {\n relation: { name: string; table: AnyTable; on: [string, string][] };\n options:\n | {\n select: unknown;\n where?: Condition;\n orderBy?: [AnyColumn, \"asc\" | \"desc\"][];\n join?: CompiledJoin[];\n limit?: number;\n }\n | false;\n};\n\nconst isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined;\n\nconst toByteArray = (value: unknown): Uint8Array | null => {\n if (value instanceof Uint8Array) {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n return null;\n};\n\nconst bytesToHex = (bytes: Uint8Array): string => {\n let hex = \"\";\n for (const byte of bytes) {\n hex += byte.toString(16).padStart(2, \"0\");\n }\n return hex;\n};\n\ntype DbNow = { tag: \"db-now\" };\n\nconst isDbNow = (value: unknown): value is DbNow =>\n typeof value === \"object\" && value !== null && (value as { tag?: string }).tag === \"db-now\";\n\nconst resolveFragnoIdValue = (value: unknown, col: AnyColumn): unknown => {\n if (value instanceof FragnoReference) {\n return value.internalId;\n }\n\n if (value instanceof FragnoId) {\n if (col.role === \"external-id\") {\n return value.externalId;\n }\n if (col.role === \"internal-id\") {\n if (value.internalId === undefined) {\n throw new Error(`FragnoId must have internalId for internal-id column ${col.name}`);\n }\n return value.internalId;\n }\n if (col.role === \"reference\") {\n return value.databaseId;\n }\n return value.externalId;\n }\n\n return value;\n};\n\nconst buildSelection = (\n table: AnyTable,\n select: undefined | true | readonly string[],\n): Set<string> => {\n const selection = new Set<string>();\n\n if (!select || select === true) {\n for (const columnName of Object.keys(table.columns)) {\n selection.add(columnName);\n }\n } else {\n for (const columnName of select) {\n selection.add(columnName);\n }\n }\n\n selection.add(\"_internalId\");\n selection.add(\"_version\");\n\n return selection;\n};\n\nconst getColumnValue = (row: InMemoryLofiRow, columnName: string, column: AnyColumn): unknown => {\n if (column.role === \"external-id\") {\n return row.id;\n }\n if (column.role === \"internal-id\") {\n return row._lofi.internalId;\n }\n if (column.role === \"version\") {\n return row._lofi.version;\n }\n\n return row.data[columnName];\n};\n\nconst selectRow = (\n row: InMemoryLofiRow,\n table: AnyTable,\n select: undefined | true | readonly string[],\n): RowSelection => {\n const selection = buildSelection(table, select);\n const selected: RowSelection = {};\n\n for (const columnName of selection) {\n if (columnName === \"_internalId\") {\n selected[columnName] = row._lofi.internalId;\n continue;\n }\n if (columnName === \"_version\") {\n selected[columnName] = row._lofi.version;\n continue;\n }\n\n const column = table.columns[columnName];\n if (!column) {\n continue;\n }\n\n if (column.role === \"reference\") {\n selected[columnName] = row._lofi.norm[columnName];\n continue;\n }\n\n selected[columnName] = getColumnValue(row, columnName, column);\n }\n\n return selected;\n};\n\nconst prefixSelection = (\n row: InMemoryLofiRow,\n table: AnyTable,\n select: undefined | true | readonly string[],\n prefix: string,\n): RowSelection => {\n const selected = selectRow(row, table, select);\n const prefixed: RowSelection = {};\n\n for (const key in selected) {\n prefixed[`${prefix}:${key}`] = selected[key];\n }\n\n return prefixed;\n};\n\nconst buildOutputValueForColumn = (row: InMemoryLofiRow, column: AnyColumn): unknown => {\n if (column.isHidden) {\n return undefined;\n }\n\n if (column.role === \"external-id\") {\n return new FragnoId({\n externalId: row.id,\n internalId: BigInt(row._lofi.internalId),\n version: row._lofi.version,\n });\n }\n\n if (column.role === \"reference\") {\n const value = row._lofi.norm[column.name];\n return value === null || value === undefined\n ? null\n : FragnoReference.fromInternal(BigInt(value as number));\n }\n\n if (column.role === \"internal-id\") {\n return BigInt(row._lofi.internalId);\n }\n\n if (column.role === \"version\") {\n return row._lofi.version;\n }\n\n return row.data[column.name];\n};\n\nconst decodeRow = (row: RowSelection, table: AnyTable): Record<string, unknown> => {\n const output: Record<string, unknown> = {};\n const columnValues: Record<string, unknown> = {};\n const relationData: Record<string, Record<string, unknown>> = {};\n\n for (const key in row) {\n const colonIndex = key.indexOf(\":\");\n if (colonIndex === -1) {\n if (table.columns[key]) {\n columnValues[key] = row[key];\n }\n continue;\n }\n\n const relationName = key.slice(0, colonIndex);\n const remainder = key.slice(colonIndex + 1);\n const relation = table.relations[relationName];\n if (!relation) {\n continue;\n }\n\n relationData[relationName] ??= {};\n relationData[relationName][remainder] = row[key];\n }\n\n for (const relationName in relationData) {\n const relation = table.relations[relationName];\n if (!relation) {\n continue;\n }\n output[relationName] = decodeRow(relationData[relationName], relation.table);\n }\n\n for (const key in columnValues) {\n const column = table.columns[key];\n if (!column || column.isHidden) {\n continue;\n }\n\n if (column.role === \"external-id\" && columnValues[\"_internalId\"] !== undefined) {\n output[key] = new FragnoId({\n externalId: columnValues[key] as string,\n internalId: BigInt(columnValues[\"_internalId\"] as number),\n version: columnValues[\"_version\"] as number,\n });\n continue;\n }\n\n if (column.role === \"reference\") {\n const value = columnValues[key];\n output[key] =\n value === null || value === undefined\n ? null\n : FragnoReference.fromInternal(BigInt(value as number));\n continue;\n }\n\n output[key] = columnValues[key];\n }\n\n return output;\n};\n\nconst coerceLocalInternalId = (value: unknown): number | unknown => {\n if (typeof value === \"bigint\") {\n const asNumber = Number(value);\n if (!Number.isSafeInteger(asNumber)) {\n throw new Error(`Local internalId is not a safe integer: ${value.toString()}`);\n }\n return asNumber;\n }\n return value;\n};\n\nconst resolveReferenceExternalId = (options: {\n value: string;\n schemaName: string;\n table: AnyTable;\n columnName: string;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): number | null => {\n const { value, schemaName, table, columnName, store, referenceTargets } = options;\n const target = referenceTargets.get(`${schemaName}::${table.name}::${columnName}`);\n if (!target) {\n return null;\n }\n const referenced = store.getRow(target.schema, target.table, value);\n if (!referenced) {\n return null;\n }\n return referenced._lofi.internalId;\n};\n\nconst resolveReferenceValue = (options: {\n value: unknown;\n column: AnyColumn;\n table: AnyTable;\n schemaName: string;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): unknown => {\n const { value, column, table, schemaName, store, referenceTargets } = options;\n\n if (value instanceof FragnoReference) {\n return coerceLocalInternalId(value.internalId);\n }\n\n if (value instanceof FragnoId) {\n if (value.internalId !== undefined) {\n return coerceLocalInternalId(value.internalId);\n }\n return resolveReferenceExternalId({\n value: value.externalId,\n schemaName,\n table,\n columnName: column.name,\n store,\n referenceTargets,\n });\n }\n\n if (typeof value === \"string\") {\n return resolveReferenceExternalId({\n value,\n schemaName,\n table,\n columnName: column.name,\n store,\n referenceTargets,\n });\n }\n\n return resolveFragnoIdValue(value, column);\n};\n\nconst resolveComparisonValue = (options: {\n value: unknown;\n column: AnyColumn;\n table: AnyTable;\n row: InMemoryLofiRow;\n schemaName: string;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): { value: unknown; column: AnyColumn } => {\n const { value, column, table, row, schemaName, store, referenceTargets } = options;\n\n if (value instanceof Column) {\n return { value: row._lofi.norm[value.name], column: value };\n }\n\n if (isDbNow(value)) {\n return { value: new Date(), column };\n }\n\n if (column.role === \"reference\") {\n const resolved = resolveReferenceValue({\n value,\n column,\n table,\n schemaName,\n store,\n referenceTargets,\n });\n return { value: resolved, column };\n }\n\n return { value: resolveFragnoIdValue(value, column), column };\n};\n\nconst normalizeLikeValue = (value: unknown, column: AnyColumn): string | null => {\n const normalized =\n column.role === \"reference\" || column.role === \"internal-id\"\n ? coerceLocalInternalId(value)\n : normalizeValue(value, column);\n if (normalized === null || normalized === undefined) {\n return null;\n }\n const bytes = toByteArray(normalized);\n if (bytes) {\n return bytesToHex(bytes);\n }\n return String(normalized);\n};\n\nconst evaluateCondition = async (\n condition: Condition | boolean,\n table: AnyTable,\n row: InMemoryLofiRow,\n context: QueryContext,\n): Promise<boolean> => {\n if (typeof condition === \"boolean\") {\n return condition;\n }\n\n switch (condition.type) {\n case \"and\": {\n for (const item of condition.items) {\n if (!(await evaluateCondition(item, table, row, context))) {\n return false;\n }\n }\n return true;\n }\n case \"or\": {\n for (const item of condition.items) {\n if (await evaluateCondition(item, table, row, context)) {\n return true;\n }\n }\n return false;\n }\n case \"not\":\n return !(await evaluateCondition(condition.item, table, row, context));\n case \"compare\":\n break;\n default: {\n const exhaustiveCheck: never = condition;\n throw new Error(`Unsupported condition type: ${JSON.stringify(exhaustiveCheck)}`);\n }\n }\n\n const leftColumn = condition.a;\n const leftValue = row._lofi.norm[leftColumn.name];\n const right = resolveComparisonValue({\n value: condition.b,\n column: leftColumn,\n table,\n row,\n schemaName: context.schemaName,\n store: context.store,\n referenceTargets: context.referenceTargets,\n });\n\n const op = condition.operator;\n const rightValue = right.value;\n\n if (op === \"is\" || op === \"is not\") {\n if (isNullish(rightValue)) {\n const matches = isNullish(leftValue);\n return op === \"is\" ? matches : !matches;\n }\n\n if (isNullish(leftValue)) {\n return op === \"is not\";\n }\n\n const leftNormalized = leftValue;\n const rightNormalized =\n right.column.role === \"reference\" || right.column.role === \"internal-id\"\n ? coerceLocalInternalId(rightValue)\n : normalizeValue(rightValue, right.column);\n const matches = compareNormalizedValues(leftNormalized, rightNormalized) === 0;\n return op === \"is\" ? matches : !matches;\n }\n\n if (isNullish(leftValue) || isNullish(rightValue)) {\n return false;\n }\n\n if (op === \"in\" || op === \"not in\") {\n if (!Array.isArray(rightValue)) {\n throw new Error(`Operator \"${op}\" expects an array value.`);\n }\n\n const leftNormalized = leftValue;\n let hasNull = false;\n let hasMatch = false;\n\n for (const item of rightValue) {\n const resolved = resolveComparisonValue({\n value: item,\n column: leftColumn,\n table,\n row,\n schemaName: context.schemaName,\n store: context.store,\n referenceTargets: context.referenceTargets,\n });\n if (isNullish(resolved.value)) {\n hasNull = true;\n continue;\n }\n\n const normalized =\n resolved.column.role === \"reference\" || resolved.column.role === \"internal-id\"\n ? coerceLocalInternalId(resolved.value)\n : normalizeValue(resolved.value, resolved.column);\n if (compareNormalizedValues(leftNormalized, normalized) === 0) {\n hasMatch = true;\n break;\n }\n }\n\n if (hasMatch) {\n return op === \"in\";\n }\n\n if (hasNull) {\n return false;\n }\n\n return op === \"not in\";\n }\n\n if (\n op === \"contains\" ||\n op === \"starts with\" ||\n op === \"ends with\" ||\n op === \"not contains\" ||\n op === \"not starts with\" ||\n op === \"not ends with\"\n ) {\n const leftLike = normalizeLikeValue(leftValue, leftColumn);\n const rightLike = normalizeLikeValue(rightValue, right.column);\n\n if (leftLike === null || rightLike === null) {\n return false;\n }\n\n const leftText = leftLike.toLowerCase();\n const rightText = rightLike.toLowerCase();\n let matches = false;\n\n if (op.includes(\"contains\")) {\n matches = leftText.includes(rightText);\n } else if (op.includes(\"starts with\")) {\n matches = leftText.startsWith(rightText);\n } else {\n matches = leftText.endsWith(rightText);\n }\n\n if (op.startsWith(\"not \")) {\n return !matches;\n }\n return matches;\n }\n\n const leftNormalized = leftValue;\n const rightNormalized =\n right.column.role === \"reference\" || right.column.role === \"internal-id\"\n ? coerceLocalInternalId(rightValue)\n : normalizeValue(rightValue, right.column);\n const comparison = compareNormalizedValues(leftNormalized, rightNormalized);\n\n switch (op) {\n case \"=\":\n return comparison === 0;\n case \"!=\":\n return comparison !== 0;\n case \">\":\n return comparison > 0;\n case \">=\":\n return comparison >= 0;\n case \"<\":\n return comparison < 0;\n case \"<=\":\n return comparison <= 0;\n default:\n throw new Error(`Unsupported operator \"${op}\".`);\n }\n};\n\nconst orderRows = (\n rows: InMemoryLofiRow[],\n orderBy: [AnyColumn, \"asc\" | \"desc\"][] | undefined,\n): InMemoryLofiRow[] => {\n if (!orderBy || orderBy.length === 0) {\n return rows;\n }\n\n return rows.slice().sort((left, right) => {\n for (const [column, direction] of orderBy) {\n const leftValue = left._lofi.norm[column.name];\n const rightValue = right._lofi.norm[column.name];\n const comparison = compareNormalizedValues(leftValue, rightValue);\n if (comparison !== 0) {\n return direction === \"asc\" ? comparison : -comparison;\n }\n }\n return 0;\n });\n};\n\nconst buildOrderColumns = (table: AnyTable, indexName: string): AnyColumn[] => {\n if (indexName === \"_primary\") {\n return [table.getIdColumn()];\n }\n\n const index = table.indexes[indexName];\n const columns = index ? [...index.columns] : [table.getIdColumn()];\n const idColumn = table.getIdColumn();\n if (!columns.some((col) => col.name === idColumn.name)) {\n columns.push(idColumn);\n }\n return columns;\n};\n\nconst getCursorValue = (value: unknown, column: AnyColumn): unknown => {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"externalId\" in value &&\n typeof (value as { externalId?: unknown }).externalId === \"string\"\n ) {\n const fragnoLike = value as { externalId: string; internalId?: string | number | bigint };\n if (column.role === \"external-id\") {\n return fragnoLike.externalId;\n }\n if ((column.role === \"internal-id\" || column.role === \"reference\") && fragnoLike.internalId) {\n return coerceLocalInternalId(\n typeof fragnoLike.internalId === \"string\"\n ? BigInt(fragnoLike.internalId)\n : fragnoLike.internalId,\n );\n }\n }\n\n if (value instanceof FragnoId) {\n if (column.role === \"external-id\") {\n return value.externalId;\n }\n if ((column.role === \"internal-id\" || column.role === \"reference\") && value.internalId) {\n return coerceLocalInternalId(value.internalId);\n }\n }\n\n if (value instanceof FragnoReference) {\n return coerceLocalInternalId(value.internalId);\n }\n\n return value;\n};\n\nconst buildCursorValues = (\n cursor: Cursor | string | undefined,\n columns: AnyColumn[],\n): readonly unknown[] | undefined => {\n if (!cursor) {\n return undefined;\n }\n\n const cursorObj = typeof cursor === \"string\" ? decodeCursor(cursor) : cursor;\n return columns.map((column) => {\n if (!(column.name in cursorObj.indexValues)) {\n throw new Error(`Cursor is missing index value for ${column.name}`);\n }\n const value = getCursorValue(cursorObj.indexValues[column.name], column);\n return column.role === \"reference\" || column.role === \"internal-id\"\n ? coerceLocalInternalId(value)\n : normalizeValue(value, column);\n });\n};\n\nconst compareRowToCursor = (\n row: InMemoryLofiRow,\n columns: AnyColumn[],\n cursorValues: readonly unknown[],\n): number => {\n for (let i = 0; i < columns.length; i += 1) {\n const column = columns[i];\n const leftValue = row._lofi.norm[column.name];\n const rightValue = cursorValues[i];\n const comparison = compareNormalizedValues(leftValue, rightValue);\n if (comparison !== 0) {\n return comparison;\n }\n }\n return 0;\n};\n\nconst collectRows = (options: { context: QueryContext; tableName: string }): InMemoryLofiRow[] => {\n const { context, tableName } = options;\n return context.store.getTableRows(context.schemaName, tableName);\n};\n\nconst findJoinMatches = async (options: {\n parentRow: InMemoryLofiRow;\n parentTable: AnyTable;\n join: CompiledJoin;\n rowsByTable: Map<string, InMemoryLofiRow[]>;\n context: QueryContext;\n}): Promise<InMemoryLofiRow[]> => {\n const { parentRow, parentTable, join, rowsByTable, context } = options;\n if (join.options === false) {\n return [];\n }\n\n const targetTable = join.relation.table;\n const cacheKey = `${context.schemaName}::${targetTable.name}`;\n let targetRows = rowsByTable.get(cacheKey);\n if (!targetRows) {\n targetRows = collectRows({\n context,\n tableName: targetTable.name,\n });\n rowsByTable.set(cacheKey, targetRows);\n }\n\n const matches: InMemoryLofiRow[] = [];\n\n for (const row of targetRows) {\n let matchesJoin = true;\n\n for (const [left, right] of join.relation.on) {\n const leftColumn = parentTable.columns[left];\n if (!leftColumn) {\n throw new Error(`Column \"${left}\" not found on table \"${parentTable.name}\".`);\n }\n\n const rightColumn = targetTable.columns[right];\n if (!rightColumn) {\n throw new Error(`Column \"${right}\" not found on table \"${targetTable.name}\".`);\n }\n\n const actualRight = rightColumn.role === \"external-id\" ? \"_internalId\" : right;\n const actualRightColumn = targetTable.columns[actualRight];\n if (!actualRightColumn) {\n throw new Error(`Column \"${actualRight}\" not found on table \"${targetTable.name}\".`);\n }\n\n const leftValue = parentRow._lofi.norm[leftColumn.name];\n const rightValue = row._lofi.norm[actualRightColumn.name];\n if (isNullish(leftValue) || isNullish(rightValue)) {\n matchesJoin = false;\n break;\n }\n if (compareNormalizedValues(leftValue, rightValue) !== 0) {\n matchesJoin = false;\n break;\n }\n }\n\n if (!matchesJoin) {\n continue;\n }\n\n if (join.options.where) {\n const matchesWhere = await evaluateCondition(join.options.where, targetTable, row, context);\n if (!matchesWhere) {\n continue;\n }\n }\n\n matches.push(row);\n }\n\n if (join.options.orderBy && join.options.orderBy.length > 0) {\n return orderRows(matches, join.options.orderBy as [AnyColumn, \"asc\" | \"desc\"][]);\n }\n\n return matches;\n};\n\nconst applyJoins = async (options: {\n baseOutput: RowSelection;\n parentRow: InMemoryLofiRow;\n parentTable: AnyTable;\n joins: CompiledJoin[];\n rowsByTable: Map<string, InMemoryLofiRow[]>;\n context: QueryContext;\n parentPath?: string;\n}): Promise<RowSelection[]> => {\n const { baseOutput, parentRow, parentTable, joins, rowsByTable, context, parentPath } = options;\n\n if (!joins || joins.length === 0) {\n return [baseOutput];\n }\n\n let outputs: RowSelection[] = [baseOutput];\n\n for (const join of joins) {\n if (join.options === false) {\n continue;\n }\n\n const relationPath = parentPath ? `${parentPath}:${join.relation.name}` : join.relation.name;\n const nextOutputs: RowSelection[] = [];\n\n for (const currentOutput of outputs) {\n const matches = await findJoinMatches({\n parentRow,\n parentTable,\n join,\n rowsByTable,\n context,\n });\n\n if (matches.length === 0) {\n nextOutputs.push(currentOutput);\n continue;\n }\n\n for (const matchRow of matches) {\n const prefixed = prefixSelection(\n matchRow,\n join.relation.table,\n join.options.select as undefined | true | readonly string[],\n relationPath,\n );\n const merged = { ...currentOutput, ...prefixed };\n\n if (join.options.join && join.options.join.length > 0) {\n nextOutputs.push(\n ...(await applyJoins({\n baseOutput: merged,\n parentRow: matchRow,\n parentTable: join.relation.table,\n joins: join.options.join,\n rowsByTable,\n context,\n parentPath: relationPath,\n })),\n );\n } else {\n nextOutputs.push(merged);\n }\n }\n }\n\n outputs = nextOutputs;\n }\n\n return outputs;\n};\n\nconst buildFindBuilder = <TTable extends AnyTable>(tableName: string, table: TTable) =>\n new FindBuilder<TTable>(tableName, table);\n\ntype OverlayFindOptions<TTable extends AnyTable = AnyTable> = {\n useIndex: string;\n select?: unknown;\n where?: ((builder: ConditionBuilder<TTable[\"columns\"]>) => Condition | boolean) | Condition;\n orderByIndex?: {\n indexName: string;\n direction: \"asc\" | \"desc\";\n };\n after?: Cursor | string;\n before?: Cursor | string;\n pageSize?: number;\n joins?: CompiledJoin[];\n};\n\ntype OverlayRetrievalOperation =\n | {\n type: \"find\";\n table: AnyTable;\n indexName: string;\n options: OverlayFindOptions;\n withCursor: boolean;\n }\n | {\n type: \"count\";\n table: AnyTable;\n indexName: string;\n options: Pick<OverlayFindOptions, \"where\">;\n };\n\nconst resolveFindCondition = <TTable extends AnyTable>(\n table: TTable,\n input: OverlayFindOptions<TTable>[\"where\"],\n): Condition | undefined | false => {\n if (!input) {\n return undefined;\n }\n if (typeof input === \"function\") {\n const built = buildCondition(table.columns, input);\n if (built === true) {\n return undefined;\n }\n return built;\n }\n return input;\n};\n\nconst applyCursorFilters = (options: {\n rows: InMemoryLofiRow[];\n orderColumns: AnyColumn[];\n direction: \"asc\" | \"desc\";\n after?: Cursor | string;\n before?: Cursor | string;\n}): InMemoryLofiRow[] => {\n const { rows, orderColumns, direction, after, before } = options;\n\n const afterValues = buildCursorValues(after, orderColumns);\n const beforeValues = buildCursorValues(before, orderColumns);\n\n return rows.filter((row) => {\n if (afterValues) {\n const comparison = compareRowToCursor(row, orderColumns, afterValues);\n if (direction === \"asc\" ? comparison <= 0 : comparison >= 0) {\n return false;\n }\n }\n\n if (beforeValues) {\n const comparison = compareRowToCursor(row, orderColumns, beforeValues);\n if (direction === \"asc\" ? comparison >= 0 : comparison <= 0) {\n return false;\n }\n }\n\n return true;\n });\n};\n\nexport const executeInMemoryRetrievalOperation = async (options: {\n operation: OverlayRetrievalOperation;\n context: QueryContext;\n}): Promise<Record<string, unknown>[] | CursorResult<Record<string, unknown>> | number> => {\n const { operation, context } = options;\n\n const rows = collectRows({\n context,\n tableName: operation.table.name,\n });\n\n const condition =\n operation.options.where !== undefined\n ? resolveFindCondition(operation.table, operation.options.where)\n : undefined;\n\n if (condition === false) {\n if (operation.type === \"count\") {\n return 0;\n }\n return operation.withCursor ? { items: [], hasNextPage: false } : [];\n }\n\n if (operation.type === \"count\") {\n let count = 0;\n for (const row of rows) {\n if (condition && !(await evaluateCondition(condition, operation.table, row, context))) {\n continue;\n }\n count += 1;\n }\n return count;\n }\n\n const filtered: InMemoryLofiRow[] = [];\n for (const row of rows) {\n if (condition && !(await evaluateCondition(condition, operation.table, row, context))) {\n continue;\n }\n filtered.push(row);\n }\n\n const orderIndexName = operation.options.orderByIndex?.indexName ?? operation.indexName;\n const direction = operation.options.orderByIndex?.direction ?? \"asc\";\n const orderColumns = buildOrderColumns(operation.table, orderIndexName);\n\n let ordered = orderRows(\n filtered,\n orderColumns.map((col) => [col, direction]),\n );\n ordered = applyCursorFilters({\n rows: ordered,\n orderColumns,\n direction,\n after: operation.options.after,\n before: operation.options.before,\n });\n\n const limit =\n operation.withCursor && operation.options.pageSize !== undefined\n ? operation.options.pageSize + 1\n : operation.options.pageSize;\n\n const results: RowSelection[] = [];\n const resultSources: InMemoryLofiRow[] = [];\n const rowsByTable = new Map<string, InMemoryLofiRow[]>();\n\n for (const row of ordered) {\n const select = operation.options.select as undefined | true | readonly string[];\n const baseOutput = selectRow(row, operation.table, select);\n\n if (operation.options.joins && operation.options.joins.length > 0) {\n const joined = await applyJoins({\n baseOutput,\n parentRow: row,\n parentTable: operation.table,\n joins: operation.options.joins,\n rowsByTable,\n context,\n });\n for (const joinedRow of joined) {\n results.push(joinedRow);\n resultSources.push(row);\n if (limit !== undefined && results.length >= limit) {\n break;\n }\n }\n } else {\n results.push(baseOutput);\n resultSources.push(row);\n }\n\n if (limit !== undefined && results.length >= limit) {\n break;\n }\n }\n\n const decoded = results.map((row) => decodeRow(row, operation.table));\n\n if (!operation.withCursor) {\n return decoded;\n }\n\n let cursor: Cursor | undefined;\n let hasNextPage = false;\n let items = decoded;\n\n if (\n operation.options.pageSize &&\n operation.options.pageSize > 0 &&\n decoded.length > operation.options.pageSize\n ) {\n hasNextPage = true;\n items = decoded.slice(0, operation.options.pageSize);\n\n const lastRow = items[items.length - 1];\n if (lastRow) {\n const cursorRecord: Record<string, unknown> = { ...lastRow };\n const sourceRow = resultSources[operation.options.pageSize - 1];\n for (const column of orderColumns) {\n if (cursorRecord[column.name] === undefined) {\n cursorRecord[column.name] = sourceRow\n ? buildOutputValueForColumn(sourceRow, column)\n : cursorRecord[column.name];\n }\n }\n\n cursor = createCursorFromRecord(cursorRecord, orderColumns, {\n indexName: orderIndexName,\n orderDirection: direction,\n pageSize: operation.options.pageSize,\n });\n }\n }\n\n return { items, cursor, hasNextPage };\n};\n\nexport const createInMemoryQueryEngine = <T extends AnySchema>(options: {\n schema: T;\n store: InMemoryLofiStore;\n schemaName?: string;\n}): LofiQueryInterface<T> => {\n const schemaName = options.schemaName ?? options.schema.name;\n const context: QueryContext = {\n endpointName: options.store.endpointName,\n schemaName,\n store: options.store,\n referenceTargets: options.store.referenceTargets,\n };\n\n const runFind = async (\n tableName: string,\n builderFn: ((builder: FindBuilder<AnyTable>) => unknown) | undefined,\n withCursor: boolean,\n ): Promise<Record<string, unknown>[] | CursorResult<Record<string, unknown>> | number> => {\n const tableMap = options.schema.tables as Record<string, AnyTable>;\n const table = tableMap[tableName];\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n\n const builder = buildFindBuilder(tableName, table);\n if (builderFn) {\n builderFn(builder);\n } else {\n builder.whereIndex(\"primary\");\n }\n\n const built = builder.build();\n if (built.type === \"count\") {\n return executeInMemoryRetrievalOperation({\n operation: {\n type: \"count\",\n table,\n indexName: built.indexName,\n options: { where: built.options.where },\n },\n context,\n });\n }\n\n return executeInMemoryRetrievalOperation({\n operation: {\n type: \"find\",\n table,\n indexName: built.indexName,\n options: built.options,\n withCursor,\n },\n context,\n });\n };\n\n const queryEngine = {\n async find(tableName, builderFn) {\n const result = await runFind(\n tableName,\n builderFn as unknown as (builder: FindBuilder<AnyTable>) => unknown,\n false,\n );\n return result as Record<string, unknown>[] | number;\n },\n\n async findWithCursor(tableName, builderFn) {\n const result = await runFind(\n tableName,\n builderFn as unknown as (builder: FindBuilder<AnyTable>) => unknown,\n true,\n );\n return result as CursorResult<Record<string, unknown>>;\n },\n\n async findFirst(tableName, builderFn) {\n const result = await runFind(\n tableName,\n builderFn\n ? (builder: FindBuilder<AnyTable>) => {\n (builderFn as unknown as (b: FindBuilder<AnyTable>) => unknown)(builder);\n builder.pageSize(1);\n return builder;\n }\n : (builder: FindBuilder<AnyTable>) => builder.whereIndex(\"primary\").pageSize(1),\n false,\n );\n\n if (typeof result === \"number\") {\n return null;\n }\n\n return (result as Record<string, unknown>[])[0] ?? null;\n },\n } as LofiQueryInterface<T>;\n\n return queryEngine;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","names":[],"sources":["../../../src/adapters/in-memory/store.ts"],"sourcesContent":[],"mappings":";;;;;;KAQY,eAAA;;EAAA,QAAA,EAAA,MAAA;EAsCP,MAAA,EAAA,MAAA;EA2RQ,KAAA,EAAA,MAAA;EAEO,EAAA,EAAA,MAAA;EACc,IAAA,EA9T1B,MA8T0B,CAAA,MAAA,EAAA,OAAA,CAAA;EAAZ,KAAA,EAAA;IACuB,YAAA,EAAA,MAAA;IAAZ,IAAA,EA5TvB,MA4TuB,CAAA,MAAA,EAAA,OAAA,CAAA;IAAZ,UAAA,EAAA,MAAA;IACoB,OAAA,EAAA,MAAA;EAAZ,CAAA;CAGN;KAnSlB,oBAAA,GAgVY;EAWW,YAAA,EAAA,MAAA;EAMF,OAAA,EA/Vf,SA+Ve,EAAA;CAoE2C;AAQb,cAlJ3C,iBAAA,CAkJ2C;EAID,CAAA,OAAA;EAS3C,SAAA,YAAA,EAAA,MAAA;EAEF,SAAA,OAAA,EA/JU,SA+JV,EAAA;EAIJ,SAAA,SAAA,EAlKgB,GAkKhB,CAAA,MAAA,EAlK4B,SAkK5B,CAAA;EAAe,SAAA,QAAA,EAjKA,GAiKA,CAAA,MAAA,EAjKY,GAiKZ,CAAA,MAAA,EAjKwB,QAiKxB,CAAA,CAAA;6BAhKQ,YAAY;uBAGlB;;;iBA6CN;4BAWW;0BAMF;qEAoE2C;;wDAQb;uDAID;;;;;YAS3C;;UAEF;;;;MAIJ"}
1
+ {"version":3,"file":"store.d.ts","names":[],"sources":["../../../src/adapters/in-memory/store.ts"],"sourcesContent":[],"mappings":";;;;;;KASY,eAAA;;EAAA,QAAA,EAAA,MAAA;EAsCP,MAAA,EAAA,MAAA;EA2RQ,KAAA,EAAA,MAAA;EAEO,EAAA,EAAA,MAAA;EACc,IAAA,EA9T1B,MA8T0B,CAAA,MAAA,EAAA,OAAA,CAAA;EAAZ,KAAA,EAAA;IACuB,YAAA,EAAA,MAAA;IAAZ,IAAA,EA5TvB,MA4TuB,CAAA,MAAA,EAAA,OAAA,CAAA;IAAZ,UAAA,EAAA,MAAA;IACoB,OAAA,EAAA,MAAA;EAAZ,CAAA;CAGN;KAnSlB,oBAAA,GAgVY;EAWW,YAAA,EAAA,MAAA;EAMF,OAAA,EA/Vf,SA+Ve,EAAA;CAoE2C;AAQb,cAlJ3C,iBAAA,CAkJ2C;EAID,CAAA,OAAA;EAS3C,SAAA,YAAA,EAAA,MAAA;EAEF,SAAA,OAAA,EA/JU,SA+JV,EAAA;EAIJ,SAAA,SAAA,EAlKgB,GAkKhB,CAAA,MAAA,EAlK4B,SAkK5B,CAAA;EAAe,SAAA,QAAA,EAjKA,GAiKA,CAAA,MAAA,EAjKY,GAiKZ,CAAA,MAAA,EAjKwB,QAiKxB,CAAA,CAAA;6BAhKQ,YAAY;uBAGlB;;;iBA6CN;4BAWW;0BAMF;qEAoE2C;;wDAQb;uDAID;;;;;YAS3C;;UAEF;;;;MAIJ"}
@@ -1,6 +1,6 @@
1
1
  import { normalizeValue } from "../../query/normalize.js";
2
- import { compareNormalizedValues } from "./value-comparison.js";
3
2
  import { SortedArrayIndex } from "./sorted-array-index.js";
3
+ import { compareNormalizedValues } from "./value-comparison.js";
4
4
  import { FragnoId, FragnoReference } from "@fragno-dev/db/schema";
5
5
 
6
6
  //#region src/adapters/in-memory/store.ts
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","names":["primaryDefinition: InMemoryIndexDefinition","definition: InMemoryIndexDefinition","applied: typeof updates","rawValue","norm: Record<string, unknown>","#stores","row: InMemoryLofiRow","rows: InMemoryLofiRow[]"],"sources":["../../../src/adapters/in-memory/store.ts"],"sourcesContent":["import type { AnyColumn, AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\nimport { FragnoId, FragnoReference } from \"@fragno-dev/db/schema\";\nimport type { LofiMutation } from \"../../types\";\nimport type { ReferenceTarget } from \"../../indexeddb/types\";\nimport { normalizeValue } from \"../../query/normalize\";\nimport { compareNormalizedValues } from \"./value-comparison\";\nimport { SortedArrayIndex, type IndexKey } from \"./sorted-array-index\";\n\nexport type InMemoryLofiRow = {\n key: [string, string, string, string];\n endpoint: string;\n schema: string;\n table: string;\n id: string;\n data: Record<string, unknown>;\n _lofi: {\n versionstamp: string;\n norm: Record<string, unknown>;\n internalId: number;\n version: number;\n };\n};\n\ntype InMemoryIndexDefinition = {\n name: string;\n columnNames: string[];\n unique: boolean;\n};\n\ntype InMemoryIndexStore = {\n definition: InMemoryIndexDefinition;\n index: SortedArrayIndex<number>;\n};\n\ntype InMemoryTableStore = {\n rowsByExternalId: Map<string, InMemoryLofiRow>;\n rowsByInternalId: Map<number, InMemoryLofiRow>;\n nextInternalId: number;\n indexes: Map<string, InMemoryIndexStore>;\n tombstones: Set<string>;\n};\n\ntype InMemorySchemaStore = {\n tables: Map<string, InMemoryTableStore>;\n};\n\ntype InMemoryStoreOptions = {\n endpointName: string;\n schemas: AnySchema[];\n};\n\nconst createReferenceTargets = (schemas: AnySchema[]): Map<string, ReferenceTarget> => {\n const referenceTargets = new Map<string, ReferenceTarget>();\n for (const schema of schemas) {\n for (const table of Object.values(schema.tables)) {\n for (const relation of Object.values(table.relations)) {\n for (const [fromColumn] of relation.on) {\n referenceTargets.set(`${schema.name}::${table.name}::${fromColumn}`, {\n schema: schema.name,\n table: relation.table.name,\n });\n }\n }\n }\n }\n return referenceTargets;\n};\n\nconst createTableIndexes = (table: AnyTable): Map<string, InMemoryIndexStore> => {\n const indexes = new Map<string, InMemoryIndexStore>();\n const primaryIndex = table.indexes[\"_primary\"];\n const primaryColumnNames = primaryIndex\n ? [...primaryIndex.columnNames]\n : [table.getIdColumn().name];\n const primaryDefinition: InMemoryIndexDefinition = {\n name: \"_primary\",\n columnNames: primaryColumnNames,\n unique: primaryIndex?.unique ?? true,\n };\n indexes.set(\"_primary\", {\n definition: primaryDefinition,\n index: new SortedArrayIndex(compareNormalizedValues, { unique: primaryDefinition.unique }),\n });\n\n for (const [name, index] of Object.entries(table.indexes)) {\n if (name === \"_primary\") {\n continue;\n }\n const definition: InMemoryIndexDefinition = {\n name,\n columnNames: [...index.columnNames],\n unique: index.unique,\n };\n indexes.set(name, {\n definition,\n index: new SortedArrayIndex(compareNormalizedValues, { unique: index.unique }),\n });\n }\n\n return indexes;\n};\n\nconst createTableStore = (table: AnyTable): InMemoryTableStore => ({\n rowsByExternalId: new Map(),\n rowsByInternalId: new Map(),\n nextInternalId: 1,\n indexes: createTableIndexes(table),\n tombstones: new Set(),\n});\n\nconst createSchemaStore = (schema: AnySchema): InMemorySchemaStore => {\n const tables = new Map<string, InMemoryTableStore>();\n for (const table of Object.values(schema.tables)) {\n tables.set(table.name, createTableStore(table));\n }\n return { tables };\n};\n\nconst buildIndexKey = (row: InMemoryLofiRow, index: InMemoryIndexDefinition): IndexKey =>\n index.columnNames.map((columnName) => row._lofi.norm[columnName]);\n\nconst insertRowIntoIndexes = (store: InMemoryTableStore, row: InMemoryLofiRow): void => {\n for (const indexStore of store.indexes.values()) {\n const key = buildIndexKey(row, indexStore.definition);\n indexStore.index.insert(key, row._lofi.internalId, { enforceUnique: true });\n }\n};\n\nconst removeRowFromIndexes = (store: InMemoryTableStore, row: InMemoryLofiRow): void => {\n for (const indexStore of store.indexes.values()) {\n const key = buildIndexKey(row, indexStore.definition);\n indexStore.index.remove(key, row._lofi.internalId);\n }\n};\n\nconst updateRowIndexes = (\n store: InMemoryTableStore,\n existing: InMemoryLofiRow,\n next: InMemoryLofiRow,\n): void => {\n const updates = Array.from(store.indexes.values()).map((indexStore) => ({\n indexStore,\n oldKey: buildIndexKey(existing, indexStore.definition),\n newKey: buildIndexKey(next, indexStore.definition),\n }));\n\n const applied: typeof updates = [];\n\n try {\n for (const update of updates) {\n update.indexStore.index.update(update.oldKey, update.newKey, existing._lofi.internalId, {\n enforceUnique: true,\n });\n applied.push(update);\n }\n } catch (error) {\n for (const update of applied.slice().reverse()) {\n update.indexStore.index.update(update.newKey, update.oldKey, existing._lofi.internalId, {\n enforceUnique: false,\n });\n }\n throw error;\n }\n};\n\nconst coerceInternalIdValue = (\n value: bigint | number,\n schema: AnySchema,\n table: AnyTable,\n columnName: string,\n): number => {\n const asNumber = typeof value === \"bigint\" ? Number(value) : value;\n if (!Number.isSafeInteger(asNumber)) {\n throw new Error(\n `Reference internalId is not a safe integer for ${schema.name}.${table.name}.${columnName}: ${value.toString()}`,\n );\n }\n return asNumber;\n};\n\nconst resolveReferenceExternalId = (options: {\n schema: AnySchema;\n table: AnyTable;\n columnName: string;\n externalId: string;\n referenceTargets: Map<string, ReferenceTarget>;\n store: InMemoryLofiStore;\n}): number | undefined => {\n const { schema, table, columnName, externalId, referenceTargets, store } = options;\n const target = referenceTargets.get(`${schema.name}::${table.name}::${columnName}`);\n if (!target) {\n return undefined;\n }\n const referenced = store.getRow(target.schema, target.table, externalId);\n if (!referenced) {\n return undefined;\n }\n return referenced._lofi.internalId;\n};\n\nconst resolveColumnValue = (options: {\n schema: AnySchema;\n table: AnyTable;\n columnName: string;\n column: AnyColumn;\n data: Record<string, unknown>;\n rowId: string;\n internalId: number;\n version: number;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): unknown => {\n const {\n schema,\n table,\n columnName,\n column,\n data,\n rowId,\n internalId,\n version,\n store,\n referenceTargets,\n } = options;\n\n if (column.role === \"external-id\") {\n return rowId;\n }\n\n if (column.role === \"internal-id\") {\n return internalId;\n }\n\n if (column.role === \"version\") {\n return version;\n }\n\n if (column.role === \"reference\") {\n const rawValue = data[columnName];\n if (rawValue == null) {\n return rawValue;\n }\n\n if (rawValue instanceof FragnoReference) {\n return coerceInternalIdValue(rawValue.internalId, schema, table, columnName);\n }\n\n if (rawValue instanceof FragnoId) {\n if (rawValue.internalId !== undefined) {\n return coerceInternalIdValue(rawValue.internalId, schema, table, columnName);\n }\n return resolveReferenceExternalId({\n schema,\n table,\n columnName,\n externalId: rawValue.externalId,\n store,\n referenceTargets,\n });\n }\n\n if (typeof rawValue === \"number\") {\n throw new Error(\n `Expected reference value to be external ID string for ${schema.name}.${table.name}.${columnName}.`,\n );\n }\n\n if (typeof rawValue === \"bigint\") {\n return coerceInternalIdValue(rawValue, schema, table, columnName);\n }\n\n if (typeof rawValue !== \"string\") {\n throw new Error(\n `Expected reference value to be external ID string for ${schema.name}.${table.name}.${columnName}.`,\n );\n }\n\n return resolveReferenceExternalId({\n schema,\n table,\n columnName,\n externalId: rawValue,\n store,\n referenceTargets,\n });\n }\n\n const rawValue = data[columnName];\n if (rawValue === undefined) {\n return undefined;\n }\n if (rawValue === null) {\n return null;\n }\n\n return normalizeValue(rawValue, column);\n};\n\nconst buildNormalizedValues = (options: {\n schema: AnySchema;\n table: AnyTable;\n data: Record<string, unknown>;\n rowId: string;\n internalId: number;\n version: number;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Record<string, unknown> => {\n const { schema, table, data, rowId, internalId, version, store, referenceTargets } = options;\n const norm: Record<string, unknown> = {};\n\n for (const [columnName, column] of Object.entries(table.columns)) {\n norm[columnName] = resolveColumnValue({\n schema,\n table,\n columnName,\n column,\n data,\n rowId,\n internalId,\n version,\n store,\n referenceTargets,\n });\n }\n\n return norm;\n};\n\nexport class InMemoryLofiStore {\n readonly endpointName: string;\n readonly schemas: AnySchema[];\n readonly schemaMap: Map<string, AnySchema>;\n readonly tableMap: Map<string, Map<string, AnyTable>>;\n readonly referenceTargets: Map<string, ReferenceTarget>;\n #stores: Map<string, InMemorySchemaStore>;\n\n constructor(options: InMemoryStoreOptions) {\n if (!options.endpointName || options.endpointName.trim().length === 0) {\n throw new Error(\"InMemoryLofiStore requires a non-empty endpointName.\");\n }\n\n const schemaMap = new Map<string, AnySchema>();\n const tableMap = new Map<string, Map<string, AnyTable>>();\n\n for (const schema of options.schemas) {\n if (!schema.name || schema.name.trim().length === 0) {\n throw new Error(\"InMemoryLofiStore schemas must have a non-empty name.\");\n }\n if (schemaMap.has(schema.name)) {\n throw new Error(`InMemoryLofiStore schema name must be unique: ${schema.name}`);\n }\n schemaMap.set(schema.name, schema);\n const tables = new Map<string, AnyTable>();\n for (const [tableName, table] of Object.entries(schema.tables)) {\n tables.set(tableName, table);\n }\n tableMap.set(schema.name, tables);\n }\n\n this.endpointName = options.endpointName;\n this.schemas = [...schemaMap.values()];\n this.schemaMap = schemaMap;\n this.tableMap = tableMap;\n this.referenceTargets = createReferenceTargets(this.schemas);\n this.#stores = new Map();\n for (const schema of this.schemas) {\n this.#stores.set(schema.name, createSchemaStore(schema));\n }\n }\n\n clear(): void {\n this.#stores = new Map();\n for (const schema of this.schemas) {\n this.#stores.set(schema.name, createSchemaStore(schema));\n }\n }\n\n reset(): void {\n this.clear();\n }\n\n seedRows(rows: InMemoryLofiRow[]): void {\n for (const row of rows) {\n if (row.endpoint !== this.endpointName) {\n continue;\n }\n const tableStore = this.getTableStore(row.schema, row.table);\n this.upsertRow(tableStore, row as InMemoryLofiRow);\n tableStore.tombstones.delete(row.id);\n }\n }\n\n applyMutations(mutations: LofiMutation[]): void {\n for (const mutation of mutations) {\n this.applyMutation(mutation);\n }\n }\n\n applyMutation(mutation: LofiMutation): void {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n throw new Error(`Unknown mutation schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n throw new Error(`Unknown mutation table: ${mutation.schema}.${mutation.table}`);\n }\n\n const tableStore = this.getTableStore(schema.name, table.name);\n const existing = tableStore.rowsByExternalId.get(mutation.externalId);\n\n if (mutation.op === \"delete\") {\n if (existing) {\n removeRowFromIndexes(tableStore, existing);\n tableStore.rowsByExternalId.delete(existing.id);\n tableStore.rowsByInternalId.delete(existing._lofi.internalId);\n }\n tableStore.tombstones.add(mutation.externalId);\n return;\n }\n\n const values = mutation.op === \"create\" ? mutation.values : mutation.set;\n if (!existing && mutation.op === \"update\") {\n return;\n }\n\n tableStore.tombstones.delete(mutation.externalId);\n const data = existing ? { ...existing.data, ...values } : { ...values };\n const internalId = existing ? existing._lofi.internalId : this.allocateInternalId(tableStore);\n const version = existing ? existing._lofi.version + (mutation.op === \"update\" ? 1 : 0) : 1;\n const norm = buildNormalizedValues({\n schema,\n table,\n data,\n rowId: mutation.externalId,\n internalId,\n version,\n store: this,\n referenceTargets: this.referenceTargets,\n });\n\n const row: InMemoryLofiRow = {\n key: [this.endpointName, schema.name, table.name, mutation.externalId],\n endpoint: this.endpointName,\n schema: schema.name,\n table: table.name,\n id: mutation.externalId,\n data,\n _lofi: {\n versionstamp: mutation.versionstamp,\n norm,\n internalId,\n version,\n },\n };\n\n if (existing) {\n updateRowIndexes(tableStore, existing, row);\n tableStore.rowsByExternalId.set(row.id, row);\n tableStore.rowsByInternalId.set(row._lofi.internalId, row);\n return;\n }\n\n this.upsertRow(tableStore, row);\n }\n\n getRow(schemaName: string, tableName: string, externalId: string): InMemoryLofiRow | undefined {\n return this.getTableStore(schemaName, tableName).rowsByExternalId.get(externalId);\n }\n\n hasTombstone(schemaName: string, tableName: string, externalId: string): boolean {\n return this.getTableStore(schemaName, tableName).tombstones.has(externalId);\n }\n\n getTombstones(schemaName: string, tableName: string): Set<string> {\n return new Set(this.getTableStore(schemaName, tableName).tombstones);\n }\n\n getTableRows(schemaName: string, tableName: string): InMemoryLofiRow[] {\n const tableStore = this.getTableStore(schemaName, tableName);\n return Array.from(tableStore.rowsByExternalId.values());\n }\n\n scanIndex(options: {\n schemaName: string;\n tableName: string;\n indexName: string;\n start?: IndexKey;\n startInclusive?: boolean;\n end?: IndexKey;\n endInclusive?: boolean;\n direction?: \"asc\" | \"desc\";\n limit?: number;\n }): InMemoryLofiRow[] {\n const {\n schemaName,\n tableName,\n indexName,\n start,\n startInclusive,\n end,\n endInclusive,\n direction,\n limit,\n } = options;\n const tableStore = this.getTableStore(schemaName, tableName);\n const indexStore = tableStore.indexes.get(indexName);\n if (!indexStore) {\n throw new Error(`Missing in-memory index \"${indexName}\" on ${schemaName}.${tableName}.`);\n }\n const entries = indexStore.index.scan({\n start,\n startInclusive,\n end,\n endInclusive,\n direction,\n limit,\n });\n\n const rows: InMemoryLofiRow[] = [];\n for (const entry of entries) {\n const row = tableStore.rowsByInternalId.get(entry.value);\n if (row) {\n rows.push(row);\n }\n }\n return rows;\n }\n\n private getTableStore(schemaName: string, tableName: string): InMemoryTableStore {\n const schemaStore = this.#stores.get(schemaName);\n if (!schemaStore) {\n throw new Error(`Unknown in-memory schema: ${schemaName}`);\n }\n const tableStore = schemaStore.tables.get(tableName);\n if (!tableStore) {\n throw new Error(`Unknown in-memory table: ${schemaName}.${tableName}`);\n }\n return tableStore;\n }\n\n private allocateInternalId(tableStore: InMemoryTableStore): number {\n const next = tableStore.nextInternalId;\n tableStore.nextInternalId += 1;\n if (!Number.isSafeInteger(next)) {\n throw new Error(\"InMemoryLofiStore internalId overflow.\");\n }\n return next;\n }\n\n private upsertRow(tableStore: InMemoryTableStore, row: InMemoryLofiRow): void {\n const existing = tableStore.rowsByExternalId.get(row.id);\n if (existing) {\n removeRowFromIndexes(tableStore, existing);\n tableStore.rowsByExternalId.delete(existing.id);\n tableStore.rowsByInternalId.delete(existing._lofi.internalId);\n }\n\n insertRowIntoIndexes(tableStore, row);\n tableStore.rowsByExternalId.set(row.id, row);\n tableStore.rowsByInternalId.set(row._lofi.internalId, row);\n if (row._lofi.internalId >= tableStore.nextInternalId) {\n tableStore.nextInternalId = row._lofi.internalId + 1;\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"store.js","names":["primaryDefinition: InMemoryIndexDefinition","definition: InMemoryIndexDefinition","applied: typeof updates","rawValue","norm: Record<string, unknown>","#stores","row: InMemoryLofiRow","rows: InMemoryLofiRow[]"],"sources":["../../../src/adapters/in-memory/store.ts"],"sourcesContent":["import type { AnyColumn, AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\nimport { FragnoId, FragnoReference } from \"@fragno-dev/db/schema\";\n\nimport type { ReferenceTarget } from \"../../indexeddb/types\";\nimport { normalizeValue } from \"../../query/normalize\";\nimport type { LofiMutation } from \"../../types\";\nimport { SortedArrayIndex, type IndexKey } from \"./sorted-array-index\";\nimport { compareNormalizedValues } from \"./value-comparison\";\n\nexport type InMemoryLofiRow = {\n key: [string, string, string, string];\n endpoint: string;\n schema: string;\n table: string;\n id: string;\n data: Record<string, unknown>;\n _lofi: {\n versionstamp: string;\n norm: Record<string, unknown>;\n internalId: number;\n version: number;\n };\n};\n\ntype InMemoryIndexDefinition = {\n name: string;\n columnNames: string[];\n unique: boolean;\n};\n\ntype InMemoryIndexStore = {\n definition: InMemoryIndexDefinition;\n index: SortedArrayIndex<number>;\n};\n\ntype InMemoryTableStore = {\n rowsByExternalId: Map<string, InMemoryLofiRow>;\n rowsByInternalId: Map<number, InMemoryLofiRow>;\n nextInternalId: number;\n indexes: Map<string, InMemoryIndexStore>;\n tombstones: Set<string>;\n};\n\ntype InMemorySchemaStore = {\n tables: Map<string, InMemoryTableStore>;\n};\n\ntype InMemoryStoreOptions = {\n endpointName: string;\n schemas: AnySchema[];\n};\n\nconst createReferenceTargets = (schemas: AnySchema[]): Map<string, ReferenceTarget> => {\n const referenceTargets = new Map<string, ReferenceTarget>();\n for (const schema of schemas) {\n for (const table of Object.values(schema.tables)) {\n for (const relation of Object.values(table.relations)) {\n for (const [fromColumn] of relation.on) {\n referenceTargets.set(`${schema.name}::${table.name}::${fromColumn}`, {\n schema: schema.name,\n table: relation.table.name,\n });\n }\n }\n }\n }\n return referenceTargets;\n};\n\nconst createTableIndexes = (table: AnyTable): Map<string, InMemoryIndexStore> => {\n const indexes = new Map<string, InMemoryIndexStore>();\n const primaryIndex = table.indexes[\"_primary\"];\n const primaryColumnNames = primaryIndex\n ? [...primaryIndex.columnNames]\n : [table.getIdColumn().name];\n const primaryDefinition: InMemoryIndexDefinition = {\n name: \"_primary\",\n columnNames: primaryColumnNames,\n unique: primaryIndex?.unique ?? true,\n };\n indexes.set(\"_primary\", {\n definition: primaryDefinition,\n index: new SortedArrayIndex(compareNormalizedValues, { unique: primaryDefinition.unique }),\n });\n\n for (const [name, index] of Object.entries(table.indexes)) {\n if (name === \"_primary\") {\n continue;\n }\n const definition: InMemoryIndexDefinition = {\n name,\n columnNames: [...index.columnNames],\n unique: index.unique,\n };\n indexes.set(name, {\n definition,\n index: new SortedArrayIndex(compareNormalizedValues, { unique: index.unique }),\n });\n }\n\n return indexes;\n};\n\nconst createTableStore = (table: AnyTable): InMemoryTableStore => ({\n rowsByExternalId: new Map(),\n rowsByInternalId: new Map(),\n nextInternalId: 1,\n indexes: createTableIndexes(table),\n tombstones: new Set(),\n});\n\nconst createSchemaStore = (schema: AnySchema): InMemorySchemaStore => {\n const tables = new Map<string, InMemoryTableStore>();\n for (const table of Object.values(schema.tables)) {\n tables.set(table.name, createTableStore(table));\n }\n return { tables };\n};\n\nconst buildIndexKey = (row: InMemoryLofiRow, index: InMemoryIndexDefinition): IndexKey =>\n index.columnNames.map((columnName) => row._lofi.norm[columnName]);\n\nconst insertRowIntoIndexes = (store: InMemoryTableStore, row: InMemoryLofiRow): void => {\n for (const indexStore of store.indexes.values()) {\n const key = buildIndexKey(row, indexStore.definition);\n indexStore.index.insert(key, row._lofi.internalId, { enforceUnique: true });\n }\n};\n\nconst removeRowFromIndexes = (store: InMemoryTableStore, row: InMemoryLofiRow): void => {\n for (const indexStore of store.indexes.values()) {\n const key = buildIndexKey(row, indexStore.definition);\n indexStore.index.remove(key, row._lofi.internalId);\n }\n};\n\nconst updateRowIndexes = (\n store: InMemoryTableStore,\n existing: InMemoryLofiRow,\n next: InMemoryLofiRow,\n): void => {\n const updates = Array.from(store.indexes.values()).map((indexStore) => ({\n indexStore,\n oldKey: buildIndexKey(existing, indexStore.definition),\n newKey: buildIndexKey(next, indexStore.definition),\n }));\n\n const applied: typeof updates = [];\n\n try {\n for (const update of updates) {\n update.indexStore.index.update(update.oldKey, update.newKey, existing._lofi.internalId, {\n enforceUnique: true,\n });\n applied.push(update);\n }\n } catch (error) {\n for (const update of applied.slice().reverse()) {\n update.indexStore.index.update(update.newKey, update.oldKey, existing._lofi.internalId, {\n enforceUnique: false,\n });\n }\n throw error;\n }\n};\n\nconst coerceInternalIdValue = (\n value: bigint | number,\n schema: AnySchema,\n table: AnyTable,\n columnName: string,\n): number => {\n const asNumber = typeof value === \"bigint\" ? Number(value) : value;\n if (!Number.isSafeInteger(asNumber)) {\n throw new Error(\n `Reference internalId is not a safe integer for ${schema.name}.${table.name}.${columnName}: ${value.toString()}`,\n );\n }\n return asNumber;\n};\n\nconst resolveReferenceExternalId = (options: {\n schema: AnySchema;\n table: AnyTable;\n columnName: string;\n externalId: string;\n referenceTargets: Map<string, ReferenceTarget>;\n store: InMemoryLofiStore;\n}): number | undefined => {\n const { schema, table, columnName, externalId, referenceTargets, store } = options;\n const target = referenceTargets.get(`${schema.name}::${table.name}::${columnName}`);\n if (!target) {\n return undefined;\n }\n const referenced = store.getRow(target.schema, target.table, externalId);\n if (!referenced) {\n return undefined;\n }\n return referenced._lofi.internalId;\n};\n\nconst resolveColumnValue = (options: {\n schema: AnySchema;\n table: AnyTable;\n columnName: string;\n column: AnyColumn;\n data: Record<string, unknown>;\n rowId: string;\n internalId: number;\n version: number;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): unknown => {\n const {\n schema,\n table,\n columnName,\n column,\n data,\n rowId,\n internalId,\n version,\n store,\n referenceTargets,\n } = options;\n\n if (column.role === \"external-id\") {\n return rowId;\n }\n\n if (column.role === \"internal-id\") {\n return internalId;\n }\n\n if (column.role === \"version\") {\n return version;\n }\n\n if (column.role === \"reference\") {\n const rawValue = data[columnName];\n if (rawValue == null) {\n return rawValue;\n }\n\n if (rawValue instanceof FragnoReference) {\n return coerceInternalIdValue(rawValue.internalId, schema, table, columnName);\n }\n\n if (rawValue instanceof FragnoId) {\n if (rawValue.internalId !== undefined) {\n return coerceInternalIdValue(rawValue.internalId, schema, table, columnName);\n }\n return resolveReferenceExternalId({\n schema,\n table,\n columnName,\n externalId: rawValue.externalId,\n store,\n referenceTargets,\n });\n }\n\n if (typeof rawValue === \"number\") {\n throw new Error(\n `Expected reference value to be external ID string for ${schema.name}.${table.name}.${columnName}.`,\n );\n }\n\n if (typeof rawValue === \"bigint\") {\n return coerceInternalIdValue(rawValue, schema, table, columnName);\n }\n\n if (typeof rawValue !== \"string\") {\n throw new Error(\n `Expected reference value to be external ID string for ${schema.name}.${table.name}.${columnName}.`,\n );\n }\n\n return resolveReferenceExternalId({\n schema,\n table,\n columnName,\n externalId: rawValue,\n store,\n referenceTargets,\n });\n }\n\n const rawValue = data[columnName];\n if (rawValue === undefined) {\n return undefined;\n }\n if (rawValue === null) {\n return null;\n }\n\n return normalizeValue(rawValue, column);\n};\n\nconst buildNormalizedValues = (options: {\n schema: AnySchema;\n table: AnyTable;\n data: Record<string, unknown>;\n rowId: string;\n internalId: number;\n version: number;\n store: InMemoryLofiStore;\n referenceTargets: Map<string, ReferenceTarget>;\n}): Record<string, unknown> => {\n const { schema, table, data, rowId, internalId, version, store, referenceTargets } = options;\n const norm: Record<string, unknown> = {};\n\n for (const [columnName, column] of Object.entries(table.columns)) {\n norm[columnName] = resolveColumnValue({\n schema,\n table,\n columnName,\n column,\n data,\n rowId,\n internalId,\n version,\n store,\n referenceTargets,\n });\n }\n\n return norm;\n};\n\nexport class InMemoryLofiStore {\n readonly endpointName: string;\n readonly schemas: AnySchema[];\n readonly schemaMap: Map<string, AnySchema>;\n readonly tableMap: Map<string, Map<string, AnyTable>>;\n readonly referenceTargets: Map<string, ReferenceTarget>;\n #stores: Map<string, InMemorySchemaStore>;\n\n constructor(options: InMemoryStoreOptions) {\n if (!options.endpointName || options.endpointName.trim().length === 0) {\n throw new Error(\"InMemoryLofiStore requires a non-empty endpointName.\");\n }\n\n const schemaMap = new Map<string, AnySchema>();\n const tableMap = new Map<string, Map<string, AnyTable>>();\n\n for (const schema of options.schemas) {\n if (!schema.name || schema.name.trim().length === 0) {\n throw new Error(\"InMemoryLofiStore schemas must have a non-empty name.\");\n }\n if (schemaMap.has(schema.name)) {\n throw new Error(`InMemoryLofiStore schema name must be unique: ${schema.name}`);\n }\n schemaMap.set(schema.name, schema);\n const tables = new Map<string, AnyTable>();\n for (const [tableName, table] of Object.entries(schema.tables)) {\n tables.set(tableName, table);\n }\n tableMap.set(schema.name, tables);\n }\n\n this.endpointName = options.endpointName;\n this.schemas = [...schemaMap.values()];\n this.schemaMap = schemaMap;\n this.tableMap = tableMap;\n this.referenceTargets = createReferenceTargets(this.schemas);\n this.#stores = new Map();\n for (const schema of this.schemas) {\n this.#stores.set(schema.name, createSchemaStore(schema));\n }\n }\n\n clear(): void {\n this.#stores = new Map();\n for (const schema of this.schemas) {\n this.#stores.set(schema.name, createSchemaStore(schema));\n }\n }\n\n reset(): void {\n this.clear();\n }\n\n seedRows(rows: InMemoryLofiRow[]): void {\n for (const row of rows) {\n if (row.endpoint !== this.endpointName) {\n continue;\n }\n const tableStore = this.getTableStore(row.schema, row.table);\n this.upsertRow(tableStore, row as InMemoryLofiRow);\n tableStore.tombstones.delete(row.id);\n }\n }\n\n applyMutations(mutations: LofiMutation[]): void {\n for (const mutation of mutations) {\n this.applyMutation(mutation);\n }\n }\n\n applyMutation(mutation: LofiMutation): void {\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n throw new Error(`Unknown mutation schema: ${mutation.schema}`);\n }\n const table = this.tableMap.get(mutation.schema)?.get(mutation.table);\n if (!table) {\n throw new Error(`Unknown mutation table: ${mutation.schema}.${mutation.table}`);\n }\n\n const tableStore = this.getTableStore(schema.name, table.name);\n const existing = tableStore.rowsByExternalId.get(mutation.externalId);\n\n if (mutation.op === \"delete\") {\n if (existing) {\n removeRowFromIndexes(tableStore, existing);\n tableStore.rowsByExternalId.delete(existing.id);\n tableStore.rowsByInternalId.delete(existing._lofi.internalId);\n }\n tableStore.tombstones.add(mutation.externalId);\n return;\n }\n\n const values = mutation.op === \"create\" ? mutation.values : mutation.set;\n if (!existing && mutation.op === \"update\") {\n return;\n }\n\n tableStore.tombstones.delete(mutation.externalId);\n const data = existing ? { ...existing.data, ...values } : { ...values };\n const internalId = existing ? existing._lofi.internalId : this.allocateInternalId(tableStore);\n const version = existing ? existing._lofi.version + (mutation.op === \"update\" ? 1 : 0) : 1;\n const norm = buildNormalizedValues({\n schema,\n table,\n data,\n rowId: mutation.externalId,\n internalId,\n version,\n store: this,\n referenceTargets: this.referenceTargets,\n });\n\n const row: InMemoryLofiRow = {\n key: [this.endpointName, schema.name, table.name, mutation.externalId],\n endpoint: this.endpointName,\n schema: schema.name,\n table: table.name,\n id: mutation.externalId,\n data,\n _lofi: {\n versionstamp: mutation.versionstamp,\n norm,\n internalId,\n version,\n },\n };\n\n if (existing) {\n updateRowIndexes(tableStore, existing, row);\n tableStore.rowsByExternalId.set(row.id, row);\n tableStore.rowsByInternalId.set(row._lofi.internalId, row);\n return;\n }\n\n this.upsertRow(tableStore, row);\n }\n\n getRow(schemaName: string, tableName: string, externalId: string): InMemoryLofiRow | undefined {\n return this.getTableStore(schemaName, tableName).rowsByExternalId.get(externalId);\n }\n\n hasTombstone(schemaName: string, tableName: string, externalId: string): boolean {\n return this.getTableStore(schemaName, tableName).tombstones.has(externalId);\n }\n\n getTombstones(schemaName: string, tableName: string): Set<string> {\n return new Set(this.getTableStore(schemaName, tableName).tombstones);\n }\n\n getTableRows(schemaName: string, tableName: string): InMemoryLofiRow[] {\n const tableStore = this.getTableStore(schemaName, tableName);\n return Array.from(tableStore.rowsByExternalId.values());\n }\n\n scanIndex(options: {\n schemaName: string;\n tableName: string;\n indexName: string;\n start?: IndexKey;\n startInclusive?: boolean;\n end?: IndexKey;\n endInclusive?: boolean;\n direction?: \"asc\" | \"desc\";\n limit?: number;\n }): InMemoryLofiRow[] {\n const {\n schemaName,\n tableName,\n indexName,\n start,\n startInclusive,\n end,\n endInclusive,\n direction,\n limit,\n } = options;\n const tableStore = this.getTableStore(schemaName, tableName);\n const indexStore = tableStore.indexes.get(indexName);\n if (!indexStore) {\n throw new Error(`Missing in-memory index \"${indexName}\" on ${schemaName}.${tableName}.`);\n }\n const entries = indexStore.index.scan({\n start,\n startInclusive,\n end,\n endInclusive,\n direction,\n limit,\n });\n\n const rows: InMemoryLofiRow[] = [];\n for (const entry of entries) {\n const row = tableStore.rowsByInternalId.get(entry.value);\n if (row) {\n rows.push(row);\n }\n }\n return rows;\n }\n\n private getTableStore(schemaName: string, tableName: string): InMemoryTableStore {\n const schemaStore = this.#stores.get(schemaName);\n if (!schemaStore) {\n throw new Error(`Unknown in-memory schema: ${schemaName}`);\n }\n const tableStore = schemaStore.tables.get(tableName);\n if (!tableStore) {\n throw new Error(`Unknown in-memory table: ${schemaName}.${tableName}`);\n }\n return tableStore;\n }\n\n private allocateInternalId(tableStore: InMemoryTableStore): number {\n const next = tableStore.nextInternalId;\n tableStore.nextInternalId += 1;\n if (!Number.isSafeInteger(next)) {\n throw new Error(\"InMemoryLofiStore internalId overflow.\");\n }\n return next;\n }\n\n private upsertRow(tableStore: InMemoryTableStore, row: InMemoryLofiRow): void {\n const existing = tableStore.rowsByExternalId.get(row.id);\n if (existing) {\n removeRowFromIndexes(tableStore, existing);\n tableStore.rowsByExternalId.delete(existing.id);\n tableStore.rowsByInternalId.delete(existing._lofi.internalId);\n }\n\n insertRowIntoIndexes(tableStore, row);\n tableStore.rowsByExternalId.set(row.id, row);\n tableStore.rowsByInternalId.set(row._lofi.internalId, row);\n if (row._lofi.internalId >= tableStore.nextInternalId) {\n tableStore.nextInternalId = row._lofi.internalId + 1;\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","names":[],"sources":["../../../src/adapters/stacked/adapter.ts"],"sourcesContent":[],"mappings":";;;;;KAWY,yBAAA;QACJ,cAAc;EADV,OAAA,EAED,mBAF0B;EAC7B,OAAA,EAEG,SAFH,EAAA;CAAc;AACX,cAiBE,kBAAA,YAA8B,WAjBhC,EAiB6C,oBAjB7C,CAAA;EACA,iBAAA,IAAA;EAAS,iBAAA,OAAA;EAgBP,iBAAA,SAAmB;EAKT,WAAA,CAAA,OAAA,EAAA,yBAAA;EAqBR,gBAAA,CAAA,OAAA,EAAA;IACT,SAAA,EAAA,MAAA;IAI4B,YAAA,EAAA,MAAA;IAAiB,KAAA,EAAA,MAAA;IAoErB,SAAA,EAzEf,YAyEe,EAAA;EAIe,CAAA,CAAA,EA5EvC,OA4EuC,CAAA;IAIT,OAAA,EAAA,OAAA;EACxB,CAAA,CAAA;EACE,cAAA,CAAA,SAAA,EA9EoB,YA8EpB,EAAA,CAAA,EA9EqC,OA8ErC,CAAA,IAAA,CAAA;EACU,OAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAXM,OAWN,CAAA,MAAA,GAAA,SAAA,CAAA;EAAnB,OAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EAPwC,OAOxC,CAAA,IAAA,CAAA;EA9GsC,iBAAA,CAAA,gBA2GP,SA3GO,CAAA,CAAA,MAAA,EA4G/B,CA5G+B,EAAA,OAAA,CAAA,EA6G7B,sBA7G6B,CAAA,EA8GtC,kBA9GsC,CA8GnB,CA9GmB,CAAA"}
1
+ {"version":3,"file":"adapter.d.ts","names":[],"sources":["../../../src/adapters/stacked/adapter.ts"],"sourcesContent":[],"mappings":";;;;;KAYY,yBAAA;QACJ,cAAc;EADV,OAAA,EAED,mBAF0B;EAC7B,OAAA,EAEG,SAFH,EAAA;CAAc;AACX,cAiBE,kBAAA,YAA8B,WAjBhC,EAiB6C,oBAjB7C,CAAA;EACA,iBAAA,IAAA;EAAS,iBAAA,OAAA;EAgBP,iBAAA,SAAmB;EAKT,WAAA,CAAA,OAAA,EAAA,yBAAA;EAqBR,gBAAA,CAAA,OAAA,EAAA;IACT,SAAA,EAAA,MAAA;IAI4B,YAAA,EAAA,MAAA;IAAiB,KAAA,EAAA,MAAA;IAoErB,SAAA,EAzEf,YAyEe,EAAA;EAIe,CAAA,CAAA,EA5EvC,OA4EuC,CAAA;IAIT,OAAA,EAAA,OAAA;EACxB,CAAA,CAAA;EACE,cAAA,CAAA,SAAA,EA9EoB,YA8EpB,EAAA,CAAA,EA9EqC,OA8ErC,CAAA,IAAA,CAAA;EACU,OAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAXM,OAWN,CAAA,MAAA,GAAA,SAAA,CAAA;EAAnB,OAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EAPwC,OAOxC,CAAA,IAAA,CAAA;EA9GsC,iBAAA,CAAA,gBA2GP,SA3GO,CAAA,CAAA,MAAA,EA4G/B,CA5G+B,EAAA,OAAA,CAAA,EA6G7B,sBA7G6B,CAAA,EA8GtC,kBA9GsC,CA8GnB,CA9GmB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","names":["values: Record<string, unknown>","materialized: LofiMutation[]","values: Record<string, unknown> | null"],"sources":["../../../src/adapters/stacked/adapter.ts"],"sourcesContent":["import type { AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\nimport type {\n LofiAdapter,\n LofiMutation,\n LofiQueryEngineOptions,\n LofiQueryInterface,\n LofiQueryableAdapter,\n} from \"../../types\";\nimport { InMemoryLofiAdapter } from \"../in-memory/adapter\";\nimport { createStackedQueryEngine } from \"./merge\";\n\nexport type StackedLofiAdapterOptions = {\n base: LofiAdapter & LofiQueryableAdapter;\n overlay: InMemoryLofiAdapter;\n schemas: AnySchema[];\n};\n\nconst extractRowValues = (\n row: Record<string, unknown>,\n table: AnyTable,\n): Record<string, unknown> => {\n const values: Record<string, unknown> = {};\n for (const columnName of Object.keys(table.columns)) {\n if (columnName in row) {\n values[columnName] = row[columnName];\n }\n }\n return values;\n};\n\nexport class StackedLofiAdapter implements LofiAdapter, LofiQueryableAdapter {\n private readonly base: LofiAdapter & LofiQueryableAdapter;\n private readonly overlay: InMemoryLofiAdapter;\n private readonly schemaMap: Map<string, AnySchema>;\n\n constructor(options: StackedLofiAdapterOptions) {\n const schemaMap = new Map<string, AnySchema>();\n for (const schema of options.schemas) {\n if (!schema.name || schema.name.trim().length === 0) {\n throw new Error(\"StackedLofiAdapter schemas must have a non-empty name.\");\n }\n if (schemaMap.has(schema.name)) {\n throw new Error(`StackedLofiAdapter schema name must be unique: ${schema.name}`);\n }\n schemaMap.set(schema.name, schema);\n }\n\n this.base = options.base;\n this.overlay = options.overlay;\n this.schemaMap = schemaMap;\n }\n\n async applyOutboxEntry(options: {\n sourceKey: string;\n versionstamp: string;\n uowId: string;\n mutations: LofiMutation[];\n }): Promise<{ applied: boolean }> {\n return this.base.applyOutboxEntry(options);\n }\n\n async applyMutations(mutations: LofiMutation[]): Promise<void> {\n if (!this.base || !this.overlay) {\n return;\n }\n\n const materialized: LofiMutation[] = [];\n\n for (const mutation of mutations) {\n if (mutation.op !== \"update\") {\n materialized.push(mutation);\n continue;\n }\n\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n throw new Error(`Unknown mutation schema: ${mutation.schema}`);\n }\n const table = schema.tables[mutation.table];\n if (!table) {\n throw new Error(`Unknown mutation table: ${mutation.schema}.${mutation.table}`);\n }\n\n const baseQuery = this.base.createQueryEngine(schema);\n const baseRow = (await baseQuery.findFirst(mutation.table, (b) =>\n b.whereIndex(\"primary\", (eb) =>\n (eb as unknown as (col: string, op: \"=\", value: string) => boolean)(\n table.getIdColumn().name,\n \"=\",\n mutation.externalId,\n ),\n ),\n )) as Record<string, unknown> | null;\n\n let values: Record<string, unknown> | null = null;\n\n if (baseRow) {\n values = { ...extractRowValues(baseRow, table) };\n } else {\n const overlayRow = this.overlay.store.getRow(\n mutation.schema,\n mutation.table,\n mutation.externalId,\n );\n if (overlayRow) {\n values = { ...overlayRow.data };\n }\n }\n\n if (!values) {\n materialized.push(mutation);\n continue;\n }\n\n materialized.push({\n op: \"create\",\n schema: mutation.schema,\n table: mutation.table,\n externalId: mutation.externalId,\n values: { ...values, ...mutation.set },\n versionstamp: mutation.versionstamp,\n });\n }\n\n if (materialized.length > 0) {\n await this.overlay.applyMutations(materialized);\n }\n }\n\n async getMeta(key: string): Promise<string | undefined> {\n return this.base.getMeta(key);\n }\n\n async setMeta(key: string, value: string): Promise<void> {\n await this.base.setMeta(key, value);\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n options?: LofiQueryEngineOptions,\n ): LofiQueryInterface<T> {\n return createStackedQueryEngine({\n schema,\n base: this.base,\n overlay: this.overlay,\n schemaName: options?.schemaName,\n });\n }\n}\n"],"mappings":";;;;AAiBA,MAAM,oBACJ,KACA,UAC4B;CAC5B,MAAMA,SAAkC,EAAE;AAC1C,MAAK,MAAM,cAAc,OAAO,KAAK,MAAM,QAAQ,CACjD,KAAI,cAAc,IAChB,QAAO,cAAc,IAAI;AAG7B,QAAO;;AAGT,IAAa,qBAAb,MAA6E;CAC3E,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,SAAoC;EAC9C,MAAM,4BAAY,IAAI,KAAwB;AAC9C,OAAK,MAAM,UAAU,QAAQ,SAAS;AACpC,OAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,MAAM,CAAC,WAAW,EAChD,OAAM,IAAI,MAAM,yDAAyD;AAE3E,OAAI,UAAU,IAAI,OAAO,KAAK,CAC5B,OAAM,IAAI,MAAM,kDAAkD,OAAO,OAAO;AAElF,aAAU,IAAI,OAAO,MAAM,OAAO;;AAGpC,OAAK,OAAO,QAAQ;AACpB,OAAK,UAAU,QAAQ;AACvB,OAAK,YAAY;;CAGnB,MAAM,iBAAiB,SAKW;AAChC,SAAO,KAAK,KAAK,iBAAiB,QAAQ;;CAG5C,MAAM,eAAe,WAA0C;AAC7D,MAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,QACtB;EAGF,MAAMC,eAA+B,EAAE;AAEvC,OAAK,MAAM,YAAY,WAAW;AAChC,OAAI,SAAS,OAAO,UAAU;AAC5B,iBAAa,KAAK,SAAS;AAC3B;;GAGF,MAAM,SAAS,KAAK,UAAU,IAAI,SAAS,OAAO;AAClD,OAAI,CAAC,OACH,OAAM,IAAI,MAAM,4BAA4B,SAAS,SAAS;GAEhE,MAAM,QAAQ,OAAO,OAAO,SAAS;AACrC,OAAI,CAAC,MACH,OAAM,IAAI,MAAM,2BAA2B,SAAS,OAAO,GAAG,SAAS,QAAQ;GAIjF,MAAM,UAAW,MADC,KAAK,KAAK,kBAAkB,OAAO,CACpB,UAAU,SAAS,QAAQ,MAC1D,EAAE,WAAW,YAAY,OACtB,GACC,MAAM,aAAa,CAAC,MACpB,KACA,SAAS,WACV,CACF,CACF;GAED,IAAIC,SAAyC;AAE7C,OAAI,QACF,UAAS,EAAE,GAAG,iBAAiB,SAAS,MAAM,EAAE;QAC3C;IACL,MAAM,aAAa,KAAK,QAAQ,MAAM,OACpC,SAAS,QACT,SAAS,OACT,SAAS,WACV;AACD,QAAI,WACF,UAAS,EAAE,GAAG,WAAW,MAAM;;AAInC,OAAI,CAAC,QAAQ;AACX,iBAAa,KAAK,SAAS;AAC3B;;AAGF,gBAAa,KAAK;IAChB,IAAI;IACJ,QAAQ,SAAS;IACjB,OAAO,SAAS;IAChB,YAAY,SAAS;IACrB,QAAQ;KAAE,GAAG;KAAQ,GAAG,SAAS;KAAK;IACtC,cAAc,SAAS;IACxB,CAAC;;AAGJ,MAAI,aAAa,SAAS,EACxB,OAAM,KAAK,QAAQ,eAAe,aAAa;;CAInD,MAAM,QAAQ,KAA0C;AACtD,SAAO,KAAK,KAAK,QAAQ,IAAI;;CAG/B,MAAM,QAAQ,KAAa,OAA8B;AACvD,QAAM,KAAK,KAAK,QAAQ,KAAK,MAAM;;CAGrC,kBACE,QACA,SACuB;AACvB,SAAO,yBAAyB;GAC9B;GACA,MAAM,KAAK;GACX,SAAS,KAAK;GACd,YAAY,SAAS;GACtB,CAAC"}
1
+ {"version":3,"file":"adapter.js","names":["values: Record<string, unknown>","materialized: LofiMutation[]","values: Record<string, unknown> | null"],"sources":["../../../src/adapters/stacked/adapter.ts"],"sourcesContent":["import type { AnySchema, AnyTable } from \"@fragno-dev/db/schema\";\n\nimport type {\n LofiAdapter,\n LofiMutation,\n LofiQueryEngineOptions,\n LofiQueryInterface,\n LofiQueryableAdapter,\n} from \"../../types\";\nimport { InMemoryLofiAdapter } from \"../in-memory/adapter\";\nimport { createStackedQueryEngine } from \"./merge\";\n\nexport type StackedLofiAdapterOptions = {\n base: LofiAdapter & LofiQueryableAdapter;\n overlay: InMemoryLofiAdapter;\n schemas: AnySchema[];\n};\n\nconst extractRowValues = (\n row: Record<string, unknown>,\n table: AnyTable,\n): Record<string, unknown> => {\n const values: Record<string, unknown> = {};\n for (const columnName of Object.keys(table.columns)) {\n if (columnName in row) {\n values[columnName] = row[columnName];\n }\n }\n return values;\n};\n\nexport class StackedLofiAdapter implements LofiAdapter, LofiQueryableAdapter {\n private readonly base: LofiAdapter & LofiQueryableAdapter;\n private readonly overlay: InMemoryLofiAdapter;\n private readonly schemaMap: Map<string, AnySchema>;\n\n constructor(options: StackedLofiAdapterOptions) {\n const schemaMap = new Map<string, AnySchema>();\n for (const schema of options.schemas) {\n if (!schema.name || schema.name.trim().length === 0) {\n throw new Error(\"StackedLofiAdapter schemas must have a non-empty name.\");\n }\n if (schemaMap.has(schema.name)) {\n throw new Error(`StackedLofiAdapter schema name must be unique: ${schema.name}`);\n }\n schemaMap.set(schema.name, schema);\n }\n\n this.base = options.base;\n this.overlay = options.overlay;\n this.schemaMap = schemaMap;\n }\n\n async applyOutboxEntry(options: {\n sourceKey: string;\n versionstamp: string;\n uowId: string;\n mutations: LofiMutation[];\n }): Promise<{ applied: boolean }> {\n return this.base.applyOutboxEntry(options);\n }\n\n async applyMutations(mutations: LofiMutation[]): Promise<void> {\n if (!this.base || !this.overlay) {\n return;\n }\n\n const materialized: LofiMutation[] = [];\n\n for (const mutation of mutations) {\n if (mutation.op !== \"update\") {\n materialized.push(mutation);\n continue;\n }\n\n const schema = this.schemaMap.get(mutation.schema);\n if (!schema) {\n throw new Error(`Unknown mutation schema: ${mutation.schema}`);\n }\n const table = schema.tables[mutation.table];\n if (!table) {\n throw new Error(`Unknown mutation table: ${mutation.schema}.${mutation.table}`);\n }\n\n const baseQuery = this.base.createQueryEngine(schema);\n const baseRow = (await baseQuery.findFirst(mutation.table, (b) =>\n b.whereIndex(\"primary\", (eb) =>\n (eb as unknown as (col: string, op: \"=\", value: string) => boolean)(\n table.getIdColumn().name,\n \"=\",\n mutation.externalId,\n ),\n ),\n )) as Record<string, unknown> | null;\n\n let values: Record<string, unknown> | null = null;\n\n if (baseRow) {\n values = { ...extractRowValues(baseRow, table) };\n } else {\n const overlayRow = this.overlay.store.getRow(\n mutation.schema,\n mutation.table,\n mutation.externalId,\n );\n if (overlayRow) {\n values = { ...overlayRow.data };\n }\n }\n\n if (!values) {\n materialized.push(mutation);\n continue;\n }\n\n materialized.push({\n op: \"create\",\n schema: mutation.schema,\n table: mutation.table,\n externalId: mutation.externalId,\n values: { ...values, ...mutation.set },\n versionstamp: mutation.versionstamp,\n });\n }\n\n if (materialized.length > 0) {\n await this.overlay.applyMutations(materialized);\n }\n }\n\n async getMeta(key: string): Promise<string | undefined> {\n return this.base.getMeta(key);\n }\n\n async setMeta(key: string, value: string): Promise<void> {\n await this.base.setMeta(key, value);\n }\n\n createQueryEngine<const T extends AnySchema>(\n schema: T,\n options?: LofiQueryEngineOptions,\n ): LofiQueryInterface<T> {\n return createStackedQueryEngine({\n schema,\n base: this.base,\n overlay: this.overlay,\n schemaName: options?.schemaName,\n });\n }\n}\n"],"mappings":";;;;AAkBA,MAAM,oBACJ,KACA,UAC4B;CAC5B,MAAMA,SAAkC,EAAE;AAC1C,MAAK,MAAM,cAAc,OAAO,KAAK,MAAM,QAAQ,CACjD,KAAI,cAAc,IAChB,QAAO,cAAc,IAAI;AAG7B,QAAO;;AAGT,IAAa,qBAAb,MAA6E;CAC3E,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,SAAoC;EAC9C,MAAM,4BAAY,IAAI,KAAwB;AAC9C,OAAK,MAAM,UAAU,QAAQ,SAAS;AACpC,OAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,MAAM,CAAC,WAAW,EAChD,OAAM,IAAI,MAAM,yDAAyD;AAE3E,OAAI,UAAU,IAAI,OAAO,KAAK,CAC5B,OAAM,IAAI,MAAM,kDAAkD,OAAO,OAAO;AAElF,aAAU,IAAI,OAAO,MAAM,OAAO;;AAGpC,OAAK,OAAO,QAAQ;AACpB,OAAK,UAAU,QAAQ;AACvB,OAAK,YAAY;;CAGnB,MAAM,iBAAiB,SAKW;AAChC,SAAO,KAAK,KAAK,iBAAiB,QAAQ;;CAG5C,MAAM,eAAe,WAA0C;AAC7D,MAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,QACtB;EAGF,MAAMC,eAA+B,EAAE;AAEvC,OAAK,MAAM,YAAY,WAAW;AAChC,OAAI,SAAS,OAAO,UAAU;AAC5B,iBAAa,KAAK,SAAS;AAC3B;;GAGF,MAAM,SAAS,KAAK,UAAU,IAAI,SAAS,OAAO;AAClD,OAAI,CAAC,OACH,OAAM,IAAI,MAAM,4BAA4B,SAAS,SAAS;GAEhE,MAAM,QAAQ,OAAO,OAAO,SAAS;AACrC,OAAI,CAAC,MACH,OAAM,IAAI,MAAM,2BAA2B,SAAS,OAAO,GAAG,SAAS,QAAQ;GAIjF,MAAM,UAAW,MADC,KAAK,KAAK,kBAAkB,OAAO,CACpB,UAAU,SAAS,QAAQ,MAC1D,EAAE,WAAW,YAAY,OACtB,GACC,MAAM,aAAa,CAAC,MACpB,KACA,SAAS,WACV,CACF,CACF;GAED,IAAIC,SAAyC;AAE7C,OAAI,QACF,UAAS,EAAE,GAAG,iBAAiB,SAAS,MAAM,EAAE;QAC3C;IACL,MAAM,aAAa,KAAK,QAAQ,MAAM,OACpC,SAAS,QACT,SAAS,OACT,SAAS,WACV;AACD,QAAI,WACF,UAAS,EAAE,GAAG,WAAW,MAAM;;AAInC,OAAI,CAAC,QAAQ;AACX,iBAAa,KAAK,SAAS;AAC3B;;AAGF,gBAAa,KAAK;IAChB,IAAI;IACJ,QAAQ,SAAS;IACjB,OAAO,SAAS;IAChB,YAAY,SAAS;IACrB,QAAQ;KAAE,GAAG;KAAQ,GAAG,SAAS;KAAK;IACtC,cAAc,SAAS;IACxB,CAAC;;AAGJ,MAAI,aAAa,SAAS,EACxB,OAAM,KAAK,QAAQ,eAAe,aAAa;;CAInD,MAAM,QAAQ,KAA0C;AACtD,SAAO,KAAK,KAAK,QAAQ,IAAI;;CAG/B,MAAM,QAAQ,KAAa,OAA8B;AACvD,QAAM,KAAK,KAAK,QAAQ,KAAK,MAAM;;CAGrC,kBACE,QACA,SACuB;AACvB,SAAO,yBAAyB;GAC9B;GACA,MAAM,KAAK;GACX,SAAS,KAAK;GACd,YAAY,SAAS;GACtB,CAAC"}