@rocicorp/zero 0.25.0-canary.14 → 0.25.0-canary.17
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/shared/src/deep-merge.d.ts +6 -4
- package/out/shared/src/deep-merge.d.ts.map +1 -1
- package/out/shared/src/deep-merge.js +2 -1
- package/out/shared/src/deep-merge.js.map +1 -1
- package/out/shared/src/record-proxy.d.ts +13 -0
- package/out/shared/src/record-proxy.d.ts.map +1 -0
- package/out/shared/src/record-proxy.js +59 -0
- package/out/shared/src/record-proxy.js.map +1 -0
- package/out/z2s/src/compiler.d.ts.map +1 -1
- package/out/z2s/src/compiler.js +4 -2
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/pg.js +4 -3
- package/out/zero/src/server.js +4 -3
- package/out/zero/src/zero.js +11 -3
- package/out/zero/src/zero.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +20 -13
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +16 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +28 -0
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/server/otel-diag-logger.d.ts.map +1 -1
- package/out/zero-cache/src/server/otel-diag-logger.js +1 -22
- package/out/zero-cache/src/server/otel-diag-logger.js.map +1 -1
- package/out/zero-cache/src/server/otel-start.d.ts.map +1 -1
- package/out/zero-cache/src/server/otel-start.js +1 -5
- package/out/zero-cache/src/server/otel-start.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +6 -1
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +3 -2
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +8 -9
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +17 -11
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +2 -2
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +19 -4
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +1 -7
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-client/src/client/crud-impl.d.ts +11 -0
- package/out/zero-client/src/client/crud-impl.d.ts.map +1 -0
- package/out/zero-client/src/client/crud-impl.js +102 -0
- package/out/zero-client/src/client/crud-impl.js.map +1 -0
- package/out/zero-client/src/client/crud.d.ts +7 -40
- package/out/zero-client/src/client/crud.d.ts.map +1 -1
- package/out/zero-client/src/client/crud.js +21 -107
- package/out/zero-client/src/client/crud.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts +2 -2
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +5 -50
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +20 -13
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.d.ts +1 -1
- package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.d.ts.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js +14 -7
- package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +9 -7
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +11 -4
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.d.ts +7 -6
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-react/src/use-query.d.ts +6 -4
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +2 -1
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-server/src/custom.d.ts +44 -5
- package/out/zero-server/src/custom.d.ts.map +1 -1
- package/out/zero-server/src/custom.js +98 -35
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +5 -13
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/solid-view.d.ts +7 -2
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +3 -32
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.d.ts +5 -3
- package/out/zero-solid/src/use-query.d.ts.map +1 -1
- package/out/zero-solid/src/use-query.js +5 -1
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-types/src/schema.d.ts +4 -4
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +1 -11
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/error.js +1 -10
- package/out/zql/src/error.js.map +1 -1
- package/out/zql/src/ivm/array-view.d.ts +1 -1
- package/out/zql/src/ivm/array-view.d.ts.map +1 -1
- package/out/zql/src/ivm/array-view.js +2 -0
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts +3 -2
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +25 -23
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.d.ts +3 -3
- package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-in.js +6 -5
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.d.ts +2 -2
- package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-out.js +5 -5
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +5 -5
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +8 -8
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter-push.d.ts +2 -1
- package/out/zql/src/ivm/filter-push.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-push.js +5 -5
- package/out/zql/src/ivm/filter-push.js.map +1 -1
- package/out/zql/src/ivm/filter.d.ts +2 -2
- package/out/zql/src/ivm/filter.d.ts.map +1 -1
- package/out/zql/src/ivm/filter.js +4 -4
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +100 -83
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +52 -50
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +4 -4
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +3 -3
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +7 -4
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +10 -3
- 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/push-accumulated.d.ts +1 -1
- package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +8 -8
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/skip.d.ts +1 -1
- package/out/zql/src/ivm/skip.d.ts.map +1 -1
- package/out/zql/src/ivm/skip.js +8 -3
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/source.d.ts +15 -7
- package/out/zql/src/ivm/source.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.d.ts +2 -0
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js +5 -14
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +164 -147
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts +2 -2
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +7 -7
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.d.ts +1 -1
- package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js +3 -3
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/mutate/crud.d.ts +139 -0
- package/out/zql/src/mutate/crud.d.ts.map +1 -0
- package/out/zql/src/mutate/crud.js +53 -0
- package/out/zql/src/mutate/crud.js.map +1 -0
- package/out/zql/src/mutate/custom.d.ts +12 -53
- package/out/zql/src/mutate/custom.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.js +1 -5
- package/out/zql/src/mutate/custom.js.map +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts +33 -32
- package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator-registry.js +26 -25
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/mutate/mutator.d.ts +48 -58
- package/out/zql/src/mutate/mutator.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator.js +12 -8
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/planner/planner-builder.d.ts +2 -1
- package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
- package/out/zql/src/planner/planner-builder.js +5 -5
- package/out/zql/src/planner/planner-builder.js.map +1 -1
- package/out/zql/src/planner/planner-graph.d.ts +3 -1
- package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
- package/out/zql/src/planner/planner-graph.js +5 -5
- package/out/zql/src/planner/planner-graph.js.map +1 -1
- package/out/zql/src/query/abstract-query.d.ts +2 -3
- package/out/zql/src/query/abstract-query.d.ts.map +1 -1
- package/out/zql/src/query/abstract-query.js +0 -3
- package/out/zql/src/query/abstract-query.js.map +1 -1
- package/out/zql/src/query/create-builder.d.ts.map +1 -1
- package/out/zql/src/query/create-builder.js +7 -36
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.d.ts +1 -1
- package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +2 -2
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +2 -2
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-registry.d.ts +87 -79
- package/out/zql/src/query/query-registry.d.ts.map +1 -1
- package/out/zql/src/query/query-registry.js +44 -38
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zql/src/query/query.d.ts +3 -18
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.d.ts +2 -2
- package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.js.map +1 -1
- package/out/zql/src/query/static-query.d.ts +1 -0
- package/out/zql/src/query/static-query.d.ts.map +1 -1
- package/out/zql/src/query/static-query.js +2 -2
- package/out/zql/src/query/static-query.js.map +1 -1
- package/out/zqlite/src/internal/sql-inline.d.ts +13 -0
- package/out/zqlite/src/internal/sql-inline.d.ts.map +1 -0
- package/out/zqlite/src/internal/sql-inline.js +45 -0
- package/out/zqlite/src/internal/sql-inline.js.map +1 -0
- package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +2 -2
- package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts +3 -2
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +5 -2
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,8 +3,7 @@ import { binarySearch } from "../../../shared/src/binary-search.js";
|
|
|
3
3
|
import { emptyArray } from "../../../shared/src/sentinels.js";
|
|
4
4
|
import { constraintsAreCompatible } from "./constraint.js";
|
|
5
5
|
import { isJoinMatch, generateWithOverlayNoYield, rowEqualsForCompoundKey } from "./join-utils.js";
|
|
6
|
-
import { throwOutput
|
|
7
|
-
import { first } from "./stream.js";
|
|
6
|
+
import { throwOutput } from "./operator.js";
|
|
8
7
|
class FlippedJoin {
|
|
9
8
|
#parent;
|
|
10
9
|
#child;
|
|
@@ -222,84 +221,11 @@ class FlippedJoin {
|
|
|
222
221
|
}
|
|
223
222
|
}
|
|
224
223
|
}
|
|
225
|
-
|
|
226
|
-
const pushChildChange = (exists) => {
|
|
227
|
-
this.#inprogressChildChange = {
|
|
228
|
-
change,
|
|
229
|
-
position: void 0
|
|
230
|
-
};
|
|
231
|
-
try {
|
|
232
|
-
const parentNodeStream = this.#parent.fetch({
|
|
233
|
-
constraint: Object.fromEntries(
|
|
234
|
-
this.#parentKey.map((key, i) => [
|
|
235
|
-
key,
|
|
236
|
-
change.node.row[this.#childKey[i]]
|
|
237
|
-
])
|
|
238
|
-
)
|
|
239
|
-
});
|
|
240
|
-
for (const parentNode of skipYields(parentNodeStream)) {
|
|
241
|
-
this.#inprogressChildChange = {
|
|
242
|
-
change,
|
|
243
|
-
position: parentNode.row
|
|
244
|
-
};
|
|
245
|
-
const childNodeStream = () => this.#child.fetch({
|
|
246
|
-
constraint: Object.fromEntries(
|
|
247
|
-
this.#childKey.map((key, i) => [
|
|
248
|
-
key,
|
|
249
|
-
parentNode.row[this.#parentKey[i]]
|
|
250
|
-
])
|
|
251
|
-
)
|
|
252
|
-
});
|
|
253
|
-
if (!exists) {
|
|
254
|
-
for (const childNode of skipYields(childNodeStream())) {
|
|
255
|
-
if (this.#child.getSchema().compareRows(childNode.row, change.node.row) !== 0) {
|
|
256
|
-
exists = true;
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
if (exists) {
|
|
262
|
-
this.#output.push(
|
|
263
|
-
{
|
|
264
|
-
type: "child",
|
|
265
|
-
node: {
|
|
266
|
-
...parentNode,
|
|
267
|
-
relationships: {
|
|
268
|
-
...parentNode.relationships,
|
|
269
|
-
[this.#relationshipName]: childNodeStream
|
|
270
|
-
}
|
|
271
|
-
},
|
|
272
|
-
child: {
|
|
273
|
-
relationshipName: this.#relationshipName,
|
|
274
|
-
change
|
|
275
|
-
}
|
|
276
|
-
},
|
|
277
|
-
this
|
|
278
|
-
);
|
|
279
|
-
} else {
|
|
280
|
-
this.#output.push(
|
|
281
|
-
{
|
|
282
|
-
...change,
|
|
283
|
-
node: {
|
|
284
|
-
...parentNode,
|
|
285
|
-
relationships: {
|
|
286
|
-
...parentNode.relationships,
|
|
287
|
-
[this.#relationshipName]: () => [change.node]
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
this
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
} finally {
|
|
296
|
-
this.#inprogressChildChange = void 0;
|
|
297
|
-
}
|
|
298
|
-
};
|
|
224
|
+
*#pushChild(change) {
|
|
299
225
|
switch (change.type) {
|
|
300
226
|
case "add":
|
|
301
227
|
case "remove":
|
|
302
|
-
pushChildChange();
|
|
228
|
+
yield* this.#pushChildChange(change);
|
|
303
229
|
break;
|
|
304
230
|
case "edit": {
|
|
305
231
|
assert(
|
|
@@ -310,15 +236,96 @@ class FlippedJoin {
|
|
|
310
236
|
),
|
|
311
237
|
`Child edit must not change relationship.`
|
|
312
238
|
);
|
|
313
|
-
pushChildChange(true);
|
|
239
|
+
yield* this.#pushChildChange(change, true);
|
|
314
240
|
break;
|
|
315
241
|
}
|
|
316
242
|
case "child":
|
|
317
|
-
pushChildChange(true);
|
|
243
|
+
yield* this.#pushChildChange(change, true);
|
|
318
244
|
break;
|
|
319
245
|
}
|
|
320
246
|
}
|
|
321
|
-
|
|
247
|
+
*#pushChildChange(change, exists) {
|
|
248
|
+
this.#inprogressChildChange = {
|
|
249
|
+
change,
|
|
250
|
+
position: void 0
|
|
251
|
+
};
|
|
252
|
+
try {
|
|
253
|
+
const parentNodeStream = this.#parent.fetch({
|
|
254
|
+
constraint: Object.fromEntries(
|
|
255
|
+
this.#parentKey.map((key, i) => [
|
|
256
|
+
key,
|
|
257
|
+
change.node.row[this.#childKey[i]]
|
|
258
|
+
])
|
|
259
|
+
)
|
|
260
|
+
});
|
|
261
|
+
for (const parentNode of parentNodeStream) {
|
|
262
|
+
if (parentNode === "yield") {
|
|
263
|
+
yield "yield";
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
this.#inprogressChildChange = {
|
|
267
|
+
change,
|
|
268
|
+
position: parentNode.row
|
|
269
|
+
};
|
|
270
|
+
const childNodeStream = () => this.#child.fetch({
|
|
271
|
+
constraint: Object.fromEntries(
|
|
272
|
+
this.#childKey.map((key, i) => [
|
|
273
|
+
key,
|
|
274
|
+
parentNode.row[this.#parentKey[i]]
|
|
275
|
+
])
|
|
276
|
+
)
|
|
277
|
+
});
|
|
278
|
+
if (!exists) {
|
|
279
|
+
for (const childNode of childNodeStream()) {
|
|
280
|
+
if (childNode === "yield") {
|
|
281
|
+
yield "yield";
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (this.#child.getSchema().compareRows(childNode.row, change.node.row) !== 0) {
|
|
285
|
+
exists = true;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (exists) {
|
|
291
|
+
yield* this.#output.push(
|
|
292
|
+
{
|
|
293
|
+
type: "child",
|
|
294
|
+
node: {
|
|
295
|
+
...parentNode,
|
|
296
|
+
relationships: {
|
|
297
|
+
...parentNode.relationships,
|
|
298
|
+
[this.#relationshipName]: childNodeStream
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
child: {
|
|
302
|
+
relationshipName: this.#relationshipName,
|
|
303
|
+
change
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
this
|
|
307
|
+
);
|
|
308
|
+
} else {
|
|
309
|
+
yield* this.#output.push(
|
|
310
|
+
{
|
|
311
|
+
...change,
|
|
312
|
+
node: {
|
|
313
|
+
...parentNode,
|
|
314
|
+
relationships: {
|
|
315
|
+
...parentNode.relationships,
|
|
316
|
+
[this.#relationshipName]: () => [change.node]
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
this
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} finally {
|
|
325
|
+
this.#inprogressChildChange = void 0;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
*#pushParent(change) {
|
|
322
329
|
const childNodeStream = (node) => () => this.#child.fetch({
|
|
323
330
|
constraint: Object.fromEntries(
|
|
324
331
|
this.#childKey.map((key, i) => [key, node.row[this.#parentKey[i]]])
|
|
@@ -331,14 +338,24 @@ class FlippedJoin {
|
|
|
331
338
|
[this.#relationshipName]: childNodeStream(node)
|
|
332
339
|
}
|
|
333
340
|
});
|
|
334
|
-
|
|
341
|
+
let hasRelatedChild = false;
|
|
342
|
+
for (const node of childNodeStream(change.node)()) {
|
|
343
|
+
if (node === "yield") {
|
|
344
|
+
yield "yield";
|
|
345
|
+
continue;
|
|
346
|
+
} else {
|
|
347
|
+
hasRelatedChild = true;
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (!hasRelatedChild) {
|
|
335
352
|
return;
|
|
336
353
|
}
|
|
337
354
|
switch (change.type) {
|
|
338
355
|
case "add":
|
|
339
356
|
case "remove":
|
|
340
357
|
case "child": {
|
|
341
|
-
this.#output.push(
|
|
358
|
+
yield* this.#output.push(
|
|
342
359
|
{
|
|
343
360
|
...change,
|
|
344
361
|
node: flip(change.node)
|
|
@@ -356,7 +373,7 @@ class FlippedJoin {
|
|
|
356
373
|
),
|
|
357
374
|
`Parent edit must not change relationship.`
|
|
358
375
|
);
|
|
359
|
-
this.#output.push(
|
|
376
|
+
yield* this.#output.push(
|
|
360
377
|
{
|
|
361
378
|
type: "edit",
|
|
362
379
|
oldNode: flip(change.oldNode),
|
|
@@ -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 #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 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 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): Stream<'yield'> {\n switch (change.type) {\n case 'add':\n case 'remove':\n yield* this.#pushChildChange(change);\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 yield* this.#pushChildChange(change, true);\n break;\n }\n case 'child':\n yield* this.#pushChildChange(change, true);\n break;\n }\n }\n\n *#pushChildChange(change: Change, exists?: boolean): Stream<'yield'> {\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 parentNodeStream) {\n if (parentNode === 'yield') {\n yield 'yield';\n continue;\n }\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 childNodeStream()) {\n if (childNode === 'yield') {\n yield 'yield';\n continue;\n }\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 yield* 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 yield* 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 *#pushParent(change: Change): Stream<'yield'> {\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 let hasRelatedChild = false;\n for (const node of childNodeStream(change.node)()) {\n if (node === 'yield') {\n yield 'yield';\n continue;\n } else {\n hasRelatedChild = true;\n break;\n }\n }\n if (!hasRelatedChild) {\n return;\n }\n\n switch (change.type) {\n case 'add':\n case 'remove':\n case 'child': {\n yield* 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 yield* 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 +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;AAG3E,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAOpC,OAAO,
|
|
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,EAEL,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;CA4MlD"}
|
package/out/zql/src/ivm/join.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assert, unreachable } from "../../../shared/src/asserts.js";
|
|
2
2
|
import { rowEqualsForCompoundKey, isJoinMatch, generateWithOverlay } from "./join-utils.js";
|
|
3
|
-
import { throwOutput
|
|
3
|
+
import { throwOutput } from "./operator.js";
|
|
4
4
|
class Join {
|
|
5
5
|
#parent;
|
|
6
6
|
#child;
|
|
@@ -68,10 +68,10 @@ class Join {
|
|
|
68
68
|
yield this.#processParentNode(parentNode.row, parentNode.relationships);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
*#pushParent(change) {
|
|
72
72
|
switch (change.type) {
|
|
73
73
|
case "add":
|
|
74
|
-
this.#output.push(
|
|
74
|
+
yield* this.#output.push(
|
|
75
75
|
{
|
|
76
76
|
type: "add",
|
|
77
77
|
node: this.#processParentNode(
|
|
@@ -83,7 +83,7 @@ class Join {
|
|
|
83
83
|
);
|
|
84
84
|
break;
|
|
85
85
|
case "remove":
|
|
86
|
-
this.#output.push(
|
|
86
|
+
yield* this.#output.push(
|
|
87
87
|
{
|
|
88
88
|
type: "remove",
|
|
89
89
|
node: this.#processParentNode(
|
|
@@ -95,7 +95,7 @@ class Join {
|
|
|
95
95
|
);
|
|
96
96
|
break;
|
|
97
97
|
case "child":
|
|
98
|
-
this.#output.push(
|
|
98
|
+
yield* this.#output.push(
|
|
99
99
|
{
|
|
100
100
|
type: "child",
|
|
101
101
|
node: this.#processParentNode(
|
|
@@ -116,7 +116,7 @@ class Join {
|
|
|
116
116
|
),
|
|
117
117
|
`Parent edit must not change relationship.`
|
|
118
118
|
);
|
|
119
|
-
this.#output.push(
|
|
119
|
+
yield* this.#output.push(
|
|
120
120
|
{
|
|
121
121
|
type: "edit",
|
|
122
122
|
oldNode: this.#processParentNode(
|
|
@@ -136,54 +136,14 @@ class Join {
|
|
|
136
136
|
unreachable();
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
-
|
|
140
|
-
const pushChildChange = (childRow, change2) => {
|
|
141
|
-
this.#inprogressChildChange = {
|
|
142
|
-
change: change2,
|
|
143
|
-
position: void 0
|
|
144
|
-
};
|
|
145
|
-
try {
|
|
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(
|
|
157
|
-
this.#parent.fetch({
|
|
158
|
-
constraint
|
|
159
|
-
})
|
|
160
|
-
);
|
|
161
|
-
for (const parentNode of parentNodes) {
|
|
162
|
-
this.#inprogressChildChange.position = parentNode.row;
|
|
163
|
-
const childChange = {
|
|
164
|
-
type: "child",
|
|
165
|
-
node: this.#processParentNode(
|
|
166
|
-
parentNode.row,
|
|
167
|
-
parentNode.relationships
|
|
168
|
-
),
|
|
169
|
-
child: {
|
|
170
|
-
relationshipName: this.#relationshipName,
|
|
171
|
-
change: change2
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
this.#output.push(childChange, this);
|
|
175
|
-
}
|
|
176
|
-
} finally {
|
|
177
|
-
this.#inprogressChildChange = void 0;
|
|
178
|
-
}
|
|
179
|
-
};
|
|
139
|
+
*#pushChild(change) {
|
|
180
140
|
switch (change.type) {
|
|
181
141
|
case "add":
|
|
182
142
|
case "remove":
|
|
183
|
-
pushChildChange(change.node.row, change);
|
|
143
|
+
yield* this.#pushChildChange(change.node.row, change);
|
|
184
144
|
break;
|
|
185
145
|
case "child":
|
|
186
|
-
pushChildChange(change.node.row, change);
|
|
146
|
+
yield* this.#pushChildChange(change.node.row, change);
|
|
187
147
|
break;
|
|
188
148
|
case "edit": {
|
|
189
149
|
const childRow = change.node.row;
|
|
@@ -192,13 +152,55 @@ class Join {
|
|
|
192
152
|
rowEqualsForCompoundKey(oldChildRow, childRow, this.#childKey),
|
|
193
153
|
"Child edit must not change relationship."
|
|
194
154
|
);
|
|
195
|
-
pushChildChange(childRow, change);
|
|
155
|
+
yield* this.#pushChildChange(childRow, change);
|
|
196
156
|
break;
|
|
197
157
|
}
|
|
198
158
|
default:
|
|
199
159
|
unreachable();
|
|
200
160
|
}
|
|
201
161
|
}
|
|
162
|
+
*#pushChildChange(childRow, change) {
|
|
163
|
+
this.#inprogressChildChange = {
|
|
164
|
+
change,
|
|
165
|
+
position: void 0
|
|
166
|
+
};
|
|
167
|
+
try {
|
|
168
|
+
let anyNull = false;
|
|
169
|
+
const constraint = Object.fromEntries(
|
|
170
|
+
this.#parentKey.map((key, i) => {
|
|
171
|
+
const value = childRow[this.#childKey[i]];
|
|
172
|
+
if (value === null) {
|
|
173
|
+
anyNull = true;
|
|
174
|
+
}
|
|
175
|
+
return [key, value];
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
const parentNodes = anyNull ? [] : this.#parent.fetch({
|
|
179
|
+
constraint
|
|
180
|
+
});
|
|
181
|
+
for (const parentNode of parentNodes) {
|
|
182
|
+
if (parentNode === "yield") {
|
|
183
|
+
yield parentNode;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
this.#inprogressChildChange.position = parentNode.row;
|
|
187
|
+
const childChange = {
|
|
188
|
+
type: "child",
|
|
189
|
+
node: this.#processParentNode(
|
|
190
|
+
parentNode.row,
|
|
191
|
+
parentNode.relationships
|
|
192
|
+
),
|
|
193
|
+
child: {
|
|
194
|
+
relationshipName: this.#relationshipName,
|
|
195
|
+
change
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
yield* this.#output.push(childChange, this);
|
|
199
|
+
}
|
|
200
|
+
} finally {
|
|
201
|
+
this.#inprogressChildChange = void 0;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
202
204
|
#processParentNode(parentNodeRow, parentNodeRelations) {
|
|
203
205
|
const childStream = () => {
|
|
204
206
|
let anyNull = false;
|
|
@@ -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} 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":"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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 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): Stream<'yield'> {\n switch (change.type) {\n case 'add':\n yield* 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 yield* 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 yield* 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 yield* 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): Stream<'yield'> {\n switch (change.type) {\n case 'add':\n case 'remove':\n yield* this.#pushChildChange(change.node.row, change);\n break;\n case 'child':\n yield* this.#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 yield* this.#pushChildChange(childRow, change);\n break;\n }\n\n default:\n unreachable(change);\n }\n }\n\n *#pushChildChange(childRow: Row, change: Change): Stream<'yield'> {\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 : this.#parent.fetch({\n constraint,\n });\n\n for (const parentNode of parentNodes) {\n if (parentNode === 'yield') {\n yield parentNode;\n continue;\n }\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 yield* this.#output.push(childChange, this);\n }\n } finally {\n this.#inprogressChildChange = undefined;\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":[],"mappings":"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"}
|
|
@@ -6,5 +6,5 @@ import type { InputBase, Output } from './operator.ts';
|
|
|
6
6
|
* should be present based on the row's data. It then splits the change and
|
|
7
7
|
* pushes the appropriate changes to the output based on the predicate.
|
|
8
8
|
*/
|
|
9
|
-
export declare function maybeSplitAndPushEditChange(change: EditChange, predicate: (row: Row) => boolean, output: Output, pusher: InputBase): void
|
|
9
|
+
export declare function maybeSplitAndPushEditChange(change: EditChange, predicate: (row: Row) => boolean, output: Output, pusher: InputBase): Generator<"yield", void, any>;
|
|
10
10
|
//# sourceMappingURL=maybe-split-and-push-edit-change.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maybe-split-and-push-edit-change.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/maybe-split-and-push-edit-change.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAErD;;;;GAIG;AACH,
|
|
1
|
+
{"version":3,"file":"maybe-split-and-push-edit-change.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/maybe-split-and-push-edit-change.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AAErD;;;;GAIG;AACH,wBAAiB,2BAA2B,CAC1C,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,EAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,iCAwBlB"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
function maybeSplitAndPushEditChange(change, predicate, output, pusher) {
|
|
1
|
+
function* maybeSplitAndPushEditChange(change, predicate, output, pusher) {
|
|
2
2
|
const oldWasPresent = predicate(change.oldNode.row);
|
|
3
3
|
const newIsPresent = predicate(change.node.row);
|
|
4
4
|
if (oldWasPresent && newIsPresent) {
|
|
5
|
-
output.push(change, pusher);
|
|
5
|
+
yield* output.push(change, pusher);
|
|
6
6
|
} else if (oldWasPresent && !newIsPresent) {
|
|
7
|
-
output.push(
|
|
7
|
+
yield* output.push(
|
|
8
8
|
{
|
|
9
9
|
type: "remove",
|
|
10
10
|
node: change.oldNode
|
|
@@ -12,7 +12,7 @@ function maybeSplitAndPushEditChange(change, predicate, output, pusher) {
|
|
|
12
12
|
pusher
|
|
13
13
|
);
|
|
14
14
|
} else if (!oldWasPresent && newIsPresent) {
|
|
15
|
-
output.push(
|
|
15
|
+
yield* output.push(
|
|
16
16
|
{
|
|
17
17
|
type: "add",
|
|
18
18
|
node: change.node
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maybe-split-and-push-edit-change.js","sources":["../../../../../zql/src/ivm/maybe-split-and-push-edit-change.ts"],"sourcesContent":["import type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {EditChange} from './change.ts';\nimport type {InputBase, Output} from './operator.ts';\n\n/**\n * This takes an {@linkcode EditChange} and a predicate that determines if a row\n * should be present based on the row's data. It then splits the change and\n * pushes the appropriate changes to the output based on the predicate.\n */\nexport function maybeSplitAndPushEditChange(\n change: EditChange,\n predicate: (row: Row) => boolean,\n output: Output,\n pusher: InputBase,\n) {\n const oldWasPresent = predicate(change.oldNode.row);\n const newIsPresent = predicate(change.node.row);\n\n if (oldWasPresent && newIsPresent) {\n output.push(change, pusher);\n } else if (oldWasPresent && !newIsPresent) {\n output.push(\n {\n type: 'remove',\n node: change.oldNode,\n },\n pusher,\n );\n } else if (!oldWasPresent && newIsPresent) {\n output.push(\n {\n type: 'add',\n node: change.node,\n },\n pusher,\n );\n }\n}\n"],"names":[],"mappings":"AASO,
|
|
1
|
+
{"version":3,"file":"maybe-split-and-push-edit-change.js","sources":["../../../../../zql/src/ivm/maybe-split-and-push-edit-change.ts"],"sourcesContent":["import type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {EditChange} from './change.ts';\nimport type {InputBase, Output} from './operator.ts';\n\n/**\n * This takes an {@linkcode EditChange} and a predicate that determines if a row\n * should be present based on the row's data. It then splits the change and\n * pushes the appropriate changes to the output based on the predicate.\n */\nexport function* maybeSplitAndPushEditChange(\n change: EditChange,\n predicate: (row: Row) => boolean,\n output: Output,\n pusher: InputBase,\n) {\n const oldWasPresent = predicate(change.oldNode.row);\n const newIsPresent = predicate(change.node.row);\n\n if (oldWasPresent && newIsPresent) {\n yield* output.push(change, pusher);\n } else if (oldWasPresent && !newIsPresent) {\n yield* output.push(\n {\n type: 'remove',\n node: change.oldNode,\n },\n pusher,\n );\n } else if (!oldWasPresent && newIsPresent) {\n yield* output.push(\n {\n type: 'add',\n node: change.node,\n },\n pusher,\n );\n }\n}\n"],"names":[],"mappings":"AASO,UAAU,4BACf,QACA,WACA,QACA,QACA;AACA,QAAM,gBAAgB,UAAU,OAAO,QAAQ,GAAG;AAClD,QAAM,eAAe,UAAU,OAAO,KAAK,GAAG;AAE9C,MAAI,iBAAiB,cAAc;AACjC,WAAO,OAAO,KAAK,QAAQ,MAAM;AAAA,EACnC,WAAW,iBAAiB,CAAC,cAAc;AACzC,WAAO,OAAO;AAAA,MACZ;AAAA,QACE,MAAM;AAAA,QACN,MAAM,OAAO;AAAA,MAAA;AAAA,MAEf;AAAA,IAAA;AAAA,EAEJ,WAAW,CAAC,iBAAiB,cAAc;AACzC,WAAO,OAAO;AAAA,MACZ;AAAA,QACE,MAAM;AAAA,QACN,MAAM,OAAO;AAAA,MAAA;AAAA,MAEf;AAAA,IAAA;AAAA,EAEJ;AACF;"}
|
|
@@ -50,10 +50,10 @@ export declare class MemorySource implements Source {
|
|
|
50
50
|
get data(): BTreeSet<Row>;
|
|
51
51
|
connect(sort: Ordering, filters?: Condition, splitEditKeys?: Set<string>): SourceInput;
|
|
52
52
|
getIndexKeys(): string[];
|
|
53
|
-
push(change: SourceChange):
|
|
54
|
-
genPush(change: SourceChange): Generator<undefined, void, unknown>;
|
|
53
|
+
push(change: SourceChange): Stream<'yield'>;
|
|
54
|
+
genPush(change: SourceChange): Generator<"yield" | undefined, void, unknown>;
|
|
55
55
|
}
|
|
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
|
+
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<"yield" | undefined, void, unknown>;
|
|
57
57
|
export declare function generateWithStart(nodes: Iterable<Node | 'yield'>, start: Start | undefined, compare: (r1: Row, r2: Row) => number): Stream<Node | 'yield'>;
|
|
58
58
|
/**
|
|
59
59
|
* Takes an iterator and overlay.
|
|
@@ -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,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC;IACrB,MAAM,EAAE,GAAG,GAAG,SAAS,CAAC;CACzB,CAAC;AAQF,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IACvC,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,EACH;QACE,SAAS,EAAE,mBAAmB,CAAC;QAC/B,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;KAClC,GACD,SAAS,CAAC;IACd,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC3C,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,YAAa,YAAW,MAAM;;gBAYvC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACpC,UAAU,EAAE,UAAU,EACtB,gBAAgB,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC;IAclC,IAAI,WAAW;;;;MAMd;IAED,IAAI;IAUJ,IAAI,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,CAExB;IAeD,OAAO,CACL,IAAI,EAAE,QAAQ,EACd,OAAO,CAAC,EAAE,SAAS,EACnB,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,WAAW;IAwFd,YAAY,IAAI,MAAM,EAAE;
|
|
1
|
+
{"version":3,"file":"memory-source.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/memory-source.ts"],"names":[],"mappings":"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"}
|