@rocicorp/zero 0.25.0-canary.12 → 0.25.0-canary.14
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.
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/pg.js +4 -2
- package/out/zero/src/server.js +4 -2
- package/out/zero-cache/src/config/zero-config.d.ts +0 -4
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +5 -15
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +2 -8
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/otel-diag-logger.js +1 -0
- package/out/zero-cache/src/server/otel-diag-logger.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +62 -42
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/control.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.js +5 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +2 -0
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/json.d.ts +8 -0
- package/out/zero-cache/src/services/change-source/protocol/current/json.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/json.js +19 -0
- package/out/zero-cache/src/services/change-source/protocol/current/json.js.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current.js +3 -0
- package/out/zero-cache/src/services/change-source/protocol/current.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +0 -2
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +0 -5
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +8 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +2 -3
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/http-service.d.ts +0 -1
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +0 -4
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.d.ts +2 -0
- package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js +14 -1
- package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +3 -3
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js +8 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +4 -3
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/error.d.ts +6 -1
- package/out/zero-client/src/client/error.d.ts.map +1 -1
- package/out/zero-client/src/client/error.js +2 -2
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.d.ts +6 -9
- package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.js +3 -8
- package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.d.ts +3 -2
- package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +15 -3
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +8 -8
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-events/src/status.d.ts +1 -1
- package/out/zero-events/src/status.d.ts.map +1 -1
- package/out/zero-schema/src/permissions.d.ts +3 -0
- package/out/zero-schema/src/permissions.d.ts.map +1 -1
- package/out/zero-schema/src/permissions.js.map +1 -1
- package/out/zero-server/src/custom.d.ts +2 -2
- package/out/zero-server/src/custom.d.ts.map +1 -1
- package/out/zero-server/src/custom.js +40 -4
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.d.ts +1 -1
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +10 -6
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +9 -18
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.d.ts.map +1 -1
- package/out/zero-server/src/push-processor.js +10 -8
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/queries/process-queries.d.ts +14 -2
- package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
- package/out/zero-server/src/queries/process-queries.js +18 -15
- package/out/zero-server/src/queries/process-queries.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +1 -5
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +0 -1
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/ivm/data.js +0 -11
- package/out/zql/src/ivm/data.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts +2 -2
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +34 -20
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.d.ts +1 -1
- package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-in.js +4 -2
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.d.ts +1 -1
- package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-out.js +9 -3
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +4 -6
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +14 -27
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter.d.ts +1 -1
- package/out/zql/src/ivm/filter.d.ts.map +1 -1
- package/out/zql/src/ivm/filter.js +4 -2
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts +0 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +0 -2
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts +2 -15
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +33 -96
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +4 -3
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +24 -23
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +0 -12
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/skip.d.ts +0 -1
- package/out/zql/src/ivm/skip.d.ts.map +1 -1
- package/out/zql/src/ivm/skip.js +3 -11
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts +0 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +0 -17
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts +0 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +0 -3
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.d.ts +0 -1
- package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js +0 -3
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +1 -2
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/mutate/mutator.d.ts +2 -2
- package/out/zql/src/mutate/mutator.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/create-builder.d.ts +2 -2
- package/out/zql/src/query/create-builder.d.ts.map +1 -1
- package/out/zql/src/query/create-builder.js +12 -3
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.d.ts +0 -1
- package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +0 -3
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zql/src/query/query.d.ts +18 -5
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +6 -10
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flipped-join.js","sources":["../../../../../zql/src/ivm/flipped-join.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {binarySearch} from '../../../shared/src/binary-search.ts';\nimport {emptyArray} from '../../../shared/src/sentinels.ts';\nimport type {Writable} from '../../../shared/src/writable.ts';\nimport type {CompoundKey, System} from '../../../zero-protocol/src/ast.ts';\nimport type {Value} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport {constraintsAreCompatible, type Constraint} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport {\n generateWithOverlayNoYield,\n isJoinMatch,\n rowEqualsForCompoundKey,\n type JoinChangeOverlay,\n} from './join-utils.ts';\nimport {\n throwOutput,\n skipYields,\n type FetchRequest,\n type Input,\n type Output,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {first, type Stream} from './stream.ts';\n\ntype Args = {\n parent: Input;\n child: Input;\n // The nth key in childKey corresponds to the nth key in parentKey.\n parentKey: CompoundKey;\n childKey: CompoundKey;\n\n relationshipName: string;\n hidden: boolean;\n system: System;\n};\n\n/**\n * An *inner* join which fetches nodes from its child input first and then\n * fetches their related nodes from its parent input. Output nodes are the\n * nodes from parent input (in parent input order), which have at least one\n * related child. These output nodes have a new relationship added to them,\n * which has the name `relationshipName`. The value of the relationship is a\n * stream of related nodes from the child input (in child input order).\n */\nexport class FlippedJoin implements Input {\n readonly #parent: Input;\n readonly #child: Input;\n readonly #parentKey: CompoundKey;\n readonly #childKey: CompoundKey;\n readonly #relationshipName: string;\n readonly #schema: SourceSchema;\n\n #output: Output = throwOutput;\n\n #inprogressChildChange: JoinChangeOverlay | undefined;\n\n constructor({\n parent,\n child,\n parentKey,\n childKey,\n relationshipName,\n hidden,\n system,\n }: Args) {\n assert(parent !== child, 'Parent and child must be different operators');\n assert(\n parentKey.length === childKey.length,\n 'The parentKey and childKey keys must have same length',\n );\n this.#parent = parent;\n this.#child = child;\n this.#parentKey = parentKey;\n this.#childKey = childKey;\n this.#relationshipName = relationshipName;\n\n const parentSchema = parent.getSchema();\n const childSchema = child.getSchema();\n this.#schema = {\n ...parentSchema,\n relationships: {\n ...parentSchema.relationships,\n [relationshipName]: {\n ...childSchema,\n isHidden: hidden,\n system,\n },\n },\n };\n\n parent.setOutput({\n push: (change: Change) => this.#pushParent(change),\n });\n child.setOutput({\n push: (change: Change) => this.#pushChild(change),\n });\n }\n\n destroy(): void {\n this.#child.destroy();\n this.#parent.destroy();\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#schema;\n }\n\n // TODO: When parentKey is the parent's primary key (or more\n // generally when the parent cardinality is expected to be small) a different\n // algorithm should be used: For each child node, fetch all parent nodes\n // eagerly and then sort using quicksort.\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n // Translate constraints for the parent on parts of the join key to\n // constraints for the child.\n const childConstraint: Record<string, Value> = {};\n let hasChildConstraint = false;\n if (req.constraint) {\n for (const [key, value] of Object.entries(req.constraint)) {\n const index = this.#parentKey.indexOf(key);\n if (index !== -1) {\n hasChildConstraint = true;\n childConstraint[this.#childKey[index]] = value;\n }\n }\n }\n\n const childNodes: Node[] = [];\n for (const node of this.#child.fetch(\n hasChildConstraint ? {constraint: childConstraint} : {},\n )) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n childNodes.push(node);\n }\n\n // FlippedJoin's split-push change overlay logic is largely\n // the same as Join's with the exception of remove. For remove,\n // the change is undone here, and then re-applied to parents with order\n // less than or equal to change.position below. This is necessary\n // because if the removed node was the last related child, the\n // related parents with position greater than change.position\n // (which should not yet have the node removed), would not even\n // be fetched here, and would be absent from the output all together.\n if (this.#inprogressChildChange?.change.type === 'remove') {\n const removedNode = this.#inprogressChildChange.change.node;\n const compare = this.#child.getSchema().compareRows;\n const insertPos = binarySearch(childNodes.length, i =>\n compare(removedNode.row, childNodes[i].row),\n );\n childNodes.splice(insertPos, 0, removedNode);\n }\n const parentIterators: Iterator<Node | 'yield'>[] = [];\n let threw = false;\n try {\n for (const childNode of childNodes) {\n // TODO: consider adding the ability to pass a set of\n // ids to fetch, and have them applied to sqlite using IN.\n const constraintFromChild: Writable<Constraint> = {};\n for (let i = 0; i < this.#parentKey.length; i++) {\n constraintFromChild[this.#parentKey[i]] =\n childNode.row[this.#childKey[i]];\n }\n if (\n req.constraint &&\n !constraintsAreCompatible(constraintFromChild, req.constraint)\n ) {\n parentIterators.push(emptyArray[Symbol.iterator]());\n } else {\n const stream = this.#parent.fetch({\n ...req,\n constraint: {\n ...req.constraint,\n ...constraintFromChild,\n },\n });\n const iterator = stream[Symbol.iterator]();\n parentIterators.push(iterator);\n }\n }\n const nextParentNodes: (Node | null)[] = [];\n for (let i = 0; i < parentIterators.length; i++) {\n const iter = parentIterators[i];\n let result = iter.next();\n // yield yields when initializing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n nextParentNodes[i] = result.done ? null : (result.value as Node);\n }\n\n while (true) {\n let minParentNode = null;\n let minParentNodeChildIndexes: number[] = [];\n for (let i = 0; i < nextParentNodes.length; i++) {\n const parentNode = nextParentNodes[i];\n if (parentNode === null) {\n continue;\n }\n if (minParentNode === null) {\n minParentNode = parentNode;\n minParentNodeChildIndexes.push(i);\n } else {\n const compareResult =\n this.#schema.compareRows(parentNode.row, minParentNode.row) *\n (req.reverse ? -1 : 1);\n if (compareResult === 0) {\n minParentNodeChildIndexes.push(i);\n } else if (compareResult < 0) {\n minParentNode = parentNode;\n minParentNodeChildIndexes = [i];\n }\n }\n }\n if (minParentNode === null) {\n return;\n }\n const relatedChildNodes: Node[] = [];\n for (const minParentNodeChildIndex of minParentNodeChildIndexes) {\n relatedChildNodes.push(childNodes[minParentNodeChildIndex]);\n const iter = parentIterators[minParentNodeChildIndex];\n let result = iter.next();\n // yield yields when advancing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n nextParentNodes[minParentNodeChildIndex] = result.done\n ? null\n : (result.value as Node);\n }\n let overlaidRelatedChildNodes = relatedChildNodes;\n if (\n this.#inprogressChildChange &&\n this.#inprogressChildChange.position &&\n isJoinMatch(\n this.#inprogressChildChange.change.node.row,\n this.#childKey,\n minParentNode.row,\n this.#parentKey,\n )\n ) {\n const hasInprogressChildChangeBeenPushedForMinParentNode =\n this.#parent\n .getSchema()\n .compareRows(\n minParentNode.row,\n this.#inprogressChildChange.position,\n ) <= 0;\n if (this.#inprogressChildChange.change.type === 'remove') {\n if (hasInprogressChildChangeBeenPushedForMinParentNode) {\n // Remove form relatedChildNodes since the removed child\n // was inserted into childNodes above.\n overlaidRelatedChildNodes = relatedChildNodes.filter(\n n => n !== this.#inprogressChildChange?.change.node,\n );\n }\n } else if (!hasInprogressChildChangeBeenPushedForMinParentNode) {\n overlaidRelatedChildNodes = [\n ...generateWithOverlayNoYield(\n relatedChildNodes,\n this.#inprogressChildChange.change,\n this.#child.getSchema(),\n ),\n ];\n }\n }\n\n // yield node if after the overlay it still has relationship nodes\n if (overlaidRelatedChildNodes.length > 0) {\n yield {\n ...minParentNode,\n relationships: {\n ...minParentNode.relationships,\n [this.#relationshipName]: () => overlaidRelatedChildNodes,\n },\n };\n }\n }\n } catch (e) {\n threw = true;\n for (const iter of parentIterators) {\n try {\n iter.throw?.(e);\n } catch (_cleanupError) {\n // error in the iter.throw cleanup,\n // catch so other iterators are cleaned up\n }\n }\n throw e;\n } finally {\n if (!threw) {\n for (const iter of parentIterators) {\n try {\n iter.return?.();\n } catch (_cleanupError) {\n // error in the iter.return cleanup,\n // catch so other iterators are cleaned up\n }\n }\n }\n }\n }\n\n *cleanup(_req: FetchRequest): Stream<Node> {}\n\n #pushChild(change: Change): void {\n const pushChildChange = (exists?: boolean) => {\n this.#inprogressChildChange = {\n change,\n position: undefined,\n };\n try {\n const parentNodeStream = this.#parent.fetch({\n constraint: Object.fromEntries(\n this.#parentKey.map((key, i) => [\n key,\n change.node.row[this.#childKey[i]],\n ]),\n ),\n });\n for (const parentNode of skipYields(parentNodeStream)) {\n this.#inprogressChildChange = {\n change,\n position: parentNode.row,\n };\n const childNodeStream = () =>\n this.#child.fetch({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [\n key,\n parentNode.row[this.#parentKey[i]],\n ]),\n ),\n });\n if (!exists) {\n for (const childNode of skipYields(childNodeStream())) {\n if (\n this.#child\n .getSchema()\n .compareRows(childNode.row, change.node.row) !== 0\n ) {\n exists = true;\n break;\n }\n }\n }\n if (exists) {\n this.#output.push(\n {\n type: 'child',\n node: {\n ...parentNode,\n relationships: {\n ...parentNode.relationships,\n [this.#relationshipName]: childNodeStream,\n },\n },\n child: {\n relationshipName: this.#relationshipName,\n change,\n },\n },\n this,\n );\n } else {\n this.#output.push(\n {\n ...change,\n node: {\n ...parentNode,\n relationships: {\n ...parentNode.relationships,\n [this.#relationshipName]: () => [change.node],\n },\n },\n },\n this,\n );\n }\n }\n } finally {\n this.#inprogressChildChange = undefined;\n }\n };\n\n switch (change.type) {\n case 'add':\n case 'remove':\n pushChildChange();\n break;\n case 'edit': {\n assert(\n rowEqualsForCompoundKey(\n change.oldNode.row,\n change.node.row,\n this.#childKey,\n ),\n `Child edit must not change relationship.`,\n );\n pushChildChange(true);\n break;\n }\n case 'child':\n pushChildChange(true);\n break;\n }\n }\n\n #pushParent(change: Change): void {\n const childNodeStream = (node: Node) => () =>\n this.#child.fetch({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [key, node.row[this.#parentKey[i]]]),\n ),\n });\n\n const flip = (node: Node) => ({\n ...node,\n relationships: {\n ...node.relationships,\n [this.#relationshipName]: childNodeStream(node),\n },\n });\n\n // If no related child don't push as this is an inner join.\n if (first(skipYields(childNodeStream(change.node)())) === undefined) {\n return;\n }\n\n switch (change.type) {\n case 'add':\n case 'remove':\n case 'child': {\n this.#output.push(\n {\n ...change,\n node: flip(change.node),\n },\n this,\n );\n break;\n }\n case 'edit': {\n assert(\n rowEqualsForCompoundKey(\n change.oldNode.row,\n change.node.row,\n this.#parentKey,\n ),\n `Parent edit must not change relationship.`,\n );\n this.#output.push(\n {\n type: 'edit',\n oldNode: flip(change.oldNode),\n node: flip(change.node),\n },\n this,\n );\n break;\n }\n default:\n unreachable(change);\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flipped-join.js","sources":["../../../../../zql/src/ivm/flipped-join.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {binarySearch} from '../../../shared/src/binary-search.ts';\nimport {emptyArray} from '../../../shared/src/sentinels.ts';\nimport type {Writable} from '../../../shared/src/writable.ts';\nimport type {CompoundKey, System} from '../../../zero-protocol/src/ast.ts';\nimport type {Value} from '../../../zero-protocol/src/data.ts';\nimport type {Change} from './change.ts';\nimport {constraintsAreCompatible, type Constraint} from './constraint.ts';\nimport type {Node} from './data.ts';\nimport {\n generateWithOverlayNoYield,\n isJoinMatch,\n rowEqualsForCompoundKey,\n type JoinChangeOverlay,\n} from './join-utils.ts';\nimport {\n throwOutput,\n skipYields,\n type FetchRequest,\n type Input,\n type Output,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {first, type Stream} from './stream.ts';\n\ntype Args = {\n parent: Input;\n child: Input;\n // The nth key in childKey corresponds to the nth key in parentKey.\n parentKey: CompoundKey;\n childKey: CompoundKey;\n\n relationshipName: string;\n hidden: boolean;\n system: System;\n};\n\n/**\n * An *inner* join which fetches nodes from its child input first and then\n * fetches their related nodes from its parent input. Output nodes are the\n * nodes from parent input (in parent input order), which have at least one\n * related child. These output nodes have a new relationship added to them,\n * which has the name `relationshipName`. The value of the relationship is a\n * stream of related nodes from the child input (in child input order).\n */\nexport class FlippedJoin implements Input {\n readonly #parent: Input;\n readonly #child: Input;\n readonly #parentKey: CompoundKey;\n readonly #childKey: CompoundKey;\n readonly #relationshipName: string;\n readonly #schema: SourceSchema;\n\n #output: Output = throwOutput;\n\n #inprogressChildChange: JoinChangeOverlay | undefined;\n\n constructor({\n parent,\n child,\n parentKey,\n childKey,\n relationshipName,\n hidden,\n system,\n }: Args) {\n assert(parent !== child, 'Parent and child must be different operators');\n assert(\n parentKey.length === childKey.length,\n 'The parentKey and childKey keys must have same length',\n );\n this.#parent = parent;\n this.#child = child;\n this.#parentKey = parentKey;\n this.#childKey = childKey;\n this.#relationshipName = relationshipName;\n\n const parentSchema = parent.getSchema();\n const childSchema = child.getSchema();\n this.#schema = {\n ...parentSchema,\n relationships: {\n ...parentSchema.relationships,\n [relationshipName]: {\n ...childSchema,\n isHidden: hidden,\n system,\n },\n },\n };\n\n parent.setOutput({\n push: (change: Change) => this.#pushParent(change),\n });\n child.setOutput({\n push: (change: Change) => this.#pushChild(change),\n });\n }\n\n destroy(): void {\n this.#child.destroy();\n this.#parent.destroy();\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#schema;\n }\n\n // TODO: When parentKey is the parent's primary key (or more\n // generally when the parent cardinality is expected to be small) a different\n // algorithm should be used: For each child node, fetch all parent nodes\n // eagerly and then sort using quicksort.\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n // Translate constraints for the parent on parts of the join key to\n // constraints for the child.\n const childConstraint: Record<string, Value> = {};\n let hasChildConstraint = false;\n if (req.constraint) {\n for (const [key, value] of Object.entries(req.constraint)) {\n const index = this.#parentKey.indexOf(key);\n if (index !== -1) {\n hasChildConstraint = true;\n childConstraint[this.#childKey[index]] = value;\n }\n }\n }\n\n const childNodes: Node[] = [];\n for (const node of this.#child.fetch(\n hasChildConstraint ? {constraint: childConstraint} : {},\n )) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n childNodes.push(node);\n }\n\n // FlippedJoin's split-push change overlay logic is largely\n // the same as Join's with the exception of remove. For remove,\n // the change is undone here, and then re-applied to parents with order\n // less than or equal to change.position below. This is necessary\n // because if the removed node was the last related child, the\n // related parents with position greater than change.position\n // (which should not yet have the node removed), would not even\n // be fetched here, and would be absent from the output all together.\n if (this.#inprogressChildChange?.change.type === 'remove') {\n const removedNode = this.#inprogressChildChange.change.node;\n const compare = this.#child.getSchema().compareRows;\n const insertPos = binarySearch(childNodes.length, i =>\n compare(removedNode.row, childNodes[i].row),\n );\n childNodes.splice(insertPos, 0, removedNode);\n }\n const parentIterators: Iterator<Node | 'yield'>[] = [];\n let threw = false;\n try {\n for (const childNode of childNodes) {\n // TODO: consider adding the ability to pass a set of\n // ids to fetch, and have them applied to sqlite using IN.\n const constraintFromChild: Writable<Constraint> = {};\n for (let i = 0; i < this.#parentKey.length; i++) {\n constraintFromChild[this.#parentKey[i]] =\n childNode.row[this.#childKey[i]];\n }\n if (\n req.constraint &&\n !constraintsAreCompatible(constraintFromChild, req.constraint)\n ) {\n parentIterators.push(emptyArray[Symbol.iterator]());\n } else {\n const stream = this.#parent.fetch({\n ...req,\n constraint: {\n ...req.constraint,\n ...constraintFromChild,\n },\n });\n const iterator = stream[Symbol.iterator]();\n parentIterators.push(iterator);\n }\n }\n const nextParentNodes: (Node | null)[] = [];\n for (let i = 0; i < parentIterators.length; i++) {\n const iter = parentIterators[i];\n let result = iter.next();\n // yield yields when initializing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n nextParentNodes[i] = result.done ? null : (result.value as Node);\n }\n\n while (true) {\n let minParentNode = null;\n let minParentNodeChildIndexes: number[] = [];\n for (let i = 0; i < nextParentNodes.length; i++) {\n const parentNode = nextParentNodes[i];\n if (parentNode === null) {\n continue;\n }\n if (minParentNode === null) {\n minParentNode = parentNode;\n minParentNodeChildIndexes.push(i);\n } else {\n const compareResult =\n this.#schema.compareRows(parentNode.row, minParentNode.row) *\n (req.reverse ? -1 : 1);\n if (compareResult === 0) {\n minParentNodeChildIndexes.push(i);\n } else if (compareResult < 0) {\n minParentNode = parentNode;\n minParentNodeChildIndexes = [i];\n }\n }\n }\n if (minParentNode === null) {\n return;\n }\n const relatedChildNodes: Node[] = [];\n for (const minParentNodeChildIndex of minParentNodeChildIndexes) {\n relatedChildNodes.push(childNodes[minParentNodeChildIndex]);\n const iter = parentIterators[minParentNodeChildIndex];\n let result = iter.next();\n // yield yields when advancing\n while (!result.done && result.value === 'yield') {\n yield result.value;\n result = iter.next();\n }\n nextParentNodes[minParentNodeChildIndex] = result.done\n ? null\n : (result.value as Node);\n }\n let overlaidRelatedChildNodes = relatedChildNodes;\n if (\n this.#inprogressChildChange &&\n this.#inprogressChildChange.position &&\n isJoinMatch(\n this.#inprogressChildChange.change.node.row,\n this.#childKey,\n minParentNode.row,\n this.#parentKey,\n )\n ) {\n const hasInprogressChildChangeBeenPushedForMinParentNode =\n this.#parent\n .getSchema()\n .compareRows(\n minParentNode.row,\n this.#inprogressChildChange.position,\n ) <= 0;\n if (this.#inprogressChildChange.change.type === 'remove') {\n if (hasInprogressChildChangeBeenPushedForMinParentNode) {\n // Remove form relatedChildNodes since the removed child\n // was inserted into childNodes above.\n overlaidRelatedChildNodes = relatedChildNodes.filter(\n n => n !== this.#inprogressChildChange?.change.node,\n );\n }\n } else if (!hasInprogressChildChangeBeenPushedForMinParentNode) {\n overlaidRelatedChildNodes = [\n ...generateWithOverlayNoYield(\n relatedChildNodes,\n this.#inprogressChildChange.change,\n this.#child.getSchema(),\n ),\n ];\n }\n }\n\n // yield node if after the overlay it still has relationship nodes\n if (overlaidRelatedChildNodes.length > 0) {\n yield {\n ...minParentNode,\n relationships: {\n ...minParentNode.relationships,\n [this.#relationshipName]: () => overlaidRelatedChildNodes,\n },\n };\n }\n }\n } catch (e) {\n threw = true;\n for (const iter of parentIterators) {\n try {\n iter.throw?.(e);\n } catch (_cleanupError) {\n // error in the iter.throw cleanup,\n // catch so other iterators are cleaned up\n }\n }\n throw e;\n } finally {\n if (!threw) {\n for (const iter of parentIterators) {\n try {\n iter.return?.();\n } catch (_cleanupError) {\n // error in the iter.return cleanup,\n // catch so other iterators are cleaned up\n }\n }\n }\n }\n }\n\n #pushChild(change: Change): void {\n const pushChildChange = (exists?: boolean) => {\n this.#inprogressChildChange = {\n change,\n position: undefined,\n };\n try {\n const parentNodeStream = this.#parent.fetch({\n constraint: Object.fromEntries(\n this.#parentKey.map((key, i) => [\n key,\n change.node.row[this.#childKey[i]],\n ]),\n ),\n });\n for (const parentNode of skipYields(parentNodeStream)) {\n this.#inprogressChildChange = {\n change,\n position: parentNode.row,\n };\n const childNodeStream = () =>\n this.#child.fetch({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [\n key,\n parentNode.row[this.#parentKey[i]],\n ]),\n ),\n });\n if (!exists) {\n for (const childNode of skipYields(childNodeStream())) {\n if (\n this.#child\n .getSchema()\n .compareRows(childNode.row, change.node.row) !== 0\n ) {\n exists = true;\n break;\n }\n }\n }\n if (exists) {\n this.#output.push(\n {\n type: 'child',\n node: {\n ...parentNode,\n relationships: {\n ...parentNode.relationships,\n [this.#relationshipName]: childNodeStream,\n },\n },\n child: {\n relationshipName: this.#relationshipName,\n change,\n },\n },\n this,\n );\n } else {\n this.#output.push(\n {\n ...change,\n node: {\n ...parentNode,\n relationships: {\n ...parentNode.relationships,\n [this.#relationshipName]: () => [change.node],\n },\n },\n },\n this,\n );\n }\n }\n } finally {\n this.#inprogressChildChange = undefined;\n }\n };\n\n switch (change.type) {\n case 'add':\n case 'remove':\n pushChildChange();\n break;\n case 'edit': {\n assert(\n rowEqualsForCompoundKey(\n change.oldNode.row,\n change.node.row,\n this.#childKey,\n ),\n `Child edit must not change relationship.`,\n );\n pushChildChange(true);\n break;\n }\n case 'child':\n pushChildChange(true);\n break;\n }\n }\n\n #pushParent(change: Change): void {\n const childNodeStream = (node: Node) => () =>\n this.#child.fetch({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [key, node.row[this.#parentKey[i]]]),\n ),\n });\n\n const flip = (node: Node) => ({\n ...node,\n relationships: {\n ...node.relationships,\n [this.#relationshipName]: childNodeStream(node),\n },\n });\n\n // If no related child don't push as this is an inner join.\n if (first(skipYields(childNodeStream(change.node)())) === undefined) {\n return;\n }\n\n switch (change.type) {\n case 'add':\n case 'remove':\n case 'child': {\n this.#output.push(\n {\n ...change,\n node: flip(change.node),\n },\n this,\n );\n break;\n }\n case 'edit': {\n assert(\n rowEqualsForCompoundKey(\n change.oldNode.row,\n change.node.row,\n this.#parentKey,\n ),\n `Parent edit must not change relationship.`,\n );\n this.#output.push(\n {\n type: 'edit',\n oldNode: flip(change.oldNode),\n node: flip(change.node),\n },\n this,\n );\n break;\n }\n default:\n unreachable(change);\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import type { CompoundKey, System } from '../../../zero-protocol/src/ast.ts';
|
|
2
|
-
import type { Row, Value } from '../../../zero-protocol/src/data.ts';
|
|
3
|
-
import type { PrimaryKey } from '../../../zero-protocol/src/primary-key.ts';
|
|
4
2
|
import type { Node } from './data.ts';
|
|
5
|
-
import { type FetchRequest, type Input, type Output
|
|
3
|
+
import { type FetchRequest, type Input, type Output } from './operator.ts';
|
|
6
4
|
import type { SourceSchema } from './schema.ts';
|
|
7
5
|
import { type Stream } from './stream.ts';
|
|
8
6
|
type Args = {
|
|
9
7
|
parent: Input;
|
|
10
8
|
child: Input;
|
|
11
|
-
storage: Storage;
|
|
12
9
|
parentKey: CompoundKey;
|
|
13
10
|
childKey: CompoundKey;
|
|
14
11
|
relationshipName: string;
|
|
@@ -27,21 +24,11 @@ type Args = {
|
|
|
27
24
|
*/
|
|
28
25
|
export declare class Join implements Input {
|
|
29
26
|
#private;
|
|
30
|
-
constructor({ parent, child,
|
|
27
|
+
constructor({ parent, child, parentKey, childKey, relationshipName, hidden, system, }: Args);
|
|
31
28
|
destroy(): void;
|
|
32
29
|
setOutput(output: Output): void;
|
|
33
30
|
getSchema(): SourceSchema;
|
|
34
31
|
fetch(req: FetchRequest): Stream<Node | 'yield'>;
|
|
35
|
-
cleanup(req: FetchRequest): Stream<Node>;
|
|
36
32
|
}
|
|
37
|
-
/** Exported for testing. */
|
|
38
|
-
export declare function makeStorageKeyForValues(values: readonly Value[]): string;
|
|
39
|
-
/** Exported for testing. */
|
|
40
|
-
export declare function makeStorageKeyPrefix(row: Row, key: CompoundKey): string;
|
|
41
|
-
/** Exported for testing.
|
|
42
|
-
* This storage key tracks the primary keys seen for each unique
|
|
43
|
-
* value joined on. This is used to know when to cleanup a child's state.
|
|
44
|
-
*/
|
|
45
|
-
export declare function makeStorageKey(key: CompoundKey, primaryKey: PrimaryKey, row: Row): string;
|
|
46
33
|
export {};
|
|
47
34
|
//# sourceMappingURL=join.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/join.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/join.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAG3E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAOpC,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IAEb,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;;;GASG;AACH,qBAAa,IAAK,YAAW,KAAK;;gBAYpB,EACV,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,MAAM,EACN,MAAM,GACP,EAAE,IAAI;IAkCP,OAAO,IAAI,IAAI;IAKf,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,SAAS,IAAI,YAAY;IAIxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;CA0MlD"}
|
package/out/zql/src/ivm/join.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { assert, unreachable } from "../../../shared/src/asserts.js";
|
|
2
2
|
import { rowEqualsForCompoundKey, isJoinMatch, generateWithOverlay } from "./join-utils.js";
|
|
3
3
|
import { throwOutput, skipYields } from "./operator.js";
|
|
4
|
-
import { take } from "./stream.js";
|
|
5
4
|
class Join {
|
|
6
5
|
#parent;
|
|
7
6
|
#child;
|
|
8
|
-
#storage;
|
|
9
7
|
#parentKey;
|
|
10
8
|
#childKey;
|
|
11
9
|
#relationshipName;
|
|
@@ -15,7 +13,6 @@ class Join {
|
|
|
15
13
|
constructor({
|
|
16
14
|
parent,
|
|
17
15
|
child,
|
|
18
|
-
storage,
|
|
19
16
|
parentKey,
|
|
20
17
|
childKey,
|
|
21
18
|
relationshipName,
|
|
@@ -29,7 +26,6 @@ class Join {
|
|
|
29
26
|
);
|
|
30
27
|
this.#parent = parent;
|
|
31
28
|
this.#child = child;
|
|
32
|
-
this.#storage = storage;
|
|
33
29
|
this.#parentKey = parentKey;
|
|
34
30
|
this.#childKey = childKey;
|
|
35
31
|
this.#relationshipName = relationshipName;
|
|
@@ -69,20 +65,7 @@ class Join {
|
|
|
69
65
|
yield parentNode;
|
|
70
66
|
continue;
|
|
71
67
|
}
|
|
72
|
-
yield this.#processParentNode(
|
|
73
|
-
parentNode.row,
|
|
74
|
-
parentNode.relationships,
|
|
75
|
-
"fetch"
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
*cleanup(req) {
|
|
80
|
-
for (const parentNode of this.#parent.cleanup(req)) {
|
|
81
|
-
yield this.#processParentNode(
|
|
82
|
-
parentNode.row,
|
|
83
|
-
parentNode.relationships,
|
|
84
|
-
"cleanup"
|
|
85
|
-
);
|
|
68
|
+
yield this.#processParentNode(parentNode.row, parentNode.relationships);
|
|
86
69
|
}
|
|
87
70
|
}
|
|
88
71
|
#pushParent(change) {
|
|
@@ -93,8 +76,7 @@ class Join {
|
|
|
93
76
|
type: "add",
|
|
94
77
|
node: this.#processParentNode(
|
|
95
78
|
change.node.row,
|
|
96
|
-
change.node.relationships
|
|
97
|
-
"fetch"
|
|
79
|
+
change.node.relationships
|
|
98
80
|
)
|
|
99
81
|
},
|
|
100
82
|
this
|
|
@@ -106,8 +88,7 @@ class Join {
|
|
|
106
88
|
type: "remove",
|
|
107
89
|
node: this.#processParentNode(
|
|
108
90
|
change.node.row,
|
|
109
|
-
change.node.relationships
|
|
110
|
-
"cleanup"
|
|
91
|
+
change.node.relationships
|
|
111
92
|
)
|
|
112
93
|
},
|
|
113
94
|
this
|
|
@@ -119,8 +100,7 @@ class Join {
|
|
|
119
100
|
type: "child",
|
|
120
101
|
node: this.#processParentNode(
|
|
121
102
|
change.node.row,
|
|
122
|
-
change.node.relationships
|
|
123
|
-
"fetch"
|
|
103
|
+
change.node.relationships
|
|
124
104
|
),
|
|
125
105
|
child: change.child
|
|
126
106
|
},
|
|
@@ -141,13 +121,11 @@ class Join {
|
|
|
141
121
|
type: "edit",
|
|
142
122
|
oldNode: this.#processParentNode(
|
|
143
123
|
change.oldNode.row,
|
|
144
|
-
change.oldNode.relationships
|
|
145
|
-
"cleanup"
|
|
124
|
+
change.oldNode.relationships
|
|
146
125
|
),
|
|
147
126
|
node: this.#processParentNode(
|
|
148
127
|
change.node.row,
|
|
149
|
-
change.node.relationships
|
|
150
|
-
"fetch"
|
|
128
|
+
change.node.relationships
|
|
151
129
|
)
|
|
152
130
|
},
|
|
153
131
|
this
|
|
@@ -165,14 +143,19 @@ class Join {
|
|
|
165
143
|
position: void 0
|
|
166
144
|
};
|
|
167
145
|
try {
|
|
168
|
-
|
|
146
|
+
let anyNull = false;
|
|
147
|
+
const constraint = Object.fromEntries(
|
|
148
|
+
this.#parentKey.map((key, i) => {
|
|
149
|
+
const value = childRow[this.#childKey[i]];
|
|
150
|
+
if (value === null) {
|
|
151
|
+
anyNull = true;
|
|
152
|
+
}
|
|
153
|
+
return [key, value];
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
const parentNodes = anyNull ? [] : skipYields(
|
|
169
157
|
this.#parent.fetch({
|
|
170
|
-
constraint
|
|
171
|
-
this.#parentKey.map((key, i) => [
|
|
172
|
-
key,
|
|
173
|
-
childRow[this.#childKey[i]]
|
|
174
|
-
])
|
|
175
|
-
)
|
|
158
|
+
constraint
|
|
176
159
|
})
|
|
177
160
|
);
|
|
178
161
|
for (const parentNode of parentNodes) {
|
|
@@ -181,8 +164,7 @@ class Join {
|
|
|
181
164
|
type: "child",
|
|
182
165
|
node: this.#processParentNode(
|
|
183
166
|
parentNode.row,
|
|
184
|
-
parentNode.relationships
|
|
185
|
-
"fetch"
|
|
167
|
+
parentNode.relationships
|
|
186
168
|
),
|
|
187
169
|
child: {
|
|
188
170
|
relationshipName: this.#relationshipName,
|
|
@@ -217,48 +199,20 @@ class Join {
|
|
|
217
199
|
unreachable();
|
|
218
200
|
}
|
|
219
201
|
}
|
|
220
|
-
#processParentNode(parentNodeRow, parentNodeRelations
|
|
221
|
-
let method = mode;
|
|
222
|
-
let storageUpdated = false;
|
|
202
|
+
#processParentNode(parentNodeRow, parentNodeRelations) {
|
|
223
203
|
const childStream = () => {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
prefix: makeStorageKeyPrefix(parentNodeRow, this.#parentKey)
|
|
237
|
-
}),
|
|
238
|
-
1
|
|
239
|
-
)
|
|
240
|
-
].length === 0;
|
|
241
|
-
method = empty ? "cleanup" : "fetch";
|
|
242
|
-
}
|
|
243
|
-
storageUpdated = true;
|
|
244
|
-
if (mode === "fetch") {
|
|
245
|
-
this.#storage.set(
|
|
246
|
-
makeStorageKey(
|
|
247
|
-
this.#parentKey,
|
|
248
|
-
this.#parent.getSchema().primaryKey,
|
|
249
|
-
parentNodeRow
|
|
250
|
-
),
|
|
251
|
-
true
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
const stream = this.#child[method]({
|
|
256
|
-
constraint: Object.fromEntries(
|
|
257
|
-
this.#childKey.map((key, i) => [
|
|
258
|
-
key,
|
|
259
|
-
parentNodeRow[this.#parentKey[i]]
|
|
260
|
-
])
|
|
261
|
-
)
|
|
204
|
+
let anyNull = false;
|
|
205
|
+
const constraint = Object.fromEntries(
|
|
206
|
+
this.#childKey.map((key, i) => {
|
|
207
|
+
const value = parentNodeRow[this.#parentKey[i]];
|
|
208
|
+
if (value === null) {
|
|
209
|
+
anyNull = true;
|
|
210
|
+
}
|
|
211
|
+
return [key, value];
|
|
212
|
+
})
|
|
213
|
+
);
|
|
214
|
+
const stream = anyNull ? [] : this.#child.fetch({
|
|
215
|
+
constraint
|
|
262
216
|
});
|
|
263
217
|
if (this.#inprogressChildChange && isJoinMatch(
|
|
264
218
|
parentNodeRow,
|
|
@@ -286,24 +240,7 @@ class Join {
|
|
|
286
240
|
};
|
|
287
241
|
}
|
|
288
242
|
}
|
|
289
|
-
function makeStorageKeyForValues(values) {
|
|
290
|
-
const json = JSON.stringify(["pKeySet", ...values]);
|
|
291
|
-
return json.substring(1, json.length - 1) + ",";
|
|
292
|
-
}
|
|
293
|
-
function makeStorageKeyPrefix(row, key) {
|
|
294
|
-
return makeStorageKeyForValues(key.map((k) => row[k]));
|
|
295
|
-
}
|
|
296
|
-
function makeStorageKey(key, primaryKey, row) {
|
|
297
|
-
const values = key.map((k) => row[k]);
|
|
298
|
-
for (const key2 of primaryKey) {
|
|
299
|
-
values.push(row[key2]);
|
|
300
|
-
}
|
|
301
|
-
return makeStorageKeyForValues(values);
|
|
302
|
-
}
|
|
303
243
|
export {
|
|
304
|
-
Join
|
|
305
|
-
makeStorageKey,
|
|
306
|
-
makeStorageKeyForValues,
|
|
307
|
-
makeStorageKeyPrefix
|
|
244
|
+
Join
|
|
308
245
|
};
|
|
309
246
|
//# sourceMappingURL=join.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"join.js","sources":["../../../../../zql/src/ivm/join.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport type {CompoundKey, System} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport type {Change, ChildChange} from './change.ts';\nimport type {Node} from './data.ts';\nimport {\n generateWithOverlay,\n isJoinMatch,\n rowEqualsForCompoundKey,\n type JoinChangeOverlay,\n} from './join-utils.ts';\nimport {\n throwOutput,\n skipYields,\n type FetchRequest,\n type Input,\n type Output,\n type Storage,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {take, type Stream} from './stream.ts';\n\ntype Args = {\n parent: Input;\n child: Input;\n storage: Storage;\n // The nth key in parentKey corresponds to the nth key in childKey.\n parentKey: CompoundKey;\n childKey: CompoundKey;\n relationshipName: string;\n hidden: boolean;\n system: System;\n};\n\n/**\n * The Join operator joins the output from two upstream inputs. Zero's join\n * is a little different from SQL's join in that we output hierarchical data,\n * not a flat table. This makes it a lot more useful for UI programming and\n * avoids duplicating tons of data like left join would.\n *\n * The Nodes output from Join have a new relationship added to them, which has\n * the name #relationshipName. The value of the relationship is a stream of\n * child nodes which are the corresponding values from the child source.\n */\nexport class Join implements Input {\n readonly #parent: Input;\n readonly #child: Input;\n readonly #storage: Storage;\n readonly #parentKey: CompoundKey;\n readonly #childKey: CompoundKey;\n readonly #relationshipName: string;\n readonly #schema: SourceSchema;\n\n #output: Output = throwOutput;\n\n #inprogressChildChange: JoinChangeOverlay | undefined;\n\n constructor({\n parent,\n child,\n storage,\n parentKey,\n childKey,\n relationshipName,\n hidden,\n system,\n }: Args) {\n assert(parent !== child, 'Parent and child must be different operators');\n assert(\n parentKey.length === childKey.length,\n 'The parentKey and childKey keys must have same length',\n );\n this.#parent = parent;\n this.#child = child;\n this.#storage = storage;\n this.#parentKey = parentKey;\n this.#childKey = childKey;\n this.#relationshipName = relationshipName;\n\n const parentSchema = parent.getSchema();\n const childSchema = child.getSchema();\n this.#schema = {\n ...parentSchema,\n relationships: {\n ...parentSchema.relationships,\n [relationshipName]: {\n ...childSchema,\n isHidden: hidden,\n system,\n },\n },\n };\n\n parent.setOutput({\n push: (change: Change) => this.#pushParent(change),\n });\n child.setOutput({\n push: (change: Change) => this.#pushChild(change),\n });\n }\n\n destroy(): void {\n this.#parent.destroy();\n this.#child.destroy();\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#schema;\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n for (const parentNode of this.#parent.fetch(req)) {\n if (parentNode === 'yield') {\n yield parentNode;\n continue;\n }\n yield this.#processParentNode(\n parentNode.row,\n parentNode.relationships,\n 'fetch',\n );\n }\n }\n\n *cleanup(req: FetchRequest): Stream<Node> {\n for (const parentNode of this.#parent.cleanup(req)) {\n yield this.#processParentNode(\n parentNode.row,\n parentNode.relationships,\n 'cleanup',\n );\n }\n }\n\n #pushParent(change: Change): void {\n switch (change.type) {\n case 'add':\n this.#output.push(\n {\n type: 'add',\n node: this.#processParentNode(\n change.node.row,\n change.node.relationships,\n 'fetch',\n ),\n },\n this,\n );\n break;\n case 'remove':\n this.#output.push(\n {\n type: 'remove',\n node: this.#processParentNode(\n change.node.row,\n change.node.relationships,\n 'cleanup',\n ),\n },\n this,\n );\n break;\n case 'child':\n this.#output.push(\n {\n type: 'child',\n node: this.#processParentNode(\n change.node.row,\n change.node.relationships,\n 'fetch',\n ),\n child: change.child,\n },\n this,\n );\n break;\n case 'edit': {\n // Assert the edit could not change the relationship.\n assert(\n rowEqualsForCompoundKey(\n change.oldNode.row,\n change.node.row,\n this.#parentKey,\n ),\n `Parent edit must not change relationship.`,\n );\n this.#output.push(\n {\n type: 'edit',\n oldNode: this.#processParentNode(\n change.oldNode.row,\n change.oldNode.relationships,\n 'cleanup',\n ),\n node: this.#processParentNode(\n change.node.row,\n change.node.relationships,\n 'fetch',\n ),\n },\n this,\n );\n break;\n }\n default:\n unreachable(change);\n }\n }\n\n #pushChild(change: Change): void {\n const pushChildChange = (childRow: Row, change: Change) => {\n this.#inprogressChildChange = {\n change,\n position: undefined,\n };\n try {\n const parentNodes = skipYields(\n this.#parent.fetch({\n constraint: Object.fromEntries(\n this.#parentKey.map((key, i) => [\n key,\n childRow[this.#childKey[i]],\n ]),\n ),\n }),\n );\n\n for (const parentNode of parentNodes) {\n this.#inprogressChildChange.position = parentNode.row;\n const childChange: ChildChange = {\n type: 'child',\n node: this.#processParentNode(\n parentNode.row,\n parentNode.relationships,\n 'fetch',\n ),\n child: {\n relationshipName: this.#relationshipName,\n change,\n },\n };\n this.#output.push(childChange, this);\n }\n } finally {\n this.#inprogressChildChange = undefined;\n }\n };\n\n switch (change.type) {\n case 'add':\n case 'remove':\n pushChildChange(change.node.row, change);\n break;\n case 'child':\n pushChildChange(change.node.row, change);\n break;\n case 'edit': {\n const childRow = change.node.row;\n const oldChildRow = change.oldNode.row;\n // Assert the edit could not change the relationship.\n assert(\n rowEqualsForCompoundKey(oldChildRow, childRow, this.#childKey),\n 'Child edit must not change relationship.',\n );\n pushChildChange(childRow, change);\n break;\n }\n\n default:\n unreachable(change);\n }\n }\n\n #processParentNode(\n parentNodeRow: Row,\n parentNodeRelations: Record<string, () => Stream<Node | 'yield'>>,\n mode: ProcessParentMode,\n ): Node {\n let method: ProcessParentMode = mode;\n let storageUpdated = false;\n const childStream = () => {\n if (!storageUpdated) {\n if (mode === 'cleanup') {\n this.#storage.del(\n makeStorageKey(\n this.#parentKey,\n this.#parent.getSchema().primaryKey,\n parentNodeRow,\n ),\n );\n const empty =\n [\n ...take(\n this.#storage.scan({\n prefix: makeStorageKeyPrefix(parentNodeRow, this.#parentKey),\n }),\n 1,\n ),\n ].length === 0;\n method = empty ? 'cleanup' : 'fetch';\n }\n\n storageUpdated = true;\n // Defer the work to update storage until the child stream\n // is actually accessed\n if (mode === 'fetch') {\n this.#storage.set(\n makeStorageKey(\n this.#parentKey,\n this.#parent.getSchema().primaryKey,\n parentNodeRow,\n ),\n true,\n );\n }\n }\n\n const stream = this.#child[method]({\n constraint: Object.fromEntries(\n this.#childKey.map((key, i) => [\n key,\n parentNodeRow[this.#parentKey[i]],\n ]),\n ),\n });\n\n if (\n this.#inprogressChildChange &&\n isJoinMatch(\n parentNodeRow,\n this.#parentKey,\n this.#inprogressChildChange.change.node.row,\n this.#childKey,\n ) &&\n this.#inprogressChildChange.position &&\n this.#schema.compareRows(\n parentNodeRow,\n this.#inprogressChildChange.position,\n ) > 0\n ) {\n return generateWithOverlay(\n stream,\n this.#inprogressChildChange.change,\n this.#child.getSchema(),\n );\n }\n return stream;\n };\n\n return {\n row: parentNodeRow,\n relationships: {\n ...parentNodeRelations,\n [this.#relationshipName]: childStream,\n },\n };\n }\n}\n\ntype ProcessParentMode = 'fetch' | 'cleanup';\n\n/** Exported for testing. */\nexport function makeStorageKeyForValues(values: readonly Value[]): string {\n const json = JSON.stringify(['pKeySet', ...values]);\n return json.substring(1, json.length - 1) + ',';\n}\n\n/** Exported for testing. */\nexport function makeStorageKeyPrefix(row: Row, key: CompoundKey): string {\n return makeStorageKeyForValues(key.map(k => row[k]));\n}\n\n/** Exported for testing.\n * This storage key tracks the primary keys seen for each unique\n * value joined on. This is used to know when to cleanup a child's state.\n */\nexport function makeStorageKey(\n key: CompoundKey,\n primaryKey: PrimaryKey,\n row: Row,\n): string {\n const values: Value[] = key.map(k => row[k]);\n for (const key of primaryKey) {\n values.push(row[key]);\n }\n return makeStorageKeyForValues(values);\n}\n"],"names":["change","key"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"join.js","sources":["../../../../../zql/src/ivm/join.ts"],"sourcesContent":["import {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport type {CompoundKey, System} from '../../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {Change, ChildChange} from './change.ts';\nimport type {Node} from './data.ts';\nimport {\n generateWithOverlay,\n isJoinMatch,\n rowEqualsForCompoundKey,\n type JoinChangeOverlay,\n} from './join-utils.ts';\nimport {\n throwOutput,\n skipYields,\n type FetchRequest,\n type Input,\n type Output,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.ts';\n\ntype Args = {\n parent: Input;\n child: Input;\n // The nth key in parentKey corresponds to the nth key in childKey.\n parentKey: CompoundKey;\n childKey: CompoundKey;\n relationshipName: string;\n hidden: boolean;\n system: System;\n};\n\n/**\n * The Join operator joins the output from two upstream inputs. Zero's join\n * is a little different from SQL's join in that we output hierarchical data,\n * not a flat table. This makes it a lot more useful for UI programming and\n * avoids duplicating tons of data like left join would.\n *\n * The Nodes output from Join have a new relationship added to them, which has\n * the name #relationshipName. The value of the relationship is a stream of\n * child nodes which are the corresponding values from the child source.\n */\nexport class Join implements Input {\n readonly #parent: Input;\n readonly #child: Input;\n readonly #parentKey: CompoundKey;\n readonly #childKey: CompoundKey;\n readonly #relationshipName: string;\n readonly #schema: SourceSchema;\n\n #output: Output = throwOutput;\n\n #inprogressChildChange: JoinChangeOverlay | undefined;\n\n constructor({\n parent,\n child,\n parentKey,\n childKey,\n relationshipName,\n hidden,\n system,\n }: Args) {\n assert(parent !== child, 'Parent and child must be different operators');\n assert(\n parentKey.length === childKey.length,\n 'The parentKey and childKey keys must have same length',\n );\n this.#parent = parent;\n this.#child = child;\n this.#parentKey = parentKey;\n this.#childKey = childKey;\n this.#relationshipName = relationshipName;\n\n const parentSchema = parent.getSchema();\n const childSchema = child.getSchema();\n this.#schema = {\n ...parentSchema,\n relationships: {\n ...parentSchema.relationships,\n [relationshipName]: {\n ...childSchema,\n isHidden: hidden,\n system,\n },\n },\n };\n\n parent.setOutput({\n push: (change: Change) => this.#pushParent(change),\n });\n child.setOutput({\n push: (change: Change) => this.#pushChild(change),\n });\n }\n\n destroy(): void {\n this.#parent.destroy();\n this.#child.destroy();\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#schema;\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n for (const parentNode of this.#parent.fetch(req)) {\n if (parentNode === 'yield') {\n yield parentNode;\n continue;\n }\n yield this.#processParentNode(parentNode.row, parentNode.relationships);\n }\n }\n\n #pushParent(change: Change): void {\n switch (change.type) {\n case 'add':\n this.#output.push(\n {\n type: 'add',\n node: this.#processParentNode(\n change.node.row,\n change.node.relationships,\n ),\n },\n this,\n );\n break;\n case 'remove':\n this.#output.push(\n {\n type: 'remove',\n node: this.#processParentNode(\n change.node.row,\n change.node.relationships,\n ),\n },\n this,\n );\n break;\n case 'child':\n this.#output.push(\n {\n type: 'child',\n node: this.#processParentNode(\n change.node.row,\n change.node.relationships,\n ),\n child: change.child,\n },\n this,\n );\n break;\n case 'edit': {\n // Assert the edit could not change the relationship.\n assert(\n rowEqualsForCompoundKey(\n change.oldNode.row,\n change.node.row,\n this.#parentKey,\n ),\n `Parent edit must not change relationship.`,\n );\n this.#output.push(\n {\n type: 'edit',\n oldNode: this.#processParentNode(\n change.oldNode.row,\n change.oldNode.relationships,\n ),\n node: this.#processParentNode(\n change.node.row,\n change.node.relationships,\n ),\n },\n this,\n );\n break;\n }\n default:\n unreachable(change);\n }\n }\n\n #pushChild(change: Change): void {\n const pushChildChange = (childRow: Row, change: Change) => {\n this.#inprogressChildChange = {\n change,\n position: undefined,\n };\n try {\n let anyNull = false;\n const constraint = Object.fromEntries(\n this.#parentKey.map((key, i) => {\n const value = childRow[this.#childKey[i]];\n if (value === null) {\n anyNull = true;\n }\n return [key, value];\n }),\n );\n const parentNodes = anyNull\n ? []\n : skipYields(\n this.#parent.fetch({\n constraint,\n }),\n );\n\n for (const parentNode of parentNodes) {\n this.#inprogressChildChange.position = parentNode.row;\n const childChange: ChildChange = {\n type: 'child',\n node: this.#processParentNode(\n parentNode.row,\n parentNode.relationships,\n ),\n child: {\n relationshipName: this.#relationshipName,\n change,\n },\n };\n this.#output.push(childChange, this);\n }\n } finally {\n this.#inprogressChildChange = undefined;\n }\n };\n\n switch (change.type) {\n case 'add':\n case 'remove':\n pushChildChange(change.node.row, change);\n break;\n case 'child':\n pushChildChange(change.node.row, change);\n break;\n case 'edit': {\n const childRow = change.node.row;\n const oldChildRow = change.oldNode.row;\n // Assert the edit could not change the relationship.\n assert(\n rowEqualsForCompoundKey(oldChildRow, childRow, this.#childKey),\n 'Child edit must not change relationship.',\n );\n pushChildChange(childRow, change);\n break;\n }\n\n default:\n unreachable(change);\n }\n }\n\n #processParentNode(\n parentNodeRow: Row,\n parentNodeRelations: Record<string, () => Stream<Node | 'yield'>>,\n ): Node {\n const childStream = () => {\n let anyNull = false;\n const constraint = Object.fromEntries(\n this.#childKey.map((key, i) => {\n const value = parentNodeRow[this.#parentKey[i]];\n if (value === null) {\n anyNull = true;\n }\n return [key, value];\n }),\n );\n const stream = anyNull\n ? []\n : this.#child.fetch({\n constraint,\n });\n\n if (\n this.#inprogressChildChange &&\n isJoinMatch(\n parentNodeRow,\n this.#parentKey,\n this.#inprogressChildChange.change.node.row,\n this.#childKey,\n ) &&\n this.#inprogressChildChange.position &&\n this.#schema.compareRows(\n parentNodeRow,\n this.#inprogressChildChange.position,\n ) > 0\n ) {\n return generateWithOverlay(\n stream,\n this.#inprogressChildChange.change,\n this.#child.getSchema(),\n );\n }\n return stream;\n };\n\n return {\n row: parentNodeRow,\n relationships: {\n ...parentNodeRelations,\n [this.#relationshipName]: childStream,\n },\n };\n }\n}\n"],"names":["change"],"mappings":";;;AA0CO,MAAM,KAAsB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,UAAkB;AAAA,EAElB;AAAA,EAEA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,GACO;AACP,WAAO,WAAW,OAAO,8CAA8C;AACvE;AAAA,MACE,UAAU,WAAW,SAAS;AAAA,MAC9B;AAAA,IAAA;AAEF,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,aAAa;AAClB,SAAK,YAAY;AACjB,SAAK,oBAAoB;AAEzB,UAAM,eAAe,OAAO,UAAA;AAC5B,UAAM,cAAc,MAAM,UAAA;AAC1B,SAAK,UAAU;AAAA,MACb,GAAG;AAAA,MACH,eAAe;AAAA,QACb,GAAG,aAAa;AAAA,QAChB,CAAC,gBAAgB,GAAG;AAAA,UAClB,GAAG;AAAA,UACH,UAAU;AAAA,UACV;AAAA,QAAA;AAAA,MACF;AAAA,IACF;AAGF,WAAO,UAAU;AAAA,MACf,MAAM,CAAC,WAAmB,KAAK,YAAY,MAAM;AAAA,IAAA,CAClD;AACD,UAAM,UAAU;AAAA,MACd,MAAM,CAAC,WAAmB,KAAK,WAAW,MAAM;AAAA,IAAA,CACjD;AAAA,EACH;AAAA,EAEA,UAAgB;AACd,SAAK,QAAQ,QAAA;AACb,SAAK,OAAO,QAAA;AAAA,EACd;AAAA,EAEA,UAAU,QAAsB;AAC9B,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,YAA0B;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,CAAC,MAAM,KAA2C;AAChD,eAAW,cAAc,KAAK,QAAQ,MAAM,GAAG,GAAG;AAChD,UAAI,eAAe,SAAS;AAC1B,cAAM;AACN;AAAA,MACF;AACA,YAAM,KAAK,mBAAmB,WAAW,KAAK,WAAW,aAAa;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,YAAY,QAAsB;AAChC,YAAQ,OAAO,MAAA;AAAA,MACb,KAAK;AACH,aAAK,QAAQ;AAAA,UACX;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK;AAAA,cACT,OAAO,KAAK;AAAA,cACZ,OAAO,KAAK;AAAA,YAAA;AAAA,UACd;AAAA,UAEF;AAAA,QAAA;AAEF;AAAA,MACF,KAAK;AACH,aAAK,QAAQ;AAAA,UACX;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK;AAAA,cACT,OAAO,KAAK;AAAA,cACZ,OAAO,KAAK;AAAA,YAAA;AAAA,UACd;AAAA,UAEF;AAAA,QAAA;AAEF;AAAA,MACF,KAAK;AACH,aAAK,QAAQ;AAAA,UACX;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK;AAAA,cACT,OAAO,KAAK;AAAA,cACZ,OAAO,KAAK;AAAA,YAAA;AAAA,YAEd,OAAO,OAAO;AAAA,UAAA;AAAA,UAEhB;AAAA,QAAA;AAEF;AAAA,MACF,KAAK,QAAQ;AAEX;AAAA,UACE;AAAA,YACE,OAAO,QAAQ;AAAA,YACf,OAAO,KAAK;AAAA,YACZ,KAAK;AAAA,UAAA;AAAA,UAEP;AAAA,QAAA;AAEF,aAAK,QAAQ;AAAA,UACX;AAAA,YACE,MAAM;AAAA,YACN,SAAS,KAAK;AAAA,cACZ,OAAO,QAAQ;AAAA,cACf,OAAO,QAAQ;AAAA,YAAA;AAAA,YAEjB,MAAM,KAAK;AAAA,cACT,OAAO,KAAK;AAAA,cACZ,OAAO,KAAK;AAAA,YAAA;AAAA,UACd;AAAA,UAEF;AAAA,QAAA;AAEF;AAAA,MACF;AAAA,MACA;AACE,oBAAkB;AAAA,IAAA;AAAA,EAExB;AAAA,EAEA,WAAW,QAAsB;AAC/B,UAAM,kBAAkB,CAAC,UAAeA,YAAmB;AACzD,WAAK,yBAAyB;AAAA,QAC5B,QAAAA;AAAAA,QACA,UAAU;AAAA,MAAA;AAEZ,UAAI;AACF,YAAI,UAAU;AACd,cAAM,aAAa,OAAO;AAAA,UACxB,KAAK,WAAW,IAAI,CAAC,KAAK,MAAM;AAC9B,kBAAM,QAAQ,SAAS,KAAK,UAAU,CAAC,CAAC;AACxC,gBAAI,UAAU,MAAM;AAClB,wBAAU;AAAA,YACZ;AACA,mBAAO,CAAC,KAAK,KAAK;AAAA,UACpB,CAAC;AAAA,QAAA;AAEH,cAAM,cAAc,UAChB,CAAA,IACA;AAAA,UACE,KAAK,QAAQ,MAAM;AAAA,YACjB;AAAA,UAAA,CACD;AAAA,QAAA;AAGP,mBAAW,cAAc,aAAa;AACpC,eAAK,uBAAuB,WAAW,WAAW;AAClD,gBAAM,cAA2B;AAAA,YAC/B,MAAM;AAAA,YACN,MAAM,KAAK;AAAA,cACT,WAAW;AAAA,cACX,WAAW;AAAA,YAAA;AAAA,YAEb,OAAO;AAAA,cACL,kBAAkB,KAAK;AAAA,cACvB,QAAAA;AAAAA,YAAA;AAAA,UACF;AAEF,eAAK,QAAQ,KAAK,aAAa,IAAI;AAAA,QACrC;AAAA,MACF,UAAA;AACE,aAAK,yBAAyB;AAAA,MAChC;AAAA,IACF;AAEA,YAAQ,OAAO,MAAA;AAAA,MACb,KAAK;AAAA,MACL,KAAK;AACH,wBAAgB,OAAO,KAAK,KAAK,MAAM;AACvC;AAAA,MACF,KAAK;AACH,wBAAgB,OAAO,KAAK,KAAK,MAAM;AACvC;AAAA,MACF,KAAK,QAAQ;AACX,cAAM,WAAW,OAAO,KAAK;AAC7B,cAAM,cAAc,OAAO,QAAQ;AAEnC;AAAA,UACE,wBAAwB,aAAa,UAAU,KAAK,SAAS;AAAA,UAC7D;AAAA,QAAA;AAEF,wBAAgB,UAAU,MAAM;AAChC;AAAA,MACF;AAAA,MAEA;AACE,oBAAkB;AAAA,IAAA;AAAA,EAExB;AAAA,EAEA,mBACE,eACA,qBACM;AACN,UAAM,cAAc,MAAM;AACxB,UAAI,UAAU;AACd,YAAM,aAAa,OAAO;AAAA,QACxB,KAAK,UAAU,IAAI,CAAC,KAAK,MAAM;AAC7B,gBAAM,QAAQ,cAAc,KAAK,WAAW,CAAC,CAAC;AAC9C,cAAI,UAAU,MAAM;AAClB,sBAAU;AAAA,UACZ;AACA,iBAAO,CAAC,KAAK,KAAK;AAAA,QACpB,CAAC;AAAA,MAAA;AAEH,YAAM,SAAS,UACX,CAAA,IACA,KAAK,OAAO,MAAM;AAAA,QAChB;AAAA,MAAA,CACD;AAEL,UACE,KAAK,0BACL;AAAA,QACE;AAAA,QACA,KAAK;AAAA,QACL,KAAK,uBAAuB,OAAO,KAAK;AAAA,QACxC,KAAK;AAAA,MAAA,KAEP,KAAK,uBAAuB,YAC5B,KAAK,QAAQ;AAAA,QACX;AAAA,QACA,KAAK,uBAAuB;AAAA,MAAA,IAC1B,GACJ;AACA,eAAO;AAAA,UACL;AAAA,UACA,KAAK,uBAAuB;AAAA,UAC5B,KAAK,OAAO,UAAA;AAAA,QAAU;AAAA,MAE1B;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,eAAe;AAAA,QACb,GAAG;AAAA,QACH,CAAC,KAAK,iBAAiB,GAAG;AAAA,MAAA;AAAA,IAC5B;AAAA,EAEJ;AACF;"}
|
|
@@ -11,7 +11,7 @@ import { type Input, type Output, type Start } from './operator.ts';
|
|
|
11
11
|
import type { Source, SourceChange, SourceInput } from './source.ts';
|
|
12
12
|
import type { Stream } from './stream.ts';
|
|
13
13
|
export type Overlay = {
|
|
14
|
-
|
|
14
|
+
epoch: number;
|
|
15
15
|
change: SourceChange;
|
|
16
16
|
};
|
|
17
17
|
export type Overlays = {
|
|
@@ -29,6 +29,7 @@ export type Connection = {
|
|
|
29
29
|
predicate: (row: Row) => boolean;
|
|
30
30
|
} | undefined;
|
|
31
31
|
readonly debug?: DebugDelegate | undefined;
|
|
32
|
+
lastPushedEpoch: number;
|
|
32
33
|
};
|
|
33
34
|
/**
|
|
34
35
|
* A `MemorySource` is a source that provides data to the pipeline from an
|
|
@@ -52,7 +53,7 @@ export declare class MemorySource implements Source {
|
|
|
52
53
|
push(change: SourceChange): void;
|
|
53
54
|
genPush(change: SourceChange): Generator<undefined, void, unknown>;
|
|
54
55
|
}
|
|
55
|
-
export declare function genPushAndWriteWithSplitEdit(connections: readonly Connection[], change: SourceChange, exists: (row: Row) => boolean, setOverlay: (o: Overlay | undefined) => Overlay | undefined, writeChange: (c: SourceChange) => void): Generator<undefined, void, unknown>;
|
|
56
|
+
export declare function genPushAndWriteWithSplitEdit(connections: readonly Connection[], change: SourceChange, exists: (row: Row) => boolean, setOverlay: (o: Overlay | undefined) => Overlay | undefined, writeChange: (c: SourceChange) => void, getNextEpoch: () => number): Generator<undefined, void, unknown>;
|
|
56
57
|
export declare function generateWithStart(nodes: Iterable<Node | 'yield'>, start: Start | undefined, compare: (r1: Row, r2: Row) => number): Stream<Node | 'yield'>;
|
|
57
58
|
/**
|
|
58
59
|
* Takes an iterator and overlay.
|
|
@@ -66,7 +67,7 @@ export declare function generateWithStart(nodes: Iterable<Node | 'yield'>, start
|
|
|
66
67
|
* @param overlay - the overlay values to splice in
|
|
67
68
|
* @param compare - the comparator to use to find the position for the overlay
|
|
68
69
|
*/
|
|
69
|
-
export declare function generateWithOverlay(startAt: Row | undefined, rows: Iterable<Row>, constraint: Constraint | undefined, overlay: Overlay | undefined,
|
|
70
|
+
export declare function generateWithOverlay(startAt: Row | undefined, rows: Iterable<Row>, constraint: Constraint | undefined, overlay: Overlay | undefined, lastPushedEpoch: number, compare: Comparator, filterPredicate?: (row: Row) => boolean | undefined): Generator<{
|
|
70
71
|
row: Readonly<Record<string, import("../../../shared/src/json.ts").ReadonlyJSONValue | undefined>>;
|
|
71
72
|
relationships: {};
|
|
72
73
|
}, void, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-source.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/memory-source.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,kCAAkC,CAAC;AAG1D,OAAO,KAAK,EACV,SAAS,EACT,QAAQ,EAET,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAC,GAAG,EAAQ,MAAM,oCAAoC,CAAC;AACnE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2CAA2C,CAAC;AAC1E,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,IAAI,EACV,MAAM,WAAW,CAAC;AAEnB,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,MAAM,EACX,KAAK,KAAK,EACX,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EAIZ,WAAW,EACZ,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAExC,MAAM,MAAM,OAAO,GAAG;IACpB,
|
|
1
|
+
{"version":3,"file":"memory-source.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/memory-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@ class MemorySource {
|
|
|
16
16
|
#indexes = /* @__PURE__ */ new Map();
|
|
17
17
|
#connections = [];
|
|
18
18
|
#overlay;
|
|
19
|
+
#pushEpoch = 0;
|
|
19
20
|
constructor(tableName, columns, primaryKey, primaryIndexData) {
|
|
20
21
|
this.#tableName = tableName;
|
|
21
22
|
this.#columns = columns;
|
|
@@ -64,7 +65,6 @@ class MemorySource {
|
|
|
64
65
|
const input = {
|
|
65
66
|
getSchema: () => schema,
|
|
66
67
|
fetch: (req) => this.#fetch(req, connection),
|
|
67
|
-
cleanup: (req) => this.#cleanup(req, connection),
|
|
68
68
|
setOutput: (output) => {
|
|
69
69
|
connection.output = output;
|
|
70
70
|
},
|
|
@@ -82,7 +82,8 @@ class MemorySource {
|
|
|
82
82
|
filters: transformedFilters.filters ? {
|
|
83
83
|
condition: transformedFilters.filters,
|
|
84
84
|
predicate: createPredicate(transformedFilters.filters)
|
|
85
|
-
} : void 0
|
|
85
|
+
} : void 0,
|
|
86
|
+
lastPushedEpoch: 0
|
|
86
87
|
};
|
|
87
88
|
const schema = this.#getSchema(connection);
|
|
88
89
|
assertOrderingIncludesPK(sort, this.#primaryKey);
|
|
@@ -119,10 +120,7 @@ class MemorySource {
|
|
|
119
120
|
getIndexKeys() {
|
|
120
121
|
return [...this.#indexes.keys()];
|
|
121
122
|
}
|
|
122
|
-
*#fetch(req,
|
|
123
|
-
const callingConnectionIndex = this.#connections.indexOf(from);
|
|
124
|
-
assert(callingConnectionIndex !== -1, "Output not found");
|
|
125
|
-
const conn = this.#connections[callingConnectionIndex];
|
|
123
|
+
*#fetch(req, conn) {
|
|
126
124
|
const { sort: requestedSort, compareRows } = conn;
|
|
127
125
|
const connectionComparator = (r1, r2) => compareRows(r1, r2) * (req.reverse ? -1 : 1);
|
|
128
126
|
const pkConstraint = primaryKeyConstraintFromFilters(
|
|
@@ -139,7 +137,7 @@ class MemorySource {
|
|
|
139
137
|
if (this.#primaryKey.length > 1 || !fetchOrPkConstraint || !constraintMatchesPrimaryKey(fetchOrPkConstraint, this.#primaryKey)) {
|
|
140
138
|
indexSort.push(...requestedSort);
|
|
141
139
|
}
|
|
142
|
-
const index = this.#getOrCreateIndex(indexSort,
|
|
140
|
+
const index = this.#getOrCreateIndex(indexSort, conn);
|
|
143
141
|
const { data, comparator: compare } = index;
|
|
144
142
|
const indexComparator = (r1, r2) => compare(r1, r2) * (req.reverse ? -1 : 1);
|
|
145
143
|
const startAt = req.start?.row;
|
|
@@ -169,7 +167,7 @@ class MemorySource {
|
|
|
169
167
|
// rather than as the fetch constraint.
|
|
170
168
|
req.constraint,
|
|
171
169
|
this.#overlay,
|
|
172
|
-
|
|
170
|
+
conn.lastPushedEpoch,
|
|
173
171
|
// Use indexComparator, generateWithOverlayInner has a subtle dependency
|
|
174
172
|
// on this. Since generateWithConstraint is done after
|
|
175
173
|
// generateWithOverlay, the generator consumed by generateWithOverlayInner
|
|
@@ -192,9 +190,6 @@ class MemorySource {
|
|
|
192
190
|
);
|
|
193
191
|
yield* conn.filters ? generateWithFilter(withConstraint, conn.filters.predicate) : withConstraint;
|
|
194
192
|
}
|
|
195
|
-
#cleanup(req, connection) {
|
|
196
|
-
return this.#fetch(req, connection);
|
|
197
|
-
}
|
|
198
193
|
push(change) {
|
|
199
194
|
for (const _ of this.genPush(change)) {
|
|
200
195
|
}
|
|
@@ -210,7 +205,8 @@ class MemorySource {
|
|
|
210
205
|
change,
|
|
211
206
|
exists,
|
|
212
207
|
setOverlay,
|
|
213
|
-
writeChange
|
|
208
|
+
writeChange,
|
|
209
|
+
() => ++this.#pushEpoch
|
|
214
210
|
);
|
|
215
211
|
}
|
|
216
212
|
#writeChange(change) {
|
|
@@ -253,7 +249,7 @@ function* generateWithFilter(it, filter) {
|
|
|
253
249
|
}
|
|
254
250
|
}
|
|
255
251
|
}
|
|
256
|
-
function* genPushAndWriteWithSplitEdit(connections, change, exists, setOverlay, writeChange) {
|
|
252
|
+
function* genPushAndWriteWithSplitEdit(connections, change, exists, setOverlay, writeChange, getNextEpoch) {
|
|
257
253
|
let shouldSplitEdit = false;
|
|
258
254
|
if (change.type === "edit") {
|
|
259
255
|
for (const { splitEditKeys } of connections) {
|
|
@@ -276,7 +272,8 @@ function* genPushAndWriteWithSplitEdit(connections, change, exists, setOverlay,
|
|
|
276
272
|
},
|
|
277
273
|
exists,
|
|
278
274
|
setOverlay,
|
|
279
|
-
writeChange
|
|
275
|
+
writeChange,
|
|
276
|
+
getNextEpoch()
|
|
280
277
|
);
|
|
281
278
|
yield* genPushAndWrite(
|
|
282
279
|
connections,
|
|
@@ -286,7 +283,8 @@ function* genPushAndWriteWithSplitEdit(connections, change, exists, setOverlay,
|
|
|
286
283
|
},
|
|
287
284
|
exists,
|
|
288
285
|
setOverlay,
|
|
289
|
-
writeChange
|
|
286
|
+
writeChange,
|
|
287
|
+
getNextEpoch()
|
|
290
288
|
);
|
|
291
289
|
} else {
|
|
292
290
|
yield* genPushAndWrite(
|
|
@@ -294,17 +292,18 @@ function* genPushAndWriteWithSplitEdit(connections, change, exists, setOverlay,
|
|
|
294
292
|
change,
|
|
295
293
|
exists,
|
|
296
294
|
setOverlay,
|
|
297
|
-
writeChange
|
|
295
|
+
writeChange,
|
|
296
|
+
getNextEpoch()
|
|
298
297
|
);
|
|
299
298
|
}
|
|
300
299
|
}
|
|
301
|
-
function* genPushAndWrite(connections, change, exists, setOverlay, writeChange) {
|
|
302
|
-
for (const x of genPush(connections, change, exists, setOverlay)) {
|
|
300
|
+
function* genPushAndWrite(connections, change, exists, setOverlay, writeChange, pushEpoch) {
|
|
301
|
+
for (const x of genPush(connections, change, exists, setOverlay, pushEpoch)) {
|
|
303
302
|
yield x;
|
|
304
303
|
}
|
|
305
304
|
writeChange(change);
|
|
306
305
|
}
|
|
307
|
-
function* genPush(connections, change, exists, setOverlay) {
|
|
306
|
+
function* genPush(connections, change, exists, setOverlay, pushEpoch) {
|
|
308
307
|
switch (change.type) {
|
|
309
308
|
case "add":
|
|
310
309
|
assert(
|
|
@@ -321,9 +320,11 @@ function* genPush(connections, change, exists, setOverlay) {
|
|
|
321
320
|
default:
|
|
322
321
|
unreachable();
|
|
323
322
|
}
|
|
324
|
-
for (const
|
|
323
|
+
for (const conn of connections) {
|
|
324
|
+
const { output, filters, input } = conn;
|
|
325
325
|
if (output) {
|
|
326
|
-
|
|
326
|
+
conn.lastPushedEpoch = pushEpoch;
|
|
327
|
+
setOverlay({ epoch: pushEpoch, change });
|
|
327
328
|
const outputChange = change.type === "edit" ? {
|
|
328
329
|
type: change.type,
|
|
329
330
|
oldNode: {
|
|
@@ -374,9 +375,9 @@ function* generateWithStart(nodes, start, compare) {
|
|
|
374
375
|
}
|
|
375
376
|
}
|
|
376
377
|
}
|
|
377
|
-
function* generateWithOverlay(startAt, rows, constraint, overlay,
|
|
378
|
+
function* generateWithOverlay(startAt, rows, constraint, overlay, lastPushedEpoch, compare, filterPredicate) {
|
|
378
379
|
let overlayToApply = void 0;
|
|
379
|
-
if (overlay &&
|
|
380
|
+
if (overlay && lastPushedEpoch >= overlay.epoch) {
|
|
380
381
|
overlayToApply = overlay;
|
|
381
382
|
}
|
|
382
383
|
const overlays = computeOverlays(
|