@rocicorp/zero 0.24.2025100900 → 0.24.2025101200
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/bin-analyze.d.ts.map +1 -1
- package/out/analyze-query/src/bin-analyze.js +4 -3
- package/out/analyze-query/src/bin-analyze.js.map +1 -1
- package/out/analyze-query/src/run-ast.d.ts.map +1 -1
- package/out/analyze-query/src/run-ast.js +12 -4
- package/out/analyze-query/src/run-ast.js.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/{chunk-2MVN6X6T.js → chunk-5J6ROZSO.js} +4521 -164
- package/out/chunk-5J6ROZSO.js.map +7 -0
- package/out/{chunk-IQYQOLDZ.js → chunk-6AP73APB.js} +15 -8
- package/out/chunk-6AP73APB.js.map +7 -0
- package/out/chunk-HLJ3FQU5.js +4122 -0
- package/out/chunk-HLJ3FQU5.js.map +7 -0
- package/out/{lazy-inspector-A5VQLZYJ.js → lazy-inspector-YKNSCAI3.js} +21 -3
- package/out/lazy-inspector-YKNSCAI3.js.map +7 -0
- package/out/react-native.js +1 -71
- package/out/react-native.js.map +4 -4
- package/out/react.js +2 -2
- package/out/replicache/src/btree/read.d.ts.map +1 -1
- package/out/replicache/src/btree/write.d.ts.map +1 -1
- package/out/replicache/src/dag/lazy-store.d.ts.map +1 -1
- package/out/replicache/src/persist/gather-not-cached-visitor.d.ts.map +1 -1
- package/out/shared/src/size-of-value.d.ts.map +1 -0
- package/out/solid.js +7 -7
- package/out/solid.js.map +2 -2
- package/out/zero/package.json +8 -7
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +1 -0
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +10 -0
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +33 -0
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +8 -3
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
- package/out/zero-cache/src/services/analyze.js +2 -2
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +6 -5
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +26 -22
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +50 -36
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/run-ast.d.ts +21 -0
- package/out/zero-cache/src/services/run-ast.d.ts.map +1 -0
- package/out/zero-cache/src/services/run-ast.js +91 -0
- package/out/zero-cache/src/services/run-ast.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +10 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +95 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +6 -5
- 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 +59 -115
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-client/src/client/inspector/inspector.d.ts +4 -0
- package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.d.ts +4 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +4 -4
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/mod.d.ts +1 -1
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-events/src/index.d.ts +4 -6
- package/out/zero-events/src/index.d.ts.map +1 -1
- package/out/zero-events/src/index.js +1 -27
- package/out/zero-events/src/index.js.map +1 -1
- package/out/zero-events/src/status.d.ts +43 -111
- package/out/zero-events/src/status.d.ts.map +1 -1
- package/out/zero-events/src/status.js +2 -73
- package/out/zero-events/src/status.js.map +1 -1
- package/out/zero-events/src/util.d.ts +26 -0
- package/out/zero-events/src/util.d.ts.map +1 -0
- package/out/zero-events/src/util.js +2 -0
- package/out/zero-events/src/util.js.map +1 -0
- package/out/zero-protocol/src/analyze-query-result.d.ts +5 -0
- package/out/zero-protocol/src/analyze-query-result.d.ts.map +1 -1
- package/out/zero-protocol/src/analyze-query-result.js +5 -0
- package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
- package/out/zero-protocol/src/ast.d.ts +2 -1
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js +1 -0
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +8 -0
- package/out/zero-protocol/src/down.d.ts.map +1 -1
- package/out/zero-protocol/src/inspect-down.d.ts +26 -0
- package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
- package/out/zero-protocol/src/inspect-down.js +5 -1
- package/out/zero-protocol/src/inspect-down.js.map +1 -1
- package/out/zero-protocol/src/inspect-up.d.ts +18 -6
- package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
- package/out/zero-protocol/src/inspect-up.js +6 -1
- package/out/zero-protocol/src/inspect-up.js.map +1 -1
- 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 +3 -1
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +1 -1
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/up.d.ts +5 -2
- package/out/zero-protocol/src/up.d.ts.map +1 -1
- package/out/zero-react-native/src/mod.d.ts +0 -1
- package/out/zero-react-native/src/mod.d.ts.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.d.ts +3 -25
- package/out/zero-schema/src/builder/schema-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
- package/out/zero-schema/src/name-mapper.d.ts +2 -19
- package/out/zero-schema/src/name-mapper.d.ts.map +1 -1
- package/out/zero-schema/src/name-mapper.js +2 -44
- package/out/zero-schema/src/name-mapper.js.map +1 -1
- package/out/zero-schema/src/permissions.d.ts +1 -0
- package/out/zero-schema/src/permissions.d.ts.map +1 -1
- package/out/zero-schema/src/schema-config.d.ts +1 -1
- package/out/zero-schema/src/table-schema.d.ts +3 -55
- package/out/zero-schema/src/table-schema.d.ts.map +1 -1
- package/out/zero-schema/src/table-schema.js +0 -6
- package/out/zero-schema/src/table-schema.js.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +1 -1
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/query.d.ts +2 -2
- package/out/zero-server/src/query.d.ts.map +1 -1
- package/out/zero-server/src/query.js +2 -1
- package/out/zero-server/src/query.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 +10 -0
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/use-query.d.ts +3 -1
- package/out/zero-solid/src/use-query.d.ts.map +1 -1
- package/out/zero-solid/src/use-zero.d.ts +4 -1
- package/out/zero-solid/src/use-zero.d.ts.map +1 -1
- package/out/zero-types/src/format.d.ts +11 -0
- package/out/zero-types/src/format.d.ts.map +1 -0
- package/out/zero-types/src/format.js +5 -0
- package/out/zero-types/src/format.js.map +1 -0
- package/out/zero-types/src/name-mapper.d.ts +19 -0
- package/out/zero-types/src/name-mapper.d.ts.map +1 -0
- package/out/zero-types/src/name-mapper.js +45 -0
- package/out/zero-types/src/name-mapper.js.map +1 -0
- package/out/zero-types/src/schema-value.d.ts +36 -0
- package/out/zero-types/src/schema-value.d.ts.map +1 -0
- package/out/zero-types/src/schema-value.js +2 -0
- package/out/zero-types/src/schema-value.js.map +1 -0
- package/out/zero-types/src/schema.d.ts +54 -0
- package/out/zero-types/src/schema.d.ts.map +1 -0
- package/out/zero-types/src/schema.js +2 -0
- package/out/zero-types/src/schema.js.map +1 -0
- package/out/zero.js +4 -5
- package/out/zql/src/ivm/default-format.d.ts +2 -0
- package/out/zql/src/ivm/default-format.d.ts.map +1 -0
- package/out/zql/src/ivm/default-format.js +2 -0
- package/out/zql/src/ivm/default-format.js.map +1 -0
- package/out/zql/src/ivm/memory-source.d.ts +2 -2
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +2 -2
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/schema.d.ts +1 -1
- package/out/zql/src/ivm/schema.d.ts.map +1 -1
- package/out/zql/src/ivm/view.d.ts +3 -5
- package/out/zql/src/ivm/view.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.d.ts +2 -2
- package/out/zql/src/mutate/custom.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.js.map +1 -1
- package/out/zql/src/query/expression.d.ts +1 -1
- package/out/zql/src/query/expression.d.ts.map +1 -1
- package/out/zql/src/query/named.d.ts +2 -3
- package/out/zql/src/query/named.d.ts.map +1 -1
- package/out/zql/src/query/named.js.map +1 -1
- package/out/zql/src/query/query-delegate.d.ts +1 -1
- package/out/zql/src/query/query-delegate.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +4 -10
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +12 -19
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query.d.ts +7 -5
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/query.js.map +1 -1
- package/out/zql/src/query/static-query.d.ts +1 -1
- package/out/zql/src/query/static-query.d.ts.map +1 -1
- package/out/zql/src/query/static-query.js +2 -1
- package/out/zql/src/query/static-query.js.map +1 -1
- package/out/zqlite/src/explain-queries.d.ts +4 -0
- package/out/zqlite/src/explain-queries.d.ts.map +1 -0
- package/out/zqlite/src/explain-queries.js +18 -0
- package/out/zqlite/src/explain-queries.js.map +1 -0
- package/out/zqlite/src/mod.d.ts +2 -1
- package/out/zqlite/src/mod.d.ts.map +1 -1
- package/out/zqlite/src/mod.js +2 -1
- package/out/zqlite/src/mod.js.map +1 -1
- package/package.json +8 -7
- package/out/chunk-2MVN6X6T.js.map +0 -7
- package/out/chunk-IQYQOLDZ.js.map +0 -7
- package/out/chunk-YXYKEMHQ.js +0 -8491
- package/out/chunk-YXYKEMHQ.js.map +0 -7
- package/out/lazy-inspector-A5VQLZYJ.js.map +0 -7
- package/out/replicache/src/kv/op-sqlite/store.d.ts +0 -14
- package/out/replicache/src/kv/op-sqlite/store.d.ts.map +0 -1
- package/out/replicache/src/kv/op-sqlite/types.d.ts +0 -13
- package/out/replicache/src/kv/op-sqlite/types.d.ts.map +0 -1
- package/out/replicache/src/size-of-value.d.ts.map +0 -1
- /package/out/{replicache → shared}/src/size-of-value.d.ts +0 -0
|
@@ -11,16 +11,20 @@ import {
|
|
|
11
11
|
ClientStateNotFoundError,
|
|
12
12
|
DD31,
|
|
13
13
|
DEFAULT_HEAD_NAME,
|
|
14
|
+
DEFAULT_PRELOAD_TTL_MS,
|
|
15
|
+
DEFAULT_TTL_MS,
|
|
14
16
|
DiffsMap,
|
|
15
17
|
ENTITIES_KEY_PREFIX,
|
|
16
18
|
GOT_QUERIES_KEY_PREFIX,
|
|
17
19
|
Inspector,
|
|
18
20
|
Latest,
|
|
19
21
|
MUTATIONS_KEY_PREFIX,
|
|
22
|
+
SUBQ_PREFIX,
|
|
20
23
|
TDigest,
|
|
21
24
|
V6,
|
|
22
25
|
V7,
|
|
23
26
|
addDiffsForIndexes,
|
|
27
|
+
areEqual,
|
|
24
28
|
assertClientV6,
|
|
25
29
|
assertCookie,
|
|
26
30
|
assertHasClientState,
|
|
@@ -28,7 +32,6 @@ import {
|
|
|
28
32
|
assertJSONObject,
|
|
29
33
|
assertJSONValue,
|
|
30
34
|
assertLocalMetaDD31,
|
|
31
|
-
assertOrderingIncludesPK,
|
|
32
35
|
assertRefs,
|
|
33
36
|
assertSnapshotCommitDD31,
|
|
34
37
|
assertSnapshotMetaDD31,
|
|
@@ -48,24 +51,16 @@ import {
|
|
|
48
51
|
compareCookies,
|
|
49
52
|
compareCookiesForSnapshots,
|
|
50
53
|
compareTTL,
|
|
51
|
-
compareValues,
|
|
52
|
-
constraintMatchesPrimaryKey,
|
|
53
|
-
constraintMatchesRow,
|
|
54
54
|
createChunk,
|
|
55
|
-
createPredicate,
|
|
56
55
|
decodeIndexKey,
|
|
57
56
|
deepEqual,
|
|
58
|
-
delegateSymbol,
|
|
59
57
|
desiredQueriesPrefixForClient,
|
|
60
58
|
diff,
|
|
61
59
|
diff2,
|
|
62
60
|
diffCommits,
|
|
63
61
|
disableClientGroup,
|
|
64
|
-
emptyFunction,
|
|
65
62
|
emptyHash,
|
|
66
|
-
emptyObject,
|
|
67
63
|
encodeIndexScanKey,
|
|
68
|
-
filterPush,
|
|
69
64
|
getClientGroup,
|
|
70
65
|
getClientGroupForClient,
|
|
71
66
|
getClientGroupIDForClient,
|
|
@@ -75,8 +70,6 @@ import {
|
|
|
75
70
|
getSizeOfValue,
|
|
76
71
|
h64,
|
|
77
72
|
hasClientState,
|
|
78
|
-
hashOfAST,
|
|
79
|
-
hashOfNameAndArgs,
|
|
80
73
|
initClientV6,
|
|
81
74
|
inspectDownMessageSchema,
|
|
82
75
|
isLocalMetaDD31,
|
|
@@ -88,24 +81,21 @@ import {
|
|
|
88
81
|
localMutationsDD31,
|
|
89
82
|
localMutationsGreaterThan,
|
|
90
83
|
makeClientID,
|
|
91
|
-
makeComparator,
|
|
92
84
|
mapAST,
|
|
93
85
|
mapAllEntries,
|
|
94
86
|
mapEntries,
|
|
95
|
-
|
|
87
|
+
mergeIterables,
|
|
96
88
|
must,
|
|
97
89
|
mustGetChunk,
|
|
98
90
|
mustGetClient,
|
|
99
91
|
mustGetHeadHash,
|
|
100
92
|
nanoid,
|
|
101
|
-
newQuery,
|
|
102
93
|
newRandomHash,
|
|
103
94
|
newWriteLocal,
|
|
104
95
|
newWriteSnapshotDD31,
|
|
105
96
|
normalizeAST,
|
|
106
97
|
once,
|
|
107
98
|
parse,
|
|
108
|
-
primaryKeyConstraintFromFilters,
|
|
109
99
|
primaryKeySchema,
|
|
110
100
|
primaryKeyValueRecordSchema,
|
|
111
101
|
readFromDefaultHead,
|
|
@@ -122,23 +112,22 @@ import {
|
|
|
122
112
|
sourceNameFromKey,
|
|
123
113
|
stringCompare,
|
|
124
114
|
test,
|
|
125
|
-
throwOutput,
|
|
126
115
|
toDesiredQueriesKey,
|
|
127
116
|
toGotQueriesKey,
|
|
128
117
|
toMutationResponseKey,
|
|
129
118
|
toPrimaryKeyString,
|
|
130
|
-
|
|
119
|
+
toStaticParam,
|
|
131
120
|
using,
|
|
132
121
|
valita_exports,
|
|
133
|
-
valuesEqual,
|
|
134
122
|
withRead,
|
|
135
123
|
withWrite,
|
|
136
124
|
withWriteNoImplicitCommit,
|
|
137
125
|
wrapIterable
|
|
138
|
-
} from "./chunk-
|
|
126
|
+
} from "./chunk-HLJ3FQU5.js";
|
|
139
127
|
import {
|
|
140
128
|
assert,
|
|
141
129
|
assertArray,
|
|
130
|
+
assertBoolean,
|
|
142
131
|
assertNotNull,
|
|
143
132
|
assertNumber,
|
|
144
133
|
assertObject,
|
|
@@ -1859,6 +1848,334 @@ function clientSchemaFrom(schema) {
|
|
|
1859
1848
|
return { clientSchema, hash };
|
|
1860
1849
|
}
|
|
1861
1850
|
|
|
1851
|
+
// ../zql/src/ivm/data.ts
|
|
1852
|
+
import { compareUTF8 } from "compare-utf8";
|
|
1853
|
+
function compareValues(a, b) {
|
|
1854
|
+
a = normalizeUndefined(a);
|
|
1855
|
+
b = normalizeUndefined(b);
|
|
1856
|
+
if (a === b) {
|
|
1857
|
+
return 0;
|
|
1858
|
+
}
|
|
1859
|
+
if (a === null) {
|
|
1860
|
+
return -1;
|
|
1861
|
+
}
|
|
1862
|
+
if (b === null) {
|
|
1863
|
+
return 1;
|
|
1864
|
+
}
|
|
1865
|
+
if (typeof a === "boolean") {
|
|
1866
|
+
assertBoolean(b);
|
|
1867
|
+
return a ? 1 : -1;
|
|
1868
|
+
}
|
|
1869
|
+
if (typeof a === "number") {
|
|
1870
|
+
assertNumber(b);
|
|
1871
|
+
return a - b;
|
|
1872
|
+
}
|
|
1873
|
+
if (typeof a === "string") {
|
|
1874
|
+
assertString(b);
|
|
1875
|
+
return compareUTF8(a, b);
|
|
1876
|
+
}
|
|
1877
|
+
throw new Error(`Unsupported type: ${a}`);
|
|
1878
|
+
}
|
|
1879
|
+
function normalizeUndefined(v) {
|
|
1880
|
+
return v ?? null;
|
|
1881
|
+
}
|
|
1882
|
+
function makeComparator(order, reverse) {
|
|
1883
|
+
return (a, b) => {
|
|
1884
|
+
for (const ord of order) {
|
|
1885
|
+
const field = ord[0];
|
|
1886
|
+
const comp = compareValues(a[field], b[field]);
|
|
1887
|
+
if (comp !== 0) {
|
|
1888
|
+
const result = ord[1] === "asc" ? comp : -comp;
|
|
1889
|
+
return reverse ? -result : result;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
return 0;
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
function valuesEqual(a, b) {
|
|
1896
|
+
if (a == null || b == null) {
|
|
1897
|
+
return false;
|
|
1898
|
+
}
|
|
1899
|
+
return a === b;
|
|
1900
|
+
}
|
|
1901
|
+
function drainStreams(node) {
|
|
1902
|
+
for (const stream of Object.values(node.relationships)) {
|
|
1903
|
+
for (const node2 of stream()) {
|
|
1904
|
+
drainStreams(node2);
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
// ../zql/src/ivm/view-apply-change.ts
|
|
1910
|
+
var refCountSymbol = Symbol("rc");
|
|
1911
|
+
var idSymbol = Symbol("id");
|
|
1912
|
+
function applyChange(parentEntry, change, schema, relationship, format, withIDs = false) {
|
|
1913
|
+
if (schema.isHidden) {
|
|
1914
|
+
switch (change.type) {
|
|
1915
|
+
case "add":
|
|
1916
|
+
case "remove":
|
|
1917
|
+
for (const [relationship2, children] of Object.entries(
|
|
1918
|
+
change.node.relationships
|
|
1919
|
+
)) {
|
|
1920
|
+
const childSchema = must(schema.relationships[relationship2]);
|
|
1921
|
+
for (const node of children()) {
|
|
1922
|
+
applyChange(
|
|
1923
|
+
parentEntry,
|
|
1924
|
+
{ type: change.type, node },
|
|
1925
|
+
childSchema,
|
|
1926
|
+
relationship2,
|
|
1927
|
+
format,
|
|
1928
|
+
withIDs
|
|
1929
|
+
);
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
return;
|
|
1933
|
+
case "edit":
|
|
1934
|
+
return;
|
|
1935
|
+
case "child": {
|
|
1936
|
+
const childSchema = must(
|
|
1937
|
+
schema.relationships[change.child.relationshipName]
|
|
1938
|
+
);
|
|
1939
|
+
applyChange(
|
|
1940
|
+
parentEntry,
|
|
1941
|
+
change.child.change,
|
|
1942
|
+
childSchema,
|
|
1943
|
+
relationship,
|
|
1944
|
+
format,
|
|
1945
|
+
withIDs
|
|
1946
|
+
);
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1949
|
+
default:
|
|
1950
|
+
unreachable(change);
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
const { singular, relationships: childFormats } = format;
|
|
1954
|
+
switch (change.type) {
|
|
1955
|
+
case "add": {
|
|
1956
|
+
let newEntry;
|
|
1957
|
+
if (singular) {
|
|
1958
|
+
const oldEntry = parentEntry[relationship];
|
|
1959
|
+
if (oldEntry !== void 0) {
|
|
1960
|
+
assert(
|
|
1961
|
+
schema.compareRows(oldEntry, change.node.row) === 0,
|
|
1962
|
+
`Singular relationship '${relationship}' should not have multiple rows. You may need to declare this relationship with the \`many\` helper instead of the \`one\` helper in your schema.`
|
|
1963
|
+
);
|
|
1964
|
+
oldEntry[refCountSymbol]++;
|
|
1965
|
+
} else {
|
|
1966
|
+
newEntry = makeNewMetaEntry(change.node.row, schema, withIDs, 1);
|
|
1967
|
+
parentEntry[relationship] = newEntry;
|
|
1968
|
+
}
|
|
1969
|
+
} else {
|
|
1970
|
+
newEntry = add(
|
|
1971
|
+
change.node.row,
|
|
1972
|
+
getChildEntryList(parentEntry, relationship),
|
|
1973
|
+
schema,
|
|
1974
|
+
withIDs
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
if (newEntry) {
|
|
1978
|
+
for (const [relationship2, children] of Object.entries(
|
|
1979
|
+
change.node.relationships
|
|
1980
|
+
)) {
|
|
1981
|
+
const childSchema = must(schema.relationships[relationship2]);
|
|
1982
|
+
const childFormat = childFormats[relationship2];
|
|
1983
|
+
if (childFormat === void 0) {
|
|
1984
|
+
continue;
|
|
1985
|
+
}
|
|
1986
|
+
const newView = childFormat.singular ? void 0 : [];
|
|
1987
|
+
newEntry[relationship2] = newView;
|
|
1988
|
+
for (const node of children()) {
|
|
1989
|
+
applyChange(
|
|
1990
|
+
newEntry,
|
|
1991
|
+
{ type: "add", node },
|
|
1992
|
+
childSchema,
|
|
1993
|
+
relationship2,
|
|
1994
|
+
childFormat,
|
|
1995
|
+
withIDs
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
break;
|
|
2001
|
+
}
|
|
2002
|
+
case "remove": {
|
|
2003
|
+
if (singular) {
|
|
2004
|
+
const oldEntry = parentEntry[relationship];
|
|
2005
|
+
assert(oldEntry !== void 0, "node does not exist");
|
|
2006
|
+
const rc = oldEntry[refCountSymbol];
|
|
2007
|
+
if (rc === 1) {
|
|
2008
|
+
parentEntry[relationship] = void 0;
|
|
2009
|
+
}
|
|
2010
|
+
oldEntry[refCountSymbol]--;
|
|
2011
|
+
} else {
|
|
2012
|
+
removeAndUpdateRefCount(
|
|
2013
|
+
getChildEntryList(parentEntry, relationship),
|
|
2014
|
+
change.node.row,
|
|
2015
|
+
schema.compareRows
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
drainStreams(change.node);
|
|
2019
|
+
break;
|
|
2020
|
+
}
|
|
2021
|
+
case "child": {
|
|
2022
|
+
let existing;
|
|
2023
|
+
if (singular) {
|
|
2024
|
+
existing = getSingularEntry(parentEntry, relationship);
|
|
2025
|
+
} else {
|
|
2026
|
+
const view = getChildEntryList(parentEntry, relationship);
|
|
2027
|
+
const { pos, found } = binarySearch2(
|
|
2028
|
+
view,
|
|
2029
|
+
change.node.row,
|
|
2030
|
+
schema.compareRows
|
|
2031
|
+
);
|
|
2032
|
+
assert(found, "node does not exist");
|
|
2033
|
+
existing = view[pos];
|
|
2034
|
+
}
|
|
2035
|
+
const childSchema = must(
|
|
2036
|
+
schema.relationships[change.child.relationshipName]
|
|
2037
|
+
);
|
|
2038
|
+
const childFormat = format.relationships[change.child.relationshipName];
|
|
2039
|
+
if (childFormat !== void 0) {
|
|
2040
|
+
applyChange(
|
|
2041
|
+
existing,
|
|
2042
|
+
change.child.change,
|
|
2043
|
+
childSchema,
|
|
2044
|
+
change.child.relationshipName,
|
|
2045
|
+
childFormat,
|
|
2046
|
+
withIDs
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
break;
|
|
2050
|
+
}
|
|
2051
|
+
case "edit": {
|
|
2052
|
+
if (singular) {
|
|
2053
|
+
const existing = parentEntry[relationship];
|
|
2054
|
+
assertMetaEntry(existing);
|
|
2055
|
+
applyEdit(existing, change, schema, withIDs);
|
|
2056
|
+
} else {
|
|
2057
|
+
const view = getChildEntryList(parentEntry, relationship);
|
|
2058
|
+
if (schema.compareRows(change.oldNode.row, change.node.row) !== 0) {
|
|
2059
|
+
const { pos: oldPos, found: oldFound } = binarySearch2(
|
|
2060
|
+
view,
|
|
2061
|
+
change.oldNode.row,
|
|
2062
|
+
schema.compareRows
|
|
2063
|
+
);
|
|
2064
|
+
assert(oldFound, "old node does not exist");
|
|
2065
|
+
const oldEntry = view[oldPos];
|
|
2066
|
+
const { pos, found } = binarySearch2(
|
|
2067
|
+
view,
|
|
2068
|
+
change.node.row,
|
|
2069
|
+
schema.compareRows
|
|
2070
|
+
);
|
|
2071
|
+
if (oldEntry[refCountSymbol] === 1 && (pos === oldPos || pos - 1 === oldPos)) {
|
|
2072
|
+
applyEdit(oldEntry, change, schema, withIDs);
|
|
2073
|
+
} else {
|
|
2074
|
+
oldEntry[refCountSymbol]--;
|
|
2075
|
+
let adjustedPos = pos;
|
|
2076
|
+
if (oldEntry[refCountSymbol] === 0) {
|
|
2077
|
+
view.splice(oldPos, 1);
|
|
2078
|
+
adjustedPos = oldPos < pos ? pos - 1 : pos;
|
|
2079
|
+
}
|
|
2080
|
+
let entryToEdit;
|
|
2081
|
+
if (found) {
|
|
2082
|
+
entryToEdit = view[adjustedPos];
|
|
2083
|
+
} else {
|
|
2084
|
+
view.splice(adjustedPos, 0, oldEntry);
|
|
2085
|
+
entryToEdit = oldEntry;
|
|
2086
|
+
if (oldEntry[refCountSymbol] > 0) {
|
|
2087
|
+
const oldEntryCopy = { ...oldEntry };
|
|
2088
|
+
view[oldPos] = oldEntryCopy;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
entryToEdit[refCountSymbol]++;
|
|
2092
|
+
applyEdit(entryToEdit, change, schema, withIDs);
|
|
2093
|
+
}
|
|
2094
|
+
} else {
|
|
2095
|
+
const { pos, found } = binarySearch2(
|
|
2096
|
+
view,
|
|
2097
|
+
change.oldNode.row,
|
|
2098
|
+
schema.compareRows
|
|
2099
|
+
);
|
|
2100
|
+
assert(found, "node does not exist");
|
|
2101
|
+
applyEdit(view[pos], change, schema, withIDs);
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
break;
|
|
2105
|
+
}
|
|
2106
|
+
default:
|
|
2107
|
+
unreachable(change);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
function applyEdit(existing, change, schema, withIDs) {
|
|
2111
|
+
Object.assign(existing, change.node.row);
|
|
2112
|
+
if (withIDs) {
|
|
2113
|
+
existing[idSymbol] = makeID(change.node.row, schema);
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
function add(row, view, schema, withIDs) {
|
|
2117
|
+
const { pos, found } = binarySearch2(view, row, schema.compareRows);
|
|
2118
|
+
if (found) {
|
|
2119
|
+
view[pos][refCountSymbol]++;
|
|
2120
|
+
return void 0;
|
|
2121
|
+
}
|
|
2122
|
+
const newEntry = makeNewMetaEntry(row, schema, withIDs, 1);
|
|
2123
|
+
view.splice(pos, 0, newEntry);
|
|
2124
|
+
return newEntry;
|
|
2125
|
+
}
|
|
2126
|
+
function removeAndUpdateRefCount(view, row, compareRows) {
|
|
2127
|
+
const { pos, found } = binarySearch2(view, row, compareRows);
|
|
2128
|
+
assert(found, "node does not exist");
|
|
2129
|
+
const oldEntry = view[pos];
|
|
2130
|
+
const rc = oldEntry[refCountSymbol];
|
|
2131
|
+
if (rc === 1) {
|
|
2132
|
+
view.splice(pos, 1);
|
|
2133
|
+
}
|
|
2134
|
+
oldEntry[refCountSymbol]--;
|
|
2135
|
+
return oldEntry;
|
|
2136
|
+
}
|
|
2137
|
+
function binarySearch2(view, target, comparator2) {
|
|
2138
|
+
let low = 0;
|
|
2139
|
+
let high = view.length - 1;
|
|
2140
|
+
while (low <= high) {
|
|
2141
|
+
const mid = low + high >>> 1;
|
|
2142
|
+
const comparison = comparator2(view[mid], target);
|
|
2143
|
+
if (comparison < 0) {
|
|
2144
|
+
low = mid + 1;
|
|
2145
|
+
} else if (comparison > 0) {
|
|
2146
|
+
high = mid - 1;
|
|
2147
|
+
} else {
|
|
2148
|
+
return { pos: mid, found: true };
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
return { pos: low, found: false };
|
|
2152
|
+
}
|
|
2153
|
+
function getChildEntryList(parentEntry, relationship) {
|
|
2154
|
+
const view = parentEntry[relationship];
|
|
2155
|
+
assertArray(view);
|
|
2156
|
+
return view;
|
|
2157
|
+
}
|
|
2158
|
+
function assertMetaEntry(v) {
|
|
2159
|
+
assertNumber(v[refCountSymbol]);
|
|
2160
|
+
}
|
|
2161
|
+
function getSingularEntry(parentEntry, relationship) {
|
|
2162
|
+
const e = parentEntry[relationship];
|
|
2163
|
+
assertNumber(e[refCountSymbol]);
|
|
2164
|
+
return e;
|
|
2165
|
+
}
|
|
2166
|
+
function makeNewMetaEntry(row, schema, withIDs, rc) {
|
|
2167
|
+
if (withIDs) {
|
|
2168
|
+
return { ...row, [refCountSymbol]: rc, [idSymbol]: makeID(row, schema) };
|
|
2169
|
+
}
|
|
2170
|
+
return { ...row, [refCountSymbol]: rc };
|
|
2171
|
+
}
|
|
2172
|
+
function makeID(row, schema) {
|
|
2173
|
+
if (schema.primaryKey.length === 1) {
|
|
2174
|
+
return JSON.stringify(row[schema.primaryKey[0]]);
|
|
2175
|
+
}
|
|
2176
|
+
return JSON.stringify(schema.primaryKey.map((k) => row[k]));
|
|
2177
|
+
}
|
|
2178
|
+
|
|
1862
2179
|
// ../zero-client/src/client/update-needed-reason-type-enum.ts
|
|
1863
2180
|
var update_needed_reason_type_enum_exports = {};
|
|
1864
2181
|
__export(update_needed_reason_type_enum_exports, {
|
|
@@ -1872,7 +2189,7 @@ var SchemaVersionNotSupported2 = "SchemaVersionNotSupported";
|
|
|
1872
2189
|
|
|
1873
2190
|
// ../zero-client/src/client/zero.ts
|
|
1874
2191
|
import "@rocicorp/logger";
|
|
1875
|
-
import { resolver as
|
|
2192
|
+
import { resolver as resolver10 } from "@rocicorp/resolver";
|
|
1876
2193
|
|
|
1877
2194
|
// ../replicache/src/replicache-impl.ts
|
|
1878
2195
|
import { Lock } from "@rocicorp/lock";
|
|
@@ -4421,7 +4738,7 @@ function setIntervalWithSignal(fn, ms, signal) {
|
|
|
4421
4738
|
}
|
|
4422
4739
|
|
|
4423
4740
|
// ../replicache/src/subscriptions.ts
|
|
4424
|
-
import { compareUTF8, greaterThan as greaterThan3, lessThan, lessThanEq } from "compare-utf8";
|
|
4741
|
+
import { compareUTF8 as compareUTF82, greaterThan as greaterThan3, lessThan, lessThanEq } from "compare-utf8";
|
|
4425
4742
|
|
|
4426
4743
|
// ../replicache/src/invoke-kind-enum.ts
|
|
4427
4744
|
var InitialRun = 0;
|
|
@@ -4764,7 +5081,7 @@ function watcherMatchesDiff(diff3, prefix, indexName) {
|
|
|
4764
5081
|
function diffBinarySearch(diff3, prefix, compareKey) {
|
|
4765
5082
|
return binarySearch(
|
|
4766
5083
|
diff3.length,
|
|
4767
|
-
(i) =>
|
|
5084
|
+
(i) => compareUTF82(prefix, compareKey(diff3[i]))
|
|
4768
5085
|
);
|
|
4769
5086
|
}
|
|
4770
5087
|
|
|
@@ -5970,6 +6287,15 @@ function validateOptions(options) {
|
|
|
5970
6287
|
}
|
|
5971
6288
|
}
|
|
5972
6289
|
|
|
6290
|
+
// ../shared/src/sentinels.ts
|
|
6291
|
+
function emptyFunction() {
|
|
6292
|
+
}
|
|
6293
|
+
var emptyObject = Object.freeze({});
|
|
6294
|
+
var emptyArray = Object.freeze([]);
|
|
6295
|
+
function identity(x) {
|
|
6296
|
+
return x;
|
|
6297
|
+
}
|
|
6298
|
+
|
|
5973
6299
|
// ../shared/src/subscribable.ts
|
|
5974
6300
|
var Subscribable = class {
|
|
5975
6301
|
_listeners = /* @__PURE__ */ new Set();
|
|
@@ -6428,46 +6754,11 @@ var downstreamSchema = valita_exports.union(
|
|
|
6428
6754
|
);
|
|
6429
6755
|
|
|
6430
6756
|
// ../zero-protocol/src/protocol-version.ts
|
|
6431
|
-
var PROTOCOL_VERSION =
|
|
6757
|
+
var PROTOCOL_VERSION = 36;
|
|
6432
6758
|
var MIN_SERVER_SUPPORTED_SYNC_PROTOCOL = 18;
|
|
6433
6759
|
assert(MIN_SERVER_SUPPORTED_SYNC_PROTOCOL < PROTOCOL_VERSION);
|
|
6434
6760
|
|
|
6435
|
-
// ../zero-
|
|
6436
|
-
function clientToServer(tables) {
|
|
6437
|
-
return createMapperFrom("client", tables);
|
|
6438
|
-
}
|
|
6439
|
-
function serverToClient(tables) {
|
|
6440
|
-
return createMapperFrom("server", tables);
|
|
6441
|
-
}
|
|
6442
|
-
function createMapperFrom(src, tables) {
|
|
6443
|
-
const mapping = new Map(
|
|
6444
|
-
Object.entries(tables).map(
|
|
6445
|
-
([tableName, { serverName: serverTableName, columns }]) => {
|
|
6446
|
-
let allColumnsSame = true;
|
|
6447
|
-
const names = {};
|
|
6448
|
-
for (const [name, { serverName }] of Object.entries(columns)) {
|
|
6449
|
-
if (serverName && serverName !== name) {
|
|
6450
|
-
allColumnsSame = false;
|
|
6451
|
-
}
|
|
6452
|
-
if (src === "client") {
|
|
6453
|
-
names[name] = serverName ?? name;
|
|
6454
|
-
} else {
|
|
6455
|
-
names[serverName ?? name] = name;
|
|
6456
|
-
}
|
|
6457
|
-
}
|
|
6458
|
-
return [
|
|
6459
|
-
src === "client" ? tableName : serverTableName ?? tableName,
|
|
6460
|
-
{
|
|
6461
|
-
tableName: src === "client" ? serverTableName ?? tableName : tableName,
|
|
6462
|
-
columns: names,
|
|
6463
|
-
allColumnsSame
|
|
6464
|
-
}
|
|
6465
|
-
];
|
|
6466
|
-
}
|
|
6467
|
-
)
|
|
6468
|
-
);
|
|
6469
|
-
return new NameMapper(mapping);
|
|
6470
|
-
}
|
|
6761
|
+
// ../zero-types/src/name-mapper.ts
|
|
6471
6762
|
var NameMapper = class {
|
|
6472
6763
|
#tables = /* @__PURE__ */ new Map();
|
|
6473
6764
|
constructor(tables) {
|
|
@@ -6513,6 +6804,43 @@ var NameMapper = class {
|
|
|
6513
6804
|
}
|
|
6514
6805
|
};
|
|
6515
6806
|
|
|
6807
|
+
// ../zero-schema/src/name-mapper.ts
|
|
6808
|
+
function clientToServer(tables) {
|
|
6809
|
+
return createMapperFrom("client", tables);
|
|
6810
|
+
}
|
|
6811
|
+
function serverToClient(tables) {
|
|
6812
|
+
return createMapperFrom("server", tables);
|
|
6813
|
+
}
|
|
6814
|
+
function createMapperFrom(src, tables) {
|
|
6815
|
+
const mapping = new Map(
|
|
6816
|
+
Object.entries(tables).map(
|
|
6817
|
+
([tableName, { serverName: serverTableName, columns }]) => {
|
|
6818
|
+
let allColumnsSame = true;
|
|
6819
|
+
const names = {};
|
|
6820
|
+
for (const [name, { serverName }] of Object.entries(columns)) {
|
|
6821
|
+
if (serverName && serverName !== name) {
|
|
6822
|
+
allColumnsSame = false;
|
|
6823
|
+
}
|
|
6824
|
+
if (src === "client") {
|
|
6825
|
+
names[name] = serverName ?? name;
|
|
6826
|
+
} else {
|
|
6827
|
+
names[serverName ?? name] = name;
|
|
6828
|
+
}
|
|
6829
|
+
}
|
|
6830
|
+
return [
|
|
6831
|
+
src === "client" ? tableName : serverTableName ?? tableName,
|
|
6832
|
+
{
|
|
6833
|
+
tableName: src === "client" ? serverTableName ?? tableName : tableName,
|
|
6834
|
+
columns: names,
|
|
6835
|
+
allColumnsSame
|
|
6836
|
+
}
|
|
6837
|
+
];
|
|
6838
|
+
}
|
|
6839
|
+
)
|
|
6840
|
+
);
|
|
6841
|
+
return new NameMapper(mapping);
|
|
6842
|
+
}
|
|
6843
|
+
|
|
6516
6844
|
// ../zql/src/mutate/custom.ts
|
|
6517
6845
|
function customMutatorKey(namespace, name) {
|
|
6518
6846
|
assert(!namespace.includes("|"), "mutator namespaces must not include a |");
|
|
@@ -6525,77 +6853,4099 @@ function isClientMetric(metric) {
|
|
|
6525
6853
|
return metric.endsWith("-client") || metric.endsWith("-end-to-end");
|
|
6526
6854
|
}
|
|
6527
6855
|
|
|
6528
|
-
// ../
|
|
6529
|
-
function send(ws, data) {
|
|
6530
|
-
ws.send(JSON.stringify(data));
|
|
6531
|
-
}
|
|
6532
|
-
|
|
6533
|
-
// ../zero-client/src/client/active-clients-manager.ts
|
|
6856
|
+
// ../zql/src/query/query-impl.ts
|
|
6534
6857
|
import { resolver as resolver7 } from "@rocicorp/resolver";
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6858
|
+
|
|
6859
|
+
// ../zero-protocol/src/query-hash.ts
|
|
6860
|
+
var hashCache = /* @__PURE__ */ new WeakMap();
|
|
6861
|
+
function hashOfAST(ast) {
|
|
6862
|
+
const normalized = normalizeAST(ast);
|
|
6863
|
+
const cached = hashCache.get(normalized);
|
|
6864
|
+
if (cached) {
|
|
6865
|
+
return cached;
|
|
6866
|
+
}
|
|
6867
|
+
const hash = h64(JSON.stringify(normalized)).toString(36);
|
|
6868
|
+
hashCache.set(normalized, hash);
|
|
6869
|
+
return hash;
|
|
6538
6870
|
}
|
|
6539
|
-
function
|
|
6540
|
-
|
|
6871
|
+
function hashOfNameAndArgs(name, args) {
|
|
6872
|
+
const argsString = JSON.stringify(args);
|
|
6873
|
+
return h64(`${name}:${argsString}`).toString(36);
|
|
6541
6874
|
}
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6875
|
+
|
|
6876
|
+
// ../zql/src/ivm/filter-operators.ts
|
|
6877
|
+
var throwFilterOutput = {
|
|
6878
|
+
push(_change) {
|
|
6879
|
+
throw new Error("Output not set");
|
|
6880
|
+
},
|
|
6881
|
+
filter(_node, _cleanup) {
|
|
6882
|
+
throw new Error("Output not set");
|
|
6545
6883
|
}
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6884
|
+
};
|
|
6885
|
+
var FilterStart = class {
|
|
6886
|
+
#input;
|
|
6887
|
+
#output = throwFilterOutput;
|
|
6888
|
+
constructor(input) {
|
|
6889
|
+
this.#input = input;
|
|
6890
|
+
input.setOutput(this);
|
|
6549
6891
|
}
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
clientID: parts[2]
|
|
6553
|
-
};
|
|
6554
|
-
}
|
|
6555
|
-
function ignoreAbortError(e) {
|
|
6556
|
-
if (e instanceof Error && e.name === "AbortError") {
|
|
6557
|
-
return;
|
|
6892
|
+
setFilterOutput(output) {
|
|
6893
|
+
this.#output = output;
|
|
6558
6894
|
}
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
var ActiveClientsManager = class _ActiveClientsManager {
|
|
6562
|
-
clientGroupID;
|
|
6563
|
-
clientID;
|
|
6564
|
-
#resolver = resolver7();
|
|
6565
|
-
#lockManager;
|
|
6566
|
-
#activeClients = /* @__PURE__ */ new Set();
|
|
6567
|
-
/**
|
|
6568
|
-
* A callback that is called when a client is added to the client group.
|
|
6569
|
-
* It receives the client ID of the added client.
|
|
6570
|
-
*/
|
|
6571
|
-
onAdd;
|
|
6572
|
-
/**
|
|
6573
|
-
* A callback that is called when a client is deleted from the client group.
|
|
6574
|
-
* It receives the client ID of the deleted client.
|
|
6575
|
-
*/
|
|
6576
|
-
onDelete;
|
|
6577
|
-
/**
|
|
6578
|
-
* Creates an instance of `ActiveClientsManager` for the specified client
|
|
6579
|
-
* group and client ID. It will return a promise that resolves when the
|
|
6580
|
-
* instance is ready to use, which means that it has successfully acquired the
|
|
6581
|
-
* exclusive lock for the client and has retrieved the list of active clients.
|
|
6582
|
-
*/
|
|
6583
|
-
static async create(clientGroupID, clientID, signal) {
|
|
6584
|
-
const instance = new _ActiveClientsManager(clientGroupID, clientID, signal);
|
|
6585
|
-
await instance.#init(signal);
|
|
6586
|
-
return instance;
|
|
6895
|
+
destroy() {
|
|
6896
|
+
this.#input.destroy();
|
|
6587
6897
|
}
|
|
6588
|
-
|
|
6589
|
-
this.
|
|
6590
|
-
this.clientID = clientID;
|
|
6591
|
-
this.#lockManager = getClientLockManager(signal);
|
|
6592
|
-
this.#activeClients.add(clientID);
|
|
6898
|
+
getSchema() {
|
|
6899
|
+
return this.#input.getSchema();
|
|
6593
6900
|
}
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6901
|
+
push(change) {
|
|
6902
|
+
this.#output.push(change, this);
|
|
6903
|
+
}
|
|
6904
|
+
*fetch(req) {
|
|
6905
|
+
for (const node of this.#input.fetch(req)) {
|
|
6906
|
+
if (this.#output.filter(node, false)) {
|
|
6907
|
+
yield node;
|
|
6908
|
+
}
|
|
6909
|
+
}
|
|
6910
|
+
}
|
|
6911
|
+
*cleanup(req) {
|
|
6912
|
+
for (const node of this.#input.cleanup(req)) {
|
|
6913
|
+
if (this.#output.filter(node, true)) {
|
|
6914
|
+
yield node;
|
|
6915
|
+
} else {
|
|
6916
|
+
drainStreams(node);
|
|
6917
|
+
}
|
|
6918
|
+
}
|
|
6919
|
+
}
|
|
6920
|
+
};
|
|
6921
|
+
var FilterEnd = class {
|
|
6922
|
+
#start;
|
|
6923
|
+
#input;
|
|
6924
|
+
#output = throwFilterOutput;
|
|
6925
|
+
constructor(start, input) {
|
|
6926
|
+
this.#start = start;
|
|
6927
|
+
this.#input = input;
|
|
6928
|
+
input.setFilterOutput(this);
|
|
6929
|
+
}
|
|
6930
|
+
*fetch(req) {
|
|
6931
|
+
for (const node of this.#start.fetch(req)) {
|
|
6932
|
+
yield node;
|
|
6933
|
+
}
|
|
6934
|
+
}
|
|
6935
|
+
*cleanup(req) {
|
|
6936
|
+
for (const node of this.#start.cleanup(req)) {
|
|
6937
|
+
yield node;
|
|
6938
|
+
}
|
|
6939
|
+
}
|
|
6940
|
+
filter(_node, _cleanup) {
|
|
6941
|
+
return true;
|
|
6942
|
+
}
|
|
6943
|
+
setOutput(output) {
|
|
6944
|
+
this.#output = output;
|
|
6945
|
+
}
|
|
6946
|
+
destroy() {
|
|
6947
|
+
this.#input.destroy();
|
|
6948
|
+
}
|
|
6949
|
+
getSchema() {
|
|
6950
|
+
return this.#input.getSchema();
|
|
6951
|
+
}
|
|
6952
|
+
push(change) {
|
|
6953
|
+
this.#output.push(change, this);
|
|
6954
|
+
}
|
|
6955
|
+
};
|
|
6956
|
+
function buildFilterPipeline(input, delegate, pipeline) {
|
|
6957
|
+
const filterStart = new FilterStart(input);
|
|
6958
|
+
delegate.addEdge(input, filterStart);
|
|
6959
|
+
const middle = pipeline(filterStart);
|
|
6960
|
+
delegate.addEdge(filterStart, middle);
|
|
6961
|
+
const filterEnd = new FilterEnd(filterStart, middle);
|
|
6962
|
+
delegate.addEdge(middle, filterEnd);
|
|
6963
|
+
return filterEnd;
|
|
6964
|
+
}
|
|
6965
|
+
|
|
6966
|
+
// ../zql/src/ivm/operator.ts
|
|
6967
|
+
var throwOutput = {
|
|
6968
|
+
push(_change) {
|
|
6969
|
+
throw new Error("Output not set");
|
|
6970
|
+
}
|
|
6971
|
+
};
|
|
6972
|
+
|
|
6973
|
+
// ../zql/src/ivm/stream.ts
|
|
6974
|
+
function* take(stream, limit) {
|
|
6975
|
+
if (limit < 1) {
|
|
6976
|
+
return;
|
|
6977
|
+
}
|
|
6978
|
+
let count = 0;
|
|
6979
|
+
for (const v of stream) {
|
|
6980
|
+
yield v;
|
|
6981
|
+
if (++count === limit) {
|
|
6982
|
+
break;
|
|
6983
|
+
}
|
|
6984
|
+
}
|
|
6985
|
+
}
|
|
6986
|
+
function first(stream) {
|
|
6987
|
+
const it = stream[Symbol.iterator]();
|
|
6988
|
+
const { value } = it.next();
|
|
6989
|
+
it.return?.();
|
|
6990
|
+
return value;
|
|
6991
|
+
}
|
|
6992
|
+
|
|
6993
|
+
// ../zql/src/ivm/exists.ts
|
|
6994
|
+
var Exists = class {
|
|
6995
|
+
#input;
|
|
6996
|
+
#relationshipName;
|
|
6997
|
+
#storage;
|
|
6998
|
+
#not;
|
|
6999
|
+
#parentJoinKey;
|
|
7000
|
+
#noSizeReuse;
|
|
7001
|
+
#output = throwFilterOutput;
|
|
7002
|
+
/**
|
|
7003
|
+
* This instance variable is `true` when this operator is processing a `push`,
|
|
7004
|
+
* and is used to disable reuse of cached sizes across rows with the
|
|
7005
|
+
* same parent join key value.
|
|
7006
|
+
* This is necessary because during a push relationships can be inconsistent
|
|
7007
|
+
* due to push communicating changes (which may change multiple Nodes) one
|
|
7008
|
+
* Node at a time.
|
|
7009
|
+
*/
|
|
7010
|
+
#inPush = false;
|
|
7011
|
+
constructor(input, storage, relationshipName, parentJoinKey, type) {
|
|
7012
|
+
this.#input = input;
|
|
7013
|
+
this.#relationshipName = relationshipName;
|
|
7014
|
+
this.#input.setFilterOutput(this);
|
|
7015
|
+
this.#storage = storage;
|
|
7016
|
+
assert(
|
|
7017
|
+
this.#input.getSchema().relationships[relationshipName],
|
|
7018
|
+
`Input schema missing ${relationshipName}`
|
|
7019
|
+
);
|
|
7020
|
+
this.#not = type === "NOT EXISTS";
|
|
7021
|
+
this.#parentJoinKey = parentJoinKey;
|
|
7022
|
+
this.#noSizeReuse = areEqual(
|
|
7023
|
+
parentJoinKey,
|
|
7024
|
+
this.#input.getSchema().primaryKey
|
|
7025
|
+
);
|
|
7026
|
+
}
|
|
7027
|
+
setFilterOutput(output) {
|
|
7028
|
+
this.#output = output;
|
|
7029
|
+
}
|
|
7030
|
+
filter(node, cleanup) {
|
|
7031
|
+
const result = this.#filter(node) && this.#output.filter(node, cleanup);
|
|
7032
|
+
if (cleanup) {
|
|
7033
|
+
this.#delSize(node);
|
|
7034
|
+
}
|
|
7035
|
+
return result;
|
|
7036
|
+
}
|
|
7037
|
+
destroy() {
|
|
7038
|
+
this.#input.destroy();
|
|
7039
|
+
}
|
|
7040
|
+
getSchema() {
|
|
7041
|
+
return this.#input.getSchema();
|
|
7042
|
+
}
|
|
7043
|
+
push(change) {
|
|
7044
|
+
assert(!this.#inPush, "Unexpected re-entrancy");
|
|
7045
|
+
this.#inPush = true;
|
|
7046
|
+
try {
|
|
7047
|
+
switch (change.type) {
|
|
7048
|
+
// add, remove and edit cannot change the size of the
|
|
7049
|
+
// this.#relationshipName relationship, so simply #pushWithFilter
|
|
7050
|
+
case "add":
|
|
7051
|
+
case "edit": {
|
|
7052
|
+
this.#pushWithFilter(change);
|
|
7053
|
+
return;
|
|
7054
|
+
}
|
|
7055
|
+
case "remove": {
|
|
7056
|
+
const size = this.#getSize(change.node);
|
|
7057
|
+
if (size === void 0) {
|
|
7058
|
+
return;
|
|
7059
|
+
}
|
|
7060
|
+
this.#pushWithFilter(change, size);
|
|
7061
|
+
this.#delSize(change.node);
|
|
7062
|
+
return;
|
|
7063
|
+
}
|
|
7064
|
+
case "child":
|
|
7065
|
+
if (change.child.relationshipName !== this.#relationshipName || change.child.change.type === "edit" || change.child.change.type === "child") {
|
|
7066
|
+
this.#pushWithFilter(change);
|
|
7067
|
+
return;
|
|
7068
|
+
}
|
|
7069
|
+
switch (change.child.change.type) {
|
|
7070
|
+
case "add": {
|
|
7071
|
+
let size = this.#getSize(change.node);
|
|
7072
|
+
if (size !== void 0) {
|
|
7073
|
+
size++;
|
|
7074
|
+
this.#setSize(change.node, size);
|
|
7075
|
+
} else {
|
|
7076
|
+
size = this.#fetchSize(change.node);
|
|
7077
|
+
}
|
|
7078
|
+
if (size === 1) {
|
|
7079
|
+
if (this.#not) {
|
|
7080
|
+
this.#output.push(
|
|
7081
|
+
{
|
|
7082
|
+
type: "remove",
|
|
7083
|
+
node: {
|
|
7084
|
+
row: change.node.row,
|
|
7085
|
+
relationships: {
|
|
7086
|
+
...change.node.relationships,
|
|
7087
|
+
[this.#relationshipName]: () => []
|
|
7088
|
+
}
|
|
7089
|
+
}
|
|
7090
|
+
},
|
|
7091
|
+
this
|
|
7092
|
+
);
|
|
7093
|
+
} else {
|
|
7094
|
+
this.#output.push(
|
|
7095
|
+
{
|
|
7096
|
+
type: "add",
|
|
7097
|
+
node: change.node
|
|
7098
|
+
},
|
|
7099
|
+
this
|
|
7100
|
+
);
|
|
7101
|
+
}
|
|
7102
|
+
} else {
|
|
7103
|
+
this.#pushWithFilter(change, size);
|
|
7104
|
+
}
|
|
7105
|
+
return;
|
|
7106
|
+
}
|
|
7107
|
+
case "remove": {
|
|
7108
|
+
let size = this.#getSize(change.node);
|
|
7109
|
+
if (size !== void 0) {
|
|
7110
|
+
assert(size > 0);
|
|
7111
|
+
size--;
|
|
7112
|
+
this.#setSize(change.node, size);
|
|
7113
|
+
} else {
|
|
7114
|
+
size = this.#fetchSize(change.node);
|
|
7115
|
+
}
|
|
7116
|
+
if (size === 0) {
|
|
7117
|
+
if (this.#not) {
|
|
7118
|
+
this.#output.push(
|
|
7119
|
+
{
|
|
7120
|
+
type: "add",
|
|
7121
|
+
node: change.node
|
|
7122
|
+
},
|
|
7123
|
+
this
|
|
7124
|
+
);
|
|
7125
|
+
} else {
|
|
7126
|
+
this.#output.push(
|
|
7127
|
+
{
|
|
7128
|
+
type: "remove",
|
|
7129
|
+
node: {
|
|
7130
|
+
row: change.node.row,
|
|
7131
|
+
relationships: {
|
|
7132
|
+
...change.node.relationships,
|
|
7133
|
+
[this.#relationshipName]: () => [
|
|
7134
|
+
change.child.change.node
|
|
7135
|
+
]
|
|
7136
|
+
}
|
|
7137
|
+
}
|
|
7138
|
+
},
|
|
7139
|
+
this
|
|
7140
|
+
);
|
|
7141
|
+
}
|
|
7142
|
+
} else {
|
|
7143
|
+
this.#pushWithFilter(change, size);
|
|
7144
|
+
}
|
|
7145
|
+
return;
|
|
7146
|
+
}
|
|
7147
|
+
}
|
|
7148
|
+
return;
|
|
7149
|
+
default:
|
|
7150
|
+
unreachable(change);
|
|
7151
|
+
}
|
|
7152
|
+
} finally {
|
|
7153
|
+
this.#inPush = false;
|
|
7154
|
+
}
|
|
7155
|
+
}
|
|
7156
|
+
/**
|
|
7157
|
+
* Returns whether or not the node's this.#relationshipName
|
|
7158
|
+
* relationship passes the exist/not exists filter condition.
|
|
7159
|
+
* If the optional `size` is passed it is used.
|
|
7160
|
+
* Otherwise, if there is a stored size for the row it is used.
|
|
7161
|
+
* Otherwise the size is computed by streaming the node's
|
|
7162
|
+
* relationship with this.#relationshipName (this computed size is also
|
|
7163
|
+
* stored).
|
|
7164
|
+
*/
|
|
7165
|
+
#filter(node, size) {
|
|
7166
|
+
const exists = (size ?? this.#getOrFetchSize(node)) > 0;
|
|
7167
|
+
return this.#not ? !exists : exists;
|
|
7168
|
+
}
|
|
7169
|
+
/**
|
|
7170
|
+
* Pushes a change if this.#filter is true for its row.
|
|
7171
|
+
*/
|
|
7172
|
+
#pushWithFilter(change, size) {
|
|
7173
|
+
if (this.#filter(change.node, size)) {
|
|
7174
|
+
this.#output.push(change, this);
|
|
7175
|
+
}
|
|
7176
|
+
}
|
|
7177
|
+
#getSize(node) {
|
|
7178
|
+
return this.#storage.get(this.#makeSizeStorageKey(node));
|
|
7179
|
+
}
|
|
7180
|
+
#setSize(node, size) {
|
|
7181
|
+
this.#storage.set(this.#makeSizeStorageKey(node), size);
|
|
7182
|
+
}
|
|
7183
|
+
#delSize(node) {
|
|
7184
|
+
this.#storage.del(this.#makeSizeStorageKey(node));
|
|
7185
|
+
}
|
|
7186
|
+
#getOrFetchSize(node) {
|
|
7187
|
+
const size = this.#getSize(node);
|
|
7188
|
+
if (size !== void 0) {
|
|
7189
|
+
return size;
|
|
7190
|
+
}
|
|
7191
|
+
return this.#fetchSize(node);
|
|
7192
|
+
}
|
|
7193
|
+
#fetchSize(node) {
|
|
7194
|
+
if (!this.#noSizeReuse && !this.#inPush) {
|
|
7195
|
+
const cachedSizeEntry = first(
|
|
7196
|
+
this.#storage.scan({
|
|
7197
|
+
prefix: this.#makeSizeStorageKeyPrefix(node)
|
|
7198
|
+
})
|
|
7199
|
+
);
|
|
7200
|
+
if (cachedSizeEntry !== void 0) {
|
|
7201
|
+
this.#setSize(node, cachedSizeEntry[1]);
|
|
7202
|
+
return cachedSizeEntry[1];
|
|
7203
|
+
}
|
|
7204
|
+
}
|
|
7205
|
+
const relationship = node.relationships[this.#relationshipName];
|
|
7206
|
+
assert(relationship);
|
|
7207
|
+
let size = 0;
|
|
7208
|
+
for (const _relatedNode of relationship()) {
|
|
7209
|
+
size++;
|
|
7210
|
+
}
|
|
7211
|
+
this.#setSize(node, size);
|
|
7212
|
+
return size;
|
|
7213
|
+
}
|
|
7214
|
+
#makeSizeStorageKeyPrefix(node) {
|
|
7215
|
+
return `row/${this.#noSizeReuse ? "" : JSON.stringify(this.#getKeyValues(node, this.#parentJoinKey))}/`;
|
|
7216
|
+
}
|
|
7217
|
+
#makeSizeStorageKey(node) {
|
|
7218
|
+
return `${this.#makeSizeStorageKeyPrefix(node)}${JSON.stringify(
|
|
7219
|
+
this.#getKeyValues(node, this.#input.getSchema().primaryKey)
|
|
7220
|
+
)}`;
|
|
7221
|
+
}
|
|
7222
|
+
#getKeyValues(node, def) {
|
|
7223
|
+
const values = [];
|
|
7224
|
+
for (const key of def) {
|
|
7225
|
+
values.push(normalizeUndefined(node.row[key]));
|
|
7226
|
+
}
|
|
7227
|
+
return values;
|
|
7228
|
+
}
|
|
7229
|
+
};
|
|
7230
|
+
|
|
7231
|
+
// ../zql/src/ivm/push-accumulated.ts
|
|
7232
|
+
function pushAccumulatedChanges(accumulatedPushes, output, pusher, fanOutChangeType, mergeRelationships2, addEmptyRelationships) {
|
|
7233
|
+
if (accumulatedPushes.length === 0) {
|
|
7234
|
+
return;
|
|
7235
|
+
}
|
|
7236
|
+
const candidatesToPush = /* @__PURE__ */ new Map();
|
|
7237
|
+
for (const change of accumulatedPushes) {
|
|
7238
|
+
if (fanOutChangeType === "child" && change.type !== "child") {
|
|
7239
|
+
assert(
|
|
7240
|
+
candidatesToPush.has(change.type) === false,
|
|
7241
|
+
() => `Fan-in:child expected at most one ${change.type} when fan-out is of type child`
|
|
7242
|
+
);
|
|
7243
|
+
}
|
|
7244
|
+
const existing = candidatesToPush.get(change.type);
|
|
7245
|
+
let mergedChange = change;
|
|
7246
|
+
if (existing) {
|
|
7247
|
+
mergedChange = mergeRelationships2(existing, change);
|
|
7248
|
+
}
|
|
7249
|
+
candidatesToPush.set(change.type, mergedChange);
|
|
7250
|
+
}
|
|
7251
|
+
accumulatedPushes.length = 0;
|
|
7252
|
+
const types = [...candidatesToPush.keys()];
|
|
7253
|
+
switch (fanOutChangeType) {
|
|
7254
|
+
case "remove":
|
|
7255
|
+
assert(
|
|
7256
|
+
types.length === 1 && types[0] === "remove",
|
|
7257
|
+
"Fan-in:remove expected all removes"
|
|
7258
|
+
);
|
|
7259
|
+
output.push(
|
|
7260
|
+
addEmptyRelationships(must(candidatesToPush.get("remove"))),
|
|
7261
|
+
pusher
|
|
7262
|
+
);
|
|
7263
|
+
return;
|
|
7264
|
+
case "add":
|
|
7265
|
+
assert(
|
|
7266
|
+
types.length === 1 && types[0] === "add",
|
|
7267
|
+
"Fan-in:add expected all adds"
|
|
7268
|
+
);
|
|
7269
|
+
output.push(
|
|
7270
|
+
addEmptyRelationships(must(candidatesToPush.get("add"))),
|
|
7271
|
+
pusher
|
|
7272
|
+
);
|
|
7273
|
+
return;
|
|
7274
|
+
case "edit": {
|
|
7275
|
+
assert(
|
|
7276
|
+
types.every(
|
|
7277
|
+
(type) => type === "add" || type === "remove" || type === "edit"
|
|
7278
|
+
),
|
|
7279
|
+
"Fan-in:edit expected all adds, removes, or edits"
|
|
7280
|
+
);
|
|
7281
|
+
const addChange = candidatesToPush.get("add");
|
|
7282
|
+
const removeChange = candidatesToPush.get("remove");
|
|
7283
|
+
let editChange = candidatesToPush.get("edit");
|
|
7284
|
+
if (editChange) {
|
|
7285
|
+
if (addChange) {
|
|
7286
|
+
editChange = mergeRelationships2(editChange, addChange);
|
|
7287
|
+
}
|
|
7288
|
+
if (removeChange) {
|
|
7289
|
+
editChange = mergeRelationships2(editChange, removeChange);
|
|
7290
|
+
}
|
|
7291
|
+
output.push(addEmptyRelationships(editChange), pusher);
|
|
7292
|
+
return;
|
|
7293
|
+
}
|
|
7294
|
+
if (addChange && removeChange) {
|
|
7295
|
+
output.push(
|
|
7296
|
+
addEmptyRelationships({
|
|
7297
|
+
type: "edit",
|
|
7298
|
+
node: addChange.node,
|
|
7299
|
+
oldNode: removeChange.node
|
|
7300
|
+
}),
|
|
7301
|
+
pusher
|
|
7302
|
+
);
|
|
7303
|
+
return;
|
|
7304
|
+
}
|
|
7305
|
+
output.push(
|
|
7306
|
+
addEmptyRelationships(must(addChange ?? removeChange)),
|
|
7307
|
+
pusher
|
|
7308
|
+
);
|
|
7309
|
+
return;
|
|
7310
|
+
}
|
|
7311
|
+
case "child": {
|
|
7312
|
+
assert(
|
|
7313
|
+
types.every(
|
|
7314
|
+
(type) => type === "add" || // exists can change child to add or remove
|
|
7315
|
+
type === "remove" || // exists can change child to add or remove
|
|
7316
|
+
type === "child"
|
|
7317
|
+
// other operators may preserve the child change
|
|
7318
|
+
),
|
|
7319
|
+
"Fan-in:child expected all adds, removes, or children"
|
|
7320
|
+
);
|
|
7321
|
+
assert(
|
|
7322
|
+
types.length <= 2,
|
|
7323
|
+
"Fan-in:child expected at most 2 types on a child change from fan-out"
|
|
7324
|
+
);
|
|
7325
|
+
const childChange = candidatesToPush.get("child");
|
|
7326
|
+
if (childChange) {
|
|
7327
|
+
output.push(childChange, pusher);
|
|
7328
|
+
return;
|
|
7329
|
+
}
|
|
7330
|
+
const addChange = candidatesToPush.get("add");
|
|
7331
|
+
const removeChange = candidatesToPush.get("remove");
|
|
7332
|
+
assert(
|
|
7333
|
+
addChange === void 0 || removeChange === void 0,
|
|
7334
|
+
"Fan-in:child expected either add or remove, not both"
|
|
7335
|
+
);
|
|
7336
|
+
output.push(
|
|
7337
|
+
addEmptyRelationships(must(addChange ?? removeChange)),
|
|
7338
|
+
pusher
|
|
7339
|
+
);
|
|
7340
|
+
return;
|
|
7341
|
+
}
|
|
7342
|
+
default:
|
|
7343
|
+
fanOutChangeType;
|
|
7344
|
+
}
|
|
7345
|
+
}
|
|
7346
|
+
function mergeRelationships(left, right) {
|
|
7347
|
+
if (left.type === right.type) {
|
|
7348
|
+
switch (left.type) {
|
|
7349
|
+
case "add": {
|
|
7350
|
+
return {
|
|
7351
|
+
type: "add",
|
|
7352
|
+
node: {
|
|
7353
|
+
row: left.node.row,
|
|
7354
|
+
relationships: {
|
|
7355
|
+
...right.node.relationships,
|
|
7356
|
+
...left.node.relationships
|
|
7357
|
+
}
|
|
7358
|
+
}
|
|
7359
|
+
};
|
|
7360
|
+
}
|
|
7361
|
+
case "remove": {
|
|
7362
|
+
return {
|
|
7363
|
+
type: "remove",
|
|
7364
|
+
node: {
|
|
7365
|
+
row: left.node.row,
|
|
7366
|
+
relationships: {
|
|
7367
|
+
...right.node.relationships,
|
|
7368
|
+
...left.node.relationships
|
|
7369
|
+
}
|
|
7370
|
+
}
|
|
7371
|
+
};
|
|
7372
|
+
}
|
|
7373
|
+
case "edit": {
|
|
7374
|
+
assert(right.type === "edit");
|
|
7375
|
+
return {
|
|
7376
|
+
type: "edit",
|
|
7377
|
+
node: {
|
|
7378
|
+
row: left.node.row,
|
|
7379
|
+
relationships: {
|
|
7380
|
+
...right.node.relationships,
|
|
7381
|
+
...left.node.relationships
|
|
7382
|
+
}
|
|
7383
|
+
},
|
|
7384
|
+
oldNode: {
|
|
7385
|
+
row: left.oldNode.row,
|
|
7386
|
+
relationships: {
|
|
7387
|
+
...right.oldNode.relationships,
|
|
7388
|
+
...left.oldNode.relationships
|
|
7389
|
+
}
|
|
7390
|
+
}
|
|
7391
|
+
};
|
|
7392
|
+
}
|
|
7393
|
+
}
|
|
7394
|
+
}
|
|
7395
|
+
assert(left.type === "edit");
|
|
7396
|
+
switch (right.type) {
|
|
7397
|
+
case "add": {
|
|
7398
|
+
return {
|
|
7399
|
+
type: "edit",
|
|
7400
|
+
node: {
|
|
7401
|
+
...left.node,
|
|
7402
|
+
relationships: {
|
|
7403
|
+
...right.node.relationships,
|
|
7404
|
+
...left.node.relationships
|
|
7405
|
+
}
|
|
7406
|
+
},
|
|
7407
|
+
oldNode: left.oldNode
|
|
7408
|
+
};
|
|
7409
|
+
}
|
|
7410
|
+
case "remove": {
|
|
7411
|
+
return {
|
|
7412
|
+
type: "edit",
|
|
7413
|
+
node: left.node,
|
|
7414
|
+
oldNode: {
|
|
7415
|
+
...left.oldNode,
|
|
7416
|
+
relationships: {
|
|
7417
|
+
...right.node.relationships,
|
|
7418
|
+
...left.oldNode.relationships
|
|
7419
|
+
}
|
|
7420
|
+
}
|
|
7421
|
+
};
|
|
7422
|
+
}
|
|
7423
|
+
}
|
|
7424
|
+
unreachable();
|
|
7425
|
+
}
|
|
7426
|
+
function makeAddEmptyRelationships(schema) {
|
|
7427
|
+
return (change) => {
|
|
7428
|
+
if (Object.keys(schema.relationships).length === 0) {
|
|
7429
|
+
return change;
|
|
7430
|
+
}
|
|
7431
|
+
switch (change.type) {
|
|
7432
|
+
case "add":
|
|
7433
|
+
case "remove": {
|
|
7434
|
+
const ret = {
|
|
7435
|
+
...change,
|
|
7436
|
+
node: {
|
|
7437
|
+
...change.node,
|
|
7438
|
+
relationships: {
|
|
7439
|
+
...change.node.relationships
|
|
7440
|
+
}
|
|
7441
|
+
}
|
|
7442
|
+
};
|
|
7443
|
+
mergeEmpty(ret.node.relationships, Object.keys(schema.relationships));
|
|
7444
|
+
return ret;
|
|
7445
|
+
}
|
|
7446
|
+
case "edit": {
|
|
7447
|
+
const ret = {
|
|
7448
|
+
...change,
|
|
7449
|
+
node: {
|
|
7450
|
+
...change.node,
|
|
7451
|
+
relationships: {
|
|
7452
|
+
...change.node.relationships
|
|
7453
|
+
}
|
|
7454
|
+
},
|
|
7455
|
+
oldNode: {
|
|
7456
|
+
...change.oldNode,
|
|
7457
|
+
relationships: {
|
|
7458
|
+
...change.oldNode.relationships
|
|
7459
|
+
}
|
|
7460
|
+
}
|
|
7461
|
+
};
|
|
7462
|
+
mergeEmpty(ret.node.relationships, Object.keys(schema.relationships));
|
|
7463
|
+
mergeEmpty(
|
|
7464
|
+
ret.oldNode.relationships,
|
|
7465
|
+
Object.keys(schema.relationships)
|
|
7466
|
+
);
|
|
7467
|
+
return ret;
|
|
7468
|
+
}
|
|
7469
|
+
case "child":
|
|
7470
|
+
return change;
|
|
7471
|
+
}
|
|
7472
|
+
};
|
|
7473
|
+
}
|
|
7474
|
+
function mergeEmpty(relationships, relationshipNames) {
|
|
7475
|
+
for (const relName of relationshipNames) {
|
|
7476
|
+
if (relationships[relName] === void 0) {
|
|
7477
|
+
relationships[relName] = () => emptyArray;
|
|
7478
|
+
}
|
|
7479
|
+
}
|
|
7480
|
+
}
|
|
7481
|
+
|
|
7482
|
+
// ../zql/src/ivm/fan-in.ts
|
|
7483
|
+
var FanIn = class {
|
|
7484
|
+
#inputs;
|
|
7485
|
+
#schema;
|
|
7486
|
+
#output = throwFilterOutput;
|
|
7487
|
+
#accumulatedPushes = [];
|
|
7488
|
+
constructor(fanOut, inputs) {
|
|
7489
|
+
this.#inputs = inputs;
|
|
7490
|
+
this.#schema = fanOut.getSchema();
|
|
7491
|
+
for (const input of inputs) {
|
|
7492
|
+
input.setFilterOutput(this);
|
|
7493
|
+
assert(this.#schema === input.getSchema(), `Schema mismatch in fan-in`);
|
|
7494
|
+
}
|
|
7495
|
+
}
|
|
7496
|
+
setFilterOutput(output) {
|
|
7497
|
+
this.#output = output;
|
|
7498
|
+
}
|
|
7499
|
+
destroy() {
|
|
7500
|
+
for (const input of this.#inputs) {
|
|
7501
|
+
input.destroy();
|
|
7502
|
+
}
|
|
7503
|
+
}
|
|
7504
|
+
getSchema() {
|
|
7505
|
+
return this.#schema;
|
|
7506
|
+
}
|
|
7507
|
+
filter(node, cleanup) {
|
|
7508
|
+
return this.#output.filter(node, cleanup);
|
|
7509
|
+
}
|
|
7510
|
+
push(change) {
|
|
7511
|
+
this.#accumulatedPushes.push(change);
|
|
7512
|
+
}
|
|
7513
|
+
fanOutDonePushingToAllBranches(fanOutChangeType) {
|
|
7514
|
+
if (this.#inputs.length === 0) {
|
|
7515
|
+
assert(
|
|
7516
|
+
this.#accumulatedPushes.length === 0,
|
|
7517
|
+
"If there are no inputs then fan-in should not receive any pushes."
|
|
7518
|
+
);
|
|
7519
|
+
return;
|
|
7520
|
+
}
|
|
7521
|
+
pushAccumulatedChanges(
|
|
7522
|
+
this.#accumulatedPushes,
|
|
7523
|
+
this.#output,
|
|
7524
|
+
this,
|
|
7525
|
+
fanOutChangeType,
|
|
7526
|
+
identity,
|
|
7527
|
+
identity
|
|
7528
|
+
);
|
|
7529
|
+
}
|
|
7530
|
+
};
|
|
7531
|
+
|
|
7532
|
+
// ../zql/src/ivm/fan-out.ts
|
|
7533
|
+
var FanOut = class {
|
|
7534
|
+
#input;
|
|
7535
|
+
#outputs = [];
|
|
7536
|
+
#fanIn;
|
|
7537
|
+
#destroyCount = 0;
|
|
7538
|
+
constructor(input) {
|
|
7539
|
+
this.#input = input;
|
|
7540
|
+
input.setFilterOutput(this);
|
|
7541
|
+
}
|
|
7542
|
+
setFanIn(fanIn) {
|
|
7543
|
+
this.#fanIn = fanIn;
|
|
7544
|
+
}
|
|
7545
|
+
setFilterOutput(output) {
|
|
7546
|
+
this.#outputs.push(output);
|
|
7547
|
+
}
|
|
7548
|
+
destroy() {
|
|
7549
|
+
if (this.#destroyCount < this.#outputs.length) {
|
|
7550
|
+
++this.#destroyCount;
|
|
7551
|
+
if (this.#destroyCount === this.#outputs.length) {
|
|
7552
|
+
this.#input.destroy();
|
|
7553
|
+
}
|
|
7554
|
+
} else {
|
|
7555
|
+
throw new Error("FanOut already destroyed once for each output");
|
|
7556
|
+
}
|
|
7557
|
+
}
|
|
7558
|
+
getSchema() {
|
|
7559
|
+
return this.#input.getSchema();
|
|
7560
|
+
}
|
|
7561
|
+
filter(node, cleanup) {
|
|
7562
|
+
let result = false;
|
|
7563
|
+
for (const output of this.#outputs) {
|
|
7564
|
+
result = output.filter(node, cleanup) || result;
|
|
7565
|
+
if (!cleanup && result) {
|
|
7566
|
+
return true;
|
|
7567
|
+
}
|
|
7568
|
+
}
|
|
7569
|
+
return result;
|
|
7570
|
+
}
|
|
7571
|
+
push(change) {
|
|
7572
|
+
for (const out of this.#outputs) {
|
|
7573
|
+
out.push(change, this);
|
|
7574
|
+
}
|
|
7575
|
+
must(
|
|
7576
|
+
this.#fanIn,
|
|
7577
|
+
"fan-out must have a corresponding fan-in set!"
|
|
7578
|
+
).fanOutDonePushingToAllBranches(change.type);
|
|
7579
|
+
}
|
|
7580
|
+
};
|
|
7581
|
+
|
|
7582
|
+
// ../zql/src/ivm/maybe-split-and-push-edit-change.ts
|
|
7583
|
+
function maybeSplitAndPushEditChange(change, predicate, output, pusher) {
|
|
7584
|
+
const oldWasPresent = predicate(change.oldNode.row);
|
|
7585
|
+
const newIsPresent = predicate(change.node.row);
|
|
7586
|
+
if (oldWasPresent && newIsPresent) {
|
|
7587
|
+
output.push(change, pusher);
|
|
7588
|
+
} else if (oldWasPresent && !newIsPresent) {
|
|
7589
|
+
output.push(
|
|
7590
|
+
{
|
|
7591
|
+
type: "remove",
|
|
7592
|
+
node: change.oldNode
|
|
7593
|
+
},
|
|
7594
|
+
pusher
|
|
7595
|
+
);
|
|
7596
|
+
} else if (!oldWasPresent && newIsPresent) {
|
|
7597
|
+
output.push(
|
|
7598
|
+
{
|
|
7599
|
+
type: "add",
|
|
7600
|
+
node: change.node
|
|
7601
|
+
},
|
|
7602
|
+
pusher
|
|
7603
|
+
);
|
|
7604
|
+
}
|
|
7605
|
+
}
|
|
7606
|
+
|
|
7607
|
+
// ../zql/src/ivm/filter-push.ts
|
|
7608
|
+
function filterPush(change, output, pusher, predicate) {
|
|
7609
|
+
if (!predicate) {
|
|
7610
|
+
output.push(change, pusher);
|
|
7611
|
+
return;
|
|
7612
|
+
}
|
|
7613
|
+
switch (change.type) {
|
|
7614
|
+
case "add":
|
|
7615
|
+
case "remove":
|
|
7616
|
+
if (predicate(change.node.row)) {
|
|
7617
|
+
output.push(change, pusher);
|
|
7618
|
+
}
|
|
7619
|
+
break;
|
|
7620
|
+
case "child":
|
|
7621
|
+
if (predicate(change.node.row)) {
|
|
7622
|
+
output.push(change, pusher);
|
|
7623
|
+
}
|
|
7624
|
+
break;
|
|
7625
|
+
case "edit":
|
|
7626
|
+
maybeSplitAndPushEditChange(change, predicate, output, pusher);
|
|
7627
|
+
break;
|
|
7628
|
+
default:
|
|
7629
|
+
unreachable(change);
|
|
7630
|
+
}
|
|
7631
|
+
}
|
|
7632
|
+
|
|
7633
|
+
// ../zql/src/ivm/filter.ts
|
|
7634
|
+
var Filter = class {
|
|
7635
|
+
#input;
|
|
7636
|
+
#predicate;
|
|
7637
|
+
#output = throwFilterOutput;
|
|
7638
|
+
constructor(input, predicate) {
|
|
7639
|
+
this.#input = input;
|
|
7640
|
+
this.#predicate = predicate;
|
|
7641
|
+
input.setFilterOutput(this);
|
|
7642
|
+
}
|
|
7643
|
+
filter(node, cleanup) {
|
|
7644
|
+
return this.#predicate(node.row) && this.#output.filter(node, cleanup);
|
|
7645
|
+
}
|
|
7646
|
+
setFilterOutput(output) {
|
|
7647
|
+
this.#output = output;
|
|
7648
|
+
}
|
|
7649
|
+
destroy() {
|
|
7650
|
+
this.#input.destroy();
|
|
7651
|
+
}
|
|
7652
|
+
getSchema() {
|
|
7653
|
+
return this.#input.getSchema();
|
|
7654
|
+
}
|
|
7655
|
+
push(change) {
|
|
7656
|
+
filterPush(change, this.#output, this, this.#predicate);
|
|
7657
|
+
}
|
|
7658
|
+
};
|
|
7659
|
+
|
|
7660
|
+
// ../zql/src/ivm/constraint.ts
|
|
7661
|
+
function constraintMatchesRow(constraint, row) {
|
|
7662
|
+
for (const key in constraint) {
|
|
7663
|
+
if (!valuesEqual(row[key], constraint[key])) {
|
|
7664
|
+
return false;
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
return true;
|
|
7668
|
+
}
|
|
7669
|
+
function constraintsAreCompatible(left, right) {
|
|
7670
|
+
for (const key in left) {
|
|
7671
|
+
if (key in right && !valuesEqual(left[key], right[key])) {
|
|
7672
|
+
return false;
|
|
7673
|
+
}
|
|
7674
|
+
}
|
|
7675
|
+
return true;
|
|
7676
|
+
}
|
|
7677
|
+
function constraintMatchesPrimaryKey(constraint, primary) {
|
|
7678
|
+
const constraintKeys = Object.keys(constraint);
|
|
7679
|
+
if (constraintKeys.length !== primary.length) {
|
|
7680
|
+
return false;
|
|
7681
|
+
}
|
|
7682
|
+
constraintKeys.sort(stringCompare);
|
|
7683
|
+
for (let i = 0; i < constraintKeys.length; i++) {
|
|
7684
|
+
if (constraintKeys[i] !== primary[i]) {
|
|
7685
|
+
return false;
|
|
7686
|
+
}
|
|
7687
|
+
}
|
|
7688
|
+
return true;
|
|
7689
|
+
}
|
|
7690
|
+
function pullSimpleAndComponents(condition) {
|
|
7691
|
+
if (condition.type === "and") {
|
|
7692
|
+
return condition.conditions.flatMap(pullSimpleAndComponents);
|
|
7693
|
+
}
|
|
7694
|
+
if (condition.type === "simple") {
|
|
7695
|
+
return [condition];
|
|
7696
|
+
}
|
|
7697
|
+
if (condition.type === "or" && condition.conditions.length === 1) {
|
|
7698
|
+
return pullSimpleAndComponents(condition.conditions[0]);
|
|
7699
|
+
}
|
|
7700
|
+
return [];
|
|
7701
|
+
}
|
|
7702
|
+
function primaryKeyConstraintFromFilters(condition, primary) {
|
|
7703
|
+
if (condition === void 0) {
|
|
7704
|
+
return void 0;
|
|
7705
|
+
}
|
|
7706
|
+
const conditions = pullSimpleAndComponents(condition);
|
|
7707
|
+
if (conditions.length === 0) {
|
|
7708
|
+
return void 0;
|
|
7709
|
+
}
|
|
7710
|
+
const ret = {};
|
|
7711
|
+
for (const subCondition of conditions) {
|
|
7712
|
+
if (subCondition.op === "=") {
|
|
7713
|
+
const column = extractColumn(subCondition);
|
|
7714
|
+
if (column !== void 0) {
|
|
7715
|
+
if (!primary.includes(column.name)) {
|
|
7716
|
+
continue;
|
|
7717
|
+
}
|
|
7718
|
+
ret[column.name] = column.value;
|
|
7719
|
+
}
|
|
7720
|
+
}
|
|
7721
|
+
}
|
|
7722
|
+
if (Object.keys(ret).length !== primary.length) {
|
|
7723
|
+
return void 0;
|
|
7724
|
+
}
|
|
7725
|
+
return ret;
|
|
7726
|
+
}
|
|
7727
|
+
function extractColumn(condition) {
|
|
7728
|
+
if (condition.left.type === "column") {
|
|
7729
|
+
assert(condition.right.type === "literal");
|
|
7730
|
+
return { name: condition.left.name, value: condition.right.value };
|
|
7731
|
+
}
|
|
7732
|
+
return void 0;
|
|
7733
|
+
}
|
|
7734
|
+
|
|
7735
|
+
// ../zql/src/ivm/join-utils.ts
|
|
7736
|
+
function* generateWithOverlay(stream, overlay, schema) {
|
|
7737
|
+
let applied = false;
|
|
7738
|
+
let editOldApplied = false;
|
|
7739
|
+
let editNewApplied = false;
|
|
7740
|
+
for (const node of stream) {
|
|
7741
|
+
let yieldNode = true;
|
|
7742
|
+
if (!applied) {
|
|
7743
|
+
switch (overlay.type) {
|
|
7744
|
+
case "add": {
|
|
7745
|
+
if (schema.compareRows(overlay.node.row, node.row) === 0) {
|
|
7746
|
+
applied = true;
|
|
7747
|
+
yieldNode = false;
|
|
7748
|
+
}
|
|
7749
|
+
break;
|
|
7750
|
+
}
|
|
7751
|
+
case "remove": {
|
|
7752
|
+
if (schema.compareRows(overlay.node.row, node.row) < 0) {
|
|
7753
|
+
applied = true;
|
|
7754
|
+
yield overlay.node;
|
|
7755
|
+
}
|
|
7756
|
+
break;
|
|
7757
|
+
}
|
|
7758
|
+
case "edit": {
|
|
7759
|
+
if (!editOldApplied && schema.compareRows(overlay.oldNode.row, node.row) < 0) {
|
|
7760
|
+
editOldApplied = true;
|
|
7761
|
+
if (editNewApplied) {
|
|
7762
|
+
applied = true;
|
|
7763
|
+
}
|
|
7764
|
+
yield overlay.oldNode;
|
|
7765
|
+
}
|
|
7766
|
+
if (!editNewApplied && schema.compareRows(overlay.node.row, node.row) === 0) {
|
|
7767
|
+
editNewApplied = true;
|
|
7768
|
+
if (editOldApplied) {
|
|
7769
|
+
applied = true;
|
|
7770
|
+
}
|
|
7771
|
+
yieldNode = false;
|
|
7772
|
+
}
|
|
7773
|
+
break;
|
|
7774
|
+
}
|
|
7775
|
+
case "child": {
|
|
7776
|
+
if (schema.compareRows(overlay.node.row, node.row) === 0) {
|
|
7777
|
+
applied = true;
|
|
7778
|
+
yield {
|
|
7779
|
+
row: node.row,
|
|
7780
|
+
relationships: {
|
|
7781
|
+
...node.relationships,
|
|
7782
|
+
[overlay.child.relationshipName]: () => generateWithOverlay(
|
|
7783
|
+
node.relationships[overlay.child.relationshipName](),
|
|
7784
|
+
overlay.child.change,
|
|
7785
|
+
schema.relationships[overlay.child.relationshipName]
|
|
7786
|
+
)
|
|
7787
|
+
}
|
|
7788
|
+
};
|
|
7789
|
+
yieldNode = false;
|
|
7790
|
+
}
|
|
7791
|
+
break;
|
|
7792
|
+
}
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
if (yieldNode) {
|
|
7796
|
+
yield node;
|
|
7797
|
+
}
|
|
7798
|
+
}
|
|
7799
|
+
if (!applied) {
|
|
7800
|
+
if (overlay.type === "remove") {
|
|
7801
|
+
applied = true;
|
|
7802
|
+
yield overlay.node;
|
|
7803
|
+
} else if (overlay.type === "edit") {
|
|
7804
|
+
assert(editNewApplied);
|
|
7805
|
+
editOldApplied = true;
|
|
7806
|
+
applied = true;
|
|
7807
|
+
yield overlay.oldNode;
|
|
7808
|
+
}
|
|
7809
|
+
}
|
|
7810
|
+
assert(applied);
|
|
7811
|
+
}
|
|
7812
|
+
function rowEqualsForCompoundKey(a, b, key) {
|
|
7813
|
+
for (let i = 0; i < key.length; i++) {
|
|
7814
|
+
if (compareValues(a[key[i]], b[key[i]]) !== 0) {
|
|
7815
|
+
return false;
|
|
7816
|
+
}
|
|
7817
|
+
}
|
|
7818
|
+
return true;
|
|
7819
|
+
}
|
|
7820
|
+
function isJoinMatch(parent, parentKey, child, childKey) {
|
|
7821
|
+
for (let i = 0; i < parentKey.length; i++) {
|
|
7822
|
+
if (!valuesEqual(parent[parentKey[i]], child[childKey[i]])) {
|
|
7823
|
+
return false;
|
|
7824
|
+
}
|
|
7825
|
+
}
|
|
7826
|
+
return true;
|
|
7827
|
+
}
|
|
7828
|
+
|
|
7829
|
+
// ../zql/src/ivm/flipped-join.ts
|
|
7830
|
+
var FlippedJoin = class {
|
|
7831
|
+
#parent;
|
|
7832
|
+
#child;
|
|
7833
|
+
#parentKey;
|
|
7834
|
+
#childKey;
|
|
7835
|
+
#relationshipName;
|
|
7836
|
+
#schema;
|
|
7837
|
+
#output = throwOutput;
|
|
7838
|
+
#inprogressChildChange;
|
|
7839
|
+
constructor({
|
|
7840
|
+
parent,
|
|
7841
|
+
child,
|
|
7842
|
+
parentKey,
|
|
7843
|
+
childKey,
|
|
7844
|
+
relationshipName,
|
|
7845
|
+
hidden,
|
|
7846
|
+
system
|
|
7847
|
+
}) {
|
|
7848
|
+
assert(parent !== child, "Parent and child must be different operators");
|
|
7849
|
+
assert(
|
|
7850
|
+
parentKey.length === childKey.length,
|
|
7851
|
+
"The parentKey and childKey keys must have same length"
|
|
7852
|
+
);
|
|
7853
|
+
this.#parent = parent;
|
|
7854
|
+
this.#child = child;
|
|
7855
|
+
this.#parentKey = parentKey;
|
|
7856
|
+
this.#childKey = childKey;
|
|
7857
|
+
this.#relationshipName = relationshipName;
|
|
7858
|
+
const parentSchema = parent.getSchema();
|
|
7859
|
+
const childSchema = child.getSchema();
|
|
7860
|
+
this.#schema = {
|
|
7861
|
+
...parentSchema,
|
|
7862
|
+
relationships: {
|
|
7863
|
+
...parentSchema.relationships,
|
|
7864
|
+
[relationshipName]: {
|
|
7865
|
+
...childSchema,
|
|
7866
|
+
isHidden: hidden,
|
|
7867
|
+
system
|
|
7868
|
+
}
|
|
7869
|
+
}
|
|
7870
|
+
};
|
|
7871
|
+
parent.setOutput({
|
|
7872
|
+
push: (change) => this.#pushParent(change)
|
|
7873
|
+
});
|
|
7874
|
+
child.setOutput({
|
|
7875
|
+
push: (change) => this.#pushChild(change)
|
|
7876
|
+
});
|
|
7877
|
+
}
|
|
7878
|
+
destroy() {
|
|
7879
|
+
this.#child.destroy();
|
|
7880
|
+
this.#parent.destroy();
|
|
7881
|
+
}
|
|
7882
|
+
setOutput(output) {
|
|
7883
|
+
this.#output = output;
|
|
7884
|
+
}
|
|
7885
|
+
getSchema() {
|
|
7886
|
+
return this.#schema;
|
|
7887
|
+
}
|
|
7888
|
+
// TODO: When parentKey is the parent's primary key (or more
|
|
7889
|
+
// generally when the parent cardinality is expected to be small) a different
|
|
7890
|
+
// algorithm should be used: For each child node, fetch all parent nodes
|
|
7891
|
+
// eagerly and then sort using quicksort.
|
|
7892
|
+
*fetch(req) {
|
|
7893
|
+
const childNodes = [...this.#child.fetch({})];
|
|
7894
|
+
if (this.#inprogressChildChange?.change.type === "remove") {
|
|
7895
|
+
const removedNode = this.#inprogressChildChange.change.node;
|
|
7896
|
+
const compare2 = this.#child.getSchema().compareRows;
|
|
7897
|
+
const insertPos = binarySearch(
|
|
7898
|
+
childNodes.length,
|
|
7899
|
+
(i) => compare2(removedNode.row, childNodes[i].row)
|
|
7900
|
+
);
|
|
7901
|
+
childNodes.splice(insertPos, 0, removedNode);
|
|
7902
|
+
}
|
|
7903
|
+
const parentIterators = [];
|
|
7904
|
+
let threw = false;
|
|
7905
|
+
try {
|
|
7906
|
+
for (const childNode of childNodes) {
|
|
7907
|
+
const constraintFromChild = {};
|
|
7908
|
+
for (let i = 0; i < this.#parentKey.length; i++) {
|
|
7909
|
+
constraintFromChild[this.#parentKey[i]] = childNode.row[this.#childKey[i]];
|
|
7910
|
+
}
|
|
7911
|
+
if (req.constraint && !constraintsAreCompatible(constraintFromChild, req.constraint)) {
|
|
7912
|
+
parentIterators.push(emptyArray[Symbol.iterator]());
|
|
7913
|
+
} else {
|
|
7914
|
+
const stream = this.#parent.fetch({
|
|
7915
|
+
...req,
|
|
7916
|
+
constraint: {
|
|
7917
|
+
...req.constraint,
|
|
7918
|
+
...constraintFromChild
|
|
7919
|
+
}
|
|
7920
|
+
});
|
|
7921
|
+
const iterator2 = stream[Symbol.iterator]();
|
|
7922
|
+
parentIterators.push(iterator2);
|
|
7923
|
+
}
|
|
7924
|
+
}
|
|
7925
|
+
const nextParentNodes = [];
|
|
7926
|
+
for (let i = 0; i < parentIterators.length; i++) {
|
|
7927
|
+
const iter = parentIterators[i];
|
|
7928
|
+
const result = iter.next();
|
|
7929
|
+
nextParentNodes[i] = result.done ? null : result.value;
|
|
7930
|
+
}
|
|
7931
|
+
while (true) {
|
|
7932
|
+
let minParentNode = null;
|
|
7933
|
+
let minParentNodeChildIndexes = [];
|
|
7934
|
+
for (let i = 0; i < nextParentNodes.length; i++) {
|
|
7935
|
+
const parentNode = nextParentNodes[i];
|
|
7936
|
+
if (parentNode === null) {
|
|
7937
|
+
continue;
|
|
7938
|
+
}
|
|
7939
|
+
if (minParentNode === null) {
|
|
7940
|
+
minParentNode = parentNode;
|
|
7941
|
+
minParentNodeChildIndexes.push(i);
|
|
7942
|
+
} else {
|
|
7943
|
+
const compareResult = this.#schema.compareRows(parentNode.row, minParentNode.row) * (req.reverse ? -1 : 1);
|
|
7944
|
+
if (compareResult === 0) {
|
|
7945
|
+
minParentNodeChildIndexes.push(i);
|
|
7946
|
+
} else if (compareResult < 0) {
|
|
7947
|
+
minParentNode = parentNode;
|
|
7948
|
+
minParentNodeChildIndexes = [i];
|
|
7949
|
+
}
|
|
7950
|
+
}
|
|
7951
|
+
}
|
|
7952
|
+
if (minParentNode === null) {
|
|
7953
|
+
return;
|
|
7954
|
+
}
|
|
7955
|
+
const relatedChildNodes = [];
|
|
7956
|
+
for (const minParentNodeChildIndex of minParentNodeChildIndexes) {
|
|
7957
|
+
relatedChildNodes.push(childNodes[minParentNodeChildIndex]);
|
|
7958
|
+
const iter = parentIterators[minParentNodeChildIndex];
|
|
7959
|
+
const result = iter.next();
|
|
7960
|
+
nextParentNodes[minParentNodeChildIndex] = result.done ? null : result.value;
|
|
7961
|
+
}
|
|
7962
|
+
let overlaidRelatedChildNodes = relatedChildNodes;
|
|
7963
|
+
if (this.#inprogressChildChange && this.#inprogressChildChange.position && isJoinMatch(
|
|
7964
|
+
this.#inprogressChildChange.change.node.row,
|
|
7965
|
+
this.#childKey,
|
|
7966
|
+
minParentNode.row,
|
|
7967
|
+
this.#parentKey
|
|
7968
|
+
)) {
|
|
7969
|
+
const hasInprogressChildChangeBeenPushedForMinParentNode = this.#parent.getSchema().compareRows(
|
|
7970
|
+
minParentNode.row,
|
|
7971
|
+
this.#inprogressChildChange.position
|
|
7972
|
+
) <= 0;
|
|
7973
|
+
if (this.#inprogressChildChange.change.type === "remove") {
|
|
7974
|
+
if (hasInprogressChildChangeBeenPushedForMinParentNode) {
|
|
7975
|
+
overlaidRelatedChildNodes = relatedChildNodes.filter(
|
|
7976
|
+
(n) => n !== this.#inprogressChildChange?.change.node
|
|
7977
|
+
);
|
|
7978
|
+
}
|
|
7979
|
+
} else if (!hasInprogressChildChangeBeenPushedForMinParentNode) {
|
|
7980
|
+
overlaidRelatedChildNodes = [
|
|
7981
|
+
...generateWithOverlay(
|
|
7982
|
+
relatedChildNodes,
|
|
7983
|
+
this.#inprogressChildChange.change,
|
|
7984
|
+
this.#child.getSchema()
|
|
7985
|
+
)
|
|
7986
|
+
];
|
|
7987
|
+
}
|
|
7988
|
+
}
|
|
7989
|
+
if (overlaidRelatedChildNodes.length > 0) {
|
|
7990
|
+
yield {
|
|
7991
|
+
...minParentNode,
|
|
7992
|
+
relationships: {
|
|
7993
|
+
...minParentNode.relationships,
|
|
7994
|
+
[this.#relationshipName]: () => overlaidRelatedChildNodes
|
|
7995
|
+
}
|
|
7996
|
+
};
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7999
|
+
} catch (e) {
|
|
8000
|
+
threw = true;
|
|
8001
|
+
for (const iter of parentIterators) {
|
|
8002
|
+
try {
|
|
8003
|
+
iter.throw?.(e);
|
|
8004
|
+
} catch (_cleanupError) {
|
|
8005
|
+
}
|
|
8006
|
+
}
|
|
8007
|
+
throw e;
|
|
8008
|
+
} finally {
|
|
8009
|
+
if (!threw) {
|
|
8010
|
+
for (const iter of parentIterators) {
|
|
8011
|
+
try {
|
|
8012
|
+
iter.return?.();
|
|
8013
|
+
} catch (_cleanupError) {
|
|
8014
|
+
}
|
|
8015
|
+
}
|
|
8016
|
+
}
|
|
8017
|
+
}
|
|
8018
|
+
}
|
|
8019
|
+
*cleanup(_req) {
|
|
8020
|
+
}
|
|
8021
|
+
#pushChild(change) {
|
|
8022
|
+
const pushChildChange = (exists) => {
|
|
8023
|
+
this.#inprogressChildChange = {
|
|
8024
|
+
change,
|
|
8025
|
+
position: void 0
|
|
8026
|
+
};
|
|
8027
|
+
try {
|
|
8028
|
+
const parentNodeStream = this.#parent.fetch({
|
|
8029
|
+
constraint: Object.fromEntries(
|
|
8030
|
+
this.#parentKey.map((key, i) => [
|
|
8031
|
+
key,
|
|
8032
|
+
change.node.row[this.#childKey[i]]
|
|
8033
|
+
])
|
|
8034
|
+
)
|
|
8035
|
+
});
|
|
8036
|
+
for (const parentNode of parentNodeStream) {
|
|
8037
|
+
this.#inprogressChildChange = {
|
|
8038
|
+
change,
|
|
8039
|
+
position: parentNode.row
|
|
8040
|
+
};
|
|
8041
|
+
const childNodeStream = () => this.#child.fetch({
|
|
8042
|
+
constraint: Object.fromEntries(
|
|
8043
|
+
this.#childKey.map((key, i) => [
|
|
8044
|
+
key,
|
|
8045
|
+
parentNode.row[this.#parentKey[i]]
|
|
8046
|
+
])
|
|
8047
|
+
)
|
|
8048
|
+
});
|
|
8049
|
+
if (!exists) {
|
|
8050
|
+
for (const childNode of childNodeStream()) {
|
|
8051
|
+
if (this.#child.getSchema().compareRows(childNode.row, change.node.row) !== 0) {
|
|
8052
|
+
exists = true;
|
|
8053
|
+
break;
|
|
8054
|
+
}
|
|
8055
|
+
}
|
|
8056
|
+
}
|
|
8057
|
+
if (exists) {
|
|
8058
|
+
this.#output.push(
|
|
8059
|
+
{
|
|
8060
|
+
type: "child",
|
|
8061
|
+
node: {
|
|
8062
|
+
...parentNode,
|
|
8063
|
+
relationships: {
|
|
8064
|
+
...parentNode.relationships,
|
|
8065
|
+
[this.#relationshipName]: childNodeStream
|
|
8066
|
+
}
|
|
8067
|
+
},
|
|
8068
|
+
child: {
|
|
8069
|
+
relationshipName: this.#relationshipName,
|
|
8070
|
+
change
|
|
8071
|
+
}
|
|
8072
|
+
},
|
|
8073
|
+
this
|
|
8074
|
+
);
|
|
8075
|
+
} else {
|
|
8076
|
+
this.#output.push(
|
|
8077
|
+
{
|
|
8078
|
+
...change,
|
|
8079
|
+
node: {
|
|
8080
|
+
...parentNode,
|
|
8081
|
+
relationships: {
|
|
8082
|
+
...parentNode.relationships,
|
|
8083
|
+
[this.#relationshipName]: () => [change.node]
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
},
|
|
8087
|
+
this
|
|
8088
|
+
);
|
|
8089
|
+
}
|
|
8090
|
+
}
|
|
8091
|
+
} finally {
|
|
8092
|
+
this.#inprogressChildChange = void 0;
|
|
8093
|
+
}
|
|
8094
|
+
};
|
|
8095
|
+
switch (change.type) {
|
|
8096
|
+
case "add":
|
|
8097
|
+
case "remove":
|
|
8098
|
+
pushChildChange();
|
|
8099
|
+
break;
|
|
8100
|
+
case "edit": {
|
|
8101
|
+
assert(
|
|
8102
|
+
rowEqualsForCompoundKey(
|
|
8103
|
+
change.oldNode.row,
|
|
8104
|
+
change.node.row,
|
|
8105
|
+
this.#childKey
|
|
8106
|
+
),
|
|
8107
|
+
`Child edit must not change relationship.`
|
|
8108
|
+
);
|
|
8109
|
+
pushChildChange(true);
|
|
8110
|
+
break;
|
|
8111
|
+
}
|
|
8112
|
+
case "child":
|
|
8113
|
+
pushChildChange(true);
|
|
8114
|
+
break;
|
|
8115
|
+
}
|
|
8116
|
+
}
|
|
8117
|
+
#pushParent(change) {
|
|
8118
|
+
const childNodeStream = (node) => () => this.#child.fetch({
|
|
8119
|
+
constraint: Object.fromEntries(
|
|
8120
|
+
this.#childKey.map((key, i) => [key, node.row[this.#parentKey[i]]])
|
|
8121
|
+
)
|
|
8122
|
+
});
|
|
8123
|
+
const flip = (node) => ({
|
|
8124
|
+
...node,
|
|
8125
|
+
relationships: {
|
|
8126
|
+
...node.relationships,
|
|
8127
|
+
[this.#relationshipName]: childNodeStream(node)
|
|
8128
|
+
}
|
|
8129
|
+
});
|
|
8130
|
+
if (first(childNodeStream(change.node)()) === void 0) {
|
|
8131
|
+
return;
|
|
8132
|
+
}
|
|
8133
|
+
switch (change.type) {
|
|
8134
|
+
case "add":
|
|
8135
|
+
case "remove":
|
|
8136
|
+
case "child": {
|
|
8137
|
+
this.#output.push(
|
|
8138
|
+
{
|
|
8139
|
+
...change,
|
|
8140
|
+
node: flip(change.node)
|
|
8141
|
+
},
|
|
8142
|
+
this
|
|
8143
|
+
);
|
|
8144
|
+
break;
|
|
8145
|
+
}
|
|
8146
|
+
case "edit": {
|
|
8147
|
+
assert(
|
|
8148
|
+
rowEqualsForCompoundKey(
|
|
8149
|
+
change.oldNode.row,
|
|
8150
|
+
change.node.row,
|
|
8151
|
+
this.#parentKey
|
|
8152
|
+
),
|
|
8153
|
+
`Parent edit must not change relationship.`
|
|
8154
|
+
);
|
|
8155
|
+
this.#output.push(
|
|
8156
|
+
{
|
|
8157
|
+
type: "edit",
|
|
8158
|
+
oldNode: flip(change.oldNode),
|
|
8159
|
+
node: flip(change.node)
|
|
8160
|
+
},
|
|
8161
|
+
this
|
|
8162
|
+
);
|
|
8163
|
+
break;
|
|
8164
|
+
}
|
|
8165
|
+
default:
|
|
8166
|
+
unreachable(change);
|
|
8167
|
+
}
|
|
8168
|
+
}
|
|
8169
|
+
};
|
|
8170
|
+
|
|
8171
|
+
// ../zql/src/ivm/join.ts
|
|
8172
|
+
var Join = class {
|
|
8173
|
+
#parent;
|
|
8174
|
+
#child;
|
|
8175
|
+
#storage;
|
|
8176
|
+
#parentKey;
|
|
8177
|
+
#childKey;
|
|
8178
|
+
#relationshipName;
|
|
8179
|
+
#schema;
|
|
8180
|
+
#output = throwOutput;
|
|
8181
|
+
#inprogressChildChange;
|
|
8182
|
+
constructor({
|
|
8183
|
+
parent,
|
|
8184
|
+
child,
|
|
8185
|
+
storage,
|
|
8186
|
+
parentKey,
|
|
8187
|
+
childKey,
|
|
8188
|
+
relationshipName,
|
|
8189
|
+
hidden,
|
|
8190
|
+
system
|
|
8191
|
+
}) {
|
|
8192
|
+
assert(parent !== child, "Parent and child must be different operators");
|
|
8193
|
+
assert(
|
|
8194
|
+
parentKey.length === childKey.length,
|
|
8195
|
+
"The parentKey and childKey keys must have same length"
|
|
8196
|
+
);
|
|
8197
|
+
this.#parent = parent;
|
|
8198
|
+
this.#child = child;
|
|
8199
|
+
this.#storage = storage;
|
|
8200
|
+
this.#parentKey = parentKey;
|
|
8201
|
+
this.#childKey = childKey;
|
|
8202
|
+
this.#relationshipName = relationshipName;
|
|
8203
|
+
const parentSchema = parent.getSchema();
|
|
8204
|
+
const childSchema = child.getSchema();
|
|
8205
|
+
this.#schema = {
|
|
8206
|
+
...parentSchema,
|
|
8207
|
+
relationships: {
|
|
8208
|
+
...parentSchema.relationships,
|
|
8209
|
+
[relationshipName]: {
|
|
8210
|
+
...childSchema,
|
|
8211
|
+
isHidden: hidden,
|
|
8212
|
+
system
|
|
8213
|
+
}
|
|
8214
|
+
}
|
|
8215
|
+
};
|
|
8216
|
+
parent.setOutput({
|
|
8217
|
+
push: (change) => this.#pushParent(change)
|
|
8218
|
+
});
|
|
8219
|
+
child.setOutput({
|
|
8220
|
+
push: (change) => this.#pushChild(change)
|
|
8221
|
+
});
|
|
8222
|
+
}
|
|
8223
|
+
destroy() {
|
|
8224
|
+
this.#parent.destroy();
|
|
8225
|
+
this.#child.destroy();
|
|
8226
|
+
}
|
|
8227
|
+
setOutput(output) {
|
|
8228
|
+
this.#output = output;
|
|
8229
|
+
}
|
|
8230
|
+
getSchema() {
|
|
8231
|
+
return this.#schema;
|
|
8232
|
+
}
|
|
8233
|
+
*fetch(req) {
|
|
8234
|
+
for (const parentNode of this.#parent.fetch(req)) {
|
|
8235
|
+
yield this.#processParentNode(
|
|
8236
|
+
parentNode.row,
|
|
8237
|
+
parentNode.relationships,
|
|
8238
|
+
"fetch"
|
|
8239
|
+
);
|
|
8240
|
+
}
|
|
8241
|
+
}
|
|
8242
|
+
*cleanup(req) {
|
|
8243
|
+
for (const parentNode of this.#parent.cleanup(req)) {
|
|
8244
|
+
yield this.#processParentNode(
|
|
8245
|
+
parentNode.row,
|
|
8246
|
+
parentNode.relationships,
|
|
8247
|
+
"cleanup"
|
|
8248
|
+
);
|
|
8249
|
+
}
|
|
8250
|
+
}
|
|
8251
|
+
#pushParent(change) {
|
|
8252
|
+
switch (change.type) {
|
|
8253
|
+
case "add":
|
|
8254
|
+
this.#output.push(
|
|
8255
|
+
{
|
|
8256
|
+
type: "add",
|
|
8257
|
+
node: this.#processParentNode(
|
|
8258
|
+
change.node.row,
|
|
8259
|
+
change.node.relationships,
|
|
8260
|
+
"fetch"
|
|
8261
|
+
)
|
|
8262
|
+
},
|
|
8263
|
+
this
|
|
8264
|
+
);
|
|
8265
|
+
break;
|
|
8266
|
+
case "remove":
|
|
8267
|
+
this.#output.push(
|
|
8268
|
+
{
|
|
8269
|
+
type: "remove",
|
|
8270
|
+
node: this.#processParentNode(
|
|
8271
|
+
change.node.row,
|
|
8272
|
+
change.node.relationships,
|
|
8273
|
+
"cleanup"
|
|
8274
|
+
)
|
|
8275
|
+
},
|
|
8276
|
+
this
|
|
8277
|
+
);
|
|
8278
|
+
break;
|
|
8279
|
+
case "child":
|
|
8280
|
+
this.#output.push(
|
|
8281
|
+
{
|
|
8282
|
+
type: "child",
|
|
8283
|
+
node: this.#processParentNode(
|
|
8284
|
+
change.node.row,
|
|
8285
|
+
change.node.relationships,
|
|
8286
|
+
"fetch"
|
|
8287
|
+
),
|
|
8288
|
+
child: change.child
|
|
8289
|
+
},
|
|
8290
|
+
this
|
|
8291
|
+
);
|
|
8292
|
+
break;
|
|
8293
|
+
case "edit": {
|
|
8294
|
+
assert(
|
|
8295
|
+
rowEqualsForCompoundKey(
|
|
8296
|
+
change.oldNode.row,
|
|
8297
|
+
change.node.row,
|
|
8298
|
+
this.#parentKey
|
|
8299
|
+
),
|
|
8300
|
+
`Parent edit must not change relationship.`
|
|
8301
|
+
);
|
|
8302
|
+
this.#output.push(
|
|
8303
|
+
{
|
|
8304
|
+
type: "edit",
|
|
8305
|
+
oldNode: this.#processParentNode(
|
|
8306
|
+
change.oldNode.row,
|
|
8307
|
+
change.oldNode.relationships,
|
|
8308
|
+
"cleanup"
|
|
8309
|
+
),
|
|
8310
|
+
node: this.#processParentNode(
|
|
8311
|
+
change.node.row,
|
|
8312
|
+
change.node.relationships,
|
|
8313
|
+
"fetch"
|
|
8314
|
+
)
|
|
8315
|
+
},
|
|
8316
|
+
this
|
|
8317
|
+
);
|
|
8318
|
+
break;
|
|
8319
|
+
}
|
|
8320
|
+
default:
|
|
8321
|
+
unreachable(change);
|
|
8322
|
+
}
|
|
8323
|
+
}
|
|
8324
|
+
#pushChild(change) {
|
|
8325
|
+
const pushChildChange = (childRow, change2) => {
|
|
8326
|
+
this.#inprogressChildChange = {
|
|
8327
|
+
change: change2,
|
|
8328
|
+
position: void 0
|
|
8329
|
+
};
|
|
8330
|
+
try {
|
|
8331
|
+
const parentNodes = this.#parent.fetch({
|
|
8332
|
+
constraint: Object.fromEntries(
|
|
8333
|
+
this.#parentKey.map((key, i) => [key, childRow[this.#childKey[i]]])
|
|
8334
|
+
)
|
|
8335
|
+
});
|
|
8336
|
+
for (const parentNode of parentNodes) {
|
|
8337
|
+
this.#inprogressChildChange.position = parentNode.row;
|
|
8338
|
+
const childChange = {
|
|
8339
|
+
type: "child",
|
|
8340
|
+
node: this.#processParentNode(
|
|
8341
|
+
parentNode.row,
|
|
8342
|
+
parentNode.relationships,
|
|
8343
|
+
"fetch"
|
|
8344
|
+
),
|
|
8345
|
+
child: {
|
|
8346
|
+
relationshipName: this.#relationshipName,
|
|
8347
|
+
change: change2
|
|
8348
|
+
}
|
|
8349
|
+
};
|
|
8350
|
+
this.#output.push(childChange, this);
|
|
8351
|
+
}
|
|
8352
|
+
} finally {
|
|
8353
|
+
this.#inprogressChildChange = void 0;
|
|
8354
|
+
}
|
|
8355
|
+
};
|
|
8356
|
+
switch (change.type) {
|
|
8357
|
+
case "add":
|
|
8358
|
+
case "remove":
|
|
8359
|
+
pushChildChange(change.node.row, change);
|
|
8360
|
+
break;
|
|
8361
|
+
case "child":
|
|
8362
|
+
pushChildChange(change.node.row, change);
|
|
8363
|
+
break;
|
|
8364
|
+
case "edit": {
|
|
8365
|
+
const childRow = change.node.row;
|
|
8366
|
+
const oldChildRow = change.oldNode.row;
|
|
8367
|
+
assert(
|
|
8368
|
+
rowEqualsForCompoundKey(oldChildRow, childRow, this.#childKey),
|
|
8369
|
+
"Child edit must not change relationship."
|
|
8370
|
+
);
|
|
8371
|
+
pushChildChange(childRow, change);
|
|
8372
|
+
break;
|
|
8373
|
+
}
|
|
8374
|
+
default:
|
|
8375
|
+
unreachable(change);
|
|
8376
|
+
}
|
|
8377
|
+
}
|
|
8378
|
+
#processParentNode(parentNodeRow, parentNodeRelations, mode) {
|
|
8379
|
+
let method = mode;
|
|
8380
|
+
let storageUpdated = false;
|
|
8381
|
+
const childStream = () => {
|
|
8382
|
+
if (!storageUpdated) {
|
|
8383
|
+
if (mode === "cleanup") {
|
|
8384
|
+
this.#storage.del(
|
|
8385
|
+
makeStorageKey(
|
|
8386
|
+
this.#parentKey,
|
|
8387
|
+
this.#parent.getSchema().primaryKey,
|
|
8388
|
+
parentNodeRow
|
|
8389
|
+
)
|
|
8390
|
+
);
|
|
8391
|
+
const empty = [
|
|
8392
|
+
...take(
|
|
8393
|
+
this.#storage.scan({
|
|
8394
|
+
prefix: makeStorageKeyPrefix(parentNodeRow, this.#parentKey)
|
|
8395
|
+
}),
|
|
8396
|
+
1
|
|
8397
|
+
)
|
|
8398
|
+
].length === 0;
|
|
8399
|
+
method = empty ? "cleanup" : "fetch";
|
|
8400
|
+
}
|
|
8401
|
+
storageUpdated = true;
|
|
8402
|
+
if (mode === "fetch") {
|
|
8403
|
+
this.#storage.set(
|
|
8404
|
+
makeStorageKey(
|
|
8405
|
+
this.#parentKey,
|
|
8406
|
+
this.#parent.getSchema().primaryKey,
|
|
8407
|
+
parentNodeRow
|
|
8408
|
+
),
|
|
8409
|
+
true
|
|
8410
|
+
);
|
|
8411
|
+
}
|
|
8412
|
+
}
|
|
8413
|
+
const stream = this.#child[method]({
|
|
8414
|
+
constraint: Object.fromEntries(
|
|
8415
|
+
this.#childKey.map((key, i) => [
|
|
8416
|
+
key,
|
|
8417
|
+
parentNodeRow[this.#parentKey[i]]
|
|
8418
|
+
])
|
|
8419
|
+
)
|
|
8420
|
+
});
|
|
8421
|
+
if (this.#inprogressChildChange && isJoinMatch(
|
|
8422
|
+
parentNodeRow,
|
|
8423
|
+
this.#parentKey,
|
|
8424
|
+
this.#inprogressChildChange.change.node.row,
|
|
8425
|
+
this.#childKey
|
|
8426
|
+
) && this.#inprogressChildChange.position && this.#schema.compareRows(
|
|
8427
|
+
parentNodeRow,
|
|
8428
|
+
this.#inprogressChildChange.position
|
|
8429
|
+
) > 0) {
|
|
8430
|
+
return generateWithOverlay(
|
|
8431
|
+
stream,
|
|
8432
|
+
this.#inprogressChildChange.change,
|
|
8433
|
+
this.#child.getSchema()
|
|
8434
|
+
);
|
|
8435
|
+
}
|
|
8436
|
+
return stream;
|
|
8437
|
+
};
|
|
8438
|
+
return {
|
|
8439
|
+
row: parentNodeRow,
|
|
8440
|
+
relationships: {
|
|
8441
|
+
...parentNodeRelations,
|
|
8442
|
+
[this.#relationshipName]: childStream
|
|
8443
|
+
}
|
|
8444
|
+
};
|
|
8445
|
+
}
|
|
8446
|
+
};
|
|
8447
|
+
function makeStorageKeyForValues(values) {
|
|
8448
|
+
const json2 = JSON.stringify(["pKeySet", ...values]);
|
|
8449
|
+
return json2.substring(1, json2.length - 1) + ",";
|
|
8450
|
+
}
|
|
8451
|
+
function makeStorageKeyPrefix(row, key) {
|
|
8452
|
+
return makeStorageKeyForValues(key.map((k) => row[k]));
|
|
8453
|
+
}
|
|
8454
|
+
function makeStorageKey(key, primaryKey, row) {
|
|
8455
|
+
const values = key.map((k) => row[k]);
|
|
8456
|
+
for (const key2 of primaryKey) {
|
|
8457
|
+
values.push(row[key2]);
|
|
8458
|
+
}
|
|
8459
|
+
return makeStorageKeyForValues(values);
|
|
8460
|
+
}
|
|
8461
|
+
|
|
8462
|
+
// ../zql/src/ivm/skip.ts
|
|
8463
|
+
var Skip = class {
|
|
8464
|
+
#input;
|
|
8465
|
+
#bound;
|
|
8466
|
+
#comparator;
|
|
8467
|
+
#output = throwOutput;
|
|
8468
|
+
constructor(input, bound) {
|
|
8469
|
+
this.#input = input;
|
|
8470
|
+
this.#bound = bound;
|
|
8471
|
+
this.#comparator = input.getSchema().compareRows;
|
|
8472
|
+
input.setOutput(this);
|
|
8473
|
+
}
|
|
8474
|
+
getSchema() {
|
|
8475
|
+
return this.#input.getSchema();
|
|
8476
|
+
}
|
|
8477
|
+
fetch(req) {
|
|
8478
|
+
return this.#fetchOrCleanup("fetch", req);
|
|
8479
|
+
}
|
|
8480
|
+
cleanup(req) {
|
|
8481
|
+
return this.#fetchOrCleanup("fetch", req);
|
|
8482
|
+
}
|
|
8483
|
+
*#fetchOrCleanup(method, req) {
|
|
8484
|
+
const start = this.#getStart(req);
|
|
8485
|
+
if (start === "empty") {
|
|
8486
|
+
return;
|
|
8487
|
+
}
|
|
8488
|
+
const nodes = this.#input[method]({ ...req, start });
|
|
8489
|
+
if (!req.reverse) {
|
|
8490
|
+
yield* nodes;
|
|
8491
|
+
return;
|
|
8492
|
+
}
|
|
8493
|
+
for (const node of nodes) {
|
|
8494
|
+
if (!this.#shouldBePresent(node.row)) {
|
|
8495
|
+
return;
|
|
8496
|
+
}
|
|
8497
|
+
yield node;
|
|
8498
|
+
}
|
|
8499
|
+
}
|
|
8500
|
+
setOutput(output) {
|
|
8501
|
+
this.#output = output;
|
|
8502
|
+
}
|
|
8503
|
+
destroy() {
|
|
8504
|
+
this.#input.destroy();
|
|
8505
|
+
}
|
|
8506
|
+
#shouldBePresent(row) {
|
|
8507
|
+
const cmp2 = this.#comparator(this.#bound.row, row);
|
|
8508
|
+
return cmp2 < 0 || cmp2 === 0 && !this.#bound.exclusive;
|
|
8509
|
+
}
|
|
8510
|
+
push(change) {
|
|
8511
|
+
const shouldBePresent = (row) => this.#shouldBePresent(row);
|
|
8512
|
+
if (change.type === "edit") {
|
|
8513
|
+
maybeSplitAndPushEditChange(change, shouldBePresent, this.#output, this);
|
|
8514
|
+
return;
|
|
8515
|
+
}
|
|
8516
|
+
change;
|
|
8517
|
+
if (shouldBePresent(change.node.row)) {
|
|
8518
|
+
this.#output.push(change, this);
|
|
8519
|
+
}
|
|
8520
|
+
}
|
|
8521
|
+
#getStart(req) {
|
|
8522
|
+
const boundStart = {
|
|
8523
|
+
row: this.#bound.row,
|
|
8524
|
+
basis: this.#bound.exclusive ? "after" : "at"
|
|
8525
|
+
};
|
|
8526
|
+
if (!req.start) {
|
|
8527
|
+
if (req.reverse) {
|
|
8528
|
+
return void 0;
|
|
8529
|
+
}
|
|
8530
|
+
return boundStart;
|
|
8531
|
+
}
|
|
8532
|
+
const cmp2 = this.#comparator(this.#bound.row, req.start.row);
|
|
8533
|
+
if (!req.reverse) {
|
|
8534
|
+
if (cmp2 > 0) {
|
|
8535
|
+
return boundStart;
|
|
8536
|
+
}
|
|
8537
|
+
if (cmp2 === 0) {
|
|
8538
|
+
if (this.#bound.exclusive || req.start.basis === "after") {
|
|
8539
|
+
return {
|
|
8540
|
+
row: this.#bound.row,
|
|
8541
|
+
basis: "after"
|
|
8542
|
+
};
|
|
8543
|
+
}
|
|
8544
|
+
return boundStart;
|
|
8545
|
+
}
|
|
8546
|
+
return req.start;
|
|
8547
|
+
}
|
|
8548
|
+
req.reverse;
|
|
8549
|
+
if (cmp2 > 0) {
|
|
8550
|
+
return "empty";
|
|
8551
|
+
}
|
|
8552
|
+
if (cmp2 === 0) {
|
|
8553
|
+
if (!this.#bound.exclusive && req.start.basis === "at") {
|
|
8554
|
+
return boundStart;
|
|
8555
|
+
}
|
|
8556
|
+
return "empty";
|
|
8557
|
+
}
|
|
8558
|
+
return req.start;
|
|
8559
|
+
}
|
|
8560
|
+
};
|
|
8561
|
+
|
|
8562
|
+
// ../zql/src/ivm/take.ts
|
|
8563
|
+
var MAX_BOUND_KEY = "maxBound";
|
|
8564
|
+
var Take = class {
|
|
8565
|
+
#input;
|
|
8566
|
+
#storage;
|
|
8567
|
+
#limit;
|
|
8568
|
+
#partitionKey;
|
|
8569
|
+
#partitionKeyComparator;
|
|
8570
|
+
// Fetch overlay needed for some split push cases.
|
|
8571
|
+
#rowHiddenFromFetch;
|
|
8572
|
+
#output = throwOutput;
|
|
8573
|
+
constructor(input, storage, limit, partitionKey) {
|
|
8574
|
+
assert(limit >= 0);
|
|
8575
|
+
assertOrderingIncludesPK(
|
|
8576
|
+
input.getSchema().sort,
|
|
8577
|
+
input.getSchema().primaryKey
|
|
8578
|
+
);
|
|
8579
|
+
input.setOutput(this);
|
|
8580
|
+
this.#input = input;
|
|
8581
|
+
this.#storage = storage;
|
|
8582
|
+
this.#limit = limit;
|
|
8583
|
+
this.#partitionKey = partitionKey;
|
|
8584
|
+
this.#partitionKeyComparator = partitionKey && makePartitionKeyComparator(partitionKey);
|
|
8585
|
+
}
|
|
8586
|
+
setOutput(output) {
|
|
8587
|
+
this.#output = output;
|
|
8588
|
+
}
|
|
8589
|
+
getSchema() {
|
|
8590
|
+
return this.#input.getSchema();
|
|
8591
|
+
}
|
|
8592
|
+
*fetch(req) {
|
|
8593
|
+
if (!this.#partitionKey || req.constraint && constraintMatchesPartitionKey(req.constraint, this.#partitionKey)) {
|
|
8594
|
+
const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);
|
|
8595
|
+
const takeState = this.#storage.get(takeStateKey);
|
|
8596
|
+
if (!takeState) {
|
|
8597
|
+
yield* this.#initialFetch(req);
|
|
8598
|
+
return;
|
|
8599
|
+
}
|
|
8600
|
+
if (takeState.bound === void 0) {
|
|
8601
|
+
return;
|
|
8602
|
+
}
|
|
8603
|
+
for (const inputNode of this.#input.fetch(req)) {
|
|
8604
|
+
if (this.getSchema().compareRows(takeState.bound, inputNode.row) < 0) {
|
|
8605
|
+
return;
|
|
8606
|
+
}
|
|
8607
|
+
if (this.#rowHiddenFromFetch && this.getSchema().compareRows(
|
|
8608
|
+
this.#rowHiddenFromFetch,
|
|
8609
|
+
inputNode.row
|
|
8610
|
+
) === 0) {
|
|
8611
|
+
continue;
|
|
8612
|
+
}
|
|
8613
|
+
yield inputNode;
|
|
8614
|
+
}
|
|
8615
|
+
return;
|
|
8616
|
+
}
|
|
8617
|
+
const maxBound = this.#storage.get(MAX_BOUND_KEY);
|
|
8618
|
+
if (maxBound === void 0) {
|
|
8619
|
+
return;
|
|
8620
|
+
}
|
|
8621
|
+
for (const inputNode of this.#input.fetch(req)) {
|
|
8622
|
+
if (this.getSchema().compareRows(inputNode.row, maxBound) > 0) {
|
|
8623
|
+
return;
|
|
8624
|
+
}
|
|
8625
|
+
const takeStateKey = getTakeStateKey(this.#partitionKey, inputNode.row);
|
|
8626
|
+
const takeState = this.#storage.get(takeStateKey);
|
|
8627
|
+
if (takeState?.bound !== void 0 && this.getSchema().compareRows(takeState.bound, inputNode.row) >= 0) {
|
|
8628
|
+
yield inputNode;
|
|
8629
|
+
}
|
|
8630
|
+
}
|
|
8631
|
+
}
|
|
8632
|
+
*#initialFetch(req) {
|
|
8633
|
+
assert(req.start === void 0);
|
|
8634
|
+
assert(!req.reverse);
|
|
8635
|
+
assert(constraintMatchesPartitionKey(req.constraint, this.#partitionKey));
|
|
8636
|
+
if (this.#limit === 0) {
|
|
8637
|
+
return;
|
|
8638
|
+
}
|
|
8639
|
+
const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);
|
|
8640
|
+
assert(this.#storage.get(takeStateKey) === void 0);
|
|
8641
|
+
let size = 0;
|
|
8642
|
+
let bound;
|
|
8643
|
+
let downstreamEarlyReturn = true;
|
|
8644
|
+
let exceptionThrown = false;
|
|
8645
|
+
try {
|
|
8646
|
+
for (const inputNode of this.#input.fetch(req)) {
|
|
8647
|
+
yield inputNode;
|
|
8648
|
+
bound = inputNode.row;
|
|
8649
|
+
size++;
|
|
8650
|
+
if (size === this.#limit) {
|
|
8651
|
+
break;
|
|
8652
|
+
}
|
|
8653
|
+
}
|
|
8654
|
+
downstreamEarlyReturn = false;
|
|
8655
|
+
} catch (e) {
|
|
8656
|
+
exceptionThrown = true;
|
|
8657
|
+
throw e;
|
|
8658
|
+
} finally {
|
|
8659
|
+
if (!exceptionThrown) {
|
|
8660
|
+
this.#setTakeState(
|
|
8661
|
+
takeStateKey,
|
|
8662
|
+
size,
|
|
8663
|
+
bound,
|
|
8664
|
+
this.#storage.get(MAX_BOUND_KEY)
|
|
8665
|
+
);
|
|
8666
|
+
assert(
|
|
8667
|
+
!downstreamEarlyReturn,
|
|
8668
|
+
"Unexpected early return prevented full hydration"
|
|
8669
|
+
);
|
|
8670
|
+
}
|
|
8671
|
+
}
|
|
8672
|
+
}
|
|
8673
|
+
*cleanup(req) {
|
|
8674
|
+
assert(req.start === void 0);
|
|
8675
|
+
assert(constraintMatchesPartitionKey(req.constraint, this.#partitionKey));
|
|
8676
|
+
const takeStateKey = getTakeStateKey(this.#partitionKey, req.constraint);
|
|
8677
|
+
this.#storage.del(takeStateKey);
|
|
8678
|
+
let size = 0;
|
|
8679
|
+
for (const inputNode of this.#input.cleanup(req)) {
|
|
8680
|
+
if (size === this.#limit) {
|
|
8681
|
+
return;
|
|
8682
|
+
}
|
|
8683
|
+
size++;
|
|
8684
|
+
yield inputNode;
|
|
8685
|
+
}
|
|
8686
|
+
}
|
|
8687
|
+
#getStateAndConstraint(row) {
|
|
8688
|
+
const takeStateKey = getTakeStateKey(this.#partitionKey, row);
|
|
8689
|
+
const takeState = this.#storage.get(takeStateKey);
|
|
8690
|
+
let maxBound;
|
|
8691
|
+
let constraint;
|
|
8692
|
+
if (takeState) {
|
|
8693
|
+
maxBound = this.#storage.get(MAX_BOUND_KEY);
|
|
8694
|
+
constraint = this.#partitionKey && Object.fromEntries(
|
|
8695
|
+
this.#partitionKey.map((key) => [key, row[key]])
|
|
8696
|
+
);
|
|
8697
|
+
}
|
|
8698
|
+
return { takeState, takeStateKey, maxBound, constraint };
|
|
8699
|
+
}
|
|
8700
|
+
push(change) {
|
|
8701
|
+
if (change.type === "edit") {
|
|
8702
|
+
this.#pushEditChange(change);
|
|
8703
|
+
return;
|
|
8704
|
+
}
|
|
8705
|
+
const { takeState, takeStateKey, maxBound, constraint } = this.#getStateAndConstraint(change.node.row);
|
|
8706
|
+
if (!takeState) {
|
|
8707
|
+
return;
|
|
8708
|
+
}
|
|
8709
|
+
const { compareRows } = this.getSchema();
|
|
8710
|
+
if (change.type === "add") {
|
|
8711
|
+
if (takeState.size < this.#limit) {
|
|
8712
|
+
this.#setTakeState(
|
|
8713
|
+
takeStateKey,
|
|
8714
|
+
takeState.size + 1,
|
|
8715
|
+
takeState.bound === void 0 || compareRows(takeState.bound, change.node.row) < 0 ? change.node.row : takeState.bound,
|
|
8716
|
+
maxBound
|
|
8717
|
+
);
|
|
8718
|
+
this.#output.push(change, this);
|
|
8719
|
+
return;
|
|
8720
|
+
}
|
|
8721
|
+
if (takeState.bound === void 0 || compareRows(change.node.row, takeState.bound) >= 0) {
|
|
8722
|
+
return;
|
|
8723
|
+
}
|
|
8724
|
+
let beforeBoundNode;
|
|
8725
|
+
let boundNode;
|
|
8726
|
+
if (this.#limit === 1) {
|
|
8727
|
+
boundNode = must(
|
|
8728
|
+
first(
|
|
8729
|
+
this.#input.fetch({
|
|
8730
|
+
start: {
|
|
8731
|
+
row: takeState.bound,
|
|
8732
|
+
basis: "at"
|
|
8733
|
+
},
|
|
8734
|
+
constraint
|
|
8735
|
+
})
|
|
8736
|
+
)
|
|
8737
|
+
);
|
|
8738
|
+
} else {
|
|
8739
|
+
[boundNode, beforeBoundNode] = take(
|
|
8740
|
+
this.#input.fetch({
|
|
8741
|
+
start: {
|
|
8742
|
+
row: takeState.bound,
|
|
8743
|
+
basis: "at"
|
|
8744
|
+
},
|
|
8745
|
+
constraint,
|
|
8746
|
+
reverse: true
|
|
8747
|
+
}),
|
|
8748
|
+
2
|
|
8749
|
+
);
|
|
8750
|
+
}
|
|
8751
|
+
const removeChange = {
|
|
8752
|
+
type: "remove",
|
|
8753
|
+
node: boundNode
|
|
8754
|
+
};
|
|
8755
|
+
this.#setTakeState(
|
|
8756
|
+
takeStateKey,
|
|
8757
|
+
takeState.size,
|
|
8758
|
+
beforeBoundNode === void 0 || compareRows(change.node.row, beforeBoundNode.row) > 0 ? change.node.row : beforeBoundNode.row,
|
|
8759
|
+
maxBound
|
|
8760
|
+
);
|
|
8761
|
+
this.#withRowHiddenFromFetch(change.node.row, () => {
|
|
8762
|
+
this.#output.push(removeChange, this);
|
|
8763
|
+
});
|
|
8764
|
+
this.#output.push(change, this);
|
|
8765
|
+
} else if (change.type === "remove") {
|
|
8766
|
+
if (takeState.bound === void 0) {
|
|
8767
|
+
return;
|
|
8768
|
+
}
|
|
8769
|
+
const compToBound = compareRows(change.node.row, takeState.bound);
|
|
8770
|
+
if (compToBound > 0) {
|
|
8771
|
+
return;
|
|
8772
|
+
}
|
|
8773
|
+
const [beforeBoundNode] = take(
|
|
8774
|
+
this.#input.fetch({
|
|
8775
|
+
start: {
|
|
8776
|
+
row: takeState.bound,
|
|
8777
|
+
basis: "after"
|
|
8778
|
+
},
|
|
8779
|
+
constraint,
|
|
8780
|
+
reverse: true
|
|
8781
|
+
}),
|
|
8782
|
+
1
|
|
8783
|
+
);
|
|
8784
|
+
let newBound;
|
|
8785
|
+
if (beforeBoundNode) {
|
|
8786
|
+
const push2 = compareRows(beforeBoundNode.row, takeState.bound) > 0;
|
|
8787
|
+
newBound = {
|
|
8788
|
+
node: beforeBoundNode,
|
|
8789
|
+
push: push2
|
|
8790
|
+
};
|
|
8791
|
+
}
|
|
8792
|
+
if (!newBound?.push) {
|
|
8793
|
+
for (const node of this.#input.fetch({
|
|
8794
|
+
start: {
|
|
8795
|
+
row: takeState.bound,
|
|
8796
|
+
basis: "at"
|
|
8797
|
+
},
|
|
8798
|
+
constraint
|
|
8799
|
+
})) {
|
|
8800
|
+
const push2 = compareRows(node.row, takeState.bound) > 0;
|
|
8801
|
+
newBound = {
|
|
8802
|
+
node,
|
|
8803
|
+
push: push2
|
|
8804
|
+
};
|
|
8805
|
+
if (push2) {
|
|
8806
|
+
break;
|
|
8807
|
+
}
|
|
8808
|
+
}
|
|
8809
|
+
}
|
|
8810
|
+
if (newBound?.push) {
|
|
8811
|
+
this.#output.push(change, this);
|
|
8812
|
+
this.#setTakeState(
|
|
8813
|
+
takeStateKey,
|
|
8814
|
+
takeState.size,
|
|
8815
|
+
newBound.node.row,
|
|
8816
|
+
maxBound
|
|
8817
|
+
);
|
|
8818
|
+
this.#output.push(
|
|
8819
|
+
{
|
|
8820
|
+
type: "add",
|
|
8821
|
+
node: newBound.node
|
|
8822
|
+
},
|
|
8823
|
+
this
|
|
8824
|
+
);
|
|
8825
|
+
return;
|
|
8826
|
+
}
|
|
8827
|
+
this.#setTakeState(
|
|
8828
|
+
takeStateKey,
|
|
8829
|
+
takeState.size - 1,
|
|
8830
|
+
newBound?.node.row,
|
|
8831
|
+
maxBound
|
|
8832
|
+
);
|
|
8833
|
+
this.#output.push(change, this);
|
|
8834
|
+
} else if (change.type === "child") {
|
|
8835
|
+
if (takeState.bound && compareRows(change.node.row, takeState.bound) <= 0) {
|
|
8836
|
+
this.#output.push(change, this);
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
}
|
|
8840
|
+
#pushEditChange(change) {
|
|
8841
|
+
assert(
|
|
8842
|
+
!this.#partitionKeyComparator || this.#partitionKeyComparator(change.oldNode.row, change.node.row) === 0,
|
|
8843
|
+
"Unexpected change of partition key"
|
|
8844
|
+
);
|
|
8845
|
+
const { takeState, takeStateKey, maxBound, constraint } = this.#getStateAndConstraint(change.oldNode.row);
|
|
8846
|
+
if (!takeState) {
|
|
8847
|
+
return;
|
|
8848
|
+
}
|
|
8849
|
+
assert(takeState.bound, "Bound should be set");
|
|
8850
|
+
const { compareRows } = this.getSchema();
|
|
8851
|
+
const oldCmp = compareRows(change.oldNode.row, takeState.bound);
|
|
8852
|
+
const newCmp = compareRows(change.node.row, takeState.bound);
|
|
8853
|
+
const replaceBoundAndForwardChange = () => {
|
|
8854
|
+
this.#setTakeState(
|
|
8855
|
+
takeStateKey,
|
|
8856
|
+
takeState.size,
|
|
8857
|
+
change.node.row,
|
|
8858
|
+
maxBound
|
|
8859
|
+
);
|
|
8860
|
+
this.#output.push(change, this);
|
|
8861
|
+
};
|
|
8862
|
+
if (oldCmp === 0) {
|
|
8863
|
+
if (newCmp === 0) {
|
|
8864
|
+
this.#output.push(change, this);
|
|
8865
|
+
return;
|
|
8866
|
+
}
|
|
8867
|
+
if (newCmp < 0) {
|
|
8868
|
+
if (this.#limit === 1) {
|
|
8869
|
+
replaceBoundAndForwardChange();
|
|
8870
|
+
return;
|
|
8871
|
+
}
|
|
8872
|
+
const beforeBoundNode = must(
|
|
8873
|
+
first(
|
|
8874
|
+
this.#input.fetch({
|
|
8875
|
+
start: {
|
|
8876
|
+
row: takeState.bound,
|
|
8877
|
+
basis: "after"
|
|
8878
|
+
},
|
|
8879
|
+
constraint,
|
|
8880
|
+
reverse: true
|
|
8881
|
+
})
|
|
8882
|
+
)
|
|
8883
|
+
);
|
|
8884
|
+
this.#setTakeState(
|
|
8885
|
+
takeStateKey,
|
|
8886
|
+
takeState.size,
|
|
8887
|
+
beforeBoundNode.row,
|
|
8888
|
+
maxBound
|
|
8889
|
+
);
|
|
8890
|
+
this.#output.push(change, this);
|
|
8891
|
+
return;
|
|
8892
|
+
}
|
|
8893
|
+
assert(newCmp > 0);
|
|
8894
|
+
const newBoundNode = must(
|
|
8895
|
+
first(
|
|
8896
|
+
this.#input.fetch({
|
|
8897
|
+
start: {
|
|
8898
|
+
row: takeState.bound,
|
|
8899
|
+
basis: "at"
|
|
8900
|
+
},
|
|
8901
|
+
constraint
|
|
8902
|
+
})
|
|
8903
|
+
)
|
|
8904
|
+
);
|
|
8905
|
+
if (compareRows(newBoundNode.row, change.node.row) === 0) {
|
|
8906
|
+
replaceBoundAndForwardChange();
|
|
8907
|
+
return;
|
|
8908
|
+
}
|
|
8909
|
+
this.#setTakeState(
|
|
8910
|
+
takeStateKey,
|
|
8911
|
+
takeState.size,
|
|
8912
|
+
newBoundNode.row,
|
|
8913
|
+
maxBound
|
|
8914
|
+
);
|
|
8915
|
+
this.#withRowHiddenFromFetch(newBoundNode.row, () => {
|
|
8916
|
+
this.#output.push(
|
|
8917
|
+
{
|
|
8918
|
+
type: "remove",
|
|
8919
|
+
node: change.oldNode
|
|
8920
|
+
},
|
|
8921
|
+
this
|
|
8922
|
+
);
|
|
8923
|
+
});
|
|
8924
|
+
this.#output.push(
|
|
8925
|
+
{
|
|
8926
|
+
type: "add",
|
|
8927
|
+
node: newBoundNode
|
|
8928
|
+
},
|
|
8929
|
+
this
|
|
8930
|
+
);
|
|
8931
|
+
return;
|
|
8932
|
+
}
|
|
8933
|
+
if (oldCmp > 0) {
|
|
8934
|
+
assert(newCmp !== 0, "Invalid state. Row has duplicate primary key");
|
|
8935
|
+
if (newCmp > 0) {
|
|
8936
|
+
return;
|
|
8937
|
+
}
|
|
8938
|
+
assert(newCmp < 0);
|
|
8939
|
+
const [oldBoundNode, newBoundNode] = take(
|
|
8940
|
+
this.#input.fetch({
|
|
8941
|
+
start: {
|
|
8942
|
+
row: takeState.bound,
|
|
8943
|
+
basis: "at"
|
|
8944
|
+
},
|
|
8945
|
+
constraint,
|
|
8946
|
+
reverse: true
|
|
8947
|
+
}),
|
|
8948
|
+
2
|
|
8949
|
+
);
|
|
8950
|
+
this.#setTakeState(
|
|
8951
|
+
takeStateKey,
|
|
8952
|
+
takeState.size,
|
|
8953
|
+
newBoundNode.row,
|
|
8954
|
+
maxBound
|
|
8955
|
+
);
|
|
8956
|
+
this.#withRowHiddenFromFetch(change.node.row, () => {
|
|
8957
|
+
this.#output.push(
|
|
8958
|
+
{
|
|
8959
|
+
type: "remove",
|
|
8960
|
+
node: oldBoundNode
|
|
8961
|
+
},
|
|
8962
|
+
this
|
|
8963
|
+
);
|
|
8964
|
+
});
|
|
8965
|
+
this.#output.push(
|
|
8966
|
+
{
|
|
8967
|
+
type: "add",
|
|
8968
|
+
node: change.node
|
|
8969
|
+
},
|
|
8970
|
+
this
|
|
8971
|
+
);
|
|
8972
|
+
return;
|
|
8973
|
+
}
|
|
8974
|
+
if (oldCmp < 0) {
|
|
8975
|
+
assert(newCmp !== 0, "Invalid state. Row has duplicate primary key");
|
|
8976
|
+
if (newCmp < 0) {
|
|
8977
|
+
this.#output.push(change, this);
|
|
8978
|
+
return;
|
|
8979
|
+
}
|
|
8980
|
+
assert(newCmp > 0);
|
|
8981
|
+
const afterBoundNode = must(
|
|
8982
|
+
first(
|
|
8983
|
+
this.#input.fetch({
|
|
8984
|
+
start: {
|
|
8985
|
+
row: takeState.bound,
|
|
8986
|
+
basis: "after"
|
|
8987
|
+
},
|
|
8988
|
+
constraint
|
|
8989
|
+
})
|
|
8990
|
+
)
|
|
8991
|
+
);
|
|
8992
|
+
if (compareRows(afterBoundNode.row, change.node.row) === 0) {
|
|
8993
|
+
replaceBoundAndForwardChange();
|
|
8994
|
+
return;
|
|
8995
|
+
}
|
|
8996
|
+
this.#output.push(
|
|
8997
|
+
{
|
|
8998
|
+
type: "remove",
|
|
8999
|
+
node: change.oldNode
|
|
9000
|
+
},
|
|
9001
|
+
this
|
|
9002
|
+
);
|
|
9003
|
+
this.#setTakeState(
|
|
9004
|
+
takeStateKey,
|
|
9005
|
+
takeState.size,
|
|
9006
|
+
afterBoundNode.row,
|
|
9007
|
+
maxBound
|
|
9008
|
+
);
|
|
9009
|
+
this.#output.push(
|
|
9010
|
+
{
|
|
9011
|
+
type: "add",
|
|
9012
|
+
node: afterBoundNode
|
|
9013
|
+
},
|
|
9014
|
+
this
|
|
9015
|
+
);
|
|
9016
|
+
return;
|
|
9017
|
+
}
|
|
9018
|
+
unreachable();
|
|
9019
|
+
}
|
|
9020
|
+
#withRowHiddenFromFetch(row, fn) {
|
|
9021
|
+
this.#rowHiddenFromFetch = row;
|
|
9022
|
+
try {
|
|
9023
|
+
fn();
|
|
9024
|
+
} finally {
|
|
9025
|
+
this.#rowHiddenFromFetch = void 0;
|
|
9026
|
+
}
|
|
9027
|
+
}
|
|
9028
|
+
#setTakeState(takeStateKey, size, bound, maxBound) {
|
|
9029
|
+
this.#storage.set(takeStateKey, {
|
|
9030
|
+
size,
|
|
9031
|
+
bound
|
|
9032
|
+
});
|
|
9033
|
+
if (bound !== void 0 && (maxBound === void 0 || this.getSchema().compareRows(bound, maxBound) > 0)) {
|
|
9034
|
+
this.#storage.set(MAX_BOUND_KEY, bound);
|
|
9035
|
+
}
|
|
9036
|
+
}
|
|
9037
|
+
destroy() {
|
|
9038
|
+
this.#input.destroy();
|
|
9039
|
+
}
|
|
9040
|
+
};
|
|
9041
|
+
function getTakeStateKey(partitionKey, rowOrConstraint) {
|
|
9042
|
+
const partitionValues = [];
|
|
9043
|
+
if (partitionKey && rowOrConstraint) {
|
|
9044
|
+
for (const key of partitionKey) {
|
|
9045
|
+
partitionValues.push(rowOrConstraint[key]);
|
|
9046
|
+
}
|
|
9047
|
+
}
|
|
9048
|
+
return JSON.stringify(["take", ...partitionValues]);
|
|
9049
|
+
}
|
|
9050
|
+
function constraintMatchesPartitionKey(constraint, partitionKey) {
|
|
9051
|
+
if (constraint === void 0 || partitionKey === void 0) {
|
|
9052
|
+
return constraint === partitionKey;
|
|
9053
|
+
}
|
|
9054
|
+
if (partitionKey.length !== Object.keys(constraint).length) {
|
|
9055
|
+
return false;
|
|
9056
|
+
}
|
|
9057
|
+
for (const key of partitionKey) {
|
|
9058
|
+
if (!hasOwn(constraint, key)) {
|
|
9059
|
+
return false;
|
|
9060
|
+
}
|
|
9061
|
+
}
|
|
9062
|
+
return true;
|
|
9063
|
+
}
|
|
9064
|
+
function makePartitionKeyComparator(partitionKey) {
|
|
9065
|
+
return (a, b) => {
|
|
9066
|
+
for (const key of partitionKey) {
|
|
9067
|
+
const cmp2 = compareValues(a[key], b[key]);
|
|
9068
|
+
if (cmp2 !== 0) {
|
|
9069
|
+
return cmp2;
|
|
9070
|
+
}
|
|
9071
|
+
}
|
|
9072
|
+
return 0;
|
|
9073
|
+
};
|
|
9074
|
+
}
|
|
9075
|
+
|
|
9076
|
+
// ../zql/src/ivm/union-fan-in.ts
|
|
9077
|
+
var UnionFanIn = class {
|
|
9078
|
+
#inputs;
|
|
9079
|
+
#schema;
|
|
9080
|
+
#fanOutPushStarted = false;
|
|
9081
|
+
#output = throwOutput;
|
|
9082
|
+
#accumulatedPushes = [];
|
|
9083
|
+
constructor(fanOut, inputs) {
|
|
9084
|
+
this.#inputs = inputs;
|
|
9085
|
+
const fanOutSchema = fanOut.getSchema();
|
|
9086
|
+
fanOut.setFanIn(this);
|
|
9087
|
+
const schema = {
|
|
9088
|
+
tableName: fanOutSchema.tableName,
|
|
9089
|
+
columns: fanOutSchema.columns,
|
|
9090
|
+
primaryKey: fanOutSchema.primaryKey,
|
|
9091
|
+
relationships: {
|
|
9092
|
+
...fanOutSchema.relationships
|
|
9093
|
+
},
|
|
9094
|
+
isHidden: fanOutSchema.isHidden,
|
|
9095
|
+
system: fanOutSchema.system,
|
|
9096
|
+
compareRows: fanOutSchema.compareRows,
|
|
9097
|
+
sort: fanOutSchema.sort
|
|
9098
|
+
};
|
|
9099
|
+
const relationshipsFromBranches = /* @__PURE__ */ new Set();
|
|
9100
|
+
for (const input of inputs) {
|
|
9101
|
+
const inputSchema = input.getSchema();
|
|
9102
|
+
assert(
|
|
9103
|
+
schema.tableName === inputSchema.tableName,
|
|
9104
|
+
`Table name mismatch in union fan-in: ${schema.tableName} !== ${inputSchema.tableName}`
|
|
9105
|
+
);
|
|
9106
|
+
assert(
|
|
9107
|
+
schema.primaryKey === inputSchema.primaryKey,
|
|
9108
|
+
`Primary key mismatch in union fan-in`
|
|
9109
|
+
);
|
|
9110
|
+
assert(
|
|
9111
|
+
schema.system === inputSchema.system,
|
|
9112
|
+
`System mismatch in union fan-in: ${schema.system} !== ${inputSchema.system}`
|
|
9113
|
+
);
|
|
9114
|
+
assert(
|
|
9115
|
+
schema.compareRows === inputSchema.compareRows,
|
|
9116
|
+
`compareRows mismatch in union fan-in`
|
|
9117
|
+
);
|
|
9118
|
+
assert(schema.sort === inputSchema.sort, `Sort mismatch in union fan-in`);
|
|
9119
|
+
for (const [relName, relSchema] of Object.entries(
|
|
9120
|
+
inputSchema.relationships
|
|
9121
|
+
)) {
|
|
9122
|
+
if (relName in fanOutSchema.relationships) {
|
|
9123
|
+
continue;
|
|
9124
|
+
}
|
|
9125
|
+
assert(
|
|
9126
|
+
!relationshipsFromBranches.has(relName),
|
|
9127
|
+
`Relationship ${relName} exists in multiple upstream inputs to union fan-in`
|
|
9128
|
+
);
|
|
9129
|
+
schema.relationships[relName] = relSchema;
|
|
9130
|
+
relationshipsFromBranches.add(relName);
|
|
9131
|
+
}
|
|
9132
|
+
input.setOutput(this);
|
|
9133
|
+
}
|
|
9134
|
+
this.#schema = schema;
|
|
9135
|
+
this.#inputs = inputs;
|
|
9136
|
+
}
|
|
9137
|
+
cleanup(_req) {
|
|
9138
|
+
return [];
|
|
9139
|
+
}
|
|
9140
|
+
destroy() {
|
|
9141
|
+
for (const input of this.#inputs) {
|
|
9142
|
+
input.destroy();
|
|
9143
|
+
}
|
|
9144
|
+
}
|
|
9145
|
+
fetch(req) {
|
|
9146
|
+
const iterables = this.#inputs.map((input) => input.fetch(req));
|
|
9147
|
+
return mergeIterables(
|
|
9148
|
+
iterables,
|
|
9149
|
+
(l, r) => this.#schema.compareRows(l.row, r.row),
|
|
9150
|
+
true
|
|
9151
|
+
);
|
|
9152
|
+
}
|
|
9153
|
+
getSchema() {
|
|
9154
|
+
return this.#schema;
|
|
9155
|
+
}
|
|
9156
|
+
push(change, pusher) {
|
|
9157
|
+
if (!this.#fanOutPushStarted) {
|
|
9158
|
+
this.#pushInternalChange(change, pusher);
|
|
9159
|
+
} else {
|
|
9160
|
+
this.#accumulatedPushes.push(change);
|
|
9161
|
+
}
|
|
9162
|
+
}
|
|
9163
|
+
/**
|
|
9164
|
+
* An internal change means that a change was received inside the fan-out/fan-in sub-graph.
|
|
9165
|
+
*
|
|
9166
|
+
* These changes always come from children of a flip-join as no other push generating operators
|
|
9167
|
+
* currently exist between union-fan-in and union-fan-out. All other pushes
|
|
9168
|
+
* enter into union-fan-out before reaching union-fan-in.
|
|
9169
|
+
*
|
|
9170
|
+
* - normal joins for `exists` come before `union-fan-out`
|
|
9171
|
+
* - joins for `related` come after `union-fan-out`
|
|
9172
|
+
* - take comes after `union-fan-out`
|
|
9173
|
+
*
|
|
9174
|
+
* The algorithm for deciding whether or not to forward a push that came from inside the ufo/ufi sub-graph:
|
|
9175
|
+
* 1. If the change is a `child` change we can forward it. This is because all child branches in the ufo/ufi sub-graph are unique.
|
|
9176
|
+
* 2. If the change is `add` we can forward it iff no `fetches` for the row return any results.
|
|
9177
|
+
* If another branch has it, the add was already emitted in the past.
|
|
9178
|
+
* 3. If the change is `remove` we can forward it iff no `fetches` for the row return any results.
|
|
9179
|
+
* If no other branches have the change, the remove can be sent as the value is no longer present.
|
|
9180
|
+
* If other branches have it, the last branch the processes the remove will send the remove.
|
|
9181
|
+
* 4. Edits will always come through as child changes as flip join will flip them into children.
|
|
9182
|
+
* An edit that would result in a remove or add will have been split into an add/remove pair rather than being an edit.
|
|
9183
|
+
*/
|
|
9184
|
+
#pushInternalChange(change, pusher) {
|
|
9185
|
+
if (change.type === "child") {
|
|
9186
|
+
this.#output.push(change, this);
|
|
9187
|
+
return;
|
|
9188
|
+
}
|
|
9189
|
+
assert(change.type === "add" || change.type === "remove");
|
|
9190
|
+
let hadMatch = false;
|
|
9191
|
+
for (const input of this.#inputs) {
|
|
9192
|
+
if (input === pusher) {
|
|
9193
|
+
hadMatch = true;
|
|
9194
|
+
continue;
|
|
9195
|
+
}
|
|
9196
|
+
const constraint = {};
|
|
9197
|
+
for (const key of this.#schema.primaryKey) {
|
|
9198
|
+
constraint[key] = change.node.row[key];
|
|
9199
|
+
}
|
|
9200
|
+
const fetchResult = input.fetch({
|
|
9201
|
+
constraint
|
|
9202
|
+
});
|
|
9203
|
+
if (first(fetchResult) !== void 0) {
|
|
9204
|
+
return;
|
|
9205
|
+
}
|
|
9206
|
+
}
|
|
9207
|
+
assert(hadMatch, "Pusher was not one of the inputs to union-fan-in!");
|
|
9208
|
+
this.#output.push(change, this);
|
|
9209
|
+
}
|
|
9210
|
+
fanOutStartedPushing() {
|
|
9211
|
+
assert(this.#fanOutPushStarted === false);
|
|
9212
|
+
this.#fanOutPushStarted = true;
|
|
9213
|
+
}
|
|
9214
|
+
fanOutDonePushing(fanOutChangeType) {
|
|
9215
|
+
assert(this.#fanOutPushStarted);
|
|
9216
|
+
this.#fanOutPushStarted = false;
|
|
9217
|
+
if (this.#inputs.length === 0) {
|
|
9218
|
+
return;
|
|
9219
|
+
}
|
|
9220
|
+
if (this.#accumulatedPushes.length === 0) {
|
|
9221
|
+
return;
|
|
9222
|
+
}
|
|
9223
|
+
pushAccumulatedChanges(
|
|
9224
|
+
this.#accumulatedPushes,
|
|
9225
|
+
this.#output,
|
|
9226
|
+
this,
|
|
9227
|
+
fanOutChangeType,
|
|
9228
|
+
mergeRelationships,
|
|
9229
|
+
makeAddEmptyRelationships(this.#schema)
|
|
9230
|
+
);
|
|
9231
|
+
}
|
|
9232
|
+
setOutput(output) {
|
|
9233
|
+
this.#output = output;
|
|
9234
|
+
}
|
|
9235
|
+
};
|
|
9236
|
+
|
|
9237
|
+
// ../zql/src/ivm/union-fan-out.ts
|
|
9238
|
+
var UnionFanOut = class {
|
|
9239
|
+
#destroyCount = 0;
|
|
9240
|
+
#unionFanIn;
|
|
9241
|
+
#input;
|
|
9242
|
+
#outputs = [];
|
|
9243
|
+
constructor(input) {
|
|
9244
|
+
this.#input = input;
|
|
9245
|
+
input.setOutput(this);
|
|
9246
|
+
}
|
|
9247
|
+
setFanIn(fanIn) {
|
|
9248
|
+
assert(!this.#unionFanIn, "FanIn already set for this FanOut");
|
|
9249
|
+
this.#unionFanIn = fanIn;
|
|
9250
|
+
}
|
|
9251
|
+
push(change) {
|
|
9252
|
+
must(this.#unionFanIn).fanOutStartedPushing();
|
|
9253
|
+
for (const output of this.#outputs) {
|
|
9254
|
+
output.push(change, this);
|
|
9255
|
+
}
|
|
9256
|
+
must(this.#unionFanIn).fanOutDonePushing(change.type);
|
|
9257
|
+
}
|
|
9258
|
+
setOutput(output) {
|
|
9259
|
+
this.#outputs.push(output);
|
|
9260
|
+
}
|
|
9261
|
+
getSchema() {
|
|
9262
|
+
return this.#input.getSchema();
|
|
9263
|
+
}
|
|
9264
|
+
fetch(req) {
|
|
9265
|
+
return this.#input.fetch(req);
|
|
9266
|
+
}
|
|
9267
|
+
cleanup(_req) {
|
|
9268
|
+
return [];
|
|
9269
|
+
}
|
|
9270
|
+
destroy() {
|
|
9271
|
+
if (this.#destroyCount < this.#outputs.length) {
|
|
9272
|
+
++this.#destroyCount;
|
|
9273
|
+
if (this.#destroyCount === this.#outputs.length) {
|
|
9274
|
+
this.#input.destroy();
|
|
9275
|
+
}
|
|
9276
|
+
} else {
|
|
9277
|
+
throw new Error("FanOut already destroyed once for each output");
|
|
9278
|
+
}
|
|
9279
|
+
}
|
|
9280
|
+
};
|
|
9281
|
+
|
|
9282
|
+
// ../zql/src/query/expression.ts
|
|
9283
|
+
var ExpressionBuilder = class {
|
|
9284
|
+
#exists;
|
|
9285
|
+
constructor(exists) {
|
|
9286
|
+
this.#exists = exists;
|
|
9287
|
+
this.exists = this.exists.bind(this);
|
|
9288
|
+
}
|
|
9289
|
+
get eb() {
|
|
9290
|
+
return this;
|
|
9291
|
+
}
|
|
9292
|
+
cmp(field, opOrValue, value) {
|
|
9293
|
+
return cmp(field, opOrValue, value);
|
|
9294
|
+
}
|
|
9295
|
+
cmpLit(left, op, right) {
|
|
9296
|
+
return {
|
|
9297
|
+
type: "simple",
|
|
9298
|
+
left: isParameterReference(left) ? left[toStaticParam]() : { type: "literal", value: left },
|
|
9299
|
+
right: isParameterReference(right) ? right[toStaticParam]() : { type: "literal", value: right },
|
|
9300
|
+
op
|
|
9301
|
+
};
|
|
9302
|
+
}
|
|
9303
|
+
and = and;
|
|
9304
|
+
or = or;
|
|
9305
|
+
not = not;
|
|
9306
|
+
exists = (relationship, cb, options) => this.#exists(relationship, cb, options);
|
|
9307
|
+
};
|
|
9308
|
+
function and(...conditions) {
|
|
9309
|
+
const expressions = filterTrue(filterUndefined(conditions));
|
|
9310
|
+
if (expressions.length === 1) {
|
|
9311
|
+
return expressions[0];
|
|
9312
|
+
}
|
|
9313
|
+
if (expressions.some(isAlwaysFalse)) {
|
|
9314
|
+
return FALSE;
|
|
9315
|
+
}
|
|
9316
|
+
return { type: "and", conditions: expressions };
|
|
9317
|
+
}
|
|
9318
|
+
function or(...conditions) {
|
|
9319
|
+
const expressions = filterFalse(filterUndefined(conditions));
|
|
9320
|
+
if (expressions.length === 1) {
|
|
9321
|
+
return expressions[0];
|
|
9322
|
+
}
|
|
9323
|
+
if (expressions.some(isAlwaysTrue)) {
|
|
9324
|
+
return TRUE;
|
|
9325
|
+
}
|
|
9326
|
+
return { type: "or", conditions: expressions };
|
|
9327
|
+
}
|
|
9328
|
+
function not(expression) {
|
|
9329
|
+
switch (expression.type) {
|
|
9330
|
+
case "and":
|
|
9331
|
+
return {
|
|
9332
|
+
type: "or",
|
|
9333
|
+
conditions: expression.conditions.map(not)
|
|
9334
|
+
};
|
|
9335
|
+
case "or":
|
|
9336
|
+
return {
|
|
9337
|
+
type: "and",
|
|
9338
|
+
conditions: expression.conditions.map(not)
|
|
9339
|
+
};
|
|
9340
|
+
case "correlatedSubquery":
|
|
9341
|
+
return {
|
|
9342
|
+
type: "correlatedSubquery",
|
|
9343
|
+
related: expression.related,
|
|
9344
|
+
op: negateOperator(expression.op)
|
|
9345
|
+
};
|
|
9346
|
+
case "simple":
|
|
9347
|
+
return {
|
|
9348
|
+
type: "simple",
|
|
9349
|
+
op: negateOperator(expression.op),
|
|
9350
|
+
left: expression.left,
|
|
9351
|
+
right: expression.right
|
|
9352
|
+
};
|
|
9353
|
+
}
|
|
9354
|
+
}
|
|
9355
|
+
function cmp(field, opOrValue, value) {
|
|
9356
|
+
let op;
|
|
9357
|
+
if (value === void 0) {
|
|
9358
|
+
value = opOrValue;
|
|
9359
|
+
op = "=";
|
|
9360
|
+
} else {
|
|
9361
|
+
op = opOrValue;
|
|
9362
|
+
}
|
|
9363
|
+
return {
|
|
9364
|
+
type: "simple",
|
|
9365
|
+
left: { type: "column", name: field },
|
|
9366
|
+
right: isParameterReference(value) ? value[toStaticParam]() : { type: "literal", value },
|
|
9367
|
+
op
|
|
9368
|
+
};
|
|
9369
|
+
}
|
|
9370
|
+
function isParameterReference(value) {
|
|
9371
|
+
return value !== null && typeof value === "object" && value[toStaticParam];
|
|
9372
|
+
}
|
|
9373
|
+
var TRUE = {
|
|
9374
|
+
type: "and",
|
|
9375
|
+
conditions: []
|
|
9376
|
+
};
|
|
9377
|
+
var FALSE = {
|
|
9378
|
+
type: "or",
|
|
9379
|
+
conditions: []
|
|
9380
|
+
};
|
|
9381
|
+
function isAlwaysTrue(condition) {
|
|
9382
|
+
return condition.type === "and" && condition.conditions.length === 0;
|
|
9383
|
+
}
|
|
9384
|
+
function isAlwaysFalse(condition) {
|
|
9385
|
+
return condition.type === "or" && condition.conditions.length === 0;
|
|
9386
|
+
}
|
|
9387
|
+
function simplifyCondition(c) {
|
|
9388
|
+
if (c.type === "simple" || c.type === "correlatedSubquery") {
|
|
9389
|
+
return c;
|
|
9390
|
+
}
|
|
9391
|
+
if (c.conditions.length === 1) {
|
|
9392
|
+
return simplifyCondition(c.conditions[0]);
|
|
9393
|
+
}
|
|
9394
|
+
const conditions = flatten(c.type, c.conditions.map(simplifyCondition));
|
|
9395
|
+
if (c.type === "and" && conditions.some(isAlwaysFalse)) {
|
|
9396
|
+
return FALSE;
|
|
9397
|
+
}
|
|
9398
|
+
if (c.type === "or" && conditions.some(isAlwaysTrue)) {
|
|
9399
|
+
return TRUE;
|
|
9400
|
+
}
|
|
9401
|
+
return {
|
|
9402
|
+
type: c.type,
|
|
9403
|
+
conditions
|
|
9404
|
+
};
|
|
9405
|
+
}
|
|
9406
|
+
function flatten(type, conditions) {
|
|
9407
|
+
const flattened = [];
|
|
9408
|
+
for (const c of conditions) {
|
|
9409
|
+
if (c.type === type) {
|
|
9410
|
+
flattened.push(...c.conditions);
|
|
9411
|
+
} else {
|
|
9412
|
+
flattened.push(c);
|
|
9413
|
+
}
|
|
9414
|
+
}
|
|
9415
|
+
return flattened;
|
|
9416
|
+
}
|
|
9417
|
+
var negateSimpleOperatorMap = {
|
|
9418
|
+
["="]: "!=",
|
|
9419
|
+
["!="]: "=",
|
|
9420
|
+
["<"]: ">=",
|
|
9421
|
+
[">"]: "<=",
|
|
9422
|
+
[">="]: "<",
|
|
9423
|
+
["<="]: ">",
|
|
9424
|
+
["IN"]: "NOT IN",
|
|
9425
|
+
["NOT IN"]: "IN",
|
|
9426
|
+
["LIKE"]: "NOT LIKE",
|
|
9427
|
+
["NOT LIKE"]: "LIKE",
|
|
9428
|
+
["ILIKE"]: "NOT ILIKE",
|
|
9429
|
+
["NOT ILIKE"]: "ILIKE",
|
|
9430
|
+
["IS"]: "IS NOT",
|
|
9431
|
+
["IS NOT"]: "IS"
|
|
9432
|
+
};
|
|
9433
|
+
var negateOperatorMap = {
|
|
9434
|
+
...negateSimpleOperatorMap,
|
|
9435
|
+
["EXISTS"]: "NOT EXISTS",
|
|
9436
|
+
["NOT EXISTS"]: "EXISTS"
|
|
9437
|
+
};
|
|
9438
|
+
function negateOperator(op) {
|
|
9439
|
+
return must(negateOperatorMap[op]);
|
|
9440
|
+
}
|
|
9441
|
+
function filterUndefined(array9) {
|
|
9442
|
+
return array9.filter((e) => e !== void 0);
|
|
9443
|
+
}
|
|
9444
|
+
function filterTrue(conditions) {
|
|
9445
|
+
return conditions.filter((c) => !isAlwaysTrue(c));
|
|
9446
|
+
}
|
|
9447
|
+
function filterFalse(conditions) {
|
|
9448
|
+
return conditions.filter((c) => !isAlwaysFalse(c));
|
|
9449
|
+
}
|
|
9450
|
+
|
|
9451
|
+
// ../zql/src/builder/like.ts
|
|
9452
|
+
function getLikePredicate(pattern, flags) {
|
|
9453
|
+
const op = getLikeOp(String(pattern), flags);
|
|
9454
|
+
return (lhs) => {
|
|
9455
|
+
assertString(lhs);
|
|
9456
|
+
return op(String(lhs));
|
|
9457
|
+
};
|
|
9458
|
+
}
|
|
9459
|
+
function getLikeOp(pattern, flags) {
|
|
9460
|
+
if (!/_|%|\\/.test(pattern)) {
|
|
9461
|
+
if (flags === "i") {
|
|
9462
|
+
const rhsLower = pattern.toLowerCase();
|
|
9463
|
+
return (lhs) => lhs.toLowerCase() === rhsLower;
|
|
9464
|
+
}
|
|
9465
|
+
return (lhs) => lhs === pattern;
|
|
9466
|
+
}
|
|
9467
|
+
const re = patternToRegExp(pattern, flags);
|
|
9468
|
+
return (lhs) => re.test(lhs);
|
|
9469
|
+
}
|
|
9470
|
+
var specialCharsRe = /[$()*+.?[\]\\^{|}]/;
|
|
9471
|
+
function patternToRegExp(source, flags = "") {
|
|
9472
|
+
let pattern = "^";
|
|
9473
|
+
for (let i = 0; i < source.length; i++) {
|
|
9474
|
+
let c = source[i];
|
|
9475
|
+
switch (c) {
|
|
9476
|
+
case "%":
|
|
9477
|
+
pattern += ".*";
|
|
9478
|
+
break;
|
|
9479
|
+
case "_":
|
|
9480
|
+
pattern += ".";
|
|
9481
|
+
break;
|
|
9482
|
+
// @ts-expect-error fallthrough
|
|
9483
|
+
case "\\":
|
|
9484
|
+
if (i === source.length - 1) {
|
|
9485
|
+
throw new Error("LIKE pattern must not end with escape character");
|
|
9486
|
+
}
|
|
9487
|
+
i++;
|
|
9488
|
+
c = source[i];
|
|
9489
|
+
// fall through
|
|
9490
|
+
default:
|
|
9491
|
+
if (specialCharsRe.test(c)) {
|
|
9492
|
+
pattern += "\\";
|
|
9493
|
+
}
|
|
9494
|
+
pattern += c;
|
|
9495
|
+
break;
|
|
9496
|
+
}
|
|
9497
|
+
}
|
|
9498
|
+
return new RegExp(pattern + "$", flags + "m");
|
|
9499
|
+
}
|
|
9500
|
+
|
|
9501
|
+
// ../zql/src/builder/filter.ts
|
|
9502
|
+
function createPredicate(condition) {
|
|
9503
|
+
if (condition.type !== "simple") {
|
|
9504
|
+
const predicates = condition.conditions.map((c) => createPredicate(c));
|
|
9505
|
+
return condition.type === "and" ? (row) => {
|
|
9506
|
+
for (const predicate of predicates) {
|
|
9507
|
+
if (!predicate(row)) {
|
|
9508
|
+
return false;
|
|
9509
|
+
}
|
|
9510
|
+
}
|
|
9511
|
+
return true;
|
|
9512
|
+
} : (row) => {
|
|
9513
|
+
for (const predicate of predicates) {
|
|
9514
|
+
if (predicate(row)) {
|
|
9515
|
+
return true;
|
|
9516
|
+
}
|
|
9517
|
+
}
|
|
9518
|
+
return false;
|
|
9519
|
+
};
|
|
9520
|
+
}
|
|
9521
|
+
const { left } = condition;
|
|
9522
|
+
const { right } = condition;
|
|
9523
|
+
assert(
|
|
9524
|
+
right.type !== "static",
|
|
9525
|
+
"static values should be resolved before creating predicates"
|
|
9526
|
+
);
|
|
9527
|
+
assert(
|
|
9528
|
+
left.type !== "static",
|
|
9529
|
+
"static values should be resolved before creating predicates"
|
|
9530
|
+
);
|
|
9531
|
+
switch (condition.op) {
|
|
9532
|
+
case "IS":
|
|
9533
|
+
case "IS NOT": {
|
|
9534
|
+
const impl2 = createIsPredicate(right.value, condition.op);
|
|
9535
|
+
if (left.type === "literal") {
|
|
9536
|
+
const result = impl2(left.value);
|
|
9537
|
+
return () => result;
|
|
9538
|
+
}
|
|
9539
|
+
return (row) => impl2(row[left.name]);
|
|
9540
|
+
}
|
|
9541
|
+
}
|
|
9542
|
+
if (right.value === null || right.value === void 0) {
|
|
9543
|
+
return (_row) => false;
|
|
9544
|
+
}
|
|
9545
|
+
const impl = createPredicateImpl(right.value, condition.op);
|
|
9546
|
+
if (left.type === "literal") {
|
|
9547
|
+
if (left.value === null || left.value === void 0) {
|
|
9548
|
+
return (_row) => false;
|
|
9549
|
+
}
|
|
9550
|
+
const result = impl(left.value);
|
|
9551
|
+
return () => result;
|
|
9552
|
+
}
|
|
9553
|
+
return (row) => {
|
|
9554
|
+
const lhs = row[left.name];
|
|
9555
|
+
if (lhs === null || lhs === void 0) {
|
|
9556
|
+
return false;
|
|
9557
|
+
}
|
|
9558
|
+
return impl(lhs);
|
|
9559
|
+
};
|
|
9560
|
+
}
|
|
9561
|
+
function createIsPredicate(rhs, operator) {
|
|
9562
|
+
switch (operator) {
|
|
9563
|
+
case "IS":
|
|
9564
|
+
return (lhs) => lhs === rhs;
|
|
9565
|
+
case "IS NOT":
|
|
9566
|
+
return (lhs) => lhs !== rhs;
|
|
9567
|
+
}
|
|
9568
|
+
}
|
|
9569
|
+
function createPredicateImpl(rhs, operator) {
|
|
9570
|
+
switch (operator) {
|
|
9571
|
+
case "=":
|
|
9572
|
+
return (lhs) => lhs === rhs;
|
|
9573
|
+
case "!=":
|
|
9574
|
+
return (lhs) => lhs !== rhs;
|
|
9575
|
+
case "<":
|
|
9576
|
+
return (lhs) => lhs < rhs;
|
|
9577
|
+
case "<=":
|
|
9578
|
+
return (lhs) => lhs <= rhs;
|
|
9579
|
+
case ">":
|
|
9580
|
+
return (lhs) => lhs > rhs;
|
|
9581
|
+
case ">=":
|
|
9582
|
+
return (lhs) => lhs >= rhs;
|
|
9583
|
+
case "LIKE":
|
|
9584
|
+
return getLikePredicate(rhs, "");
|
|
9585
|
+
case "NOT LIKE":
|
|
9586
|
+
return not2(getLikePredicate(rhs, ""));
|
|
9587
|
+
case "ILIKE":
|
|
9588
|
+
return getLikePredicate(rhs, "i");
|
|
9589
|
+
case "NOT ILIKE":
|
|
9590
|
+
return not2(getLikePredicate(rhs, "i"));
|
|
9591
|
+
case "IN": {
|
|
9592
|
+
assert(Array.isArray(rhs));
|
|
9593
|
+
const set = new Set(rhs);
|
|
9594
|
+
return (lhs) => set.has(lhs);
|
|
9595
|
+
}
|
|
9596
|
+
case "NOT IN": {
|
|
9597
|
+
assert(Array.isArray(rhs));
|
|
9598
|
+
const set = new Set(rhs);
|
|
9599
|
+
return (lhs) => !set.has(lhs);
|
|
9600
|
+
}
|
|
9601
|
+
default:
|
|
9602
|
+
operator;
|
|
9603
|
+
throw new Error(`Unexpected operator: ${operator}`);
|
|
9604
|
+
}
|
|
9605
|
+
}
|
|
9606
|
+
function not2(f) {
|
|
9607
|
+
return (lhs) => !f(lhs);
|
|
9608
|
+
}
|
|
9609
|
+
function transformFilters(filters) {
|
|
9610
|
+
if (!filters) {
|
|
9611
|
+
return { filters: void 0, conditionsRemoved: false };
|
|
9612
|
+
}
|
|
9613
|
+
switch (filters.type) {
|
|
9614
|
+
case "simple":
|
|
9615
|
+
return { filters, conditionsRemoved: false };
|
|
9616
|
+
case "correlatedSubquery":
|
|
9617
|
+
return { filters: void 0, conditionsRemoved: true };
|
|
9618
|
+
case "and":
|
|
9619
|
+
case "or": {
|
|
9620
|
+
const transformedConditions = [];
|
|
9621
|
+
let conditionsRemoved = false;
|
|
9622
|
+
for (const cond of filters.conditions) {
|
|
9623
|
+
const transformed = transformFilters(cond);
|
|
9624
|
+
if (transformed.filters === void 0 && filters.type === "or") {
|
|
9625
|
+
return { filters: void 0, conditionsRemoved: true };
|
|
9626
|
+
}
|
|
9627
|
+
conditionsRemoved = conditionsRemoved || transformed.conditionsRemoved;
|
|
9628
|
+
if (transformed.filters) {
|
|
9629
|
+
transformedConditions.push(transformed.filters);
|
|
9630
|
+
}
|
|
9631
|
+
}
|
|
9632
|
+
return {
|
|
9633
|
+
filters: simplifyCondition({
|
|
9634
|
+
type: filters.type,
|
|
9635
|
+
conditions: transformedConditions
|
|
9636
|
+
}),
|
|
9637
|
+
conditionsRemoved
|
|
9638
|
+
};
|
|
9639
|
+
}
|
|
9640
|
+
default:
|
|
9641
|
+
unreachable(filters);
|
|
9642
|
+
}
|
|
9643
|
+
}
|
|
9644
|
+
|
|
9645
|
+
// ../zql/src/builder/builder.ts
|
|
9646
|
+
function buildPipeline(ast, delegate, queryID) {
|
|
9647
|
+
ast = delegate.mapAst ? delegate.mapAst(ast) : ast;
|
|
9648
|
+
return buildPipelineInternal(ast, delegate, queryID, "");
|
|
9649
|
+
}
|
|
9650
|
+
var EXISTS_LIMIT = 3;
|
|
9651
|
+
var PERMISSIONS_EXISTS_LIMIT = 1;
|
|
9652
|
+
function buildPipelineInternal(ast, delegate, queryID, name, partitionKey) {
|
|
9653
|
+
const source = delegate.getSource(ast.table);
|
|
9654
|
+
if (!source) {
|
|
9655
|
+
throw new Error(`Source not found: ${ast.table}`);
|
|
9656
|
+
}
|
|
9657
|
+
ast = uniquifyCorrelatedSubqueryConditionAliases(ast);
|
|
9658
|
+
const csqConditions = gatherCorrelatedSubqueryQueryConditions(ast.where);
|
|
9659
|
+
const splitEditKeys = partitionKey ? new Set(partitionKey) : /* @__PURE__ */ new Set();
|
|
9660
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
9661
|
+
for (const csq of csqConditions) {
|
|
9662
|
+
aliases.add(csq.related.subquery.alias || "");
|
|
9663
|
+
for (const key of csq.related.correlation.parentField) {
|
|
9664
|
+
splitEditKeys.add(key);
|
|
9665
|
+
}
|
|
9666
|
+
}
|
|
9667
|
+
if (ast.related) {
|
|
9668
|
+
for (const csq of ast.related) {
|
|
9669
|
+
for (const key of csq.correlation.parentField) {
|
|
9670
|
+
splitEditKeys.add(key);
|
|
9671
|
+
}
|
|
9672
|
+
}
|
|
9673
|
+
}
|
|
9674
|
+
const conn = source.connect(
|
|
9675
|
+
must(ast.orderBy),
|
|
9676
|
+
ast.where,
|
|
9677
|
+
splitEditKeys,
|
|
9678
|
+
delegate.debug
|
|
9679
|
+
);
|
|
9680
|
+
let end = delegate.decorateSourceInput(conn, queryID);
|
|
9681
|
+
end = delegate.decorateInput(end, `${name}:source(${ast.table})`);
|
|
9682
|
+
const { fullyAppliedFilters } = conn;
|
|
9683
|
+
if (ast.start) {
|
|
9684
|
+
const skip = new Skip(end, ast.start);
|
|
9685
|
+
delegate.addEdge(end, skip);
|
|
9686
|
+
end = delegate.decorateInput(skip, `${name}:skip)`);
|
|
9687
|
+
}
|
|
9688
|
+
for (const csqCondition of csqConditions) {
|
|
9689
|
+
if (!csqCondition.flip) {
|
|
9690
|
+
end = applyCorrelatedSubQuery(
|
|
9691
|
+
{
|
|
9692
|
+
...csqCondition.related,
|
|
9693
|
+
subquery: {
|
|
9694
|
+
...csqCondition.related.subquery,
|
|
9695
|
+
limit: csqCondition.related.system === "permissions" ? PERMISSIONS_EXISTS_LIMIT : EXISTS_LIMIT
|
|
9696
|
+
}
|
|
9697
|
+
},
|
|
9698
|
+
delegate,
|
|
9699
|
+
queryID,
|
|
9700
|
+
end,
|
|
9701
|
+
name,
|
|
9702
|
+
true
|
|
9703
|
+
);
|
|
9704
|
+
}
|
|
9705
|
+
}
|
|
9706
|
+
if (ast.where && (!fullyAppliedFilters || delegate.applyFiltersAnyway)) {
|
|
9707
|
+
end = applyWhere(end, ast.where, delegate, name);
|
|
9708
|
+
}
|
|
9709
|
+
if (ast.limit !== void 0) {
|
|
9710
|
+
const takeName = `${name}:take`;
|
|
9711
|
+
const take2 = new Take(
|
|
9712
|
+
end,
|
|
9713
|
+
delegate.createStorage(takeName),
|
|
9714
|
+
ast.limit,
|
|
9715
|
+
partitionKey
|
|
9716
|
+
);
|
|
9717
|
+
delegate.addEdge(end, take2);
|
|
9718
|
+
end = delegate.decorateInput(take2, takeName);
|
|
9719
|
+
}
|
|
9720
|
+
if (ast.related) {
|
|
9721
|
+
for (const csq of ast.related) {
|
|
9722
|
+
end = applyCorrelatedSubQuery(csq, delegate, queryID, end, name, false);
|
|
9723
|
+
}
|
|
9724
|
+
}
|
|
9725
|
+
return end;
|
|
9726
|
+
}
|
|
9727
|
+
function applyWhere(input, condition, delegate, name) {
|
|
9728
|
+
if (!conditionIncludesFlippedSubqueryAtAnyLevel(condition)) {
|
|
9729
|
+
return buildFilterPipeline(
|
|
9730
|
+
input,
|
|
9731
|
+
delegate,
|
|
9732
|
+
(filterInput) => applyFilter(filterInput, condition, delegate, name)
|
|
9733
|
+
);
|
|
9734
|
+
}
|
|
9735
|
+
return applyFilterWithFlips(input, condition, delegate, name);
|
|
9736
|
+
}
|
|
9737
|
+
function applyFilterWithFlips(input, condition, delegate, name) {
|
|
9738
|
+
let end = input;
|
|
9739
|
+
assert(condition.type !== "simple", "Simple conditions cannot have flips");
|
|
9740
|
+
switch (condition.type) {
|
|
9741
|
+
case "and": {
|
|
9742
|
+
const [withFlipped, withoutFlipped] = partitionBranches(
|
|
9743
|
+
condition.conditions,
|
|
9744
|
+
conditionIncludesFlippedSubqueryAtAnyLevel
|
|
9745
|
+
);
|
|
9746
|
+
if (withoutFlipped.length > 0) {
|
|
9747
|
+
end = buildFilterPipeline(
|
|
9748
|
+
input,
|
|
9749
|
+
delegate,
|
|
9750
|
+
(filterInput) => applyAnd(
|
|
9751
|
+
filterInput,
|
|
9752
|
+
{
|
|
9753
|
+
type: "and",
|
|
9754
|
+
conditions: withoutFlipped
|
|
9755
|
+
},
|
|
9756
|
+
delegate,
|
|
9757
|
+
name
|
|
9758
|
+
)
|
|
9759
|
+
);
|
|
9760
|
+
}
|
|
9761
|
+
assert(withFlipped.length > 0, "Impossible to have no flips here");
|
|
9762
|
+
for (const cond of withFlipped) {
|
|
9763
|
+
end = applyFilterWithFlips(end, cond, delegate, name);
|
|
9764
|
+
}
|
|
9765
|
+
break;
|
|
9766
|
+
}
|
|
9767
|
+
case "or": {
|
|
9768
|
+
const [withFlipped, withoutFlipped] = partitionBranches(
|
|
9769
|
+
condition.conditions,
|
|
9770
|
+
conditionIncludesFlippedSubqueryAtAnyLevel
|
|
9771
|
+
);
|
|
9772
|
+
assert(withFlipped.length > 0, "Impossible to have no flips here");
|
|
9773
|
+
const ufo = new UnionFanOut(end);
|
|
9774
|
+
delegate.addEdge(end, ufo);
|
|
9775
|
+
end = delegate.decorateInput(ufo, `${name}:ufo`);
|
|
9776
|
+
const branches = [];
|
|
9777
|
+
if (withoutFlipped.length > 0) {
|
|
9778
|
+
branches.push(
|
|
9779
|
+
buildFilterPipeline(
|
|
9780
|
+
end,
|
|
9781
|
+
delegate,
|
|
9782
|
+
(filterInput) => applyOr(
|
|
9783
|
+
filterInput,
|
|
9784
|
+
{
|
|
9785
|
+
type: "or",
|
|
9786
|
+
conditions: withoutFlipped
|
|
9787
|
+
},
|
|
9788
|
+
delegate,
|
|
9789
|
+
name
|
|
9790
|
+
)
|
|
9791
|
+
)
|
|
9792
|
+
);
|
|
9793
|
+
}
|
|
9794
|
+
for (const cond of withFlipped) {
|
|
9795
|
+
branches.push(applyFilterWithFlips(end, cond, delegate, name));
|
|
9796
|
+
}
|
|
9797
|
+
const ufi = new UnionFanIn(ufo, branches);
|
|
9798
|
+
for (const branch of branches) {
|
|
9799
|
+
delegate.addEdge(branch, ufi);
|
|
9800
|
+
}
|
|
9801
|
+
end = delegate.decorateInput(ufi, `${name}:ufi`);
|
|
9802
|
+
break;
|
|
9803
|
+
}
|
|
9804
|
+
case "correlatedSubquery": {
|
|
9805
|
+
const sq = condition.related;
|
|
9806
|
+
const child = buildPipelineInternal(
|
|
9807
|
+
sq.subquery,
|
|
9808
|
+
delegate,
|
|
9809
|
+
"",
|
|
9810
|
+
`${name}.${sq.subquery.alias}`,
|
|
9811
|
+
sq.correlation.childField
|
|
9812
|
+
);
|
|
9813
|
+
const flippedJoin = new FlippedJoin({
|
|
9814
|
+
parent: end,
|
|
9815
|
+
child,
|
|
9816
|
+
parentKey: sq.correlation.parentField,
|
|
9817
|
+
childKey: sq.correlation.childField,
|
|
9818
|
+
relationshipName: must(
|
|
9819
|
+
sq.subquery.alias,
|
|
9820
|
+
"Subquery must have an alias"
|
|
9821
|
+
),
|
|
9822
|
+
hidden: sq.hidden ?? false,
|
|
9823
|
+
system: sq.system ?? "client"
|
|
9824
|
+
});
|
|
9825
|
+
delegate.addEdge(end, flippedJoin);
|
|
9826
|
+
delegate.addEdge(child, flippedJoin);
|
|
9827
|
+
end = delegate.decorateInput(
|
|
9828
|
+
flippedJoin,
|
|
9829
|
+
`${name}:flipped-join(${sq.subquery.alias})`
|
|
9830
|
+
);
|
|
9831
|
+
break;
|
|
9832
|
+
}
|
|
9833
|
+
}
|
|
9834
|
+
return end;
|
|
9835
|
+
}
|
|
9836
|
+
function applyFilter(input, condition, delegate, name) {
|
|
9837
|
+
switch (condition.type) {
|
|
9838
|
+
case "and":
|
|
9839
|
+
return applyAnd(input, condition, delegate, name);
|
|
9840
|
+
case "or":
|
|
9841
|
+
return applyOr(input, condition, delegate, name);
|
|
9842
|
+
case "correlatedSubquery":
|
|
9843
|
+
return applyCorrelatedSubqueryCondition(input, condition, delegate, name);
|
|
9844
|
+
case "simple":
|
|
9845
|
+
return applySimpleCondition(input, delegate, condition);
|
|
9846
|
+
}
|
|
9847
|
+
}
|
|
9848
|
+
function applyAnd(input, condition, delegate, name) {
|
|
9849
|
+
for (const subCondition of condition.conditions) {
|
|
9850
|
+
input = applyFilter(input, subCondition, delegate, name);
|
|
9851
|
+
}
|
|
9852
|
+
return input;
|
|
9853
|
+
}
|
|
9854
|
+
function applyOr(input, condition, delegate, name) {
|
|
9855
|
+
const [subqueryConditions, otherConditions] = groupSubqueryConditions(condition);
|
|
9856
|
+
if (subqueryConditions.length === 0) {
|
|
9857
|
+
const filter = new Filter(
|
|
9858
|
+
input,
|
|
9859
|
+
createPredicate({
|
|
9860
|
+
type: "or",
|
|
9861
|
+
conditions: otherConditions
|
|
9862
|
+
})
|
|
9863
|
+
);
|
|
9864
|
+
delegate.addEdge(input, filter);
|
|
9865
|
+
return filter;
|
|
9866
|
+
}
|
|
9867
|
+
const fanOut = new FanOut(input);
|
|
9868
|
+
delegate.addEdge(input, fanOut);
|
|
9869
|
+
const branches = subqueryConditions.map(
|
|
9870
|
+
(subCondition) => applyFilter(fanOut, subCondition, delegate, name)
|
|
9871
|
+
);
|
|
9872
|
+
if (otherConditions.length > 0) {
|
|
9873
|
+
const filter = new Filter(
|
|
9874
|
+
fanOut,
|
|
9875
|
+
createPredicate({
|
|
9876
|
+
type: "or",
|
|
9877
|
+
conditions: otherConditions
|
|
9878
|
+
})
|
|
9879
|
+
);
|
|
9880
|
+
delegate.addEdge(fanOut, filter);
|
|
9881
|
+
branches.push(filter);
|
|
9882
|
+
}
|
|
9883
|
+
const ret = new FanIn(fanOut, branches);
|
|
9884
|
+
for (const branch of branches) {
|
|
9885
|
+
delegate.addEdge(branch, ret);
|
|
9886
|
+
}
|
|
9887
|
+
fanOut.setFanIn(ret);
|
|
9888
|
+
return ret;
|
|
9889
|
+
}
|
|
9890
|
+
function groupSubqueryConditions(condition) {
|
|
9891
|
+
const partitioned = [[], []];
|
|
9892
|
+
for (const subCondition of condition.conditions) {
|
|
9893
|
+
if (isNotAndDoesNotContainSubquery(subCondition)) {
|
|
9894
|
+
partitioned[1].push(subCondition);
|
|
9895
|
+
} else {
|
|
9896
|
+
partitioned[0].push(subCondition);
|
|
9897
|
+
}
|
|
9898
|
+
}
|
|
9899
|
+
return partitioned;
|
|
9900
|
+
}
|
|
9901
|
+
function isNotAndDoesNotContainSubquery(condition) {
|
|
9902
|
+
if (condition.type === "correlatedSubquery") {
|
|
9903
|
+
return false;
|
|
9904
|
+
}
|
|
9905
|
+
if (condition.type === "simple") {
|
|
9906
|
+
return true;
|
|
9907
|
+
}
|
|
9908
|
+
return condition.conditions.every(isNotAndDoesNotContainSubquery);
|
|
9909
|
+
}
|
|
9910
|
+
function applySimpleCondition(input, delegate, condition) {
|
|
9911
|
+
const filter = new Filter(input, createPredicate(condition));
|
|
9912
|
+
delegate.decorateFilterInput(
|
|
9913
|
+
filter,
|
|
9914
|
+
`${valuePosName(condition.left)}:${condition.op}:${valuePosName(condition.right)}`
|
|
9915
|
+
);
|
|
9916
|
+
delegate.addEdge(input, filter);
|
|
9917
|
+
return filter;
|
|
9918
|
+
}
|
|
9919
|
+
function valuePosName(left) {
|
|
9920
|
+
switch (left.type) {
|
|
9921
|
+
case "static":
|
|
9922
|
+
return left.field;
|
|
9923
|
+
case "literal":
|
|
9924
|
+
return left.value;
|
|
9925
|
+
case "column":
|
|
9926
|
+
return left.name;
|
|
9927
|
+
}
|
|
9928
|
+
}
|
|
9929
|
+
function applyCorrelatedSubQuery(sq, delegate, queryID, end, name, fromCondition) {
|
|
9930
|
+
if (sq.subquery.limit === 0 && fromCondition) {
|
|
9931
|
+
return end;
|
|
9932
|
+
}
|
|
9933
|
+
assert(sq.subquery.alias, "Subquery must have an alias");
|
|
9934
|
+
const child = buildPipelineInternal(
|
|
9935
|
+
sq.subquery,
|
|
9936
|
+
delegate,
|
|
9937
|
+
queryID,
|
|
9938
|
+
`${name}.${sq.subquery.alias}`,
|
|
9939
|
+
sq.correlation.childField
|
|
9940
|
+
);
|
|
9941
|
+
const joinName = `${name}:join(${sq.subquery.alias})`;
|
|
9942
|
+
const join = new Join({
|
|
9943
|
+
parent: end,
|
|
9944
|
+
child,
|
|
9945
|
+
storage: delegate.createStorage(joinName),
|
|
9946
|
+
parentKey: sq.correlation.parentField,
|
|
9947
|
+
childKey: sq.correlation.childField,
|
|
9948
|
+
relationshipName: sq.subquery.alias,
|
|
9949
|
+
hidden: sq.hidden ?? false,
|
|
9950
|
+
system: sq.system ?? "client"
|
|
9951
|
+
});
|
|
9952
|
+
delegate.addEdge(end, join);
|
|
9953
|
+
delegate.addEdge(child, join);
|
|
9954
|
+
return delegate.decorateInput(join, joinName);
|
|
9955
|
+
}
|
|
9956
|
+
function applyCorrelatedSubqueryCondition(input, condition, delegate, name) {
|
|
9957
|
+
assert(condition.op === "EXISTS" || condition.op === "NOT EXISTS");
|
|
9958
|
+
if (condition.related.subquery.limit === 0) {
|
|
9959
|
+
if (condition.op === "EXISTS") {
|
|
9960
|
+
const filter2 = new Filter(input, () => false);
|
|
9961
|
+
delegate.addEdge(input, filter2);
|
|
9962
|
+
return filter2;
|
|
9963
|
+
}
|
|
9964
|
+
const filter = new Filter(input, () => true);
|
|
9965
|
+
delegate.addEdge(input, filter);
|
|
9966
|
+
return filter;
|
|
9967
|
+
}
|
|
9968
|
+
const existsName = `${name}:exists(${condition.related.subquery.alias})`;
|
|
9969
|
+
const exists = new Exists(
|
|
9970
|
+
input,
|
|
9971
|
+
delegate.createStorage(existsName),
|
|
9972
|
+
must(condition.related.subquery.alias),
|
|
9973
|
+
condition.related.correlation.parentField,
|
|
9974
|
+
condition.op
|
|
9975
|
+
);
|
|
9976
|
+
delegate.addEdge(input, exists);
|
|
9977
|
+
return delegate.decorateFilterInput(exists, existsName);
|
|
9978
|
+
}
|
|
9979
|
+
function gatherCorrelatedSubqueryQueryConditions(condition) {
|
|
9980
|
+
const csqs = [];
|
|
9981
|
+
const gather = (condition2) => {
|
|
9982
|
+
if (condition2.type === "correlatedSubquery") {
|
|
9983
|
+
csqs.push(condition2);
|
|
9984
|
+
return;
|
|
9985
|
+
}
|
|
9986
|
+
if (condition2.type === "and" || condition2.type === "or") {
|
|
9987
|
+
for (const c of condition2.conditions) {
|
|
9988
|
+
gather(c);
|
|
9989
|
+
}
|
|
9990
|
+
return;
|
|
9991
|
+
}
|
|
9992
|
+
};
|
|
9993
|
+
if (condition) {
|
|
9994
|
+
gather(condition);
|
|
9995
|
+
}
|
|
9996
|
+
return csqs;
|
|
9997
|
+
}
|
|
9998
|
+
function assertOrderingIncludesPK(ordering, pk) {
|
|
9999
|
+
const orderingFields = ordering.map(([field]) => field);
|
|
10000
|
+
const missingFields = pk.filter((pkField) => !orderingFields.includes(pkField));
|
|
10001
|
+
if (missingFields.length > 0) {
|
|
10002
|
+
throw new Error(
|
|
10003
|
+
`Ordering must include all primary key fields. Missing: ${missingFields.join(
|
|
10004
|
+
", "
|
|
10005
|
+
)}. ZQL automatically appends primary key fields to the ordering if they are missing
|
|
10006
|
+
so a common cause of this error is a casing mismatch between Postgres and ZQL.
|
|
10007
|
+
E.g., "userid" vs "userID".
|
|
10008
|
+
You may want to add double-quotes around your Postgres column names to prevent Postgres from lower-casing them:
|
|
10009
|
+
https://www.postgresql.org/docs/current/sql-syntax-lexical.htm`
|
|
10010
|
+
);
|
|
10011
|
+
}
|
|
10012
|
+
}
|
|
10013
|
+
function uniquifyCorrelatedSubqueryConditionAliases(ast) {
|
|
10014
|
+
if (!ast.where) {
|
|
10015
|
+
return ast;
|
|
10016
|
+
}
|
|
10017
|
+
const { where } = ast;
|
|
10018
|
+
if (where.type !== "and" && where.type !== "or") {
|
|
10019
|
+
return ast;
|
|
10020
|
+
}
|
|
10021
|
+
let count = 0;
|
|
10022
|
+
const uniquifyCorrelatedSubquery = (csqc) => ({
|
|
10023
|
+
...csqc,
|
|
10024
|
+
related: {
|
|
10025
|
+
...csqc.related,
|
|
10026
|
+
subquery: {
|
|
10027
|
+
...csqc.related.subquery,
|
|
10028
|
+
alias: (csqc.related.subquery.alias ?? "") + "_" + count++
|
|
10029
|
+
}
|
|
10030
|
+
}
|
|
10031
|
+
});
|
|
10032
|
+
const uniquify = (cond) => {
|
|
10033
|
+
if (cond.type === "simple") {
|
|
10034
|
+
return cond;
|
|
10035
|
+
} else if (cond.type === "correlatedSubquery") {
|
|
10036
|
+
return uniquifyCorrelatedSubquery(cond);
|
|
10037
|
+
}
|
|
10038
|
+
const conditions = [];
|
|
10039
|
+
for (const c of cond.conditions) {
|
|
10040
|
+
conditions.push(uniquify(c));
|
|
10041
|
+
}
|
|
10042
|
+
return {
|
|
10043
|
+
type: cond.type,
|
|
10044
|
+
conditions
|
|
10045
|
+
};
|
|
10046
|
+
};
|
|
10047
|
+
const result = {
|
|
10048
|
+
...ast,
|
|
10049
|
+
where: uniquify(where)
|
|
10050
|
+
};
|
|
10051
|
+
return result;
|
|
10052
|
+
}
|
|
10053
|
+
function conditionIncludesFlippedSubqueryAtAnyLevel(cond) {
|
|
10054
|
+
if (cond.type === "correlatedSubquery") {
|
|
10055
|
+
return !!cond.flip;
|
|
10056
|
+
}
|
|
10057
|
+
if (cond.type === "and" || cond.type === "or") {
|
|
10058
|
+
return cond.conditions.some(
|
|
10059
|
+
(c) => conditionIncludesFlippedSubqueryAtAnyLevel(c)
|
|
10060
|
+
);
|
|
10061
|
+
}
|
|
10062
|
+
return false;
|
|
10063
|
+
}
|
|
10064
|
+
function partitionBranches(conditions, predicate) {
|
|
10065
|
+
const matched = [];
|
|
10066
|
+
const notMatched = [];
|
|
10067
|
+
for (const c of conditions) {
|
|
10068
|
+
if (predicate(c)) {
|
|
10069
|
+
matched.push(c);
|
|
10070
|
+
} else {
|
|
10071
|
+
notMatched.push(c);
|
|
10072
|
+
}
|
|
10073
|
+
}
|
|
10074
|
+
return [matched, notMatched];
|
|
10075
|
+
}
|
|
10076
|
+
|
|
10077
|
+
// ../zql/src/error.ts
|
|
10078
|
+
var NotImplementedError = class extends Error {
|
|
10079
|
+
constructor(message) {
|
|
10080
|
+
super(message);
|
|
10081
|
+
this.name = "NotImplementedError";
|
|
10082
|
+
}
|
|
10083
|
+
};
|
|
10084
|
+
|
|
10085
|
+
// ../zql/src/ivm/array-view.ts
|
|
10086
|
+
var ArrayView = class {
|
|
10087
|
+
#input;
|
|
10088
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
10089
|
+
#schema;
|
|
10090
|
+
#format;
|
|
10091
|
+
// Synthetic "root" entry that has a single "" relationship, so that we can
|
|
10092
|
+
// treat all changes, including the root change, generically.
|
|
10093
|
+
#root;
|
|
10094
|
+
onDestroy;
|
|
10095
|
+
#dirty = false;
|
|
10096
|
+
#resultType = "unknown";
|
|
10097
|
+
#error;
|
|
10098
|
+
#updateTTL;
|
|
10099
|
+
constructor(input, format, queryComplete, updateTTL) {
|
|
10100
|
+
this.#input = input;
|
|
10101
|
+
this.#schema = input.getSchema();
|
|
10102
|
+
this.#format = format;
|
|
10103
|
+
this.#updateTTL = updateTTL;
|
|
10104
|
+
this.#root = { "": format.singular ? void 0 : [] };
|
|
10105
|
+
input.setOutput(this);
|
|
10106
|
+
if (queryComplete === true) {
|
|
10107
|
+
this.#resultType = "complete";
|
|
10108
|
+
} else if ("error" in queryComplete) {
|
|
10109
|
+
this.#resultType = "error";
|
|
10110
|
+
this.#error = queryComplete;
|
|
10111
|
+
} else {
|
|
10112
|
+
void queryComplete.then(() => {
|
|
10113
|
+
this.#resultType = "complete";
|
|
10114
|
+
this.#fireListeners();
|
|
10115
|
+
}).catch((e) => {
|
|
10116
|
+
this.#resultType = "error";
|
|
10117
|
+
this.#error = e;
|
|
10118
|
+
this.#fireListeners();
|
|
10119
|
+
});
|
|
10120
|
+
}
|
|
10121
|
+
this.#hydrate();
|
|
10122
|
+
}
|
|
10123
|
+
get data() {
|
|
10124
|
+
return this.#root[""];
|
|
10125
|
+
}
|
|
10126
|
+
addListener(listener) {
|
|
10127
|
+
assert(!this.#listeners.has(listener), "Listener already registered");
|
|
10128
|
+
this.#listeners.add(listener);
|
|
10129
|
+
this.#fireListener(listener);
|
|
10130
|
+
return () => {
|
|
10131
|
+
this.#listeners.delete(listener);
|
|
10132
|
+
};
|
|
10133
|
+
}
|
|
10134
|
+
#fireListeners() {
|
|
10135
|
+
for (const listener of this.#listeners) {
|
|
10136
|
+
this.#fireListener(listener);
|
|
10137
|
+
}
|
|
10138
|
+
}
|
|
10139
|
+
#fireListener(listener) {
|
|
10140
|
+
listener(this.data, this.#resultType, this.#error);
|
|
10141
|
+
}
|
|
10142
|
+
destroy() {
|
|
10143
|
+
this.onDestroy?.();
|
|
10144
|
+
}
|
|
10145
|
+
#hydrate() {
|
|
10146
|
+
this.#dirty = true;
|
|
10147
|
+
for (const node of this.#input.fetch({})) {
|
|
10148
|
+
applyChange(
|
|
10149
|
+
this.#root,
|
|
10150
|
+
{ type: "add", node },
|
|
10151
|
+
this.#schema,
|
|
10152
|
+
"",
|
|
10153
|
+
this.#format
|
|
10154
|
+
);
|
|
10155
|
+
}
|
|
10156
|
+
this.flush();
|
|
10157
|
+
}
|
|
10158
|
+
push(change) {
|
|
10159
|
+
this.#dirty = true;
|
|
10160
|
+
applyChange(this.#root, change, this.#schema, "", this.#format);
|
|
10161
|
+
}
|
|
10162
|
+
flush() {
|
|
10163
|
+
if (!this.#dirty) {
|
|
10164
|
+
return;
|
|
10165
|
+
}
|
|
10166
|
+
this.#dirty = false;
|
|
10167
|
+
this.#fireListeners();
|
|
10168
|
+
}
|
|
10169
|
+
updateTTL(ttl) {
|
|
10170
|
+
this.#updateTTL(ttl);
|
|
10171
|
+
}
|
|
10172
|
+
};
|
|
10173
|
+
|
|
10174
|
+
// ../zero-types/src/format.ts
|
|
10175
|
+
var defaultFormat = {
|
|
10176
|
+
singular: false,
|
|
10177
|
+
relationships: {}
|
|
10178
|
+
};
|
|
10179
|
+
|
|
10180
|
+
// ../zql/src/query/assert-no-not-exists.ts
|
|
10181
|
+
function assertNoNotExists(condition) {
|
|
10182
|
+
switch (condition.type) {
|
|
10183
|
+
case "simple":
|
|
10184
|
+
return;
|
|
10185
|
+
case "correlatedSubquery":
|
|
10186
|
+
if (condition.op === "NOT EXISTS") {
|
|
10187
|
+
throw new Error(
|
|
10188
|
+
"not(exists()) is not supported on the client - see https://bugs.rocicorp.dev/issue/3438"
|
|
10189
|
+
);
|
|
10190
|
+
}
|
|
10191
|
+
if (condition.related.subquery.where) {
|
|
10192
|
+
assertNoNotExists(condition.related.subquery.where);
|
|
10193
|
+
}
|
|
10194
|
+
return;
|
|
10195
|
+
case "and":
|
|
10196
|
+
case "or":
|
|
10197
|
+
for (const c of condition.conditions) {
|
|
10198
|
+
assertNoNotExists(c);
|
|
10199
|
+
}
|
|
10200
|
+
return;
|
|
10201
|
+
default:
|
|
10202
|
+
unreachable(condition);
|
|
10203
|
+
}
|
|
10204
|
+
}
|
|
10205
|
+
|
|
10206
|
+
// ../zql/src/query/query.ts
|
|
10207
|
+
var delegateSymbol = Symbol("delegate");
|
|
10208
|
+
|
|
10209
|
+
// ../zql/src/query/query-impl.ts
|
|
10210
|
+
function materialize(query, delegate, factoryOrOptions, maybeOptions) {
|
|
10211
|
+
if (typeof factoryOrOptions === "function") {
|
|
10212
|
+
return query[delegateSymbol](delegate).materialize(factoryOrOptions, maybeOptions?.ttl);
|
|
10213
|
+
}
|
|
10214
|
+
return query[delegateSymbol](delegate).materialize(factoryOrOptions?.ttl);
|
|
10215
|
+
}
|
|
10216
|
+
var astSymbol = Symbol();
|
|
10217
|
+
function newQuery(delegate, schema, table2) {
|
|
10218
|
+
return new QueryImpl(
|
|
10219
|
+
delegate,
|
|
10220
|
+
schema,
|
|
10221
|
+
table2,
|
|
10222
|
+
{ table: table2 },
|
|
10223
|
+
defaultFormat,
|
|
10224
|
+
void 0
|
|
10225
|
+
);
|
|
10226
|
+
}
|
|
10227
|
+
var newQuerySymbol = Symbol();
|
|
10228
|
+
var AbstractQuery = class {
|
|
10229
|
+
#schema;
|
|
10230
|
+
_delegate;
|
|
10231
|
+
#tableName;
|
|
10232
|
+
_ast;
|
|
10233
|
+
format;
|
|
10234
|
+
#hash = "";
|
|
10235
|
+
#system;
|
|
10236
|
+
#currentJunction;
|
|
10237
|
+
customQueryID;
|
|
10238
|
+
constructor(delegate, schema, tableName, ast, format, system, customQueryID, currentJunction) {
|
|
10239
|
+
this.#schema = schema;
|
|
10240
|
+
this._delegate = delegate;
|
|
10241
|
+
this.#tableName = tableName;
|
|
10242
|
+
this._ast = ast;
|
|
10243
|
+
this.format = format;
|
|
10244
|
+
this.#system = system;
|
|
10245
|
+
this.#currentJunction = currentJunction;
|
|
10246
|
+
this.customQueryID = customQueryID;
|
|
10247
|
+
}
|
|
10248
|
+
[delegateSymbol](delegate) {
|
|
10249
|
+
return this[newQuerySymbol](
|
|
10250
|
+
delegate,
|
|
10251
|
+
this.#schema,
|
|
10252
|
+
this.#tableName,
|
|
10253
|
+
this._ast,
|
|
10254
|
+
this.format,
|
|
10255
|
+
this.customQueryID,
|
|
10256
|
+
this.#currentJunction
|
|
10257
|
+
);
|
|
10258
|
+
}
|
|
10259
|
+
nameAndArgs(name, args) {
|
|
10260
|
+
return this[newQuerySymbol](
|
|
10261
|
+
this._delegate,
|
|
10262
|
+
this.#schema,
|
|
10263
|
+
this.#tableName,
|
|
10264
|
+
this._ast,
|
|
10265
|
+
this.format,
|
|
10266
|
+
{
|
|
10267
|
+
name,
|
|
10268
|
+
args
|
|
10269
|
+
},
|
|
10270
|
+
this.#currentJunction
|
|
10271
|
+
);
|
|
10272
|
+
}
|
|
10273
|
+
get [astSymbol]() {
|
|
10274
|
+
return this._ast;
|
|
10275
|
+
}
|
|
10276
|
+
get ast() {
|
|
10277
|
+
return this._completeAst();
|
|
10278
|
+
}
|
|
10279
|
+
hash() {
|
|
10280
|
+
if (!this.#hash) {
|
|
10281
|
+
this.#hash = hashOfAST(this._completeAst());
|
|
10282
|
+
}
|
|
10283
|
+
return this.#hash;
|
|
10284
|
+
}
|
|
10285
|
+
one = () => this[newQuerySymbol](
|
|
10286
|
+
this._delegate,
|
|
10287
|
+
this.#schema,
|
|
10288
|
+
this.#tableName,
|
|
10289
|
+
{
|
|
10290
|
+
...this._ast,
|
|
10291
|
+
limit: 1
|
|
10292
|
+
},
|
|
10293
|
+
{
|
|
10294
|
+
...this.format,
|
|
10295
|
+
singular: true
|
|
10296
|
+
},
|
|
10297
|
+
this.customQueryID,
|
|
10298
|
+
this.#currentJunction
|
|
10299
|
+
);
|
|
10300
|
+
whereExists = (relationship, cbOrOptions, options) => {
|
|
10301
|
+
const cb = typeof cbOrOptions === "function" ? cbOrOptions : void 0;
|
|
10302
|
+
const opts = typeof cbOrOptions === "function" ? options : cbOrOptions;
|
|
10303
|
+
const flipped = opts?.flip ?? false;
|
|
10304
|
+
return this.where(({ exists }) => exists(relationship, cb, { flip: flipped }));
|
|
10305
|
+
};
|
|
10306
|
+
related = (relationship, cb) => {
|
|
10307
|
+
if (relationship.startsWith(SUBQ_PREFIX)) {
|
|
10308
|
+
throw new Error(
|
|
10309
|
+
`Relationship names may not start with "${SUBQ_PREFIX}". That is a reserved prefix.`
|
|
10310
|
+
);
|
|
10311
|
+
}
|
|
10312
|
+
cb = cb ?? ((q) => q);
|
|
10313
|
+
const related = this.#schema.relationships[this.#tableName][relationship];
|
|
10314
|
+
assert(related, "Invalid relationship");
|
|
10315
|
+
if (isOneHop(related)) {
|
|
10316
|
+
const { destSchema, destField, sourceField, cardinality } = related[0];
|
|
10317
|
+
const q = this[newQuerySymbol](
|
|
10318
|
+
this._delegate,
|
|
10319
|
+
this.#schema,
|
|
10320
|
+
destSchema,
|
|
10321
|
+
{
|
|
10322
|
+
table: destSchema,
|
|
10323
|
+
alias: relationship
|
|
10324
|
+
},
|
|
10325
|
+
{
|
|
10326
|
+
relationships: {},
|
|
10327
|
+
singular: cardinality === "one"
|
|
10328
|
+
},
|
|
10329
|
+
this.customQueryID,
|
|
10330
|
+
void 0
|
|
10331
|
+
);
|
|
10332
|
+
const sq = cb(q);
|
|
10333
|
+
assert(
|
|
10334
|
+
isCompoundKey(sourceField),
|
|
10335
|
+
"The source of a relationship must specify at last 1 field"
|
|
10336
|
+
);
|
|
10337
|
+
assert(
|
|
10338
|
+
isCompoundKey(destField),
|
|
10339
|
+
"The destination of a relationship must specify at last 1 field"
|
|
10340
|
+
);
|
|
10341
|
+
assert(
|
|
10342
|
+
sourceField.length === destField.length,
|
|
10343
|
+
"The source and destination of a relationship must have the same number of fields"
|
|
10344
|
+
);
|
|
10345
|
+
return this[newQuerySymbol](
|
|
10346
|
+
this._delegate,
|
|
10347
|
+
this.#schema,
|
|
10348
|
+
this.#tableName,
|
|
10349
|
+
{
|
|
10350
|
+
...this._ast,
|
|
10351
|
+
related: [
|
|
10352
|
+
...this._ast.related ?? [],
|
|
10353
|
+
{
|
|
10354
|
+
system: this.#system,
|
|
10355
|
+
correlation: {
|
|
10356
|
+
parentField: sourceField,
|
|
10357
|
+
childField: destField
|
|
10358
|
+
},
|
|
10359
|
+
subquery: addPrimaryKeysToAst(
|
|
10360
|
+
this.#schema.tables[destSchema],
|
|
10361
|
+
sq._ast
|
|
10362
|
+
)
|
|
10363
|
+
}
|
|
10364
|
+
]
|
|
10365
|
+
},
|
|
10366
|
+
{
|
|
10367
|
+
...this.format,
|
|
10368
|
+
relationships: {
|
|
10369
|
+
...this.format.relationships,
|
|
10370
|
+
[relationship]: sq.format
|
|
10371
|
+
}
|
|
10372
|
+
},
|
|
10373
|
+
this.customQueryID,
|
|
10374
|
+
this.#currentJunction
|
|
10375
|
+
);
|
|
10376
|
+
}
|
|
10377
|
+
if (isTwoHop(related)) {
|
|
10378
|
+
const [firstRelation, secondRelation] = related;
|
|
10379
|
+
const { destSchema } = secondRelation;
|
|
10380
|
+
const junctionSchema = firstRelation.destSchema;
|
|
10381
|
+
const sq = cb(
|
|
10382
|
+
this[newQuerySymbol](
|
|
10383
|
+
this._delegate,
|
|
10384
|
+
this.#schema,
|
|
10385
|
+
destSchema,
|
|
10386
|
+
{
|
|
10387
|
+
table: destSchema,
|
|
10388
|
+
alias: relationship
|
|
10389
|
+
},
|
|
10390
|
+
{
|
|
10391
|
+
relationships: {},
|
|
10392
|
+
singular: secondRelation.cardinality === "one"
|
|
10393
|
+
},
|
|
10394
|
+
this.customQueryID,
|
|
10395
|
+
relationship
|
|
10396
|
+
)
|
|
10397
|
+
);
|
|
10398
|
+
assert(isCompoundKey(firstRelation.sourceField), "Invalid relationship");
|
|
10399
|
+
assert(isCompoundKey(firstRelation.destField), "Invalid relationship");
|
|
10400
|
+
assert(isCompoundKey(secondRelation.sourceField), "Invalid relationship");
|
|
10401
|
+
assert(isCompoundKey(secondRelation.destField), "Invalid relationship");
|
|
10402
|
+
return this[newQuerySymbol](
|
|
10403
|
+
this._delegate,
|
|
10404
|
+
this.#schema,
|
|
10405
|
+
this.#tableName,
|
|
10406
|
+
{
|
|
10407
|
+
...this._ast,
|
|
10408
|
+
related: [
|
|
10409
|
+
...this._ast.related ?? [],
|
|
10410
|
+
{
|
|
10411
|
+
system: this.#system,
|
|
10412
|
+
correlation: {
|
|
10413
|
+
parentField: firstRelation.sourceField,
|
|
10414
|
+
childField: firstRelation.destField
|
|
10415
|
+
},
|
|
10416
|
+
hidden: true,
|
|
10417
|
+
subquery: {
|
|
10418
|
+
table: junctionSchema,
|
|
10419
|
+
alias: relationship,
|
|
10420
|
+
orderBy: addPrimaryKeys(
|
|
10421
|
+
this.#schema.tables[junctionSchema],
|
|
10422
|
+
void 0
|
|
10423
|
+
),
|
|
10424
|
+
related: [
|
|
10425
|
+
{
|
|
10426
|
+
system: this.#system,
|
|
10427
|
+
correlation: {
|
|
10428
|
+
parentField: secondRelation.sourceField,
|
|
10429
|
+
childField: secondRelation.destField
|
|
10430
|
+
},
|
|
10431
|
+
subquery: addPrimaryKeysToAst(
|
|
10432
|
+
this.#schema.tables[destSchema],
|
|
10433
|
+
sq._ast
|
|
10434
|
+
)
|
|
10435
|
+
}
|
|
10436
|
+
]
|
|
10437
|
+
}
|
|
10438
|
+
}
|
|
10439
|
+
]
|
|
10440
|
+
},
|
|
10441
|
+
{
|
|
10442
|
+
...this.format,
|
|
10443
|
+
relationships: {
|
|
10444
|
+
...this.format.relationships,
|
|
10445
|
+
[relationship]: sq.format
|
|
10446
|
+
}
|
|
10447
|
+
},
|
|
10448
|
+
this.customQueryID,
|
|
10449
|
+
this.#currentJunction
|
|
10450
|
+
);
|
|
10451
|
+
}
|
|
10452
|
+
throw new Error(`Invalid relationship ${relationship}`);
|
|
10453
|
+
};
|
|
10454
|
+
where = (fieldOrExpressionFactory, opOrValue, value) => {
|
|
10455
|
+
let cond;
|
|
10456
|
+
if (typeof fieldOrExpressionFactory === "function") {
|
|
10457
|
+
cond = fieldOrExpressionFactory(
|
|
10458
|
+
new ExpressionBuilder(this._exists)
|
|
10459
|
+
);
|
|
10460
|
+
} else {
|
|
10461
|
+
assert(opOrValue !== void 0, "Invalid condition");
|
|
10462
|
+
cond = cmp(fieldOrExpressionFactory, opOrValue, value);
|
|
10463
|
+
}
|
|
10464
|
+
const existingWhere = this._ast.where;
|
|
10465
|
+
if (existingWhere) {
|
|
10466
|
+
cond = and(existingWhere, cond);
|
|
10467
|
+
}
|
|
10468
|
+
const where = simplifyCondition(cond);
|
|
10469
|
+
if (this.#system === "client") {
|
|
10470
|
+
assertNoNotExists(where);
|
|
10471
|
+
}
|
|
10472
|
+
return this[newQuerySymbol](
|
|
10473
|
+
this._delegate,
|
|
10474
|
+
this.#schema,
|
|
10475
|
+
this.#tableName,
|
|
10476
|
+
{
|
|
10477
|
+
...this._ast,
|
|
10478
|
+
where
|
|
10479
|
+
},
|
|
10480
|
+
this.format,
|
|
10481
|
+
this.customQueryID,
|
|
10482
|
+
this.#currentJunction
|
|
10483
|
+
);
|
|
10484
|
+
};
|
|
10485
|
+
start = (row, opts) => this[newQuerySymbol](
|
|
10486
|
+
this._delegate,
|
|
10487
|
+
this.#schema,
|
|
10488
|
+
this.#tableName,
|
|
10489
|
+
{
|
|
10490
|
+
...this._ast,
|
|
10491
|
+
start: {
|
|
10492
|
+
row,
|
|
10493
|
+
exclusive: !opts?.inclusive
|
|
10494
|
+
}
|
|
10495
|
+
},
|
|
10496
|
+
this.format,
|
|
10497
|
+
this.customQueryID,
|
|
10498
|
+
this.#currentJunction
|
|
10499
|
+
);
|
|
10500
|
+
limit = (limit) => {
|
|
10501
|
+
if (limit < 0) {
|
|
10502
|
+
throw new Error("Limit must be non-negative");
|
|
10503
|
+
}
|
|
10504
|
+
if ((limit | 0) !== limit) {
|
|
10505
|
+
throw new Error("Limit must be an integer");
|
|
10506
|
+
}
|
|
10507
|
+
if (this.#currentJunction) {
|
|
10508
|
+
throw new NotImplementedError(
|
|
10509
|
+
"Limit is not supported in junction relationships yet. Junction relationship being limited: " + this.#currentJunction
|
|
10510
|
+
);
|
|
10511
|
+
}
|
|
10512
|
+
return this[newQuerySymbol](
|
|
10513
|
+
this._delegate,
|
|
10514
|
+
this.#schema,
|
|
10515
|
+
this.#tableName,
|
|
10516
|
+
{
|
|
10517
|
+
...this._ast,
|
|
10518
|
+
limit
|
|
10519
|
+
},
|
|
10520
|
+
this.format,
|
|
10521
|
+
this.customQueryID,
|
|
10522
|
+
this.#currentJunction
|
|
10523
|
+
);
|
|
10524
|
+
};
|
|
10525
|
+
orderBy = (field, direction) => {
|
|
10526
|
+
if (this.#currentJunction) {
|
|
10527
|
+
throw new NotImplementedError(
|
|
10528
|
+
"Order by is not supported in junction relationships yet. Junction relationship being ordered: " + this.#currentJunction
|
|
10529
|
+
);
|
|
10530
|
+
}
|
|
10531
|
+
return this[newQuerySymbol](
|
|
10532
|
+
this._delegate,
|
|
10533
|
+
this.#schema,
|
|
10534
|
+
this.#tableName,
|
|
10535
|
+
{
|
|
10536
|
+
...this._ast,
|
|
10537
|
+
orderBy: [...this._ast.orderBy ?? [], [field, direction]]
|
|
10538
|
+
},
|
|
10539
|
+
this.format,
|
|
10540
|
+
this.customQueryID,
|
|
10541
|
+
this.#currentJunction
|
|
10542
|
+
);
|
|
10543
|
+
};
|
|
10544
|
+
_exists = (relationship, cb, options) => {
|
|
10545
|
+
cb = cb ?? ((q) => q);
|
|
10546
|
+
const flip = options?.flip ?? false;
|
|
10547
|
+
const related = this.#schema.relationships[this.#tableName][relationship];
|
|
10548
|
+
assert(related, "Invalid relationship");
|
|
10549
|
+
if (isOneHop(related)) {
|
|
10550
|
+
const { destSchema, sourceField, destField } = related[0];
|
|
10551
|
+
assert(isCompoundKey(sourceField), "Invalid relationship");
|
|
10552
|
+
assert(isCompoundKey(destField), "Invalid relationship");
|
|
10553
|
+
const sq = cb(
|
|
10554
|
+
this[newQuerySymbol](
|
|
10555
|
+
this._delegate,
|
|
10556
|
+
this.#schema,
|
|
10557
|
+
destSchema,
|
|
10558
|
+
{
|
|
10559
|
+
table: destSchema,
|
|
10560
|
+
alias: `${SUBQ_PREFIX}${relationship}`
|
|
10561
|
+
},
|
|
10562
|
+
defaultFormat,
|
|
10563
|
+
this.customQueryID,
|
|
10564
|
+
void 0
|
|
10565
|
+
)
|
|
10566
|
+
);
|
|
10567
|
+
return {
|
|
10568
|
+
type: "correlatedSubquery",
|
|
10569
|
+
related: {
|
|
10570
|
+
system: this.#system,
|
|
10571
|
+
correlation: {
|
|
10572
|
+
parentField: sourceField,
|
|
10573
|
+
childField: destField
|
|
10574
|
+
},
|
|
10575
|
+
subquery: addPrimaryKeysToAst(
|
|
10576
|
+
this.#schema.tables[destSchema],
|
|
10577
|
+
sq._ast
|
|
10578
|
+
)
|
|
10579
|
+
},
|
|
10580
|
+
op: "EXISTS",
|
|
10581
|
+
flip
|
|
10582
|
+
};
|
|
10583
|
+
}
|
|
10584
|
+
if (isTwoHop(related)) {
|
|
10585
|
+
const [firstRelation, secondRelation] = related;
|
|
10586
|
+
assert(isCompoundKey(firstRelation.sourceField), "Invalid relationship");
|
|
10587
|
+
assert(isCompoundKey(firstRelation.destField), "Invalid relationship");
|
|
10588
|
+
assert(isCompoundKey(secondRelation.sourceField), "Invalid relationship");
|
|
10589
|
+
assert(isCompoundKey(secondRelation.destField), "Invalid relationship");
|
|
10590
|
+
const { destSchema } = secondRelation;
|
|
10591
|
+
const junctionSchema = firstRelation.destSchema;
|
|
10592
|
+
const queryToDest = cb(
|
|
10593
|
+
this[newQuerySymbol](
|
|
10594
|
+
this._delegate,
|
|
10595
|
+
this.#schema,
|
|
10596
|
+
destSchema,
|
|
10597
|
+
{
|
|
10598
|
+
table: destSchema,
|
|
10599
|
+
alias: `${SUBQ_PREFIX}zhidden_${relationship}`
|
|
10600
|
+
},
|
|
10601
|
+
defaultFormat,
|
|
10602
|
+
this.customQueryID,
|
|
10603
|
+
relationship
|
|
10604
|
+
)
|
|
10605
|
+
);
|
|
10606
|
+
return {
|
|
10607
|
+
type: "correlatedSubquery",
|
|
10608
|
+
related: {
|
|
10609
|
+
system: this.#system,
|
|
10610
|
+
correlation: {
|
|
10611
|
+
parentField: firstRelation.sourceField,
|
|
10612
|
+
childField: firstRelation.destField
|
|
10613
|
+
},
|
|
10614
|
+
subquery: {
|
|
10615
|
+
table: junctionSchema,
|
|
10616
|
+
alias: `${SUBQ_PREFIX}${relationship}`,
|
|
10617
|
+
orderBy: addPrimaryKeys(
|
|
10618
|
+
this.#schema.tables[junctionSchema],
|
|
10619
|
+
void 0
|
|
10620
|
+
),
|
|
10621
|
+
where: {
|
|
10622
|
+
type: "correlatedSubquery",
|
|
10623
|
+
related: {
|
|
10624
|
+
system: this.#system,
|
|
10625
|
+
correlation: {
|
|
10626
|
+
parentField: secondRelation.sourceField,
|
|
10627
|
+
childField: secondRelation.destField
|
|
10628
|
+
},
|
|
10629
|
+
subquery: addPrimaryKeysToAst(
|
|
10630
|
+
this.#schema.tables[destSchema],
|
|
10631
|
+
queryToDest._ast
|
|
10632
|
+
)
|
|
10633
|
+
},
|
|
10634
|
+
op: "EXISTS",
|
|
10635
|
+
flip
|
|
10636
|
+
}
|
|
10637
|
+
}
|
|
10638
|
+
},
|
|
10639
|
+
op: "EXISTS",
|
|
10640
|
+
flip
|
|
10641
|
+
};
|
|
10642
|
+
}
|
|
10643
|
+
throw new Error(`Invalid relationship ${relationship}`);
|
|
10644
|
+
};
|
|
10645
|
+
#completedAST;
|
|
10646
|
+
_completeAst() {
|
|
10647
|
+
if (!this.#completedAST) {
|
|
10648
|
+
const finalOrderBy = addPrimaryKeys(
|
|
10649
|
+
this.#schema.tables[this.#tableName],
|
|
10650
|
+
this._ast.orderBy
|
|
10651
|
+
);
|
|
10652
|
+
if (this._ast.start) {
|
|
10653
|
+
const { row } = this._ast.start;
|
|
10654
|
+
const narrowedRow = {};
|
|
10655
|
+
for (const [field] of finalOrderBy) {
|
|
10656
|
+
narrowedRow[field] = row[field];
|
|
10657
|
+
}
|
|
10658
|
+
this.#completedAST = {
|
|
10659
|
+
...this._ast,
|
|
10660
|
+
start: {
|
|
10661
|
+
...this._ast.start,
|
|
10662
|
+
row: narrowedRow
|
|
10663
|
+
},
|
|
10664
|
+
orderBy: finalOrderBy
|
|
10665
|
+
};
|
|
10666
|
+
} else {
|
|
10667
|
+
this.#completedAST = {
|
|
10668
|
+
...this._ast,
|
|
10669
|
+
orderBy: addPrimaryKeys(
|
|
10670
|
+
this.#schema.tables[this.#tableName],
|
|
10671
|
+
this._ast.orderBy
|
|
10672
|
+
)
|
|
10673
|
+
};
|
|
10674
|
+
}
|
|
10675
|
+
}
|
|
10676
|
+
return this.#completedAST;
|
|
10677
|
+
}
|
|
10678
|
+
};
|
|
10679
|
+
var completedAstSymbol = Symbol();
|
|
10680
|
+
var QueryImpl = class _QueryImpl extends AbstractQuery {
|
|
10681
|
+
#system;
|
|
10682
|
+
constructor(delegate, schema, tableName, ast = { table: tableName }, format = defaultFormat, system = "client", customQueryID, currentJunction) {
|
|
10683
|
+
super(
|
|
10684
|
+
delegate,
|
|
10685
|
+
schema,
|
|
10686
|
+
tableName,
|
|
10687
|
+
ast,
|
|
10688
|
+
format,
|
|
10689
|
+
system,
|
|
10690
|
+
customQueryID,
|
|
10691
|
+
currentJunction
|
|
10692
|
+
);
|
|
10693
|
+
this.#system = system;
|
|
10694
|
+
}
|
|
10695
|
+
get [completedAstSymbol]() {
|
|
10696
|
+
return this._completeAst();
|
|
10697
|
+
}
|
|
10698
|
+
[newQuerySymbol](delegate, schema, tableName, ast, format, customQueryID, currentJunction) {
|
|
10699
|
+
return new _QueryImpl(
|
|
10700
|
+
delegate,
|
|
10701
|
+
schema,
|
|
10702
|
+
tableName,
|
|
10703
|
+
ast,
|
|
10704
|
+
format,
|
|
10705
|
+
this.#system,
|
|
10706
|
+
customQueryID,
|
|
10707
|
+
currentJunction
|
|
10708
|
+
);
|
|
10709
|
+
}
|
|
10710
|
+
materialize(factoryOrTTL, ttl = DEFAULT_TTL_MS) {
|
|
10711
|
+
const delegate = must(
|
|
10712
|
+
this._delegate,
|
|
10713
|
+
"materialize requires a query delegate to be set"
|
|
10714
|
+
);
|
|
10715
|
+
let factory;
|
|
10716
|
+
if (typeof factoryOrTTL === "function") {
|
|
10717
|
+
factory = factoryOrTTL;
|
|
10718
|
+
} else {
|
|
10719
|
+
ttl = factoryOrTTL ?? DEFAULT_TTL_MS;
|
|
10720
|
+
}
|
|
10721
|
+
const ast = this._completeAst();
|
|
10722
|
+
const queryID = this.customQueryID ? hashOfNameAndArgs(this.customQueryID.name, this.customQueryID.args) : this.hash();
|
|
10723
|
+
const queryCompleteResolver = resolver7();
|
|
10724
|
+
let queryComplete = delegate.defaultQueryComplete;
|
|
10725
|
+
const updateTTL = (newTTL) => {
|
|
10726
|
+
this.customQueryID ? delegate.updateCustomQuery(this.customQueryID, newTTL) : delegate.updateServerQuery(ast, newTTL);
|
|
10727
|
+
};
|
|
10728
|
+
const gotCallback = (got, error) => {
|
|
10729
|
+
if (error) {
|
|
10730
|
+
queryCompleteResolver.reject(error);
|
|
10731
|
+
queryComplete = error;
|
|
10732
|
+
return;
|
|
10733
|
+
}
|
|
10734
|
+
if (got) {
|
|
10735
|
+
delegate.addMetric(
|
|
10736
|
+
"query-materialization-end-to-end",
|
|
10737
|
+
performance.now() - t0,
|
|
10738
|
+
queryID,
|
|
10739
|
+
ast
|
|
10740
|
+
);
|
|
10741
|
+
queryComplete = true;
|
|
10742
|
+
queryCompleteResolver.resolve(true);
|
|
10743
|
+
}
|
|
10744
|
+
};
|
|
10745
|
+
let removeCommitObserver;
|
|
10746
|
+
const onDestroy = () => {
|
|
10747
|
+
input.destroy();
|
|
10748
|
+
removeCommitObserver?.();
|
|
10749
|
+
removeAddedQuery();
|
|
10750
|
+
};
|
|
10751
|
+
const t0 = performance.now();
|
|
10752
|
+
const removeAddedQuery = this.customQueryID ? delegate.addCustomQuery(ast, this.customQueryID, ttl, gotCallback) : delegate.addServerQuery(ast, ttl, gotCallback);
|
|
10753
|
+
const input = buildPipeline(ast, delegate, queryID);
|
|
10754
|
+
const view = delegate.batchViewUpdates(
|
|
10755
|
+
() => (factory ?? arrayViewFactory)(
|
|
10756
|
+
this,
|
|
10757
|
+
input,
|
|
10758
|
+
this.format,
|
|
10759
|
+
onDestroy,
|
|
10760
|
+
(cb) => {
|
|
10761
|
+
removeCommitObserver = delegate.onTransactionCommit(cb);
|
|
10762
|
+
},
|
|
10763
|
+
queryComplete || queryCompleteResolver.promise,
|
|
10764
|
+
updateTTL
|
|
10765
|
+
)
|
|
10766
|
+
);
|
|
10767
|
+
delegate.addMetric(
|
|
10768
|
+
"query-materialization-client",
|
|
10769
|
+
performance.now() - t0,
|
|
10770
|
+
queryID
|
|
10771
|
+
);
|
|
10772
|
+
return view;
|
|
10773
|
+
}
|
|
10774
|
+
run(options) {
|
|
10775
|
+
const delegate = must(
|
|
10776
|
+
this._delegate,
|
|
10777
|
+
"run requires a query delegate to be set"
|
|
10778
|
+
);
|
|
10779
|
+
delegate.assertValidRunOptions(options);
|
|
10780
|
+
const v = this.materialize(options?.ttl);
|
|
10781
|
+
if (options?.type === "complete") {
|
|
10782
|
+
return new Promise((resolve) => {
|
|
10783
|
+
v.addListener((data, type) => {
|
|
10784
|
+
if (type === "complete") {
|
|
10785
|
+
v.destroy();
|
|
10786
|
+
resolve(data);
|
|
10787
|
+
} else if (type === "error") {
|
|
10788
|
+
v.destroy();
|
|
10789
|
+
resolve(Promise.reject(data));
|
|
10790
|
+
}
|
|
10791
|
+
});
|
|
10792
|
+
});
|
|
10793
|
+
}
|
|
10794
|
+
options?.type;
|
|
10795
|
+
const ret = v.data;
|
|
10796
|
+
v.destroy();
|
|
10797
|
+
return Promise.resolve(ret);
|
|
10798
|
+
}
|
|
10799
|
+
preload(options) {
|
|
10800
|
+
const delegate = must(
|
|
10801
|
+
this._delegate,
|
|
10802
|
+
"preload requires a query delegate to be set"
|
|
10803
|
+
);
|
|
10804
|
+
const ttl = options?.ttl ?? DEFAULT_PRELOAD_TTL_MS;
|
|
10805
|
+
const ast = this._completeAst();
|
|
10806
|
+
const { resolve, promise: complete } = resolver7();
|
|
10807
|
+
if (this.customQueryID) {
|
|
10808
|
+
const cleanup2 = delegate.addCustomQuery(
|
|
10809
|
+
ast,
|
|
10810
|
+
this.customQueryID,
|
|
10811
|
+
ttl,
|
|
10812
|
+
(got) => {
|
|
10813
|
+
if (got) {
|
|
10814
|
+
resolve();
|
|
10815
|
+
}
|
|
10816
|
+
}
|
|
10817
|
+
);
|
|
10818
|
+
return {
|
|
10819
|
+
cleanup: cleanup2,
|
|
10820
|
+
complete
|
|
10821
|
+
};
|
|
10822
|
+
}
|
|
10823
|
+
const cleanup = delegate.addServerQuery(ast, ttl, (got) => {
|
|
10824
|
+
if (got) {
|
|
10825
|
+
resolve();
|
|
10826
|
+
}
|
|
10827
|
+
});
|
|
10828
|
+
return {
|
|
10829
|
+
cleanup,
|
|
10830
|
+
complete
|
|
10831
|
+
};
|
|
10832
|
+
}
|
|
10833
|
+
};
|
|
10834
|
+
function addPrimaryKeys(schema, orderBy) {
|
|
10835
|
+
orderBy = orderBy ?? [];
|
|
10836
|
+
const { primaryKey } = schema;
|
|
10837
|
+
const primaryKeysToAdd = new Set(primaryKey);
|
|
10838
|
+
for (const [field] of orderBy) {
|
|
10839
|
+
primaryKeysToAdd.delete(field);
|
|
10840
|
+
}
|
|
10841
|
+
if (primaryKeysToAdd.size === 0) {
|
|
10842
|
+
return orderBy;
|
|
10843
|
+
}
|
|
10844
|
+
return [
|
|
10845
|
+
...orderBy,
|
|
10846
|
+
...[...primaryKeysToAdd].map((key) => [key, "asc"])
|
|
10847
|
+
];
|
|
10848
|
+
}
|
|
10849
|
+
function addPrimaryKeysToAst(schema, ast) {
|
|
10850
|
+
return {
|
|
10851
|
+
...ast,
|
|
10852
|
+
orderBy: addPrimaryKeys(schema, ast.orderBy)
|
|
10853
|
+
};
|
|
10854
|
+
}
|
|
10855
|
+
function arrayViewFactory(_query, input, format, onDestroy, onTransactionCommit, queryComplete, updateTTL) {
|
|
10856
|
+
const v = new ArrayView(
|
|
10857
|
+
input,
|
|
10858
|
+
format,
|
|
10859
|
+
queryComplete,
|
|
10860
|
+
updateTTL
|
|
10861
|
+
);
|
|
10862
|
+
v.onDestroy = onDestroy;
|
|
10863
|
+
onTransactionCommit(() => {
|
|
10864
|
+
v.flush();
|
|
10865
|
+
});
|
|
10866
|
+
return v;
|
|
10867
|
+
}
|
|
10868
|
+
function isCompoundKey(field) {
|
|
10869
|
+
return Array.isArray(field) && field.length >= 1;
|
|
10870
|
+
}
|
|
10871
|
+
function isOneHop(r) {
|
|
10872
|
+
return r.length === 1;
|
|
10873
|
+
}
|
|
10874
|
+
function isTwoHop(r) {
|
|
10875
|
+
return r.length === 2;
|
|
10876
|
+
}
|
|
10877
|
+
|
|
10878
|
+
// ../zero-client/src/util/socket.ts
|
|
10879
|
+
function send(ws, data) {
|
|
10880
|
+
ws.send(JSON.stringify(data));
|
|
10881
|
+
}
|
|
10882
|
+
|
|
10883
|
+
// ../zero-client/src/client/active-clients-manager.ts
|
|
10884
|
+
import { resolver as resolver8 } from "@rocicorp/resolver";
|
|
10885
|
+
var keyPrefix = "zero-active";
|
|
10886
|
+
function toLockName(clientGroupID, clientID) {
|
|
10887
|
+
return `${keyPrefix}/${clientGroupID}/${clientID}`;
|
|
10888
|
+
}
|
|
10889
|
+
function toBroadcastChannelName(clientGroupID) {
|
|
10890
|
+
return `${keyPrefix}/${clientGroupID}`;
|
|
10891
|
+
}
|
|
10892
|
+
function fromLockName(lockKey) {
|
|
10893
|
+
if (!lockKey || !lockKey.startsWith(keyPrefix)) {
|
|
10894
|
+
return void 0;
|
|
10895
|
+
}
|
|
10896
|
+
const parts = lockKey.slice(keyPrefix.length).split("/");
|
|
10897
|
+
if (parts.length !== 3) {
|
|
10898
|
+
return void 0;
|
|
10899
|
+
}
|
|
10900
|
+
return {
|
|
10901
|
+
clientGroupID: parts[1],
|
|
10902
|
+
clientID: parts[2]
|
|
10903
|
+
};
|
|
10904
|
+
}
|
|
10905
|
+
function ignoreAbortError(e) {
|
|
10906
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
10907
|
+
return;
|
|
10908
|
+
}
|
|
10909
|
+
throw e;
|
|
10910
|
+
}
|
|
10911
|
+
var ActiveClientsManager = class _ActiveClientsManager {
|
|
10912
|
+
clientGroupID;
|
|
10913
|
+
clientID;
|
|
10914
|
+
#resolver = resolver8();
|
|
10915
|
+
#lockManager;
|
|
10916
|
+
#activeClients = /* @__PURE__ */ new Set();
|
|
10917
|
+
/**
|
|
10918
|
+
* A callback that is called when a client is added to the client group.
|
|
10919
|
+
* It receives the client ID of the added client.
|
|
10920
|
+
*/
|
|
10921
|
+
onAdd;
|
|
10922
|
+
/**
|
|
10923
|
+
* A callback that is called when a client is deleted from the client group.
|
|
10924
|
+
* It receives the client ID of the deleted client.
|
|
10925
|
+
*/
|
|
10926
|
+
onDelete;
|
|
10927
|
+
/**
|
|
10928
|
+
* Creates an instance of `ActiveClientsManager` for the specified client
|
|
10929
|
+
* group and client ID. It will return a promise that resolves when the
|
|
10930
|
+
* instance is ready to use, which means that it has successfully acquired the
|
|
10931
|
+
* exclusive lock for the client and has retrieved the list of active clients.
|
|
10932
|
+
*/
|
|
10933
|
+
static async create(clientGroupID, clientID, signal) {
|
|
10934
|
+
const instance = new _ActiveClientsManager(clientGroupID, clientID, signal);
|
|
10935
|
+
await instance.#init(signal);
|
|
10936
|
+
return instance;
|
|
10937
|
+
}
|
|
10938
|
+
constructor(clientGroupID, clientID, signal) {
|
|
10939
|
+
this.clientGroupID = clientGroupID;
|
|
10940
|
+
this.clientID = clientID;
|
|
10941
|
+
this.#lockManager = getClientLockManager(signal);
|
|
10942
|
+
this.#activeClients.add(clientID);
|
|
10943
|
+
}
|
|
10944
|
+
async #init(signal) {
|
|
10945
|
+
const { clientGroupID, clientID } = this;
|
|
10946
|
+
const name = toLockName(clientGroupID, clientID);
|
|
10947
|
+
const channel = new bc(toBroadcastChannelName(clientGroupID));
|
|
10948
|
+
channel.addEventListener(
|
|
6599
10949
|
"message",
|
|
6600
10950
|
(e) => {
|
|
6601
10951
|
const client = fromLockName(e.data);
|
|
@@ -6732,7 +11082,7 @@ var Connecting = 1;
|
|
|
6732
11082
|
var Connected = 2;
|
|
6733
11083
|
|
|
6734
11084
|
// ../zql/src/ivm/memory-storage.ts
|
|
6735
|
-
import { compareUTF8 as
|
|
11085
|
+
import { compareUTF8 as compareUTF83 } from "compare-utf8";
|
|
6736
11086
|
|
|
6737
11087
|
// ../shared/src/btree-set.ts
|
|
6738
11088
|
var MAX_NODE_SIZE = 32;
|
|
@@ -7000,8 +11350,8 @@ var BNode = class _BNode {
|
|
|
7000
11350
|
return new _BNode(keys);
|
|
7001
11351
|
}
|
|
7002
11352
|
delete(key, tree) {
|
|
7003
|
-
const
|
|
7004
|
-
const iLow = indexOf(key, this.keys, -1,
|
|
11353
|
+
const cmp2 = tree.comparator;
|
|
11354
|
+
const iLow = indexOf(key, this.keys, -1, cmp2);
|
|
7005
11355
|
const iHigh = iLow + 1;
|
|
7006
11356
|
if (iLow < 0) {
|
|
7007
11357
|
return false;
|
|
@@ -7066,21 +11416,21 @@ var BNodeInternal = class _BNodeInternal extends BNode {
|
|
|
7066
11416
|
}
|
|
7067
11417
|
set(key, tree) {
|
|
7068
11418
|
const c = this.children;
|
|
7069
|
-
const
|
|
7070
|
-
let i = Math.min(indexOf(key, this.keys, 0,
|
|
11419
|
+
const cmp2 = tree.comparator;
|
|
11420
|
+
let i = Math.min(indexOf(key, this.keys, 0, cmp2), c.length - 1);
|
|
7071
11421
|
let child = c[i];
|
|
7072
11422
|
if (child.isShared) {
|
|
7073
11423
|
c[i] = child = child.clone();
|
|
7074
11424
|
}
|
|
7075
11425
|
if (child.keys.length >= MAX_NODE_SIZE) {
|
|
7076
11426
|
let other;
|
|
7077
|
-
if (i > 0 && (other = c[i - 1]).keys.length < MAX_NODE_SIZE &&
|
|
11427
|
+
if (i > 0 && (other = c[i - 1]).keys.length < MAX_NODE_SIZE && cmp2(child.keys[0], key) < 0) {
|
|
7078
11428
|
if (other.isShared) {
|
|
7079
11429
|
c[i - 1] = other = other.clone();
|
|
7080
11430
|
}
|
|
7081
11431
|
other.takeFromRight(child);
|
|
7082
11432
|
this.keys[i - 1] = other.maxKey();
|
|
7083
|
-
} else if ((other = c[i + 1]) !== void 0 && other.keys.length < MAX_NODE_SIZE &&
|
|
11433
|
+
} else if ((other = c[i + 1]) !== void 0 && other.keys.length < MAX_NODE_SIZE && cmp2(child.maxKey(), key) < 0) {
|
|
7084
11434
|
if (other.isShared) c[i + 1] = other = other.clone();
|
|
7085
11435
|
other.takeFromLeft(child);
|
|
7086
11436
|
this.keys[i] = c[i].maxKey();
|
|
@@ -7095,7 +11445,7 @@ var BNodeInternal = class _BNodeInternal extends BNode {
|
|
|
7095
11445
|
}
|
|
7096
11446
|
const newRightSibling = this.splitOffRightSide();
|
|
7097
11447
|
let target = this;
|
|
7098
|
-
if (
|
|
11448
|
+
if (cmp2(result.maxKey(), this.maxKey()) > 0) {
|
|
7099
11449
|
target = newRightSibling;
|
|
7100
11450
|
i -= this.keys.length;
|
|
7101
11451
|
}
|
|
@@ -7131,10 +11481,10 @@ var BNodeInternal = class _BNodeInternal extends BNode {
|
|
|
7131
11481
|
this.children.unshift(lhs.children.pop());
|
|
7132
11482
|
}
|
|
7133
11483
|
delete(key, tree) {
|
|
7134
|
-
const
|
|
11484
|
+
const cmp2 = tree.comparator;
|
|
7135
11485
|
const { keys } = this;
|
|
7136
11486
|
const { children } = this;
|
|
7137
|
-
let iLow = indexOf(key, this.keys, 0,
|
|
11487
|
+
let iLow = indexOf(key, this.keys, 0, cmp2);
|
|
7138
11488
|
let i = iLow;
|
|
7139
11489
|
const iHigh = Math.min(iLow, keys.length - 1);
|
|
7140
11490
|
if (i <= iHigh) {
|
|
@@ -7223,7 +11573,7 @@ emptyLeaf.isShared = true;
|
|
|
7223
11573
|
|
|
7224
11574
|
// ../zql/src/ivm/memory-storage.ts
|
|
7225
11575
|
function comparator(a, b) {
|
|
7226
|
-
return
|
|
11576
|
+
return compareUTF83(a[0], b[0]);
|
|
7227
11577
|
}
|
|
7228
11578
|
var MemoryStorage = class {
|
|
7229
11579
|
#data = new BTreeSet(comparator);
|
|
@@ -7451,7 +11801,7 @@ var MemorySource = class _MemorySource {
|
|
|
7451
11801
|
scanStart = startAt;
|
|
7452
11802
|
}
|
|
7453
11803
|
const rowsIterable = generateRows(data, scanStart, req.reverse);
|
|
7454
|
-
const withOverlay =
|
|
11804
|
+
const withOverlay = generateWithOverlay2(
|
|
7455
11805
|
startAt,
|
|
7456
11806
|
pkConstraint ? once(rowsIterable) : rowsIterable,
|
|
7457
11807
|
// use `req.constraint` here and not `fetchOrPkConstraint` since `fetchOrPkConstraint` could be the
|
|
@@ -7673,7 +12023,7 @@ function* generateWithStart(nodes, start, compare2) {
|
|
|
7673
12023
|
}
|
|
7674
12024
|
}
|
|
7675
12025
|
}
|
|
7676
|
-
function*
|
|
12026
|
+
function* generateWithOverlay2(startAt, rows, constraint, overlay, connectionIndex, compare2, filterPredicate) {
|
|
7677
12027
|
let overlayToApply = void 0;
|
|
7678
12028
|
if (overlay && connectionIndex <= overlay.outputIndex) {
|
|
7679
12029
|
overlayToApply = overlay;
|
|
@@ -7723,24 +12073,24 @@ function computeOverlays(startAt, constraint, overlay, compare2, filterPredicate
|
|
|
7723
12073
|
}
|
|
7724
12074
|
return overlays;
|
|
7725
12075
|
}
|
|
7726
|
-
function overlaysForStartAt({ add, remove }, startAt, compare2) {
|
|
12076
|
+
function overlaysForStartAt({ add: add2, remove }, startAt, compare2) {
|
|
7727
12077
|
const undefinedIfBeforeStartAt = (row) => row === void 0 || compare2(row, startAt) < 0 ? void 0 : row;
|
|
7728
12078
|
return {
|
|
7729
|
-
add: undefinedIfBeforeStartAt(
|
|
12079
|
+
add: undefinedIfBeforeStartAt(add2),
|
|
7730
12080
|
remove: undefinedIfBeforeStartAt(remove)
|
|
7731
12081
|
};
|
|
7732
12082
|
}
|
|
7733
|
-
function overlaysForConstraint({ add, remove }, constraint) {
|
|
12083
|
+
function overlaysForConstraint({ add: add2, remove }, constraint) {
|
|
7734
12084
|
const undefinedIfDoesntMatchConstraint = (row) => row === void 0 || !constraintMatchesRow(constraint, row) ? void 0 : row;
|
|
7735
12085
|
return {
|
|
7736
|
-
add: undefinedIfDoesntMatchConstraint(
|
|
12086
|
+
add: undefinedIfDoesntMatchConstraint(add2),
|
|
7737
12087
|
remove: undefinedIfDoesntMatchConstraint(remove)
|
|
7738
12088
|
};
|
|
7739
12089
|
}
|
|
7740
|
-
function overlaysForFilterPredicate({ add, remove }, filterPredicate) {
|
|
12090
|
+
function overlaysForFilterPredicate({ add: add2, remove }, filterPredicate) {
|
|
7741
12091
|
const undefinedIfDoesntMatchFilter = (row) => row === void 0 || !filterPredicate(row) ? void 0 : row;
|
|
7742
12092
|
return {
|
|
7743
|
-
add: undefinedIfDoesntMatchFilter(
|
|
12093
|
+
add: undefinedIfDoesntMatchFilter(add2),
|
|
7744
12094
|
remove: undefinedIfDoesntMatchFilter(remove)
|
|
7745
12095
|
};
|
|
7746
12096
|
}
|
|
@@ -7749,15 +12099,15 @@ function* generateWithOverlayInner(rowIterator, overlays, compare2) {
|
|
|
7749
12099
|
let removeOverlaySkipped = false;
|
|
7750
12100
|
for (const row of rowIterator) {
|
|
7751
12101
|
if (!addOverlayYielded && overlays.add) {
|
|
7752
|
-
const
|
|
7753
|
-
if (
|
|
12102
|
+
const cmp2 = compare2(overlays.add, row);
|
|
12103
|
+
if (cmp2 < 0) {
|
|
7754
12104
|
addOverlayYielded = true;
|
|
7755
12105
|
yield { row: overlays.add, relationships: {} };
|
|
7756
12106
|
}
|
|
7757
12107
|
}
|
|
7758
12108
|
if (!removeOverlaySkipped && overlays.remove) {
|
|
7759
|
-
const
|
|
7760
|
-
if (
|
|
12109
|
+
const cmp2 = compare2(overlays.remove, row);
|
|
12110
|
+
if (cmp2 === 0) {
|
|
7761
12111
|
removeOverlaySkipped = true;
|
|
7762
12112
|
continue;
|
|
7763
12113
|
}
|
|
@@ -7774,9 +12124,9 @@ function makeBoundComparator(sort) {
|
|
|
7774
12124
|
return (a, b) => {
|
|
7775
12125
|
for (const entry of sort) {
|
|
7776
12126
|
const key = entry[0];
|
|
7777
|
-
const
|
|
7778
|
-
if (
|
|
7779
|
-
return entry[1] === "asc" ?
|
|
12127
|
+
const cmp2 = compareBounds(a[key], b[key]);
|
|
12128
|
+
if (cmp2 !== 0) {
|
|
12129
|
+
return entry[1] === "asc" ? cmp2 : -cmp2;
|
|
7780
12130
|
}
|
|
7781
12131
|
}
|
|
7782
12132
|
return 0;
|
|
@@ -8692,7 +13042,7 @@ function makeMessage(message, context, logLevel) {
|
|
|
8692
13042
|
}
|
|
8693
13043
|
|
|
8694
13044
|
// ../zero-client/src/client/version.ts
|
|
8695
|
-
var version2 = "0.24.
|
|
13045
|
+
var version2 = "0.24.2025101200";
|
|
8696
13046
|
|
|
8697
13047
|
// ../zero-client/src/client/log-options.ts
|
|
8698
13048
|
var LevelFilterLogSink = class {
|
|
@@ -8987,7 +13337,7 @@ var State = class {
|
|
|
8987
13337
|
};
|
|
8988
13338
|
|
|
8989
13339
|
// ../zero-client/src/client/mutation-tracker.ts
|
|
8990
|
-
import { resolver as
|
|
13340
|
+
import { resolver as resolver9 } from "@rocicorp/resolver";
|
|
8991
13341
|
var currentEphemeralID = 0;
|
|
8992
13342
|
function nextEphemeralID() {
|
|
8993
13343
|
return ++currentEphemeralID;
|
|
@@ -9025,7 +13375,7 @@ var MutationTracker = class {
|
|
|
9025
13375
|
}
|
|
9026
13376
|
trackMutation() {
|
|
9027
13377
|
const id = nextEphemeralID();
|
|
9028
|
-
const mutationResolver =
|
|
13378
|
+
const mutationResolver = resolver9();
|
|
9029
13379
|
this.#outstandingMutations.set(id, {
|
|
9030
13380
|
resolver: mutationResolver
|
|
9031
13381
|
});
|
|
@@ -10229,12 +14579,12 @@ var Zero = class _Zero {
|
|
|
10229
14579
|
};
|
|
10230
14580
|
#zeroContext;
|
|
10231
14581
|
queryDelegate;
|
|
10232
|
-
#connectResolver =
|
|
14582
|
+
#connectResolver = resolver10();
|
|
10233
14583
|
#pendingPullsByRequestID = /* @__PURE__ */ new Map();
|
|
10234
14584
|
#lastMutationIDReceived = 0;
|
|
10235
14585
|
#socket = void 0;
|
|
10236
|
-
#socketResolver =
|
|
10237
|
-
#connectionStateChangeResolver =
|
|
14586
|
+
#socketResolver = resolver10();
|
|
14587
|
+
#connectionStateChangeResolver = resolver10();
|
|
10238
14588
|
/**
|
|
10239
14589
|
* This resolver is only used for rejections. It is awaited in the connected
|
|
10240
14590
|
* state (including when waiting for a pong). It is rejected when we get an
|
|
@@ -10253,7 +14603,7 @@ var Zero = class _Zero {
|
|
|
10253
14603
|
}
|
|
10254
14604
|
this.#connectionState = state;
|
|
10255
14605
|
this.#connectionStateChangeResolver.resolve(state);
|
|
10256
|
-
this.#connectionStateChangeResolver =
|
|
14606
|
+
this.#connectionStateChangeResolver = resolver10();
|
|
10257
14607
|
if (false) {
|
|
10258
14608
|
asTestZero(this)[onSetConnectionStateSymbol]?.(state);
|
|
10259
14609
|
}
|
|
@@ -11081,9 +15431,9 @@ ${error.errorBody.message}`, error);
|
|
|
11081
15431
|
lc.error?.("disconnect() called while disconnected");
|
|
11082
15432
|
break;
|
|
11083
15433
|
}
|
|
11084
|
-
this.#socketResolver =
|
|
15434
|
+
this.#socketResolver = resolver10();
|
|
11085
15435
|
lc.debug?.("Creating new connect resolver");
|
|
11086
|
-
this.#connectResolver =
|
|
15436
|
+
this.#connectResolver = resolver10();
|
|
11087
15437
|
this.#setConnectionState(Disconnected);
|
|
11088
15438
|
this.#messageCount = 0;
|
|
11089
15439
|
this.#connectStart = void 0;
|
|
@@ -11130,12 +15480,12 @@ ${error.errorBody.message}`, error);
|
|
|
11130
15480
|
const body = pullResponseMessage[1];
|
|
11131
15481
|
lc = lc.withContext("requestID", body.requestID);
|
|
11132
15482
|
lc.debug?.("Handling pull response", body);
|
|
11133
|
-
const
|
|
11134
|
-
if (!
|
|
15483
|
+
const resolver11 = this.#pendingPullsByRequestID.get(body.requestID);
|
|
15484
|
+
if (!resolver11) {
|
|
11135
15485
|
lc.debug?.("No resolver found");
|
|
11136
15486
|
return;
|
|
11137
15487
|
}
|
|
11138
|
-
|
|
15488
|
+
resolver11.resolve(pullResponseMessage[1]);
|
|
11139
15489
|
}
|
|
11140
15490
|
async #pusher(req, requestID) {
|
|
11141
15491
|
assert(req.pushVersion === 1);
|
|
@@ -11268,7 +15618,7 @@ ${error.errorBody.message}`, error);
|
|
|
11268
15618
|
PING_INTERVAL_MS,
|
|
11269
15619
|
controller.signal
|
|
11270
15620
|
);
|
|
11271
|
-
this.#rejectMessageError =
|
|
15621
|
+
this.#rejectMessageError = resolver10();
|
|
11272
15622
|
const PING = 0;
|
|
11273
15623
|
const HIDDEN = 2;
|
|
11274
15624
|
const raceResult = await promiseRace([
|
|
@@ -11383,7 +15733,7 @@ ${error.errorBody.message}`, error);
|
|
|
11383
15733
|
}
|
|
11384
15734
|
];
|
|
11385
15735
|
send(socket, pullRequestMessage);
|
|
11386
|
-
const pullResponseResolver =
|
|
15736
|
+
const pullResponseResolver = resolver10();
|
|
11387
15737
|
this.#pendingPullsByRequestID.set(requestID, pullResponseResolver);
|
|
11388
15738
|
try {
|
|
11389
15739
|
const TIMEOUT = 0;
|
|
@@ -11446,7 +15796,7 @@ ${error.errorBody.message}`, error);
|
|
|
11446
15796
|
*/
|
|
11447
15797
|
async #ping(lc, messageErrorRejectionPromise) {
|
|
11448
15798
|
lc.debug?.("pinging");
|
|
11449
|
-
const { promise, resolve } =
|
|
15799
|
+
const { promise, resolve } = resolver10();
|
|
11450
15800
|
this.#onPong = resolve;
|
|
11451
15801
|
const pingMessage = ["ping", {}];
|
|
11452
15802
|
const t0 = performance.now();
|
|
@@ -11664,8 +16014,15 @@ export {
|
|
|
11664
16014
|
json,
|
|
11665
16015
|
enumeration,
|
|
11666
16016
|
createSchema,
|
|
16017
|
+
defaultFormat,
|
|
16018
|
+
ExpressionBuilder,
|
|
16019
|
+
idSymbol,
|
|
16020
|
+
applyChange,
|
|
16021
|
+
newQuery,
|
|
16022
|
+
newQuerySymbol,
|
|
16023
|
+
AbstractQuery,
|
|
11667
16024
|
clientToServer,
|
|
11668
16025
|
update_needed_reason_type_enum_exports,
|
|
11669
16026
|
Zero
|
|
11670
16027
|
};
|
|
11671
|
-
//# sourceMappingURL=chunk-
|
|
16028
|
+
//# sourceMappingURL=chunk-5J6ROZSO.js.map
|