@rocicorp/zero 1.12.0-canary.10 → 1.12.0-canary.12
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/analyze-query/src/zql-chain.js +9 -1
- package/out/analyze-query/src/zql-chain.js.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js +61 -20
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/z2s/src/compiler.d.ts +1 -1
- package/out/z2s/src/compiler.d.ts.map +1 -1
- package/out/z2s/src/compiler.js +339 -2
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.d.ts +8 -0
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +58 -11
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/bindings.js +4 -4
- package/out/zero-cache/src/auth/write-authorizer.js +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +4 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +13 -0
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/db/create.js +1 -1
- package/out/zero-cache/src/scripts/decommission.js +1 -1
- package/out/zero-cache/src/server/replicator.js +4 -2
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +8 -5
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/serving-checkpointer.js +41 -0
- package/out/zero-cache/src/server/serving-checkpointer.js.map +1 -0
- package/out/zero-cache/src/server/worker-urls.d.ts +1 -0
- package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -1
- package/out/zero-cache/src/server/worker-urls.js +2 -1
- package/out/zero-cache/src/server/worker-urls.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -1
- package/out/zero-cache/src/services/http-service.d.ts +6 -0
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +13 -1
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +19 -0
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +53 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +1 -1
- package/out/zero-cache/src/services/replicator/serving-checkpointer.js +85 -0
- package/out/zero-cache/src/services/replicator/serving-checkpointer.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +101 -13
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.js +2 -2
- package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +1 -1
- package/out/zero-cache/src/types/processes.js +4 -4
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/row-key.js +8 -1
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/workers/connection.js +2 -2
- package/out/zero-cache/src/workers/replicator.js +9 -4
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-client/src/client/bindings.d.ts +1 -1
- package/out/zero-client/src/client/bindings.d.ts.map +1 -1
- package/out/zero-client/src/client/bindings.js +4 -4
- package/out/zero-client/src/client/context.d.ts +7 -1
- package/out/zero-client/src/client/context.d.ts.map +1 -1
- package/out/zero-client/src/client/context.js +7 -0
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
- package/out/zero-client/src/client/crud-impl.js +171 -2
- package/out/zero-client/src/client/crud-impl.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +42 -3
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts +62 -2
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +152 -31
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/keys.d.ts +33 -0
- package/out/zero-client/src/client/keys.d.ts.map +1 -1
- package/out/zero-client/src/client/keys.js +43 -4
- package/out/zero-client/src/client/keys.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js +29 -1
- package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-rep.js +2 -15
- package/out/zero-client/src/client/zero-rep.js.map +1 -1
- package/out/zero-client/src/client/zero.js +1 -1
- package/out/zero-client/src/mod.d.ts +3 -3
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-protocol/src/aggregate-table.d.ts +15 -0
- package/out/zero-protocol/src/aggregate-table.d.ts.map +1 -0
- package/out/zero-protocol/src/aggregate-table.js +5 -0
- package/out/zero-protocol/src/aggregate-table.js.map +1 -0
- package/out/zero-protocol/src/ast.d.ts +141 -5
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js +244 -18
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +29 -29
- package/out/zero-protocol/src/inspect-down.d.ts +81 -81
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/query-hash-visitor.d.ts.map +1 -1
- package/out/zero-protocol/src/query-hash-visitor.js +38 -0
- package/out/zero-protocol/src/query-hash-visitor.js.map +1 -1
- package/out/zero-react/src/bindings.js +4 -4
- package/out/zero-react/src/use-query.d.ts +3 -1
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +4 -2
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.js +2 -0
- package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
- package/out/zero-schema/src/name-mapper.d.ts.map +1 -1
- package/out/zero-schema/src/name-mapper.js +7 -4
- package/out/zero-schema/src/name-mapper.js.map +1 -1
- package/out/zero-server/src/custom.js +1 -1
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +13 -2
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-solid/src/bindings.js +4 -4
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +3 -3
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-types/src/format.d.ts +13 -0
- package/out/zero-types/src/format.d.ts.map +1 -1
- package/out/zero-types/src/format.js.map +1 -1
- package/out/zero-types/src/name-mapper.d.ts +14 -0
- package/out/zero-types/src/name-mapper.d.ts.map +1 -1
- package/out/zero-types/src/name-mapper.js +12 -0
- package/out/zero-types/src/name-mapper.js.map +1 -1
- package/out/zero-types/src/schema-value.d.ts +2 -0
- package/out/zero-types/src/schema-value.d.ts.map +1 -1
- package/out/zero-types/src/schema-value.js +15 -0
- package/out/zero-types/src/schema-value.js.map +1 -0
- package/out/zero-types/src/server-schema.d.ts +18 -0
- package/out/zero-types/src/server-schema.d.ts.map +1 -1
- package/out/zql/src/builder/builder.d.ts +126 -1
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +281 -11
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/builder/filter.d.ts +1 -1
- package/out/zql/src/builder/filter.d.ts.map +1 -1
- package/out/zql/src/builder/filter.js +41 -3
- package/out/zql/src/builder/filter.js.map +1 -1
- package/out/zql/src/ivm/aggregate.d.ts +188 -0
- package/out/zql/src/ivm/aggregate.d.ts.map +1 -0
- package/out/zql/src/ivm/aggregate.js +470 -0
- package/out/zql/src/ivm/aggregate.js.map +1 -0
- 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 +3 -3
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/cap.js +2 -2
- package/out/zql/src/ivm/constraint.d.ts.map +1 -1
- package/out/zql/src/ivm/constraint.js +2 -1
- package/out/zql/src/ivm/constraint.js.map +1 -1
- package/out/zql/src/ivm/deferred-input.js +1 -1
- package/out/zql/src/ivm/fan-in.js +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +3 -2
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/group-by.d.ts +98 -0
- package/out/zql/src/ivm/group-by.d.ts.map +1 -0
- package/out/zql/src/ivm/group-by.js +384 -0
- package/out/zql/src/ivm/group-by.js.map +1 -0
- package/out/zql/src/ivm/join-index.d.ts.map +1 -1
- package/out/zql/src/ivm/join-index.js +2 -1
- package/out/zql/src/ivm/join-index.js.map +1 -1
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +2 -1
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/join.js +1 -1
- package/out/zql/src/ivm/lift-field.d.ts +54 -0
- package/out/zql/src/ivm/lift-field.d.ts.map +1 -0
- package/out/zql/src/ivm/lift-field.js +168 -0
- package/out/zql/src/ivm/lift-field.js.map +1 -0
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +2 -0
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +9 -4
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +1 -1
- package/out/zql/src/ivm/schema.d.ts +1 -0
- package/out/zql/src/ivm/schema.d.ts.map +1 -1
- package/out/zql/src/ivm/source.d.ts +21 -0
- package/out/zql/src/ivm/source.d.ts.map +1 -1
- package/out/zql/src/ivm/source.js.map +1 -1
- package/out/zql/src/ivm/take.js +1 -1
- package/out/zql/src/ivm/union-fan-in.js +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts +5 -0
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +23 -3
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/planner/planner-debug.d.ts +1 -1
- package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
- package/out/zql/src/planner/planner-debug.js +4 -0
- package/out/zql/src/planner/planner-debug.js.map +1 -1
- package/out/zql/src/query/expression.d.ts +50 -3
- package/out/zql/src/query/expression.d.ts.map +1 -1
- package/out/zql/src/query/expression.js +62 -6
- package/out/zql/src/query/expression.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +1 -1
- package/out/zql/src/query/query-delegate-base.d.ts +8 -0
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +13 -5
- package/out/zql/src/query/query-delegate-base.js.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +17 -3
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +239 -7
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query.d.ts +319 -7
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zqlite/src/pending-delta.d.ts.map +1 -1
- package/out/zqlite/src/pending-delta.js +4 -3
- package/out/zqlite/src/pending-delta.js.map +1 -1
- package/out/zqlite/src/query-builder.d.ts +12 -1
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +114 -13
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +37 -3
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { __exportAll } from "../../../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { unreachable } from "../../../shared/src/asserts.js";
|
|
3
|
+
import { hasOwn } from "../../../shared/src/has-own.js";
|
|
2
4
|
import { must } from "../../../shared/src/must.js";
|
|
3
|
-
import "../../../zero-protocol/src/
|
|
5
|
+
import { aggregateValue } from "../../../zero-protocol/src/ast.js";
|
|
6
|
+
import { assignProperty } from "../../../shared/src/objects.js";
|
|
4
7
|
import { consume } from "../../../zql/src/ivm/stream.js";
|
|
8
|
+
import { AGGREGATE_COUNT_COLUMN, AGGREGATE_KEY_COLUMN, AGGREGATE_ROWS_COLUMN, AGGREGATE_SUM_COLUMN, AGGREGATE_VALUE_COLUMN } from "../../../zql/src/ivm/aggregate.js";
|
|
9
|
+
import "../../../zero-protocol/src/mutation.js";
|
|
5
10
|
import { makeSourceChangeAdd, makeSourceChangeEdit, makeSourceChangeRemove } from "../../../zql/src/ivm/source.js";
|
|
6
|
-
import {
|
|
11
|
+
import { groupKey, groupValues } from "../../../zql/src/ivm/group-by.js";
|
|
12
|
+
import { aggregateRowKey, toPrimaryKeyString } from "./keys.js";
|
|
7
13
|
//#region ../zero-client/src/client/crud-impl.ts
|
|
8
14
|
var crud_impl_exports = /* @__PURE__ */ __exportAll({
|
|
9
15
|
delete: () => deleteImpl,
|
|
@@ -11,6 +17,166 @@ var crud_impl_exports = /* @__PURE__ */ __exportAll({
|
|
|
11
17
|
update: () => update,
|
|
12
18
|
upsert: () => upsert
|
|
13
19
|
});
|
|
20
|
+
function numberOr0(v) {
|
|
21
|
+
return typeof v === "number" ? v : 0;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The value a child row contributes to a sum/avg: its field, or the JSON leaf
|
|
25
|
+
* at the aggregate's path (see `aggregateValue`).
|
|
26
|
+
*/
|
|
27
|
+
function contribution(agg, row) {
|
|
28
|
+
return row === void 0 ? void 0 : aggregateValue(agg, row);
|
|
29
|
+
}
|
|
30
|
+
/** A child row's contribution as a number (null/absent ⇒ 0, SQL-style). */
|
|
31
|
+
function fieldNumber(agg, row) {
|
|
32
|
+
return numberOr0(contribution(agg, row));
|
|
33
|
+
}
|
|
34
|
+
/** Whether a child row contributes a non-null number to a sum/avg. */
|
|
35
|
+
function contributes(agg, row) {
|
|
36
|
+
return typeof contribution(agg, row) === "number";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The new aggregate row after a child change (`oldRow`→`newRow`: insert has only
|
|
40
|
+
* `newRow`, delete only `oldRow`, update both), or `undefined` if unchanged.
|
|
41
|
+
*/
|
|
42
|
+
function nextAggregateRow(agg, curRow, oldRowRaw, newRowRaw) {
|
|
43
|
+
const { predicate } = agg;
|
|
44
|
+
const oldRow = predicate && oldRowRaw && !predicate(oldRowRaw) ? void 0 : oldRowRaw;
|
|
45
|
+
const newRow = predicate && newRowRaw && !predicate(newRowRaw) ? void 0 : newRowRaw;
|
|
46
|
+
const value = curRow[AGGREGATE_VALUE_COLUMN];
|
|
47
|
+
switch (agg.fn) {
|
|
48
|
+
case "count": {
|
|
49
|
+
const delta = (newRow ? 1 : 0) - (oldRow ? 1 : 0);
|
|
50
|
+
return delta === 0 ? void 0 : {
|
|
51
|
+
...curRow,
|
|
52
|
+
[AGGREGATE_VALUE_COLUMN]: numberOr0(value) + delta
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
case "sum":
|
|
56
|
+
case "avg": {
|
|
57
|
+
if (agg.field === void 0) return;
|
|
58
|
+
const sumDelta = fieldNumber(agg, newRow) - fieldNumber(agg, oldRow);
|
|
59
|
+
const countDelta = (contributes(agg, newRow) ? 1 : 0) - (contributes(agg, oldRow) ? 1 : 0);
|
|
60
|
+
const hasRows = hasOwn(curRow, AGGREGATE_ROWS_COLUMN);
|
|
61
|
+
const rowsDelta = hasRows ? (newRow ? 1 : 0) - (oldRow ? 1 : 0) : 0;
|
|
62
|
+
if (sumDelta === 0 && countDelta === 0 && rowsDelta === 0) return;
|
|
63
|
+
const sum = numberOr0(curRow[AGGREGATE_SUM_COLUMN]) + sumDelta;
|
|
64
|
+
const count = numberOr0(curRow[AGGREGATE_COUNT_COLUMN]) + countDelta;
|
|
65
|
+
const result = agg.fn === "sum" ? sum : sum / count;
|
|
66
|
+
const next = {
|
|
67
|
+
...curRow,
|
|
68
|
+
[AGGREGATE_VALUE_COLUMN]: count > 0 ? result : null,
|
|
69
|
+
[AGGREGATE_SUM_COLUMN]: sum,
|
|
70
|
+
[AGGREGATE_COUNT_COLUMN]: count
|
|
71
|
+
};
|
|
72
|
+
if (hasRows) next[AGGREGATE_ROWS_COLUMN] = numberOr0(curRow[AGGREGATE_ROWS_COLUMN]) + rowsDelta;
|
|
73
|
+
return next;
|
|
74
|
+
}
|
|
75
|
+
case "min":
|
|
76
|
+
case "max": return;
|
|
77
|
+
default: unreachable(agg.fn);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The Replicache key of the aggregate row a child row contributes to, or
|
|
82
|
+
* `undefined` when a correlation value is null: such a child has no parent, so
|
|
83
|
+
* it is in no aggregate. A grouped query's row is its group's, whose values
|
|
84
|
+
* can be null.
|
|
85
|
+
*/
|
|
86
|
+
function aggregateKeyFor(agg, child) {
|
|
87
|
+
if (agg.grouped) return aggregateRowKey(agg.aggTableName, { [AGGREGATE_KEY_COLUMN]: groupKey(groupValues(child, agg.childField)) });
|
|
88
|
+
const keyRow = {};
|
|
89
|
+
for (let i = 0; i < agg.childField.length; i++) {
|
|
90
|
+
const value = child[agg.childField[i]];
|
|
91
|
+
if (value === null || value === void 0) return;
|
|
92
|
+
assignProperty(keyRow, agg.keyField[i], value);
|
|
93
|
+
}
|
|
94
|
+
return aggregateRowKey(agg.aggTableName, keyRow);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Writes the aggregate row at `aggKey` as moved by one child change, if that
|
|
98
|
+
* row is on the client (its parent is in some query's result). The row is
|
|
99
|
+
* also pushed to the transaction's branch, so a query the mutator runs after
|
|
100
|
+
* the change reads the new value.
|
|
101
|
+
*
|
|
102
|
+
* A grouped query's row is the group's: a row joining a group that isn't on
|
|
103
|
+
* the client adds it, and the last row leaving one removes it.
|
|
104
|
+
*/
|
|
105
|
+
async function applyAggregateDelta(tx, ivmBranch, agg, aggKey, oldRow, newRow) {
|
|
106
|
+
const source = ivmBranch.getSource(agg.aggTableName);
|
|
107
|
+
const cur = await tx.get(aggKey);
|
|
108
|
+
if (cur === void 0) {
|
|
109
|
+
const added = agg.grouped ? newGroupRow(agg, oldRow, newRow) : void 0;
|
|
110
|
+
if (added !== void 0) {
|
|
111
|
+
await tx.set(aggKey, added);
|
|
112
|
+
if (source) consume(source.push(makeSourceChangeAdd(added)));
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const updated = nextAggregateRow(agg, cur, oldRow, newRow);
|
|
117
|
+
if (updated === void 0) return;
|
|
118
|
+
const inBranch = source?.data.has(cur) ?? false;
|
|
119
|
+
if (agg.grouped && groupRowCount(agg, updated) === 0) {
|
|
120
|
+
await tx.del(aggKey);
|
|
121
|
+
if (inBranch) consume(must(source).push(makeSourceChangeRemove(cur)));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
await tx.set(aggKey, updated);
|
|
125
|
+
if (inBranch) consume(must(source).push(makeSourceChangeEdit(updated, cur)));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The number of rows of the group whose synced row is `row`, or `undefined`
|
|
129
|
+
* for a sum/avg row stored before the rows carried it.
|
|
130
|
+
*/
|
|
131
|
+
function groupRowCount(agg, row) {
|
|
132
|
+
return row[agg.fn === "count" ? AGGREGATE_VALUE_COLUMN : AGGREGATE_ROWS_COLUMN];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The row of a group of a grouped query that isn't on the client, when the
|
|
136
|
+
* change from `oldRow` to `newRow` makes `newRow` its first row: `newRow`
|
|
137
|
+
* passes the query's `where` and `oldRow` wasn't counted in the group
|
|
138
|
+
* already. Otherwise `undefined`.
|
|
139
|
+
*/
|
|
140
|
+
function newGroupRow(agg, oldRow, newRow) {
|
|
141
|
+
const counted = (row) => row !== void 0 && (!agg.predicate || agg.predicate(row));
|
|
142
|
+
if (!counted(newRow) || counted(oldRow)) return;
|
|
143
|
+
const values = groupValues(newRow, agg.childField);
|
|
144
|
+
const empty = {};
|
|
145
|
+
agg.keyField.forEach((col, i) => assignProperty(empty, col, values[i]));
|
|
146
|
+
empty[AGGREGATE_KEY_COLUMN] = groupKey(values);
|
|
147
|
+
if (agg.fn === "count") empty[AGGREGATE_VALUE_COLUMN] = 0;
|
|
148
|
+
else {
|
|
149
|
+
empty[AGGREGATE_VALUE_COLUMN] = null;
|
|
150
|
+
empty[AGGREGATE_SUM_COLUMN] = 0;
|
|
151
|
+
empty[AGGREGATE_COUNT_COLUMN] = 0;
|
|
152
|
+
empty[AGGREGATE_ROWS_COLUMN] = 0;
|
|
153
|
+
}
|
|
154
|
+
return nextAggregateRow(agg, empty, void 0, newRow);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Optimistically adjust any synced aggregates whose child rows live in `table`
|
|
158
|
+
* when a child row is locally inserted/deleted/updated. The adjusted value is
|
|
159
|
+
* written to Replicache (the aggregate's synthetic row, keyed by the child's
|
|
160
|
+
* correlation field) inside the mutator's transaction — so the view updates
|
|
161
|
+
* immediately, and Replicache's rebase reconciles it against the server's
|
|
162
|
+
* authoritative value when it pokes back (the pending mutation's delta is
|
|
163
|
+
* replayed while pending and absorbed into the base once confirmed — no
|
|
164
|
+
* double-count). An aggregate row that is not on the client is left alone,
|
|
165
|
+
* except that a grouped query's row is added by the first row of its group.
|
|
166
|
+
*/
|
|
167
|
+
async function applyOptimisticAggregateDeltas(tx, ivmBranch, table, oldRow, newRow) {
|
|
168
|
+
if (!ivmBranch) return;
|
|
169
|
+
for (const agg of ivmBranch.getOptimisticAggregates(table)) {
|
|
170
|
+
const oldKey = oldRow && aggregateKeyFor(agg, oldRow);
|
|
171
|
+
const newKey = newRow && aggregateKeyFor(agg, newRow);
|
|
172
|
+
if (oldKey === newKey) {
|
|
173
|
+
if (oldKey !== void 0) await applyAggregateDelta(tx, ivmBranch, agg, oldKey, oldRow, newRow);
|
|
174
|
+
} else {
|
|
175
|
+
if (oldKey !== void 0) await applyAggregateDelta(tx, ivmBranch, agg, oldKey, oldRow, void 0);
|
|
176
|
+
if (newKey !== void 0) await applyAggregateDelta(tx, ivmBranch, agg, newKey, void 0, newRow);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
14
180
|
function defaultOptionalFieldsToNull(schema, value) {
|
|
15
181
|
let rv = value;
|
|
16
182
|
for (const name in schema.columns) if (rv[name] === void 0) rv = {
|
|
@@ -25,6 +191,7 @@ async function insert(tx, arg, schema, ivmBranch) {
|
|
|
25
191
|
const val = defaultOptionalFieldsToNull(schema.tables[arg.tableName], arg.value);
|
|
26
192
|
await tx.set(key, val);
|
|
27
193
|
if (ivmBranch) consume(must(ivmBranch.getSource(arg.tableName)).push(makeSourceChangeAdd(val)));
|
|
194
|
+
await applyOptimisticAggregateDeltas(tx, ivmBranch, arg.tableName, void 0, val);
|
|
28
195
|
}
|
|
29
196
|
}
|
|
30
197
|
async function upsert(tx, arg, schema, ivmBranch) {
|
|
@@ -47,6 +214,7 @@ async function update(tx, arg, schema, ivmBranch) {
|
|
|
47
214
|
for (const k in update) if (update[k] !== void 0) next[k] = update[k];
|
|
48
215
|
await tx.set(key, next);
|
|
49
216
|
if (ivmBranch) consume(must(ivmBranch.getSource(arg.tableName)).push(makeSourceChangeEdit(next, prev)));
|
|
217
|
+
await applyOptimisticAggregateDeltas(tx, ivmBranch, arg.tableName, prev, next);
|
|
50
218
|
}
|
|
51
219
|
async function deleteImpl(tx, arg, schema, ivmBranch) {
|
|
52
220
|
const key = toPrimaryKeyString(arg.tableName, schema.tables[arg.tableName].primaryKey, arg.value);
|
|
@@ -54,6 +222,7 @@ async function deleteImpl(tx, arg, schema, ivmBranch) {
|
|
|
54
222
|
if (prev === void 0) return;
|
|
55
223
|
await tx.del(key);
|
|
56
224
|
if (ivmBranch) consume(must(ivmBranch.getSource(arg.tableName)).push(makeSourceChangeRemove(prev)));
|
|
225
|
+
await applyOptimisticAggregateDeltas(tx, ivmBranch, arg.tableName, prev, void 0);
|
|
57
226
|
}
|
|
58
227
|
//#endregion
|
|
59
228
|
export { crud_impl_exports, deleteImpl as delete, insert, update, upsert };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crud-impl.js","names":[],"sources":["../../../../../zero-client/src/client/crud-impl.ts"],"sourcesContent":["import type {ReadonlyJSONObject} from '../../../shared/src/json.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport {\n type DeleteOp,\n type InsertOp,\n type UpdateOp,\n type UpsertOp,\n} from '../../../zero-protocol/src/mutation.ts';\nimport type {TableSchema} from '../../../zero-schema/src/table-schema.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport {\n makeSourceChangeAdd,\n makeSourceChangeEdit,\n makeSourceChangeRemove,\n} from '../../../zql/src/ivm/source.ts';\nimport {consume} from '../../../zql/src/ivm/stream.ts';\nimport type {IVMSourceBranch} from './ivm-branch.ts';\nimport {toPrimaryKeyString} from './keys.ts';\nimport type {WriteTransaction} from './replicache-types.ts';\nexport type {TableMutator} from '../../../zql/src/mutate/crud.ts';\n\nfunction defaultOptionalFieldsToNull(\n schema: TableSchema,\n value: ReadonlyJSONObject,\n): ReadonlyJSONObject {\n let rv = value;\n for (const name in schema.columns) {\n if (rv[name] === undefined) {\n rv = {...rv, [name]: null};\n }\n }\n return rv;\n}\n\nexport async function insert(\n tx: WriteTransaction,\n arg: InsertOp,\n schema: Schema,\n ivmBranch: IVMSourceBranch | undefined,\n): Promise<void> {\n const key = toPrimaryKeyString(\n arg.tableName,\n schema.tables[arg.tableName].primaryKey,\n arg.value,\n );\n if (!(await tx.has(key))) {\n const val = defaultOptionalFieldsToNull(\n schema.tables[arg.tableName],\n arg.value,\n );\n await tx.set(key, val);\n if (ivmBranch) {\n consume(\n must(ivmBranch.getSource(arg.tableName)).push(makeSourceChangeAdd(val)),\n );\n }\n }\n}\n\nexport async function upsert(\n tx: WriteTransaction,\n arg: InsertOp | UpsertOp,\n schema: Schema,\n ivmBranch: IVMSourceBranch | undefined,\n): Promise<void> {\n const key = toPrimaryKeyString(\n arg.tableName,\n schema.tables[arg.tableName].primaryKey,\n arg.value,\n );\n if (await tx.has(key)) {\n await update(tx, {...arg, op: 'update'}, schema, ivmBranch);\n } else {\n await insert(tx, {...arg, op: 'insert'}, schema, ivmBranch);\n }\n}\n\nexport async function update(\n tx: WriteTransaction,\n arg: UpdateOp,\n schema: Schema,\n ivmBranch: IVMSourceBranch | undefined,\n): Promise<void> {\n const key = toPrimaryKeyString(\n arg.tableName,\n schema.tables[arg.tableName].primaryKey,\n arg.value,\n );\n const prev = await tx.get(key);\n if (prev === undefined) {\n return;\n }\n const update = arg.value;\n const next = {...(prev as ReadonlyJSONObject)};\n for (const k in update) {\n if (update[k] !== undefined) {\n next[k] = update[k];\n }\n }\n await tx.set(key, next);\n if (ivmBranch) {\n consume(\n must(ivmBranch.getSource(arg.tableName)).push(\n makeSourceChangeEdit(next, prev as Row),\n ),\n );\n }\n}\n\nasync function deleteImpl(\n tx: WriteTransaction,\n arg: DeleteOp,\n schema: Schema,\n ivmBranch: IVMSourceBranch | undefined,\n): Promise<void> {\n const key = toPrimaryKeyString(\n arg.tableName,\n schema.tables[arg.tableName].primaryKey,\n arg.value,\n );\n const prev = await tx.get(key);\n if (prev === undefined) {\n return;\n }\n await tx.del(key);\n if (ivmBranch) {\n consume(\n must(ivmBranch.getSource(arg.tableName)).push(\n makeSourceChangeRemove(prev as Row),\n ),\n );\n }\n}\n\nexport {deleteImpl as delete};\n"],"mappings":";;;;;;;;;;;;;AAsBA,SAAS,4BACP,QACA,OACoB;CACpB,IAAI,KAAK;CACT,KAAK,MAAM,QAAQ,OAAO,SACxB,IAAI,GAAG,UAAU,KAAA,GACf,KAAK;EAAC,GAAG;GAAK,OAAO;CAAI;CAG7B,OAAO;AACT;AAEA,eAAsB,OACpB,IACA,KACA,QACA,WACe;CACf,MAAM,MAAM,mBACV,IAAI,WACJ,OAAO,OAAO,IAAI,UAAU,CAAC,YAC7B,IAAI,KACN;CACA,IAAI,CAAE,MAAM,GAAG,IAAI,GAAG,GAAI;EACxB,MAAM,MAAM,4BACV,OAAO,OAAO,IAAI,YAClB,IAAI,KACN;EACA,MAAM,GAAG,IAAI,KAAK,GAAG;EACrB,IAAI,WACF,QACE,KAAK,UAAU,UAAU,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,oBAAoB,GAAG,CAAC,CACxE;CAEJ;AACF;AAEA,eAAsB,OACpB,IACA,KACA,QACA,WACe;CACf,MAAM,MAAM,mBACV,IAAI,WACJ,OAAO,OAAO,IAAI,UAAU,CAAC,YAC7B,IAAI,KACN;CACA,IAAI,MAAM,GAAG,IAAI,GAAG,GAClB,MAAM,OAAO,IAAI;EAAC,GAAG;EAAK,IAAI;CAAQ,GAAG,QAAQ,SAAS;MAE1D,MAAM,OAAO,IAAI;EAAC,GAAG;EAAK,IAAI;CAAQ,GAAG,QAAQ,SAAS;AAE9D;AAEA,eAAsB,OACpB,IACA,KACA,QACA,WACe;CACf,MAAM,MAAM,mBACV,IAAI,WACJ,OAAO,OAAO,IAAI,UAAU,CAAC,YAC7B,IAAI,KACN;CACA,MAAM,OAAO,MAAM,GAAG,IAAI,GAAG;CAC7B,IAAI,SAAS,KAAA,GACX;CAEF,MAAM,SAAS,IAAI;CACnB,MAAM,OAAO,EAAC,GAAI,KAA2B;CAC7C,KAAK,MAAM,KAAK,QACd,IAAI,OAAO,OAAO,KAAA,GAChB,KAAK,KAAK,OAAO;CAGrB,MAAM,GAAG,IAAI,KAAK,IAAI;CACtB,IAAI,WACF,QACE,KAAK,UAAU,UAAU,IAAI,SAAS,CAAC,CAAC,CAAC,KACvC,qBAAqB,MAAM,IAAW,CACxC,CACF;AAEJ;AAEA,eAAe,WACb,IACA,KACA,QACA,WACe;CACf,MAAM,MAAM,mBACV,IAAI,WACJ,OAAO,OAAO,IAAI,UAAU,CAAC,YAC7B,IAAI,KACN;CACA,MAAM,OAAO,MAAM,GAAG,IAAI,GAAG;CAC7B,IAAI,SAAS,KAAA,GACX;CAEF,MAAM,GAAG,IAAI,GAAG;CAChB,IAAI,WACF,QACE,KAAK,UAAU,UAAU,IAAI,SAAS,CAAC,CAAC,CAAC,KACvC,uBAAuB,IAAW,CACpC,CACF;AAEJ"}
|
|
1
|
+
{"version":3,"file":"crud-impl.js","names":[],"sources":["../../../../../zero-client/src/client/crud-impl.ts"],"sourcesContent":["import {unreachable} from '../../../shared/src/asserts.ts';\nimport {hasOwn} from '../../../shared/src/has-own.ts';\nimport type {ReadonlyJSONObject} from '../../../shared/src/json.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {assignProperty} from '../../../shared/src/objects.ts';\nimport {aggregateValue} from '../../../zero-protocol/src/ast.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport {\n type DeleteOp,\n type InsertOp,\n type UpdateOp,\n type UpsertOp,\n} from '../../../zero-protocol/src/mutation.ts';\nimport type {TableSchema} from '../../../zero-schema/src/table-schema.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport {\n AGGREGATE_COUNT_COLUMN,\n AGGREGATE_KEY_COLUMN,\n AGGREGATE_ROWS_COLUMN,\n AGGREGATE_SUM_COLUMN,\n AGGREGATE_VALUE_COLUMN,\n} from '../../../zql/src/ivm/aggregate.ts';\nimport {groupKey, groupValues} from '../../../zql/src/ivm/group-by.ts';\nimport {\n makeSourceChangeAdd,\n makeSourceChangeEdit,\n makeSourceChangeRemove,\n} from '../../../zql/src/ivm/source.ts';\nimport {consume} from '../../../zql/src/ivm/stream.ts';\nimport type {IVMSourceBranch, OptimisticAggregate} from './ivm-branch.ts';\nimport {aggregateRowKey, toPrimaryKeyString} from './keys.ts';\nimport type {WriteTransaction} from './replicache-types.ts';\nexport type {TableMutator} from '../../../zql/src/mutate/crud.ts';\n\nfunction numberOr0(v: unknown): number {\n return typeof v === 'number' ? v : 0;\n}\n\n/**\n * The value a child row contributes to a sum/avg: its field, or the JSON leaf\n * at the aggregate's path (see `aggregateValue`).\n */\nfunction contribution(agg: OptimisticAggregate, row: Row | undefined): unknown {\n return row === undefined ? undefined : aggregateValue(agg, row);\n}\n\n/** A child row's contribution as a number (null/absent ⇒ 0, SQL-style). */\nfunction fieldNumber(agg: OptimisticAggregate, row: Row | undefined): number {\n return numberOr0(contribution(agg, row));\n}\n\n/** Whether a child row contributes a non-null number to a sum/avg. */\nfunction contributes(agg: OptimisticAggregate, row: Row | undefined): boolean {\n return typeof contribution(agg, row) === 'number';\n}\n\n/**\n * The new aggregate row after a child change (`oldRow`→`newRow`: insert has only\n * `newRow`, delete only `oldRow`, update both), or `undefined` if unchanged.\n */\nfunction nextAggregateRow(\n agg: OptimisticAggregate,\n curRow: Row,\n oldRowRaw: Row | undefined,\n newRowRaw: Row | undefined,\n): Row | undefined {\n // A child row contributes only if it matches the aggregate's `where`\n // predicate (if any). Treating a non-matching row as absent lets all the\n // delta math below — count ±1, sum/avg ±field — naturally handle rows\n // entering or leaving the filtered set on an update (old matched / new\n // doesn't ⇒ −delta, and vice versa).\n const {predicate} = agg;\n const oldRow =\n predicate && oldRowRaw && !predicate(oldRowRaw) ? undefined : oldRowRaw;\n const newRow =\n predicate && newRowRaw && !predicate(newRowRaw) ? undefined : newRowRaw;\n const value = curRow[AGGREGATE_VALUE_COLUMN];\n switch (agg.fn) {\n case 'count': {\n const delta = (newRow ? 1 : 0) - (oldRow ? 1 : 0);\n return delta === 0\n ? undefined\n : {...curRow, [AGGREGATE_VALUE_COLUMN]: numberOr0(value) + delta};\n }\n case 'sum':\n case 'avg': {\n if (agg.field === undefined) {\n return undefined;\n }\n // The synced row carries the sum of non-null values and their count, so\n // adjust both and derive the value: SQL's sum/avg ignore nulls and are\n // null over no contributors. A group's row also carries its number of\n // rows, nulls included, except one stored before it did, which gets it\n // when the server next sends the group.\n const sumDelta = fieldNumber(agg, newRow) - fieldNumber(agg, oldRow);\n const countDelta =\n (contributes(agg, newRow) ? 1 : 0) - (contributes(agg, oldRow) ? 1 : 0);\n const hasRows = hasOwn(curRow, AGGREGATE_ROWS_COLUMN);\n const rowsDelta = hasRows ? (newRow ? 1 : 0) - (oldRow ? 1 : 0) : 0;\n if (sumDelta === 0 && countDelta === 0 && rowsDelta === 0) {\n return undefined;\n }\n const sum = numberOr0(curRow[AGGREGATE_SUM_COLUMN]) + sumDelta;\n const count = numberOr0(curRow[AGGREGATE_COUNT_COLUMN]) + countDelta;\n const result = agg.fn === 'sum' ? sum : sum / count;\n const next: Record<string, Value> = {\n ...curRow,\n [AGGREGATE_VALUE_COLUMN]: count > 0 ? result : null,\n [AGGREGATE_SUM_COLUMN]: sum,\n [AGGREGATE_COUNT_COLUMN]: count,\n };\n if (hasRows) {\n next[AGGREGATE_ROWS_COLUMN] =\n numberOr0(curRow[AGGREGATE_ROWS_COLUMN]) + rowsDelta;\n }\n return next;\n }\n // `min`/`max` are non-invertible; they update on the server poke.\n case 'min':\n case 'max':\n return undefined;\n default:\n unreachable(agg.fn);\n }\n}\n\n/**\n * The Replicache key of the aggregate row a child row contributes to, or\n * `undefined` when a correlation value is null: such a child has no parent, so\n * it is in no aggregate. A grouped query's row is its group's, whose values\n * can be null.\n */\nfunction aggregateKeyFor(\n agg: OptimisticAggregate,\n child: Row,\n): string | undefined {\n if (agg.grouped) {\n return aggregateRowKey(agg.aggTableName, {\n [AGGREGATE_KEY_COLUMN]: groupKey(groupValues(child, agg.childField)),\n });\n }\n const keyRow: Record<string, Value> = {};\n for (let i = 0; i < agg.childField.length; i++) {\n const value = child[agg.childField[i]];\n if (value === null || value === undefined) {\n return undefined;\n }\n assignProperty(keyRow, agg.keyField[i], value);\n }\n return aggregateRowKey(agg.aggTableName, keyRow);\n}\n\n/**\n * Writes the aggregate row at `aggKey` as moved by one child change, if that\n * row is on the client (its parent is in some query's result). The row is\n * also pushed to the transaction's branch, so a query the mutator runs after\n * the change reads the new value.\n *\n * A grouped query's row is the group's: a row joining a group that isn't on\n * the client adds it, and the last row leaving one removes it.\n */\nasync function applyAggregateDelta(\n tx: WriteTransaction,\n ivmBranch: IVMSourceBranch,\n agg: OptimisticAggregate,\n aggKey: string,\n oldRow: Row | undefined,\n newRow: Row | undefined,\n): Promise<void> {\n // The branch holds the row when a view of its query reads it.\n const source = ivmBranch.getSource(agg.aggTableName);\n const cur = await tx.get(aggKey);\n if (cur === undefined) {\n const added = agg.grouped ? newGroupRow(agg, oldRow, newRow) : undefined;\n if (added !== undefined) {\n await tx.set(aggKey, added);\n if (source) {\n consume(source.push(makeSourceChangeAdd(added)));\n }\n }\n return;\n }\n const updated = nextAggregateRow(agg, cur as Row, oldRow, newRow);\n if (updated === undefined) {\n return;\n }\n const inBranch = source?.data.has(cur as Row) ?? false;\n if (agg.grouped && groupRowCount(agg, updated) === 0) {\n await tx.del(aggKey);\n if (inBranch) {\n consume(must(source).push(makeSourceChangeRemove(cur as Row)));\n }\n return;\n }\n await tx.set(aggKey, updated);\n if (inBranch) {\n consume(must(source).push(makeSourceChangeEdit(updated, cur as Row)));\n }\n}\n\n/**\n * The number of rows of the group whose synced row is `row`, or `undefined`\n * for a sum/avg row stored before the rows carried it.\n */\nfunction groupRowCount(agg: OptimisticAggregate, row: Row): Value {\n return row[\n agg.fn === 'count' ? AGGREGATE_VALUE_COLUMN : AGGREGATE_ROWS_COLUMN\n ];\n}\n\n/**\n * The row of a group of a grouped query that isn't on the client, when the\n * change from `oldRow` to `newRow` makes `newRow` its first row: `newRow`\n * passes the query's `where` and `oldRow` wasn't counted in the group\n * already. Otherwise `undefined`.\n */\nfunction newGroupRow(\n agg: OptimisticAggregate,\n oldRow: Row | undefined,\n newRow: Row | undefined,\n): Row | undefined {\n const counted = (row: Row | undefined): row is Row =>\n row !== undefined && (!agg.predicate || agg.predicate(row));\n if (!counted(newRow) || counted(oldRow)) {\n return undefined;\n }\n const values = groupValues(newRow, agg.childField);\n // The group with no rows, which `newRow` then joins.\n const empty: Record<string, Value> = {};\n agg.keyField.forEach((col, i) => assignProperty(empty, col, values[i]));\n empty[AGGREGATE_KEY_COLUMN] = groupKey(values);\n if (agg.fn === 'count') {\n empty[AGGREGATE_VALUE_COLUMN] = 0;\n } else {\n empty[AGGREGATE_VALUE_COLUMN] = null;\n empty[AGGREGATE_SUM_COLUMN] = 0;\n empty[AGGREGATE_COUNT_COLUMN] = 0;\n empty[AGGREGATE_ROWS_COLUMN] = 0;\n }\n return nextAggregateRow(agg, empty, undefined, newRow);\n}\n\n/**\n * Optimistically adjust any synced aggregates whose child rows live in `table`\n * when a child row is locally inserted/deleted/updated. The adjusted value is\n * written to Replicache (the aggregate's synthetic row, keyed by the child's\n * correlation field) inside the mutator's transaction — so the view updates\n * immediately, and Replicache's rebase reconciles it against the server's\n * authoritative value when it pokes back (the pending mutation's delta is\n * replayed while pending and absorbed into the base once confirmed — no\n * double-count). An aggregate row that is not on the client is left alone,\n * except that a grouped query's row is added by the first row of its group.\n */\nasync function applyOptimisticAggregateDeltas(\n tx: WriteTransaction,\n ivmBranch: IVMSourceBranch | undefined,\n table: string,\n oldRow: Row | undefined,\n newRow: Row | undefined,\n): Promise<void> {\n if (!ivmBranch) {\n return;\n }\n for (const agg of ivmBranch.getOptimisticAggregates(table)) {\n const oldKey = oldRow && aggregateKeyFor(agg, oldRow);\n const newKey = newRow && aggregateKeyFor(agg, newRow);\n if (oldKey === newKey) {\n if (oldKey !== undefined) {\n await applyAggregateDelta(tx, ivmBranch, agg, oldKey, oldRow, newRow);\n }\n } else {\n // The child leaves one parent's aggregate and joins another's (either\n // side may be none: an insert, a delete, or a correlation value that\n // was or becomes null).\n if (oldKey !== undefined) {\n await applyAggregateDelta(\n tx,\n ivmBranch,\n agg,\n oldKey,\n oldRow,\n undefined,\n );\n }\n if (newKey !== undefined) {\n await applyAggregateDelta(\n tx,\n ivmBranch,\n agg,\n newKey,\n undefined,\n newRow,\n );\n }\n }\n }\n}\n\nfunction defaultOptionalFieldsToNull(\n schema: TableSchema,\n value: ReadonlyJSONObject,\n): ReadonlyJSONObject {\n let rv = value;\n for (const name in schema.columns) {\n if (rv[name] === undefined) {\n rv = {...rv, [name]: null};\n }\n }\n return rv;\n}\n\nexport async function insert(\n tx: WriteTransaction,\n arg: InsertOp,\n schema: Schema,\n ivmBranch: IVMSourceBranch | undefined,\n): Promise<void> {\n const key = toPrimaryKeyString(\n arg.tableName,\n schema.tables[arg.tableName].primaryKey,\n arg.value,\n );\n if (!(await tx.has(key))) {\n const val = defaultOptionalFieldsToNull(\n schema.tables[arg.tableName],\n arg.value,\n );\n await tx.set(key, val);\n if (ivmBranch) {\n consume(\n must(ivmBranch.getSource(arg.tableName)).push(makeSourceChangeAdd(val)),\n );\n }\n await applyOptimisticAggregateDeltas(\n tx,\n ivmBranch,\n arg.tableName,\n undefined,\n val,\n );\n }\n}\n\nexport async function upsert(\n tx: WriteTransaction,\n arg: InsertOp | UpsertOp,\n schema: Schema,\n ivmBranch: IVMSourceBranch | undefined,\n): Promise<void> {\n const key = toPrimaryKeyString(\n arg.tableName,\n schema.tables[arg.tableName].primaryKey,\n arg.value,\n );\n if (await tx.has(key)) {\n await update(tx, {...arg, op: 'update'}, schema, ivmBranch);\n } else {\n await insert(tx, {...arg, op: 'insert'}, schema, ivmBranch);\n }\n}\n\nexport async function update(\n tx: WriteTransaction,\n arg: UpdateOp,\n schema: Schema,\n ivmBranch: IVMSourceBranch | undefined,\n): Promise<void> {\n const key = toPrimaryKeyString(\n arg.tableName,\n schema.tables[arg.tableName].primaryKey,\n arg.value,\n );\n const prev = await tx.get(key);\n if (prev === undefined) {\n return;\n }\n const update = arg.value;\n const next = {...(prev as ReadonlyJSONObject)};\n for (const k in update) {\n if (update[k] !== undefined) {\n next[k] = update[k];\n }\n }\n await tx.set(key, next);\n if (ivmBranch) {\n consume(\n must(ivmBranch.getSource(arg.tableName)).push(\n makeSourceChangeEdit(next, prev as Row),\n ),\n );\n }\n await applyOptimisticAggregateDeltas(\n tx,\n ivmBranch,\n arg.tableName,\n prev as Row,\n next as Row,\n );\n}\n\nasync function deleteImpl(\n tx: WriteTransaction,\n arg: DeleteOp,\n schema: Schema,\n ivmBranch: IVMSourceBranch | undefined,\n): Promise<void> {\n const key = toPrimaryKeyString(\n arg.tableName,\n schema.tables[arg.tableName].primaryKey,\n arg.value,\n );\n const prev = await tx.get(key);\n if (prev === undefined) {\n return;\n }\n await tx.del(key);\n if (ivmBranch) {\n consume(\n must(ivmBranch.getSource(arg.tableName)).push(\n makeSourceChangeRemove(prev as Row),\n ),\n );\n }\n await applyOptimisticAggregateDeltas(\n tx,\n ivmBranch,\n arg.tableName,\n prev as Row,\n undefined,\n );\n}\n\nexport {deleteImpl as delete};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../../../../zero-client/src/client/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAKjD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAGnE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,0CAA0C,CAAC;AAC5E,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EACV,iBAAiB,EACjB,WAAW,EACZ,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../../../../zero-client/src/client/custom.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { assert } from "../../../shared/src/asserts.js";
|
|
2
2
|
import { must } from "../../../shared/src/must.js";
|
|
3
|
+
import { asQueryInternals } from "../../../zql/src/query/query-internals.js";
|
|
3
4
|
import { createRunnableBuilder } from "../../../zql/src/query/create-builder.js";
|
|
4
5
|
import "../../../zql/src/query/query.js";
|
|
5
6
|
import { zeroData } from "../../../replicache/src/transactions.js";
|
|
6
7
|
import { emptyFunction } from "../../../shared/src/sentinels.js";
|
|
8
|
+
import { queryIDOf } from "../../../zql/src/query/query-delegate-base.js";
|
|
9
|
+
import { toGotQueriesKey } from "./keys.js";
|
|
7
10
|
import { ZeroContext } from "./context.js";
|
|
8
11
|
import { makeCRUDExecutor } from "./crud.js";
|
|
9
12
|
import { makeTransactionMutate } from "../../../zql/src/mutate/crud.js";
|
|
@@ -24,7 +27,7 @@ var TransactionImpl = class {
|
|
|
24
27
|
this.#repTx = repTx;
|
|
25
28
|
const executor = makeCRUDExecutor(repTx, schema, ivmBranch);
|
|
26
29
|
this.mutate = makeTransactionMutate(schema, executor);
|
|
27
|
-
const zeroContext = newZeroContext(lc, txData.ivmSources);
|
|
30
|
+
const zeroContext = newZeroContext(lc, txData.ivmSources, repTx);
|
|
28
31
|
this.query = createRunnableBuilder(zeroContext, schema);
|
|
29
32
|
this.#zeroContext = zeroContext;
|
|
30
33
|
}
|
|
@@ -55,9 +58,45 @@ function makeReplicacheMutator(lc, mutator, schema, context) {
|
|
|
55
58
|
function assertValidRunOptions(options) {
|
|
56
59
|
assert(options?.type !== "complete" && options?.type !== "cached", "Cannot wait for cached or complete results in custom mutations");
|
|
57
60
|
}
|
|
58
|
-
function newZeroContext(lc, ivmBranch) {
|
|
59
|
-
return new
|
|
61
|
+
function newZeroContext(lc, ivmBranch, repTx) {
|
|
62
|
+
return new MutatorContext(lc, ivmBranch, repTx).markPipelinesReady();
|
|
60
63
|
}
|
|
64
|
+
function newContextArgs(lc, ivmBranch) {
|
|
65
|
+
return [
|
|
66
|
+
lc,
|
|
67
|
+
ivmBranch,
|
|
68
|
+
() => emptyFunction,
|
|
69
|
+
() => emptyFunction,
|
|
70
|
+
emptyFunction,
|
|
71
|
+
emptyFunction,
|
|
72
|
+
emptyFunction,
|
|
73
|
+
(applyViewUpdates) => applyViewUpdates(),
|
|
74
|
+
emptyFunction,
|
|
75
|
+
assertValidRunOptions
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The query delegate of a custom mutator. A query whose result the server has
|
|
80
|
+
* sent reads its aggregates from the rows the server synced, with this
|
|
81
|
+
* client's pending changes applied, as a view of it does. Any other query has
|
|
82
|
+
* no synced aggregate rows to read, so it computes its aggregates from the
|
|
83
|
+
* rows in the mutator's branch, like every other read the mutator makes. The
|
|
84
|
+
* server's run of the mutator computes them from all the rows.
|
|
85
|
+
*/
|
|
86
|
+
var MutatorContext = class extends ZeroContext {
|
|
87
|
+
aggregatesFromSource = false;
|
|
88
|
+
#repTx;
|
|
89
|
+
#synced;
|
|
90
|
+
constructor(lc, ivmBranch, repTx) {
|
|
91
|
+
super(...newContextArgs(lc, ivmBranch));
|
|
92
|
+
this.#repTx = repTx;
|
|
93
|
+
this.#synced = new ZeroContext(...newContextArgs(lc, ivmBranch)).markPipelinesReady();
|
|
94
|
+
}
|
|
95
|
+
async run(query, options) {
|
|
96
|
+
const queryID = queryIDOf(asQueryInternals(query));
|
|
97
|
+
return await this.#repTx.has(toGotQueriesKey(queryID)) ? this.#synced.run(query, options) : super.run(query, options);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
61
100
|
//#endregion
|
|
62
101
|
export { TransactionImpl, makeReplicacheMutator };
|
|
63
102
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom.js","names":[],"sources":["../../../../../zero-client/src/client/custom.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {ZeroTxData} from '../../../replicache/src/replicache-options.ts';\nimport type {WriteTransactionImpl} from '../../../replicache/src/transactions.ts';\nimport {zeroData} from '../../../replicache/src/transactions.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {emptyFunction} from '../../../shared/src/sentinels.ts';\nimport type {DefaultSchema} from '../../../zero-types/src/default-types.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport {\n makeTransactionMutate,\n type TransactionMutate,\n} from '../../../zql/src/mutate/crud.ts';\nimport type {\n ClientTransaction,\n Transaction,\n} from '../../../zql/src/mutate/custom.ts';\nimport {createRunnableBuilder} from '../../../zql/src/query/create-builder.ts';\nimport {\n type HumanReadable,\n type Query,\n type RunOptions,\n} from '../../../zql/src/query/query.ts';\nimport type {ConditionalSchemaQuery} from '../../../zql/src/query/schema-query.ts';\nimport type {ClientID} from '../types/client-state.ts';\nimport {ZeroContext} from './context.ts';\nimport {makeCRUDExecutor} from './crud.ts';\nimport type {IVMSourceBranch} from './ivm-branch.ts';\nimport type {WriteTransaction} from './replicache-types.ts';\n\n/**\n * The shape which a user's custom mutator definitions must conform to.\n * Supports arbitrary depth nesting of namespaces.\n */\nexport type CustomMutatorDefs = {\n // oxlint-disable-next-line no-explicit-any\n [namespaceOrKey: string]: CustomMutatorImpl<any> | CustomMutatorDefs;\n};\n\nexport type MutatorResultDetails =\n | {\n readonly type: 'success';\n readonly data?: ReadonlyJSONValue | undefined;\n }\n | {\n readonly type: 'error';\n readonly error:\n | {\n readonly type: 'app';\n readonly message: string;\n readonly details: ReadonlyJSONValue | undefined;\n }\n | {\n readonly type: 'zero';\n readonly message: string;\n };\n };\n\nexport type MutatorResultSuccessDetails = Extract<\n MutatorResultDetails,\n {type: 'success'}\n>;\nexport type MutatorResultErrorDetails = Extract<\n MutatorResultDetails,\n {type: 'error'}\n>;\n\nexport type MutatorResult = {\n client: Promise<MutatorResultDetails & {}>;\n server: Promise<MutatorResultDetails & {}>;\n} & {};\n\nexport type CustomMutatorImpl<\n S extends Schema,\n TWrappedTransaction = unknown,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n TArgs = any,\n Context = unknown,\n> = (\n tx: Transaction<S, TWrappedTransaction>,\n // TODO: many args. See commit: 52657c2f934b4a458d628ea77e56ce92b61eb3c6 which did have many args.\n // The issue being that it will be a protocol change to support varargs.\n args: TArgs,\n ctx: Context,\n) => Promise<ReadonlyJSONValue | void>;\n\n/**\n * The shape exposed on the `Zero.mutate` instance.\n * The signature of a custom mutator takes a `transaction` as its first arg\n * but the user does not provide this arg when calling the mutator.\n *\n * This utility strips the `tx` arg from the user's custom mutator signatures.\n * Supports arbitrary depth nesting of namespaces.\n */\nexport type MakeCustomMutatorInterfaces<\n S extends Schema,\n MD extends CustomMutatorDefs,\n TContext,\n> = {\n readonly [NamespaceOrName in keyof MD]: MD[NamespaceOrName] extends (\n tx: Transaction<S>,\n ...args: infer Args\n ) => Promise<unknown>\n ? (...args: Args) => MutatorResult\n : MD[NamespaceOrName] extends CustomMutatorDefs\n ? MakeCustomMutatorInterfaces<S, MD[NamespaceOrName], TContext>\n : never;\n};\n\nexport type MakeCustomMutatorInterface<TSchema extends Schema, F> = F extends (\n tx: ClientTransaction<TSchema>,\n ...args: infer Args\n) => Promise<unknown>\n ? (...args: Args) => MutatorResult\n : never;\n\nexport class TransactionImpl<\n TSchema extends Schema = DefaultSchema,\n> implements ClientTransaction<TSchema> {\n readonly location = 'client';\n readonly mutate: TransactionMutate<TSchema>;\n /**\n * @deprecated Use {@link createBuilder} with `tx.run(zql.table.where(...))` instead.\n */\n readonly query: ConditionalSchemaQuery<TSchema>;\n\n readonly #repTx: WriteTransaction;\n readonly #zeroContext: ZeroContext;\n\n constructor(lc: LogContext, repTx: WriteTransaction, schema: TSchema) {\n must(repTx.reason === 'initial' || repTx.reason === 'rebase');\n const txData = getZeroTxData(repTx);\n const ivmBranch = txData.ivmSources as IVMSourceBranch;\n\n this.#repTx = repTx;\n\n const executor = makeCRUDExecutor(repTx, schema, ivmBranch);\n this.mutate = makeTransactionMutate(schema, executor);\n\n const zeroContext = newZeroContext(\n lc,\n txData.ivmSources as IVMSourceBranch,\n );\n\n this.query = createRunnableBuilder(zeroContext, schema);\n\n this.#zeroContext = zeroContext;\n }\n\n get clientID(): ClientID {\n return this.#repTx.clientID;\n }\n\n get mutationID(): number {\n return this.#repTx.mutationID;\n }\n\n get reason(): 'optimistic' | 'rebase' {\n return this.#repTx.reason === 'initial' ? 'optimistic' : 'rebase';\n }\n\n get token(): string | undefined {\n return (this.#repTx as WriteTransactionImpl)[zeroData]?.token;\n }\n\n run<TTable extends keyof TSchema['tables'] & string, TReturn>(\n query: Query<TTable, TSchema, TReturn>,\n options?: RunOptions,\n ): Promise<HumanReadable<TReturn>> {\n return this.#zeroContext.run(query, options);\n }\n}\n\nfunction getZeroTxData(repTx: WriteTransaction): ZeroTxData {\n const txData = must(\n (repTx as WriteTransactionImpl)[zeroData],\n 'zero was not set on replicache internal options!',\n );\n return txData as ZeroTxData;\n}\n\nexport function makeReplicacheMutator<\n S extends Schema,\n TWrappedTransaction,\n Context,\n>(\n lc: LogContext,\n mutator: CustomMutatorImpl<S, TWrappedTransaction>,\n schema: S,\n context: Context,\n): (\n repTx: WriteTransaction,\n args: ReadonlyJSONValue,\n) => Promise<ReadonlyJSONValue | void> {\n return async (repTx: WriteTransaction, args: ReadonlyJSONValue) => {\n const tx = new TransactionImpl(lc, repTx, schema);\n return await mutator(tx, args, context);\n };\n}\n\nfunction assertValidRunOptions(options: RunOptions | undefined): void {\n // TODO(arv): We should enforce this with the type system too.\n assert(\n options?.type !== 'complete' && options?.type !== 'cached',\n 'Cannot wait for cached or complete results in custom mutations',\n );\n}\n\nfunction newZeroContext(lc: LogContext, ivmBranch: IVMSourceBranch) {\n // The forked branch is already populated, so there is nothing to defer.\n return new ZeroContext(\n lc,\n ivmBranch,\n () => emptyFunction,\n () => emptyFunction,\n emptyFunction,\n emptyFunction,\n emptyFunction,\n applyViewUpdates => applyViewUpdates(),\n emptyFunction,\n assertValidRunOptions,\n ).markPipelinesReady();\n}\n"],"mappings":";;;;;;;;;;AAqHA,IAAa,kBAAb,MAEwC;CACtC,WAAoB;CACpB;;;;CAIA;CAEA;CACA;CAEA,YAAY,IAAgB,OAAyB,QAAiB;EACpE,KAAK,MAAM,WAAW,aAAa,MAAM,WAAW,QAAQ;EAC5D,MAAM,SAAS,cAAc,KAAK;EAClC,MAAM,YAAY,OAAO;EAEzB,KAAK,SAAS;EAEd,MAAM,WAAW,iBAAiB,OAAO,QAAQ,SAAS;EAC1D,KAAK,SAAS,sBAAsB,QAAQ,QAAQ;EAEpD,MAAM,cAAc,eAClB,IACA,OAAO,UACT;EAEA,KAAK,QAAQ,sBAAsB,aAAa,MAAM;EAEtD,KAAK,eAAe;CACtB;CAEA,IAAI,WAAqB;EACvB,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,aAAqB;EACvB,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,SAAkC;EACpC,OAAO,KAAK,OAAO,WAAW,YAAY,eAAe;CAC3D;CAEA,IAAI,QAA4B;EAC9B,OAAQ,KAAK,OAAgC,SAAS,EAAE;CAC1D;CAEA,IACE,OACA,SACiC;EACjC,OAAO,KAAK,aAAa,IAAI,OAAO,OAAO;CAC7C;AACF;AAEA,SAAS,cAAc,OAAqC;CAK1D,OAJe,KACZ,MAA+B,WAChC,kDAEK;AACT;AAEA,SAAgB,sBAKd,IACA,SACA,QACA,SAIqC;CACrC,OAAO,OAAO,OAAyB,SAA4B;EAEjE,OAAO,MAAM,QAAQ,IADN,gBAAgB,IAAI,OAAO,MACrB,GAAI,MAAM,OAAO;CACxC;AACF;AAEA,SAAS,sBAAsB,SAAuC;CAEpE,OACE,SAAS,SAAS,cAAc,SAAS,SAAS,UAClD,gEACF;AACF;AAEA,SAAS,eAAe,IAAgB,WAA4B;CAElE,OAAO,IAAI,YACT,IACA,iBACM,qBACA,eACN,eACA,eACA,gBACA,qBAAoB,iBAAiB,GACrC,eACA,qBACF,CAAC,CAAC,mBAAmB;AACvB"}
|
|
1
|
+
{"version":3,"file":"custom.js","names":[],"sources":["../../../../../zero-client/src/client/custom.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {ZeroTxData} from '../../../replicache/src/replicache-options.ts';\nimport type {WriteTransactionImpl} from '../../../replicache/src/transactions.ts';\nimport {zeroData} from '../../../replicache/src/transactions.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {emptyFunction} from '../../../shared/src/sentinels.ts';\nimport type {DefaultSchema} from '../../../zero-types/src/default-types.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport {\n makeTransactionMutate,\n type TransactionMutate,\n} from '../../../zql/src/mutate/crud.ts';\nimport type {\n ClientTransaction,\n Transaction,\n} from '../../../zql/src/mutate/custom.ts';\nimport {createRunnableBuilder} from '../../../zql/src/query/create-builder.ts';\nimport {queryIDOf} from '../../../zql/src/query/query-delegate-base.ts';\nimport {asQueryInternals} from '../../../zql/src/query/query-internals.ts';\nimport {\n type HumanReadable,\n type Query,\n type RunOptions,\n} from '../../../zql/src/query/query.ts';\nimport type {ConditionalSchemaQuery} from '../../../zql/src/query/schema-query.ts';\nimport type {ClientID} from '../types/client-state.ts';\nimport {ZeroContext} from './context.ts';\nimport {makeCRUDExecutor} from './crud.ts';\nimport type {IVMSourceBranch} from './ivm-branch.ts';\nimport {toGotQueriesKey} from './keys.ts';\nimport type {WriteTransaction} from './replicache-types.ts';\n\n/**\n * The shape which a user's custom mutator definitions must conform to.\n * Supports arbitrary depth nesting of namespaces.\n */\nexport type CustomMutatorDefs = {\n // oxlint-disable-next-line no-explicit-any\n [namespaceOrKey: string]: CustomMutatorImpl<any> | CustomMutatorDefs;\n};\n\nexport type MutatorResultDetails =\n | {\n readonly type: 'success';\n readonly data?: ReadonlyJSONValue | undefined;\n }\n | {\n readonly type: 'error';\n readonly error:\n | {\n readonly type: 'app';\n readonly message: string;\n readonly details: ReadonlyJSONValue | undefined;\n }\n | {\n readonly type: 'zero';\n readonly message: string;\n };\n };\n\nexport type MutatorResultSuccessDetails = Extract<\n MutatorResultDetails,\n {type: 'success'}\n>;\nexport type MutatorResultErrorDetails = Extract<\n MutatorResultDetails,\n {type: 'error'}\n>;\n\nexport type MutatorResult = {\n client: Promise<MutatorResultDetails & {}>;\n server: Promise<MutatorResultDetails & {}>;\n} & {};\n\nexport type CustomMutatorImpl<\n S extends Schema,\n TWrappedTransaction = unknown,\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n TArgs = any,\n Context = unknown,\n> = (\n tx: Transaction<S, TWrappedTransaction>,\n // TODO: many args. See commit: 52657c2f934b4a458d628ea77e56ce92b61eb3c6 which did have many args.\n // The issue being that it will be a protocol change to support varargs.\n args: TArgs,\n ctx: Context,\n) => Promise<ReadonlyJSONValue | void>;\n\n/**\n * The shape exposed on the `Zero.mutate` instance.\n * The signature of a custom mutator takes a `transaction` as its first arg\n * but the user does not provide this arg when calling the mutator.\n *\n * This utility strips the `tx` arg from the user's custom mutator signatures.\n * Supports arbitrary depth nesting of namespaces.\n */\nexport type MakeCustomMutatorInterfaces<\n S extends Schema,\n MD extends CustomMutatorDefs,\n TContext,\n> = {\n readonly [NamespaceOrName in keyof MD]: MD[NamespaceOrName] extends (\n tx: Transaction<S>,\n ...args: infer Args\n ) => Promise<unknown>\n ? (...args: Args) => MutatorResult\n : MD[NamespaceOrName] extends CustomMutatorDefs\n ? MakeCustomMutatorInterfaces<S, MD[NamespaceOrName], TContext>\n : never;\n};\n\nexport type MakeCustomMutatorInterface<TSchema extends Schema, F> = F extends (\n tx: ClientTransaction<TSchema>,\n ...args: infer Args\n) => Promise<unknown>\n ? (...args: Args) => MutatorResult\n : never;\n\nexport class TransactionImpl<\n TSchema extends Schema = DefaultSchema,\n> implements ClientTransaction<TSchema> {\n readonly location = 'client';\n readonly mutate: TransactionMutate<TSchema>;\n /**\n * @deprecated Use {@link createBuilder} with `tx.run(zql.table.where(...))` instead.\n */\n readonly query: ConditionalSchemaQuery<TSchema>;\n\n readonly #repTx: WriteTransaction;\n readonly #zeroContext: ZeroContext;\n\n constructor(lc: LogContext, repTx: WriteTransaction, schema: TSchema) {\n must(repTx.reason === 'initial' || repTx.reason === 'rebase');\n const txData = getZeroTxData(repTx);\n const ivmBranch = txData.ivmSources as IVMSourceBranch;\n\n this.#repTx = repTx;\n\n const executor = makeCRUDExecutor(repTx, schema, ivmBranch);\n this.mutate = makeTransactionMutate(schema, executor);\n\n const zeroContext = newZeroContext(\n lc,\n txData.ivmSources as IVMSourceBranch,\n repTx,\n );\n\n this.query = createRunnableBuilder(zeroContext, schema);\n\n this.#zeroContext = zeroContext;\n }\n\n get clientID(): ClientID {\n return this.#repTx.clientID;\n }\n\n get mutationID(): number {\n return this.#repTx.mutationID;\n }\n\n get reason(): 'optimistic' | 'rebase' {\n return this.#repTx.reason === 'initial' ? 'optimistic' : 'rebase';\n }\n\n get token(): string | undefined {\n return (this.#repTx as WriteTransactionImpl)[zeroData]?.token;\n }\n\n run<TTable extends keyof TSchema['tables'] & string, TReturn>(\n query: Query<TTable, TSchema, TReturn>,\n options?: RunOptions,\n ): Promise<HumanReadable<TReturn>> {\n return this.#zeroContext.run(query, options);\n }\n}\n\nfunction getZeroTxData(repTx: WriteTransaction): ZeroTxData {\n const txData = must(\n (repTx as WriteTransactionImpl)[zeroData],\n 'zero was not set on replicache internal options!',\n );\n return txData as ZeroTxData;\n}\n\nexport function makeReplicacheMutator<\n S extends Schema,\n TWrappedTransaction,\n Context,\n>(\n lc: LogContext,\n mutator: CustomMutatorImpl<S, TWrappedTransaction>,\n schema: S,\n context: Context,\n): (\n repTx: WriteTransaction,\n args: ReadonlyJSONValue,\n) => Promise<ReadonlyJSONValue | void> {\n return async (repTx: WriteTransaction, args: ReadonlyJSONValue) => {\n const tx = new TransactionImpl(lc, repTx, schema);\n return await mutator(tx, args, context);\n };\n}\n\nfunction assertValidRunOptions(options: RunOptions | undefined): void {\n // TODO(arv): We should enforce this with the type system too.\n assert(\n options?.type !== 'complete' && options?.type !== 'cached',\n 'Cannot wait for cached or complete results in custom mutations',\n );\n}\n\nfunction newZeroContext(\n lc: LogContext,\n ivmBranch: IVMSourceBranch,\n repTx: WriteTransaction,\n) {\n // The forked branch is already populated, so there is nothing to defer.\n return new MutatorContext(lc, ivmBranch, repTx).markPipelinesReady();\n}\n\nfunction newContextArgs(lc: LogContext, ivmBranch: IVMSourceBranch) {\n return [\n lc,\n ivmBranch,\n () => emptyFunction,\n () => emptyFunction,\n emptyFunction,\n emptyFunction,\n emptyFunction,\n (applyViewUpdates: () => void) => applyViewUpdates(),\n emptyFunction,\n assertValidRunOptions,\n ] as const;\n}\n\n/**\n * The query delegate of a custom mutator. A query whose result the server has\n * sent reads its aggregates from the rows the server synced, with this\n * client's pending changes applied, as a view of it does. Any other query has\n * no synced aggregate rows to read, so it computes its aggregates from the\n * rows in the mutator's branch, like every other read the mutator makes. The\n * server's run of the mutator computes them from all the rows.\n */\nclass MutatorContext extends ZeroContext {\n override readonly aggregatesFromSource = false;\n readonly #repTx: WriteTransaction;\n readonly #synced: ZeroContext;\n\n constructor(\n lc: LogContext,\n ivmBranch: IVMSourceBranch,\n repTx: WriteTransaction,\n ) {\n super(...newContextArgs(lc, ivmBranch));\n this.#repTx = repTx;\n this.#synced = new ZeroContext(\n ...newContextArgs(lc, ivmBranch),\n ).markPipelinesReady();\n }\n\n override async run<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n >(\n query: Query<TTable, TSchema, TReturn>,\n options?: RunOptions,\n ): Promise<HumanReadable<TReturn>> {\n const queryID = queryIDOf(asQueryInternals(query));\n return (await this.#repTx.has(toGotQueriesKey(queryID)))\n ? this.#synced.run(query, options)\n : super.run(query, options);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAwHA,IAAa,kBAAb,MAEwC;CACtC,WAAoB;CACpB;;;;CAIA;CAEA;CACA;CAEA,YAAY,IAAgB,OAAyB,QAAiB;EACpE,KAAK,MAAM,WAAW,aAAa,MAAM,WAAW,QAAQ;EAC5D,MAAM,SAAS,cAAc,KAAK;EAClC,MAAM,YAAY,OAAO;EAEzB,KAAK,SAAS;EAEd,MAAM,WAAW,iBAAiB,OAAO,QAAQ,SAAS;EAC1D,KAAK,SAAS,sBAAsB,QAAQ,QAAQ;EAEpD,MAAM,cAAc,eAClB,IACA,OAAO,YACP,KACF;EAEA,KAAK,QAAQ,sBAAsB,aAAa,MAAM;EAEtD,KAAK,eAAe;CACtB;CAEA,IAAI,WAAqB;EACvB,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,aAAqB;EACvB,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,SAAkC;EACpC,OAAO,KAAK,OAAO,WAAW,YAAY,eAAe;CAC3D;CAEA,IAAI,QAA4B;EAC9B,OAAQ,KAAK,OAAgC,SAAS,EAAE;CAC1D;CAEA,IACE,OACA,SACiC;EACjC,OAAO,KAAK,aAAa,IAAI,OAAO,OAAO;CAC7C;AACF;AAEA,SAAS,cAAc,OAAqC;CAK1D,OAJe,KACZ,MAA+B,WAChC,kDAEK;AACT;AAEA,SAAgB,sBAKd,IACA,SACA,QACA,SAIqC;CACrC,OAAO,OAAO,OAAyB,SAA4B;EAEjE,OAAO,MAAM,QAAQ,IADN,gBAAgB,IAAI,OAAO,MACrB,GAAI,MAAM,OAAO;CACxC;AACF;AAEA,SAAS,sBAAsB,SAAuC;CAEpE,OACE,SAAS,SAAS,cAAc,SAAS,SAAS,UAClD,gEACF;AACF;AAEA,SAAS,eACP,IACA,WACA,OACA;CAEA,OAAO,IAAI,eAAe,IAAI,WAAW,KAAK,CAAC,CAAC,mBAAmB;AACrE;AAEA,SAAS,eAAe,IAAgB,WAA4B;CAClE,OAAO;EACL;EACA;QACM;QACA;EACN;EACA;EACA;GACC,qBAAiC,iBAAiB;EACnD;EACA;CACF;AACF;;;;;;;;;AAUA,IAAM,iBAAN,cAA6B,YAAY;CACvC,uBAAyC;CACzC;CACA;CAEA,YACE,IACA,WACA,OACA;EACA,MAAM,GAAG,eAAe,IAAI,SAAS,CAAC;EACtC,KAAK,SAAS;EACd,KAAK,UAAU,IAAI,YACjB,GAAG,eAAe,IAAI,SAAS,CACjC,CAAC,CAAC,mBAAmB;CACvB;CAEA,MAAe,IAKb,OACA,SACiC;EACjC,MAAM,UAAU,UAAU,iBAAiB,KAAK,CAAC;EACjD,OAAQ,MAAM,KAAK,OAAO,IAAI,gBAAgB,OAAO,CAAC,IAClD,KAAK,QAAQ,IAAI,OAAO,OAAO,IAC/B,MAAM,IAAI,OAAO,OAAO;CAC9B;AACF"}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import type { NoIndexDiff } from '../../../replicache/src/btree/node.ts';
|
|
1
|
+
import type { InternalDiffOperation, NoIndexDiff } from '../../../replicache/src/btree/node.ts';
|
|
2
2
|
import type { LazyStore } from '../../../replicache/src/dag/lazy-store.ts';
|
|
3
3
|
import { type Store } from '../../../replicache/src/dag/store.ts';
|
|
4
4
|
import type { Hash } from '../../../replicache/src/hash.ts';
|
|
5
5
|
import type { ZeroReadOptions } from '../../../replicache/src/replicache-options.ts';
|
|
6
|
+
import type { AggregateFunction, CompoundKey } from '../../../zero-protocol/src/ast.ts';
|
|
7
|
+
import type { Row } from '../../../zero-protocol/src/data.ts';
|
|
8
|
+
import type { PrimaryKey } from '../../../zero-protocol/src/primary-key.ts';
|
|
6
9
|
import type { TableSchema } from '../../../zero-schema/src/table-schema.ts';
|
|
10
|
+
import { type SchemaValue } from '../../../zero-types/src/schema-value.ts';
|
|
11
|
+
import { type AggregateOptimisticDelta } from '../../../zql/src/builder/builder.ts';
|
|
7
12
|
import { MemorySource } from '../../../zql/src/ivm/memory-source.ts';
|
|
8
13
|
/**
|
|
9
14
|
* Replicache needs to rebase mutations onto different
|
|
@@ -21,11 +26,61 @@ import { MemorySource } from '../../../zql/src/ivm/memory-source.ts';
|
|
|
21
26
|
* ever be a few outstanding diffs to apply given Zero is meant
|
|
22
27
|
* to be run in a connected state.
|
|
23
28
|
*/
|
|
29
|
+
/**
|
|
30
|
+
* Metadata for optimistically updating a synced aggregate when a child row is
|
|
31
|
+
* locally mutated. Registered when a relationship-aggregate query materializes.
|
|
32
|
+
*/
|
|
33
|
+
export type OptimisticAggregate = {
|
|
34
|
+
/** The synthetic aggregate table, e.g. `aggregate:<queryID>:<alias>`. */
|
|
35
|
+
readonly aggTableName: string;
|
|
36
|
+
/** The correlation columns of a child row, as the client names them. */
|
|
37
|
+
readonly childField: readonly string[];
|
|
38
|
+
/**
|
|
39
|
+
* The same columns as the synced aggregate rows name them (server names), in
|
|
40
|
+
* the same order. An aggregate row's key is built from these.
|
|
41
|
+
*/
|
|
42
|
+
readonly keyField: readonly string[];
|
|
43
|
+
/** The aggregate function (`count`/`sum`/`avg` are optimistically deltaed). */
|
|
44
|
+
readonly fn: AggregateFunction;
|
|
45
|
+
/** The aggregated field, for `sum`/`avg` (`undefined` for `count`). */
|
|
46
|
+
readonly field: string | undefined;
|
|
47
|
+
/** A JSON path into `field` (see `Aggregate.path`). */
|
|
48
|
+
readonly path: readonly (string | number)[] | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* The aggregate's `where`, compiled to a per-row predicate. A child row
|
|
51
|
+
* contributes only when it returns true; `undefined` means no filter (every
|
|
52
|
+
* child contributes). Only set when the whole `where` is per-row evaluable —
|
|
53
|
+
* a correlated subquery in the `where` makes the aggregate
|
|
54
|
+
* server-authoritative (it is never registered for optimism at all).
|
|
55
|
+
*/
|
|
56
|
+
readonly predicate: ((row: Row) => boolean) | undefined;
|
|
57
|
+
/** The rows are a grouped query's groups (see `AggregateOptimisticDelta`). */
|
|
58
|
+
readonly grouped: boolean;
|
|
59
|
+
};
|
|
24
60
|
export declare class IVMSourceBranch {
|
|
25
61
|
#private;
|
|
26
62
|
hash: Hash | undefined;
|
|
27
|
-
constructor(tables: Record<string, TableSchema>, hash?: Hash, sources?: Map<string, MemorySource | undefined
|
|
63
|
+
constructor(tables: Record<string, TableSchema>, hash?: Hash, sources?: Map<string, MemorySource | undefined>, aggregateOptimism?: Map<string, Map<string, OptimisticAggregate>>, isFork?: boolean);
|
|
28
64
|
getSource(name: string): MemorySource | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Get-or-create the synthetic source for a *relationship* aggregate
|
|
67
|
+
* (`aggregate:<queryID>:<alias>`), whose shape (the correlation-key columns +
|
|
68
|
+
* value) cannot be derived from the name. The query builder supplies the
|
|
69
|
+
* schema when a query materializes; {@link applyDiffs} supplies an inferred
|
|
70
|
+
* one when persisted rows are replayed before the query re-materializes (e.g.
|
|
71
|
+
* on reload). Idempotent — the first caller wins.
|
|
72
|
+
*/
|
|
73
|
+
getOrCreateAggregateSource(name: string, columns: Record<string, SchemaValue>, primaryKey: PrimaryKey, optimistic?: AggregateOptimisticDelta): MemorySource;
|
|
74
|
+
/**
|
|
75
|
+
* The server names of `columns` of `table`, in the same order. A column with
|
|
76
|
+
* no server name of its own, or of a table not in the schema, keeps its name.
|
|
77
|
+
*/
|
|
78
|
+
serverColumnNames(table: string, columns: CompoundKey): CompoundKey;
|
|
79
|
+
/**
|
|
80
|
+
* The optimistic-aggregate registrations whose child rows live in `table`.
|
|
81
|
+
* An optimistic insert/delete of such a child row bumps these aggregates.
|
|
82
|
+
*/
|
|
83
|
+
getOptimisticAggregates(table: string): Iterable<OptimisticAggregate>;
|
|
29
84
|
clear(): void;
|
|
30
85
|
/**
|
|
31
86
|
* Mutates the current branch, advancing it to the new head
|
|
@@ -47,4 +102,9 @@ export declare class IVMSourceBranch {
|
|
|
47
102
|
fork(): IVMSourceBranch;
|
|
48
103
|
}
|
|
49
104
|
export declare function initFromStore(branch: IVMSourceBranch, hash: Hash, store: Store): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* An `add` diff for each row at `hash` that the IVM sources hold: the table
|
|
107
|
+
* rows under `e/` and the aggregate rows under `a/`, in key order.
|
|
108
|
+
*/
|
|
109
|
+
export declare function readRowDiffs(store: Store, hash: Hash): Promise<InternalDiffOperation[]>;
|
|
50
110
|
//# sourceMappingURL=ivm-branch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ivm-branch.d.ts","sourceRoot":"","sources":["../../../../../zero-client/src/client/ivm-branch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ivm-branch.d.ts","sourceRoot":"","sources":["../../../../../zero-client/src/client/ivm-branch.ts"],"names":[],"mappings":"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"}
|