convex-cms 0.0.9-alpha.9 → 0.0.10
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/admin/src/components/Header.tsx +1 -1
- package/admin/src/components/RouteGuard.tsx +1 -1
- package/admin/src/components/UploadDropzone.tsx +1 -1
- package/admin/src/components/ui/sidebar.tsx +1 -1
- package/admin/src/contexts/AuthContext.tsx +1 -1
- package/admin/src/embed/components/EmbedSidebar.tsx +10 -10
- package/admin/src/embed/contexts/ApiContext.tsx +1 -1
- package/admin/src/hooks/usePermissions.ts +1 -1
- package/admin/src/index.css +432 -0
- package/admin/src/lib/cmsExports.ts +6 -0
- package/admin/src/pages/DashboardPage.tsx +2 -3
- package/admin/src/routes/__root.tsx +1 -1
- package/admin-dist/nitro.json +1 -1
- package/admin-dist/public/assets/{CmsEmptyState-DTlpzjOI.js → CmsEmptyState-BKeL4DBB.js} +1 -1
- package/admin-dist/public/assets/CmsFilterBar-CEpMHd_c.js +1 -0
- package/admin-dist/public/assets/{CmsPageHeader-0REGRH4X.js → CmsPageHeader-CIEkTbyH.js} +1 -1
- package/admin-dist/public/assets/{CmsStatusBadge-D_n8u8xa.js → CmsStatusBadge-BFMOsfMW.js} +1 -1
- package/admin-dist/public/assets/{CmsSurface-BHmvNai4.js → CmsSurface-kqqaFKUI.js} +1 -1
- package/admin-dist/public/assets/CmsTable-Db53Exq0.js +1 -0
- package/admin-dist/public/assets/ContentEntryEditor-Ct7cHayy.js +4 -0
- package/admin-dist/public/assets/TaxonomyFilter-Bm1DI1A7.js +1 -0
- package/admin-dist/public/assets/_contentTypeId-BekeCblX.js +1 -0
- package/admin-dist/public/assets/{_entryId-jPXz4z9T.js → _entryId-CoZDE0l0.js} +1 -1
- package/admin-dist/public/assets/{alert-CG97cMfC.js → alert-CpLdsTGU.js} +1 -1
- package/admin-dist/public/assets/{badge-C6qt24oj.js → badge-BQAotc5B.js} +1 -1
- package/admin-dist/public/assets/{circle-check-big-PltpxuB1.js → circle-check-big-BF3Y5nES.js} +1 -1
- package/admin-dist/public/assets/{command-CJ8i86fd.js → command-lEq6f_Ee.js} +1 -1
- package/admin-dist/public/assets/content-DH6k0dN6.js +1 -0
- package/admin-dist/public/assets/content-types-DHr9tc2V.js +1 -0
- package/admin-dist/public/assets/index-Cf0lbl0G.js +1 -0
- package/admin-dist/public/assets/index-D-4wFfgU.css +1 -0
- package/admin-dist/public/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/admin-dist/public/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/admin-dist/public/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/admin-dist/public/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/admin-dist/public/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/admin-dist/public/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/admin-dist/public/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/admin-dist/public/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/admin-dist/public/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/admin-dist/public/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/admin-dist/public/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/admin-dist/public/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/admin-dist/public/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/admin-dist/public/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/admin-dist/public/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/admin-dist/public/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/admin-dist/public/assets/main-B-6700eG.js +137 -0
- package/admin-dist/public/assets/media-DY5zD52L.js +1 -0
- package/admin-dist/public/assets/{new._contentTypeId-qsvo01mH.js → new._contentTypeId-Dq_NqTQV.js} +1 -1
- package/admin-dist/public/assets/{pencil-gAL0R34f.js → pencil-CI_KfxSx.js} +1 -1
- package/admin-dist/public/assets/refresh-cw-BrXg9a2r.js +1 -0
- package/admin-dist/public/assets/rotate-ccw-PwzxdPxd.js +1 -0
- package/admin-dist/public/assets/{scroll-area-CJBhf9pf.js → scroll-area-DX_nZYp8.js} +1 -1
- package/admin-dist/public/assets/{search-WXp6KxDJ.js → search-DlwBH4C5.js} +1 -1
- package/admin-dist/public/assets/settings-2mx3_ORG.js +1 -0
- package/admin-dist/public/assets/{switch-Ck9ecqEX.js → switch-CjPi4DKH.js} +1 -1
- package/admin-dist/public/assets/{tabs-vQYu8rjC.js → tabs-B5X37GEM.js} +1 -1
- package/admin-dist/public/assets/tanstack-adapter-KSm-nO5L.js +1 -0
- package/admin-dist/public/assets/{taxonomies-DvILUNvr.js → taxonomies-CHjJKNlR.js} +1 -1
- package/admin-dist/public/assets/trash-Cle-tcqq.js +1 -0
- package/admin-dist/public/assets/{useBreadcrumbLabel-tlSh7dtO.js → useBreadcrumbLabel-yZQG_N_3.js} +1 -1
- package/admin-dist/public/assets/{usePermissions-BTGdTOJS.js → usePermissions-D6vsoaJf.js} +1 -1
- package/admin-dist/server/_libs/convex-helpers.mjs +1077 -2
- package/admin-dist/server/_libs/convex.mjs +222 -13
- package/admin-dist/server/_libs/lucide-react.mjs +57 -51
- package/admin-dist/server/_ssr/{CmsEmptyState-CB6e53i5.mjs → CmsEmptyState-DzzuQG0S.mjs} +1 -1
- package/admin-dist/server/_ssr/CmsFilterBar-C5XADS12.mjs +81 -0
- package/admin-dist/server/_ssr/{CmsPageHeader-COUHuECp.mjs → CmsPageHeader-DZ6h7smh.mjs} +1 -1
- package/admin-dist/server/_ssr/{CmsStatusBadge-kMTL6koE.mjs → CmsStatusBadge-D-YFSAa1.mjs} +3 -3
- package/admin-dist/server/_ssr/{CmsSurface-D1HDYjRg.mjs → CmsSurface-Cv51NBLZ.mjs} +1 -1
- package/admin-dist/server/_ssr/CmsTable-DG88C5nO.mjs +189 -0
- package/admin-dist/server/_ssr/{ContentEntryEditor-Bq8FR_uK.mjs → ContentEntryEditor-CRjwXB17.mjs} +10 -10
- package/admin-dist/server/_ssr/{TaxonomyFilter-bm_p4ADg.mjs → TaxonomyFilter-xGwcgtjr.mjs} +3 -3
- package/admin-dist/server/_ssr/{_contentTypeId-B7obLmi_.mjs → _contentTypeId-DRCfeKkm.mjs} +53 -12
- package/admin-dist/server/_ssr/{_entryId-B4zhQqFg.mjs → _entryId-DULm2TDy.mjs} +11 -11
- package/admin-dist/server/_ssr/_tanstack-start-manifest_v-iX3K33p1.mjs +4 -0
- package/admin-dist/server/_ssr/{badge-NOEC9bkk.mjs → badge-CbjIvhb6.mjs} +1 -1
- package/admin-dist/server/_ssr/{command-h4-OYNBo.mjs → command-xB2uiYps.mjs} +2 -2
- package/admin-dist/server/_ssr/{content-CShtLuhK.mjs → content-BfLBaJCZ.mjs} +108 -138
- package/admin-dist/server/_ssr/{content-types-PeyRyfbc.mjs → content-types-DZbF6O2q.mjs} +130 -119
- package/admin-dist/server/_ssr/{index-CplFXpGg.mjs → index-Cfe8sZv5.mjs} +65 -39
- package/admin-dist/server/_ssr/index.mjs +2 -2
- package/admin-dist/server/_ssr/{media-QAkNdX54.mjs → media-Bds2AnPC.mjs} +36 -56
- package/admin-dist/server/_ssr/{new._contentTypeId-DEJyMphJ.mjs → new._contentTypeId-DGvz_tlW.mjs} +10 -10
- package/admin-dist/server/_ssr/{router-CQXMuGMF.mjs → router-DxF7GBcO.mjs} +8804 -4995
- package/admin-dist/server/_ssr/{scroll-area-B7zoNyWB.mjs → scroll-area-DLDlXI07.mjs} +1 -1
- package/admin-dist/server/_ssr/{settings-CNaqVa4D.mjs → settings-BbaiS6z9.mjs} +13 -10
- package/admin-dist/server/_ssr/{switch-BKZhvryc.mjs → switch-Bl89Pfxu.mjs} +1 -1
- package/admin-dist/server/_ssr/{tabs-DtIIQxiD.mjs → tabs-QkbR0iir.mjs} +3 -3
- package/admin-dist/server/_ssr/{tanstack-adapter-CLavdbUY.mjs → tanstack-adapter-CKknPtcU.mjs} +19 -1
- package/admin-dist/server/_ssr/{taxonomies-vIZYICzr.mjs → taxonomies-S_Ontd0z.mjs} +9 -9
- package/admin-dist/server/_ssr/{trash-7yGR4-dF.mjs → trash-BzAIsbbN.mjs} +109 -132
- package/admin-dist/server/_ssr/{useBreadcrumbLabel-DR5FaAMf.mjs → useBreadcrumbLabel-BjiR1fM_.mjs} +1 -1
- package/admin-dist/server/_ssr/{usePermissions-DKkpETj_.mjs → usePermissions-CDHN95Nz.mjs} +1 -1
- package/admin-dist/server/index.mjs +284 -165
- package/package.json +3 -2
- package/admin/src/styles/globals.css +0 -82
- package/admin/src/styles/tailwind-config.css +0 -111
- package/admin/src/styles/theme.css +0 -384
- package/admin-dist/public/assets/CmsToolbar-CY6GV2L8.js +0 -1
- package/admin-dist/public/assets/ContentEntryEditor-CRgcRkk5.js +0 -4
- package/admin-dist/public/assets/TaxonomyFilter-Ohv5Jg9c.js +0 -1
- package/admin-dist/public/assets/_contentTypeId-C_vJq22X.js +0 -1
- package/admin-dist/public/assets/content-pKaIL2ru.js +0 -1
- package/admin-dist/public/assets/content-types-Bl_8I1Re.js +0 -1
- package/admin-dist/public/assets/globals-CoCRjt0K.css +0 -1
- package/admin-dist/public/assets/index-CtHq_P5q.js +0 -1
- package/admin-dist/public/assets/main-CA-4LyFT.js +0 -107
- package/admin-dist/public/assets/media-Bl1tBbJQ.js +0 -1
- package/admin-dist/public/assets/refresh-cw-sdVUGJNs.js +0 -1
- package/admin-dist/public/assets/rotate-ccw-6OcXCcxb.js +0 -1
- package/admin-dist/public/assets/settings-D8crrFCn.js +0 -1
- package/admin-dist/public/assets/tanstack-adapter-BRt2CUCw.js +0 -1
- package/admin-dist/public/assets/trash-YyYaC3L9.js +0 -1
- package/admin-dist/server/_ssr/CmsToolbar-NB014hsd.mjs +0 -48
- package/admin-dist/server/_ssr/_tanstack-start-manifest_v-DndoqCo7.mjs +0 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { v } from "./convex.mjs";
|
|
1
|
+
import { v, j as jsonToConvex, c as convexToJson, a as compareValues } from "./convex.mjs";
|
|
2
2
|
function omit(obj, keys) {
|
|
3
3
|
return Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k)));
|
|
4
4
|
}
|
|
@@ -31,7 +31,1082 @@ const doc = (schema, tableName) => {
|
|
|
31
31
|
return addSystemFields(schema.tables[tableName].validator);
|
|
32
32
|
};
|
|
33
33
|
v.optional(v.any());
|
|
34
|
+
function makeExclusive(boundType) {
|
|
35
|
+
if (boundType === "gt" || boundType === "gte") {
|
|
36
|
+
return "gt";
|
|
37
|
+
}
|
|
38
|
+
return "lt";
|
|
39
|
+
}
|
|
40
|
+
function splitRange(indexFields, order, startBound, endBound, startBoundType, endBoundType) {
|
|
41
|
+
const commonPrefix2 = [];
|
|
42
|
+
while (startBound.length > 0 && endBound.length > 0 && compareValues(startBound[0], endBound[0]) === 0) {
|
|
43
|
+
const indexField = indexFields[0];
|
|
44
|
+
indexFields = indexFields.slice(1);
|
|
45
|
+
const eqBound = startBound[0];
|
|
46
|
+
startBound = startBound.slice(1);
|
|
47
|
+
endBound = endBound.slice(1);
|
|
48
|
+
commonPrefix2.push(["eq", indexField, eqBound]);
|
|
49
|
+
}
|
|
50
|
+
const makeCompare = (boundType, key) => {
|
|
51
|
+
const range = commonPrefix2.slice();
|
|
52
|
+
let i = 0;
|
|
53
|
+
for (; i < key.length - 1; i++) {
|
|
54
|
+
range.push(["eq", indexFields[i], key[i]]);
|
|
55
|
+
}
|
|
56
|
+
if (i < key.length) {
|
|
57
|
+
range.push([boundType, indexFields[i], key[i]]);
|
|
58
|
+
}
|
|
59
|
+
return range;
|
|
60
|
+
};
|
|
61
|
+
const startRanges = [];
|
|
62
|
+
while (startBound.length > 1) {
|
|
63
|
+
startRanges.push(makeCompare(startBoundType, startBound));
|
|
64
|
+
startBoundType = makeExclusive(startBoundType);
|
|
65
|
+
startBound = startBound.slice(0, -1);
|
|
66
|
+
}
|
|
67
|
+
const endRanges = [];
|
|
68
|
+
while (endBound.length > 1) {
|
|
69
|
+
endRanges.push(makeCompare(endBoundType, endBound));
|
|
70
|
+
endBoundType = makeExclusive(endBoundType);
|
|
71
|
+
endBound = endBound.slice(0, -1);
|
|
72
|
+
}
|
|
73
|
+
endRanges.reverse();
|
|
74
|
+
let middleRange;
|
|
75
|
+
if (endBound.length === 0) {
|
|
76
|
+
middleRange = makeCompare(startBoundType, startBound);
|
|
77
|
+
} else if (startBound.length === 0) {
|
|
78
|
+
middleRange = makeCompare(endBoundType, endBound);
|
|
79
|
+
} else {
|
|
80
|
+
const startValue = startBound[0];
|
|
81
|
+
const endValue = endBound[0];
|
|
82
|
+
middleRange = commonPrefix2.slice();
|
|
83
|
+
middleRange.push([startBoundType, indexFields[0], startValue]);
|
|
84
|
+
middleRange.push([endBoundType, indexFields[0], endValue]);
|
|
85
|
+
}
|
|
86
|
+
const ranges = [...startRanges, middleRange, ...endRanges];
|
|
87
|
+
if (order === "desc") {
|
|
88
|
+
ranges.reverse();
|
|
89
|
+
}
|
|
90
|
+
return ranges;
|
|
91
|
+
}
|
|
92
|
+
function rangeToQuery(range) {
|
|
93
|
+
return (q) => {
|
|
94
|
+
for (const [boundType, field, value] of range) {
|
|
95
|
+
q = q[boundType](field, value);
|
|
96
|
+
}
|
|
97
|
+
return q;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function getIndexFields(table, index, schema) {
|
|
101
|
+
const indexDescriptor = String(index ?? "by_creation_time");
|
|
102
|
+
if (indexDescriptor === "by_creation_time") {
|
|
103
|
+
return ["_creationTime", "_id"];
|
|
104
|
+
}
|
|
105
|
+
if (indexDescriptor === "by_id") {
|
|
106
|
+
return ["_id"];
|
|
107
|
+
}
|
|
108
|
+
if (!schema) {
|
|
109
|
+
throw new Error("schema is required to infer index fields");
|
|
110
|
+
}
|
|
111
|
+
const tableInfo = schema.tables[table];
|
|
112
|
+
const indexInfo = tableInfo.indexes.find((index2) => index2.indexDescriptor === indexDescriptor);
|
|
113
|
+
if (!indexInfo) {
|
|
114
|
+
throw new Error(`Index ${indexDescriptor} not found in table ${table}`);
|
|
115
|
+
}
|
|
116
|
+
const fields = indexInfo.fields.slice();
|
|
117
|
+
fields.push("_creationTime");
|
|
118
|
+
fields.push("_id");
|
|
119
|
+
return fields;
|
|
120
|
+
}
|
|
121
|
+
function getIndexKey(doc2, indexFields) {
|
|
122
|
+
const key = [];
|
|
123
|
+
for (const field of indexFields) {
|
|
124
|
+
let obj = doc2;
|
|
125
|
+
for (const subfield of field.split(".")) {
|
|
126
|
+
obj = obj[subfield];
|
|
127
|
+
}
|
|
128
|
+
key.push(obj);
|
|
129
|
+
}
|
|
130
|
+
return key;
|
|
131
|
+
}
|
|
132
|
+
function stream(db, schema) {
|
|
133
|
+
return new StreamDatabaseReader(db, schema);
|
|
134
|
+
}
|
|
135
|
+
class QueryStream {
|
|
136
|
+
/// Methods for creating new streams as modifications of the current stream.
|
|
137
|
+
/**
|
|
138
|
+
* Create a new stream with a TypeScript filter applied.
|
|
139
|
+
*
|
|
140
|
+
* This is similar to `db.query(tableName).filter(predicate)`, but it's more
|
|
141
|
+
* general because it can call arbitrary TypeScript code, including more
|
|
142
|
+
* database queries.
|
|
143
|
+
*
|
|
144
|
+
* All documents filtered out are still considered "read" from the database;
|
|
145
|
+
* they are just excluded from the output stream.
|
|
146
|
+
*
|
|
147
|
+
* In contrast to `filter` from convex-helpers/server/filter, this filterWith
|
|
148
|
+
* is applied *before* any pagination. That means if the filter excludes a lot
|
|
149
|
+
* of documents, the `.paginate()` method will read a lot of documents until
|
|
150
|
+
* it gets as many documents as it wants. If you run into issues with reading
|
|
151
|
+
* too much data, you can pass `maximumRowsRead` to `paginate()`.
|
|
152
|
+
*/
|
|
153
|
+
filterWith(predicate) {
|
|
154
|
+
const order = this.getOrder();
|
|
155
|
+
return new FlatMapStream(this, async (doc2) => {
|
|
156
|
+
const filtered = await predicate(doc2) ? doc2 : null;
|
|
157
|
+
return new SingletonStream(filtered, order, [], [], []);
|
|
158
|
+
}, []);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Create a new stream where each element is the result of applying the mapper
|
|
162
|
+
* function to the elements of the original stream.
|
|
163
|
+
*
|
|
164
|
+
* Similar to how [1, 2, 3].map(x => x * 2) => [2, 4, 6]
|
|
165
|
+
*/
|
|
166
|
+
map(mapper) {
|
|
167
|
+
const order = this.getOrder();
|
|
168
|
+
return new FlatMapStream(this, async (doc2) => {
|
|
169
|
+
const mapped = await mapper(doc2);
|
|
170
|
+
return new SingletonStream(mapped, order, [], [], []);
|
|
171
|
+
}, []);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Similar to flatMap on an array, but iterate over a stream, and the for each
|
|
175
|
+
* element, iterate over the stream created by the mapper function.
|
|
176
|
+
*
|
|
177
|
+
* Ordered by the original stream order, then the mapped stream. Similar to
|
|
178
|
+
* how ["a", "b"].flatMap(letter => [letter, letter]) => ["a", "a", "b", "b"]
|
|
179
|
+
*
|
|
180
|
+
* @param mapper A function that takes a document and returns a new stream.
|
|
181
|
+
* @param mappedIndexFields The index fields of the streams created by mapper.
|
|
182
|
+
* @returns A stream of documents returned by the mapper streams,
|
|
183
|
+
* grouped by the documents in the original stream.
|
|
184
|
+
*/
|
|
185
|
+
flatMap(mapper, mappedIndexFields) {
|
|
186
|
+
normalizeIndexFields(mappedIndexFields);
|
|
187
|
+
return new FlatMapStream(this, mapper, mappedIndexFields);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the first item from the original stream for each distinct value of the
|
|
191
|
+
* selected index fields.
|
|
192
|
+
*
|
|
193
|
+
* e.g. if the stream has an equality filter on `a`, and index fields `[a, b, c]`,
|
|
194
|
+
* we can do `stream.distinct(["b"])` to get a stream of the first item for
|
|
195
|
+
* each distinct value of `b`.
|
|
196
|
+
* Similarly, you could do `stream.distinct(["a", "b"])` with the same result,
|
|
197
|
+
* or `stream.distinct(["a", "b", "c"])` to get the original stream.
|
|
198
|
+
*
|
|
199
|
+
* This stream efficiently skips past items with the same value for the selected
|
|
200
|
+
* distinct index fields.
|
|
201
|
+
*
|
|
202
|
+
* This can be used to perform a loose index scan.
|
|
203
|
+
*/
|
|
204
|
+
distinct(distinctIndexFields) {
|
|
205
|
+
return new DistinctStream(this, distinctIndexFields);
|
|
206
|
+
}
|
|
207
|
+
/// Implementation of OrderedQuery
|
|
208
|
+
filter(_predicate) {
|
|
209
|
+
throw new Error("Cannot call .filter() directly on a query stream. Use .filterWith() for filtering or .collect() if you want to convert the stream to an array first.");
|
|
210
|
+
}
|
|
211
|
+
async paginate(opts) {
|
|
212
|
+
if (opts.numItems === 0) {
|
|
213
|
+
if (opts.cursor === null) {
|
|
214
|
+
throw new Error(".paginate called with cursor of null and 0 for numItems. This is not supported, as null is not a valid continueCursor. Advice: avoid calling paginate entirely in these cases.");
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
page: [],
|
|
218
|
+
isDone: false,
|
|
219
|
+
continueCursor: opts.cursor
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const order = this.getOrder();
|
|
223
|
+
let newStartKey = {
|
|
224
|
+
key: [],
|
|
225
|
+
inclusive: true
|
|
226
|
+
};
|
|
227
|
+
if (opts.cursor !== null) {
|
|
228
|
+
newStartKey = {
|
|
229
|
+
key: deserializeCursor(opts.cursor),
|
|
230
|
+
inclusive: false
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
let newEndKey = {
|
|
234
|
+
key: [],
|
|
235
|
+
inclusive: true
|
|
236
|
+
};
|
|
237
|
+
const maxRowsToRead = opts.maximumRowsRead;
|
|
238
|
+
const softMaxRowsToRead = opts.numItems + 1;
|
|
239
|
+
let maxRows = opts.numItems;
|
|
240
|
+
if (opts.endCursor) {
|
|
241
|
+
newEndKey = {
|
|
242
|
+
key: deserializeCursor(opts.endCursor),
|
|
243
|
+
inclusive: true
|
|
244
|
+
};
|
|
245
|
+
maxRows = void 0;
|
|
246
|
+
}
|
|
247
|
+
const newLowerBound = order === "asc" ? newStartKey : newEndKey;
|
|
248
|
+
const newUpperBound = order === "asc" ? newEndKey : newStartKey;
|
|
249
|
+
const narrowStream = this.narrow({
|
|
250
|
+
lowerBound: newLowerBound.key,
|
|
251
|
+
lowerBoundInclusive: newLowerBound.inclusive,
|
|
252
|
+
upperBound: newUpperBound.key,
|
|
253
|
+
upperBoundInclusive: newUpperBound.inclusive
|
|
254
|
+
});
|
|
255
|
+
const page = [];
|
|
256
|
+
const indexKeys = [];
|
|
257
|
+
let hasMore = opts.endCursor && opts.endCursor !== "[]";
|
|
258
|
+
let continueCursor = opts.endCursor ?? "[]";
|
|
259
|
+
for await (const [doc2, indexKey] of narrowStream.iterWithKeys()) {
|
|
260
|
+
if (doc2 !== null) {
|
|
261
|
+
page.push(doc2);
|
|
262
|
+
}
|
|
263
|
+
indexKeys.push(indexKey);
|
|
264
|
+
if (maxRows !== void 0 && page.length >= maxRows || maxRowsToRead !== void 0 && indexKeys.length >= maxRowsToRead) {
|
|
265
|
+
hasMore = true;
|
|
266
|
+
continueCursor = serializeCursor(indexKey);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
let pageStatus = void 0;
|
|
271
|
+
let splitCursor = void 0;
|
|
272
|
+
if (indexKeys.length === maxRowsToRead) {
|
|
273
|
+
pageStatus = "SplitRequired";
|
|
274
|
+
splitCursor = indexKeys[Math.floor((indexKeys.length - 1) / 2)];
|
|
275
|
+
} else if (indexKeys.length >= softMaxRowsToRead) {
|
|
276
|
+
pageStatus = "SplitRecommended";
|
|
277
|
+
splitCursor = indexKeys[Math.floor((indexKeys.length - 1) / 2)];
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
page,
|
|
281
|
+
isDone: !hasMore,
|
|
282
|
+
continueCursor,
|
|
283
|
+
pageStatus,
|
|
284
|
+
splitCursor: splitCursor ? serializeCursor(splitCursor) : void 0
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
async collect() {
|
|
288
|
+
return await this.take(Infinity);
|
|
289
|
+
}
|
|
290
|
+
async take(n) {
|
|
291
|
+
const results = [];
|
|
292
|
+
for await (const [doc2, _] of this.iterWithKeys()) {
|
|
293
|
+
if (doc2 === null) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
results.push(doc2);
|
|
297
|
+
if (results.length === n) {
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return results;
|
|
302
|
+
}
|
|
303
|
+
async unique() {
|
|
304
|
+
const docs = await this.take(2);
|
|
305
|
+
if (docs.length === 2) {
|
|
306
|
+
throw new Error("Query is not unique");
|
|
307
|
+
}
|
|
308
|
+
return docs[0] ?? null;
|
|
309
|
+
}
|
|
310
|
+
async first() {
|
|
311
|
+
const docs = await this.take(1);
|
|
312
|
+
return docs[0] ?? null;
|
|
313
|
+
}
|
|
314
|
+
[Symbol.asyncIterator]() {
|
|
315
|
+
const iterator = this.iterWithKeys()[Symbol.asyncIterator]();
|
|
316
|
+
return {
|
|
317
|
+
async next() {
|
|
318
|
+
const result = await iterator.next();
|
|
319
|
+
if (result.done) {
|
|
320
|
+
return { done: true, value: void 0 };
|
|
321
|
+
}
|
|
322
|
+
return { done: false, value: result.value[0] };
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
class StreamDatabaseReader {
|
|
328
|
+
db;
|
|
329
|
+
schema;
|
|
330
|
+
// TODO: support system tables
|
|
331
|
+
system;
|
|
332
|
+
constructor(db, schema) {
|
|
333
|
+
this.db = db;
|
|
334
|
+
this.schema = schema;
|
|
335
|
+
this.system = db.system;
|
|
336
|
+
}
|
|
337
|
+
query(tableName) {
|
|
338
|
+
return new StreamQueryInitializer(this, tableName);
|
|
339
|
+
}
|
|
340
|
+
get(_id) {
|
|
341
|
+
throw new Error("get() not supported for `paginator`");
|
|
342
|
+
}
|
|
343
|
+
normalizeId(_tableName, _id) {
|
|
344
|
+
throw new Error("normalizeId() not supported for `paginator`.");
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
class StreamableQuery extends QueryStream {
|
|
348
|
+
}
|
|
349
|
+
class StreamQueryInitializer extends StreamableQuery {
|
|
350
|
+
parent;
|
|
351
|
+
table;
|
|
352
|
+
constructor(parent, table) {
|
|
353
|
+
super();
|
|
354
|
+
this.parent = parent;
|
|
355
|
+
this.table = table;
|
|
356
|
+
}
|
|
357
|
+
fullTableScan() {
|
|
358
|
+
return this.withIndex("by_creation_time");
|
|
359
|
+
}
|
|
360
|
+
withIndex(indexName, indexRange) {
|
|
361
|
+
const indexFields = getIndexFields(this.table, indexName, this.parent.schema);
|
|
362
|
+
const q = new ReflectIndexRange(indexFields);
|
|
363
|
+
if (indexRange) {
|
|
364
|
+
indexRange(q);
|
|
365
|
+
}
|
|
366
|
+
return new StreamQuery(this, indexName, q, indexRange);
|
|
367
|
+
}
|
|
368
|
+
withSearchIndex(_indexName, _searchFilter) {
|
|
369
|
+
throw new Error("Cannot paginate withSearchIndex");
|
|
370
|
+
}
|
|
371
|
+
inner() {
|
|
372
|
+
return this.fullTableScan();
|
|
373
|
+
}
|
|
374
|
+
order(order) {
|
|
375
|
+
return this.inner().order(order);
|
|
376
|
+
}
|
|
377
|
+
reflect() {
|
|
378
|
+
return this.inner().reflect();
|
|
379
|
+
}
|
|
380
|
+
iterWithKeys() {
|
|
381
|
+
return this.inner().iterWithKeys();
|
|
382
|
+
}
|
|
383
|
+
getOrder() {
|
|
384
|
+
return this.inner().getOrder();
|
|
385
|
+
}
|
|
386
|
+
getEqualityIndexFilter() {
|
|
387
|
+
return this.inner().getEqualityIndexFilter();
|
|
388
|
+
}
|
|
389
|
+
getIndexFields() {
|
|
390
|
+
return this.inner().getIndexFields();
|
|
391
|
+
}
|
|
392
|
+
narrow(indexBounds) {
|
|
393
|
+
return this.inner().narrow(indexBounds);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
class StreamQuery extends StreamableQuery {
|
|
397
|
+
parent;
|
|
398
|
+
index;
|
|
399
|
+
q;
|
|
400
|
+
indexRange;
|
|
401
|
+
constructor(parent, index, q, indexRange) {
|
|
402
|
+
super();
|
|
403
|
+
this.parent = parent;
|
|
404
|
+
this.index = index;
|
|
405
|
+
this.q = q;
|
|
406
|
+
this.indexRange = indexRange;
|
|
407
|
+
}
|
|
408
|
+
order(order) {
|
|
409
|
+
return new OrderedStreamQuery(this, order);
|
|
410
|
+
}
|
|
411
|
+
inner() {
|
|
412
|
+
return this.order("asc");
|
|
413
|
+
}
|
|
414
|
+
reflect() {
|
|
415
|
+
return this.inner().reflect();
|
|
416
|
+
}
|
|
417
|
+
iterWithKeys() {
|
|
418
|
+
return this.inner().iterWithKeys();
|
|
419
|
+
}
|
|
420
|
+
getOrder() {
|
|
421
|
+
return this.inner().getOrder();
|
|
422
|
+
}
|
|
423
|
+
getEqualityIndexFilter() {
|
|
424
|
+
return this.inner().getEqualityIndexFilter();
|
|
425
|
+
}
|
|
426
|
+
getIndexFields() {
|
|
427
|
+
return this.inner().getIndexFields();
|
|
428
|
+
}
|
|
429
|
+
narrow(indexBounds) {
|
|
430
|
+
return this.inner().narrow(indexBounds);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
class OrderedStreamQuery extends StreamableQuery {
|
|
434
|
+
parent;
|
|
435
|
+
order;
|
|
436
|
+
constructor(parent, order) {
|
|
437
|
+
super();
|
|
438
|
+
this.parent = parent;
|
|
439
|
+
this.order = order;
|
|
440
|
+
}
|
|
441
|
+
reflect() {
|
|
442
|
+
return {
|
|
443
|
+
db: this.parent.parent.parent.db,
|
|
444
|
+
schema: this.parent.parent.parent.schema,
|
|
445
|
+
table: this.parent.parent.table,
|
|
446
|
+
index: this.parent.index,
|
|
447
|
+
indexFields: this.parent.q.indexFields,
|
|
448
|
+
order: this.order,
|
|
449
|
+
bounds: {
|
|
450
|
+
lowerBound: this.parent.q.lowerBoundIndexKey ?? [],
|
|
451
|
+
lowerBoundInclusive: this.parent.q.lowerBoundInclusive,
|
|
452
|
+
upperBound: this.parent.q.upperBoundIndexKey ?? [],
|
|
453
|
+
upperBoundInclusive: this.parent.q.upperBoundInclusive
|
|
454
|
+
},
|
|
455
|
+
indexRange: this.parent.indexRange
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* inner() is as if you had used ctx.db to construct the query.
|
|
460
|
+
*/
|
|
461
|
+
inner() {
|
|
462
|
+
const { db, table, index, order, indexRange } = this.reflect();
|
|
463
|
+
return db.query(table).withIndex(index, indexRange).order(order);
|
|
464
|
+
}
|
|
465
|
+
iterWithKeys() {
|
|
466
|
+
const { indexFields } = this.reflect();
|
|
467
|
+
const iterable = this.inner();
|
|
468
|
+
return {
|
|
469
|
+
[Symbol.asyncIterator]() {
|
|
470
|
+
const iterator = iterable[Symbol.asyncIterator]();
|
|
471
|
+
return {
|
|
472
|
+
async next() {
|
|
473
|
+
const result = await iterator.next();
|
|
474
|
+
if (result.done) {
|
|
475
|
+
return { done: true, value: void 0 };
|
|
476
|
+
}
|
|
477
|
+
return {
|
|
478
|
+
done: false,
|
|
479
|
+
value: [result.value, getIndexKey(result.value, indexFields)]
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
getOrder() {
|
|
487
|
+
return this.order;
|
|
488
|
+
}
|
|
489
|
+
getEqualityIndexFilter() {
|
|
490
|
+
return this.parent.q.equalityIndexFilter;
|
|
491
|
+
}
|
|
492
|
+
getIndexFields() {
|
|
493
|
+
return this.parent.q.indexFields;
|
|
494
|
+
}
|
|
495
|
+
narrow(indexBounds) {
|
|
496
|
+
const { db, table, index, order, bounds, schema } = this.reflect();
|
|
497
|
+
let maxLowerBound = bounds.lowerBound;
|
|
498
|
+
let maxLowerBoundInclusive = bounds.lowerBoundInclusive;
|
|
499
|
+
if (compareKeys({
|
|
500
|
+
value: indexBounds.lowerBound,
|
|
501
|
+
kind: indexBounds.lowerBoundInclusive ? "predecessor" : "successor"
|
|
502
|
+
}, {
|
|
503
|
+
value: bounds.lowerBound,
|
|
504
|
+
kind: bounds.lowerBoundInclusive ? "predecessor" : "successor"
|
|
505
|
+
}) > 0) {
|
|
506
|
+
maxLowerBound = indexBounds.lowerBound;
|
|
507
|
+
maxLowerBoundInclusive = indexBounds.lowerBoundInclusive;
|
|
508
|
+
}
|
|
509
|
+
let minUpperBound = bounds.upperBound;
|
|
510
|
+
let minUpperBoundInclusive = bounds.upperBoundInclusive;
|
|
511
|
+
if (compareKeys({
|
|
512
|
+
value: indexBounds.upperBound,
|
|
513
|
+
kind: indexBounds.upperBoundInclusive ? "successor" : "predecessor"
|
|
514
|
+
}, {
|
|
515
|
+
value: bounds.upperBound,
|
|
516
|
+
kind: bounds.upperBoundInclusive ? "successor" : "predecessor"
|
|
517
|
+
}) < 0) {
|
|
518
|
+
minUpperBound = indexBounds.upperBound;
|
|
519
|
+
minUpperBoundInclusive = indexBounds.upperBoundInclusive;
|
|
520
|
+
}
|
|
521
|
+
return streamIndexRange(db, schema, table, index, {
|
|
522
|
+
lowerBound: maxLowerBound,
|
|
523
|
+
lowerBoundInclusive: maxLowerBoundInclusive,
|
|
524
|
+
upperBound: minUpperBound,
|
|
525
|
+
upperBoundInclusive: minUpperBoundInclusive
|
|
526
|
+
}, order);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
function streamIndexRange(db, schema, table, index, bounds, order) {
|
|
530
|
+
const indexFields = getIndexFields(table, index, schema);
|
|
531
|
+
const splitBounds = splitRange(indexFields, order, bounds.lowerBound, bounds.upperBound, bounds.lowerBoundInclusive ? "gte" : "gt", bounds.upperBoundInclusive ? "lte" : "lt");
|
|
532
|
+
const subQueries = splitBounds.map((splitBound) => stream(db, schema).query(table).withIndex(index, rangeToQuery(splitBound)).order(order));
|
|
533
|
+
return new ConcatStreams(...subQueries);
|
|
534
|
+
}
|
|
535
|
+
class ReflectIndexRange {
|
|
536
|
+
indexFields;
|
|
537
|
+
#hasSuffix = false;
|
|
538
|
+
lowerBoundIndexKey = void 0;
|
|
539
|
+
lowerBoundInclusive = true;
|
|
540
|
+
upperBoundIndexKey = void 0;
|
|
541
|
+
upperBoundInclusive = true;
|
|
542
|
+
equalityIndexFilter = [];
|
|
543
|
+
constructor(indexFields) {
|
|
544
|
+
this.indexFields = indexFields;
|
|
545
|
+
}
|
|
546
|
+
eq(field, value) {
|
|
547
|
+
if (!this.#canLowerBound(field) || !this.#canUpperBound(field)) {
|
|
548
|
+
throw new Error(`Cannot use eq on field '${field}'`);
|
|
549
|
+
}
|
|
550
|
+
this.lowerBoundIndexKey = this.lowerBoundIndexKey ?? [];
|
|
551
|
+
this.lowerBoundIndexKey.push(value);
|
|
552
|
+
this.upperBoundIndexKey = this.upperBoundIndexKey ?? [];
|
|
553
|
+
this.upperBoundIndexKey.push(value);
|
|
554
|
+
this.equalityIndexFilter.push(value);
|
|
555
|
+
return this;
|
|
556
|
+
}
|
|
557
|
+
lt(field, value) {
|
|
558
|
+
if (!this.#canUpperBound(field)) {
|
|
559
|
+
throw new Error(`Cannot use lt on field '${field}'`);
|
|
560
|
+
}
|
|
561
|
+
this.upperBoundIndexKey = this.upperBoundIndexKey ?? [];
|
|
562
|
+
this.upperBoundIndexKey.push(value);
|
|
563
|
+
this.upperBoundInclusive = false;
|
|
564
|
+
this.#hasSuffix = true;
|
|
565
|
+
return this;
|
|
566
|
+
}
|
|
567
|
+
lte(field, value) {
|
|
568
|
+
if (!this.#canUpperBound(field)) {
|
|
569
|
+
throw new Error(`Cannot use lte on field '${field}'`);
|
|
570
|
+
}
|
|
571
|
+
this.upperBoundIndexKey = this.upperBoundIndexKey ?? [];
|
|
572
|
+
this.upperBoundIndexKey.push(value);
|
|
573
|
+
this.#hasSuffix = true;
|
|
574
|
+
return this;
|
|
575
|
+
}
|
|
576
|
+
gt(field, value) {
|
|
577
|
+
if (!this.#canLowerBound(field)) {
|
|
578
|
+
throw new Error(`Cannot use gt on field '${field}'`);
|
|
579
|
+
}
|
|
580
|
+
this.lowerBoundIndexKey = this.lowerBoundIndexKey ?? [];
|
|
581
|
+
this.lowerBoundIndexKey.push(value);
|
|
582
|
+
this.lowerBoundInclusive = false;
|
|
583
|
+
this.#hasSuffix = true;
|
|
584
|
+
return this;
|
|
585
|
+
}
|
|
586
|
+
gte(field, value) {
|
|
587
|
+
if (!this.#canLowerBound(field)) {
|
|
588
|
+
throw new Error(`Cannot use gte on field '${field}'`);
|
|
589
|
+
}
|
|
590
|
+
this.lowerBoundIndexKey = this.lowerBoundIndexKey ?? [];
|
|
591
|
+
this.lowerBoundIndexKey.push(value);
|
|
592
|
+
this.#hasSuffix = true;
|
|
593
|
+
return this;
|
|
594
|
+
}
|
|
595
|
+
#canLowerBound(field) {
|
|
596
|
+
const currentLowerBoundLength = this.lowerBoundIndexKey?.length ?? 0;
|
|
597
|
+
const currentUpperBoundLength = this.upperBoundIndexKey?.length ?? 0;
|
|
598
|
+
if (currentLowerBoundLength > currentUpperBoundLength) {
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
if (currentLowerBoundLength === currentUpperBoundLength && this.#hasSuffix) {
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
return currentLowerBoundLength < this.indexFields.length && this.indexFields[currentLowerBoundLength] === field;
|
|
605
|
+
}
|
|
606
|
+
#canUpperBound(field) {
|
|
607
|
+
const currentLowerBoundLength = this.lowerBoundIndexKey?.length ?? 0;
|
|
608
|
+
const currentUpperBoundLength = this.upperBoundIndexKey?.length ?? 0;
|
|
609
|
+
if (currentUpperBoundLength > currentLowerBoundLength) {
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
if (currentLowerBoundLength === currentUpperBoundLength && this.#hasSuffix) {
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
return currentUpperBoundLength < this.indexFields.length && this.indexFields[currentUpperBoundLength] === field;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function allSame(values, errorMessage) {
|
|
619
|
+
const first = values[0];
|
|
620
|
+
for (const value of values) {
|
|
621
|
+
if (compareValues(value, first)) {
|
|
622
|
+
throw new Error(errorMessage);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return first;
|
|
626
|
+
}
|
|
627
|
+
function commonPrefix(values) {
|
|
628
|
+
let commonPrefix2 = values[0];
|
|
629
|
+
for (const value of values) {
|
|
630
|
+
for (let i = 0; i < commonPrefix2.length; i++) {
|
|
631
|
+
if (i >= value.length || compareValues(commonPrefix2[i], value[i])) {
|
|
632
|
+
commonPrefix2 = commonPrefix2.slice(0, i);
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return commonPrefix2;
|
|
638
|
+
}
|
|
639
|
+
class ConcatStreams extends QueryStream {
|
|
640
|
+
#order;
|
|
641
|
+
#streams;
|
|
642
|
+
#equalityIndexFilter;
|
|
643
|
+
#indexFields;
|
|
644
|
+
constructor(...streams) {
|
|
645
|
+
super();
|
|
646
|
+
this.#streams = streams;
|
|
647
|
+
if (streams.length === 0) {
|
|
648
|
+
throw new Error("Cannot concat empty array of streams");
|
|
649
|
+
}
|
|
650
|
+
this.#order = allSame(streams.map((stream2) => stream2.getOrder()), "Cannot concat streams with different orders. Consider using .orderBy()");
|
|
651
|
+
this.#indexFields = allSame(streams.map((stream2) => stream2.getIndexFields()), "Cannot concat streams with different index fields. Consider using .orderBy()");
|
|
652
|
+
this.#equalityIndexFilter = commonPrefix(streams.map((stream2) => stream2.getEqualityIndexFilter()));
|
|
653
|
+
}
|
|
654
|
+
iterWithKeys() {
|
|
655
|
+
const iterables = this.#streams.map((stream2) => stream2.iterWithKeys());
|
|
656
|
+
const comparisonInversion = this.#order === "asc" ? 1 : -1;
|
|
657
|
+
let previousIndexKey = void 0;
|
|
658
|
+
return {
|
|
659
|
+
[Symbol.asyncIterator]() {
|
|
660
|
+
const iterators = iterables.map((iterable) => iterable[Symbol.asyncIterator]());
|
|
661
|
+
return {
|
|
662
|
+
async next() {
|
|
663
|
+
while (iterators.length > 0) {
|
|
664
|
+
const result = await iterators[0].next();
|
|
665
|
+
if (result.done) {
|
|
666
|
+
iterators.shift();
|
|
667
|
+
} else {
|
|
668
|
+
const [_, indexKey] = result.value;
|
|
669
|
+
if (previousIndexKey !== void 0 && compareKeys({
|
|
670
|
+
value: previousIndexKey,
|
|
671
|
+
kind: "exact"
|
|
672
|
+
}, {
|
|
673
|
+
value: indexKey,
|
|
674
|
+
kind: "exact"
|
|
675
|
+
}) * comparisonInversion > 0) {
|
|
676
|
+
throw new Error(`ConcatStreams in wrong order: ${JSON.stringify(previousIndexKey)}, ${JSON.stringify(indexKey)}`);
|
|
677
|
+
}
|
|
678
|
+
previousIndexKey = indexKey;
|
|
679
|
+
return result;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return { done: true, value: void 0 };
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
getOrder() {
|
|
689
|
+
return this.#order;
|
|
690
|
+
}
|
|
691
|
+
getEqualityIndexFilter() {
|
|
692
|
+
return this.#equalityIndexFilter;
|
|
693
|
+
}
|
|
694
|
+
getIndexFields() {
|
|
695
|
+
return this.#indexFields;
|
|
696
|
+
}
|
|
697
|
+
narrow(indexBounds) {
|
|
698
|
+
return new ConcatStreams(...this.#streams.map((stream2) => stream2.narrow(indexBounds)));
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
class FlatMapStreamIterator {
|
|
702
|
+
#outerStream;
|
|
703
|
+
#outerIterator;
|
|
704
|
+
#currentOuterItem = null;
|
|
705
|
+
#mapper;
|
|
706
|
+
#mappedIndexFields;
|
|
707
|
+
constructor(outerStream, mapper, mappedIndexFields) {
|
|
708
|
+
this.#outerIterator = outerStream.iterWithKeys()[Symbol.asyncIterator]();
|
|
709
|
+
this.#outerStream = outerStream;
|
|
710
|
+
this.#mapper = mapper;
|
|
711
|
+
this.#mappedIndexFields = mappedIndexFields;
|
|
712
|
+
}
|
|
713
|
+
singletonSkipInnerStream() {
|
|
714
|
+
const indexKey = this.#mappedIndexFields.map(() => null);
|
|
715
|
+
return new SingletonStream(null, this.#outerStream.getOrder(), this.#mappedIndexFields, indexKey, indexKey);
|
|
716
|
+
}
|
|
717
|
+
async setCurrentOuterItem(item) {
|
|
718
|
+
const [t, indexKey] = item;
|
|
719
|
+
let innerStream;
|
|
720
|
+
if (t === null) {
|
|
721
|
+
innerStream = this.singletonSkipInnerStream();
|
|
722
|
+
} else {
|
|
723
|
+
innerStream = await this.#mapper(t);
|
|
724
|
+
if (!equalIndexFields(innerStream.getIndexFields(), this.#mappedIndexFields)) {
|
|
725
|
+
throw new Error(`FlatMapStream: inner stream has different index fields than expected: ${JSON.stringify(innerStream.getIndexFields())} vs ${JSON.stringify(this.#mappedIndexFields)}`);
|
|
726
|
+
}
|
|
727
|
+
if (innerStream.getOrder() !== this.#outerStream.getOrder()) {
|
|
728
|
+
throw new Error(`FlatMapStream: inner stream has different order than outer stream: ${innerStream.getOrder()} vs ${this.#outerStream.getOrder()}`);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
this.#currentOuterItem = {
|
|
732
|
+
t,
|
|
733
|
+
indexKey,
|
|
734
|
+
innerIterator: innerStream.iterWithKeys()[Symbol.asyncIterator](),
|
|
735
|
+
count: 0
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
async next() {
|
|
739
|
+
if (this.#currentOuterItem === null) {
|
|
740
|
+
const result2 = await this.#outerIterator.next();
|
|
741
|
+
if (result2.done) {
|
|
742
|
+
return { done: true, value: void 0 };
|
|
743
|
+
}
|
|
744
|
+
await this.setCurrentOuterItem(result2.value);
|
|
745
|
+
return await this.next();
|
|
746
|
+
}
|
|
747
|
+
const result = await this.#currentOuterItem.innerIterator.next();
|
|
748
|
+
if (result.done) {
|
|
749
|
+
if (this.#currentOuterItem.count > 0) {
|
|
750
|
+
this.#currentOuterItem = null;
|
|
751
|
+
} else {
|
|
752
|
+
this.#currentOuterItem.innerIterator = this.singletonSkipInnerStream().iterWithKeys()[Symbol.asyncIterator]();
|
|
753
|
+
}
|
|
754
|
+
return await this.next();
|
|
755
|
+
}
|
|
756
|
+
const [u, indexKey] = result.value;
|
|
757
|
+
this.#currentOuterItem.count++;
|
|
758
|
+
const fullIndexKey = [...this.#currentOuterItem.indexKey, ...indexKey];
|
|
759
|
+
return { done: false, value: [u, fullIndexKey] };
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
class FlatMapStream extends QueryStream {
|
|
763
|
+
#stream;
|
|
764
|
+
#mapper;
|
|
765
|
+
#mappedIndexFields;
|
|
766
|
+
constructor(stream2, mapper, mappedIndexFields) {
|
|
767
|
+
super();
|
|
768
|
+
this.#stream = stream2;
|
|
769
|
+
this.#mapper = mapper;
|
|
770
|
+
this.#mappedIndexFields = mappedIndexFields;
|
|
771
|
+
}
|
|
772
|
+
iterWithKeys() {
|
|
773
|
+
const outerStream = this.#stream;
|
|
774
|
+
const mapper = this.#mapper;
|
|
775
|
+
const mappedIndexFields = this.#mappedIndexFields;
|
|
776
|
+
return {
|
|
777
|
+
[Symbol.asyncIterator]() {
|
|
778
|
+
return new FlatMapStreamIterator(outerStream, mapper, mappedIndexFields);
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
getOrder() {
|
|
783
|
+
return this.#stream.getOrder();
|
|
784
|
+
}
|
|
785
|
+
getEqualityIndexFilter() {
|
|
786
|
+
return this.#stream.getEqualityIndexFilter();
|
|
787
|
+
}
|
|
788
|
+
getIndexFields() {
|
|
789
|
+
return [...this.#stream.getIndexFields(), ...this.#mappedIndexFields];
|
|
790
|
+
}
|
|
791
|
+
narrow(indexBounds) {
|
|
792
|
+
const outerLength = this.#stream.getIndexFields().length;
|
|
793
|
+
const outerLowerBound = indexBounds.lowerBound.slice(0, outerLength);
|
|
794
|
+
const outerUpperBound = indexBounds.upperBound.slice(0, outerLength);
|
|
795
|
+
const innerLowerBound = indexBounds.lowerBound.slice(outerLength);
|
|
796
|
+
const innerUpperBound = indexBounds.upperBound.slice(outerLength);
|
|
797
|
+
const outerIndexBounds = {
|
|
798
|
+
lowerBound: outerLowerBound,
|
|
799
|
+
lowerBoundInclusive: innerLowerBound.length === 0 ? indexBounds.lowerBoundInclusive : true,
|
|
800
|
+
upperBound: outerUpperBound,
|
|
801
|
+
upperBoundInclusive: innerUpperBound.length === 0 ? indexBounds.upperBoundInclusive : true
|
|
802
|
+
};
|
|
803
|
+
const innerIndexBounds = {
|
|
804
|
+
lowerBound: innerLowerBound,
|
|
805
|
+
lowerBoundInclusive: innerLowerBound.length === 0 ? true : indexBounds.lowerBoundInclusive,
|
|
806
|
+
upperBound: innerUpperBound,
|
|
807
|
+
upperBoundInclusive: innerUpperBound.length === 0 ? true : indexBounds.upperBoundInclusive
|
|
808
|
+
};
|
|
809
|
+
return new FlatMapStream(this.#stream.narrow(outerIndexBounds), async (t) => {
|
|
810
|
+
const innerStream = await this.#mapper(t);
|
|
811
|
+
return innerStream.narrow(innerIndexBounds);
|
|
812
|
+
}, this.#mappedIndexFields);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
class SingletonStream extends QueryStream {
|
|
816
|
+
#value;
|
|
817
|
+
#order;
|
|
818
|
+
#indexFields;
|
|
819
|
+
#indexKey;
|
|
820
|
+
#equalityIndexFilter;
|
|
821
|
+
constructor(value, order = "asc", indexFields, indexKey, equalityIndexFilter) {
|
|
822
|
+
super();
|
|
823
|
+
this.#value = value;
|
|
824
|
+
this.#order = order;
|
|
825
|
+
this.#indexFields = indexFields;
|
|
826
|
+
this.#indexKey = indexKey;
|
|
827
|
+
this.#equalityIndexFilter = equalityIndexFilter;
|
|
828
|
+
if (indexKey.length !== indexFields.length) {
|
|
829
|
+
throw new Error(`indexKey must have the same length as indexFields: ${JSON.stringify(indexKey)} vs ${JSON.stringify(indexFields)}`);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
iterWithKeys() {
|
|
833
|
+
const value = this.#value;
|
|
834
|
+
const indexKey = this.#indexKey;
|
|
835
|
+
return {
|
|
836
|
+
[Symbol.asyncIterator]() {
|
|
837
|
+
let sent = false;
|
|
838
|
+
return {
|
|
839
|
+
async next() {
|
|
840
|
+
if (sent) {
|
|
841
|
+
return { done: true, value: void 0 };
|
|
842
|
+
}
|
|
843
|
+
sent = true;
|
|
844
|
+
return { done: false, value: [value, indexKey] };
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
getOrder() {
|
|
851
|
+
return this.#order;
|
|
852
|
+
}
|
|
853
|
+
getIndexFields() {
|
|
854
|
+
return this.#indexFields;
|
|
855
|
+
}
|
|
856
|
+
getEqualityIndexFilter() {
|
|
857
|
+
return this.#equalityIndexFilter;
|
|
858
|
+
}
|
|
859
|
+
narrow(indexBounds) {
|
|
860
|
+
const compareLowerBound = compareKeys({
|
|
861
|
+
value: indexBounds.lowerBound,
|
|
862
|
+
kind: indexBounds.lowerBoundInclusive ? "exact" : "successor"
|
|
863
|
+
}, {
|
|
864
|
+
value: this.#indexKey,
|
|
865
|
+
kind: "exact"
|
|
866
|
+
});
|
|
867
|
+
const compareUpperBound = compareKeys({
|
|
868
|
+
value: this.#indexKey,
|
|
869
|
+
kind: "exact"
|
|
870
|
+
}, {
|
|
871
|
+
value: indexBounds.upperBound,
|
|
872
|
+
kind: indexBounds.upperBoundInclusive ? "exact" : "predecessor"
|
|
873
|
+
});
|
|
874
|
+
if (compareLowerBound <= 0 && compareUpperBound <= 0) {
|
|
875
|
+
return new SingletonStream(this.#value, this.#order, this.#indexFields, this.#indexKey, this.#equalityIndexFilter);
|
|
876
|
+
}
|
|
877
|
+
return new EmptyStream(this.#order, this.#indexFields);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
class EmptyStream extends QueryStream {
|
|
881
|
+
#order;
|
|
882
|
+
#indexFields;
|
|
883
|
+
constructor(order, indexFields) {
|
|
884
|
+
super();
|
|
885
|
+
this.#order = order;
|
|
886
|
+
this.#indexFields = indexFields;
|
|
887
|
+
}
|
|
888
|
+
iterWithKeys() {
|
|
889
|
+
return {
|
|
890
|
+
[Symbol.asyncIterator]() {
|
|
891
|
+
return {
|
|
892
|
+
async next() {
|
|
893
|
+
return { done: true, value: void 0 };
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
getOrder() {
|
|
900
|
+
return this.#order;
|
|
901
|
+
}
|
|
902
|
+
getIndexFields() {
|
|
903
|
+
return this.#indexFields;
|
|
904
|
+
}
|
|
905
|
+
getEqualityIndexFilter() {
|
|
906
|
+
return [];
|
|
907
|
+
}
|
|
908
|
+
narrow(_indexBounds) {
|
|
909
|
+
return this;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
function normalizeIndexFields(indexFields) {
|
|
913
|
+
if (!indexFields.includes("_creationTime")) {
|
|
914
|
+
if (indexFields.length !== 1 || indexFields[0] !== "_id") {
|
|
915
|
+
indexFields.push("_creationTime");
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
if (!indexFields.includes("_id")) {
|
|
919
|
+
indexFields.push("_id");
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function* getOrderingIndexFields(stream2) {
|
|
923
|
+
const streamEqualityIndexLength = stream2.getEqualityIndexFilter().length;
|
|
924
|
+
const streamIndexFields = stream2.getIndexFields();
|
|
925
|
+
for (let i = 0; i <= streamEqualityIndexLength; i++) {
|
|
926
|
+
yield streamIndexFields.slice(i);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
class DistinctStream extends QueryStream {
|
|
930
|
+
#distinctIndexFieldsLength;
|
|
931
|
+
#stream;
|
|
932
|
+
#distinctIndexFields;
|
|
933
|
+
constructor(stream2, distinctIndexFields) {
|
|
934
|
+
super();
|
|
935
|
+
this.#stream = stream2;
|
|
936
|
+
this.#distinctIndexFields = distinctIndexFields;
|
|
937
|
+
let distinctIndexFieldsLength = void 0;
|
|
938
|
+
for (const orderingIndexFields of getOrderingIndexFields(stream2)) {
|
|
939
|
+
const prefix = orderingIndexFields.slice(0, distinctIndexFields.length);
|
|
940
|
+
if (equalIndexFields(prefix, distinctIndexFields)) {
|
|
941
|
+
const equalityLength = stream2.getIndexFields().length - orderingIndexFields.length;
|
|
942
|
+
distinctIndexFieldsLength = equalityLength + distinctIndexFields.length;
|
|
943
|
+
break;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (distinctIndexFieldsLength === void 0) {
|
|
947
|
+
throw new Error(`distinctIndexFields must be a prefix of the stream's ordering index fields: ${JSON.stringify(distinctIndexFields)}, ${JSON.stringify(stream2.getIndexFields())} (${stream2.getEqualityIndexFilter().length} equality fields)`);
|
|
948
|
+
}
|
|
949
|
+
this.#distinctIndexFieldsLength = distinctIndexFieldsLength;
|
|
950
|
+
}
|
|
951
|
+
iterWithKeys() {
|
|
952
|
+
const stream2 = this.#stream;
|
|
953
|
+
const distinctIndexFieldsLength = this.#distinctIndexFieldsLength;
|
|
954
|
+
return {
|
|
955
|
+
[Symbol.asyncIterator]() {
|
|
956
|
+
let currentStream = stream2;
|
|
957
|
+
let currentIterator = currentStream.iterWithKeys()[Symbol.asyncIterator]();
|
|
958
|
+
return {
|
|
959
|
+
async next() {
|
|
960
|
+
const result = await currentIterator.next();
|
|
961
|
+
if (result.done) {
|
|
962
|
+
return { done: true, value: void 0 };
|
|
963
|
+
}
|
|
964
|
+
const [doc2, indexKey] = result.value;
|
|
965
|
+
if (doc2 === null) {
|
|
966
|
+
return { done: false, value: [null, indexKey] };
|
|
967
|
+
}
|
|
968
|
+
const distinctIndexKey = indexKey.slice(0, distinctIndexFieldsLength);
|
|
969
|
+
if (stream2.getOrder() === "asc") {
|
|
970
|
+
currentStream = currentStream.narrow({
|
|
971
|
+
lowerBound: distinctIndexKey,
|
|
972
|
+
lowerBoundInclusive: false,
|
|
973
|
+
upperBound: [],
|
|
974
|
+
upperBoundInclusive: true
|
|
975
|
+
});
|
|
976
|
+
} else {
|
|
977
|
+
currentStream = currentStream.narrow({
|
|
978
|
+
lowerBound: [],
|
|
979
|
+
lowerBoundInclusive: true,
|
|
980
|
+
upperBound: distinctIndexKey,
|
|
981
|
+
upperBoundInclusive: false
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
currentIterator = currentStream.iterWithKeys()[Symbol.asyncIterator]();
|
|
985
|
+
return result;
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
narrow(indexBounds) {
|
|
992
|
+
const indexBoundsPrefix = {
|
|
993
|
+
...indexBounds,
|
|
994
|
+
lowerBound: indexBounds.lowerBound.slice(0, this.#distinctIndexFieldsLength),
|
|
995
|
+
upperBound: indexBounds.upperBound.slice(0, this.#distinctIndexFieldsLength)
|
|
996
|
+
};
|
|
997
|
+
return new DistinctStream(this.#stream.narrow(indexBoundsPrefix), this.#distinctIndexFields);
|
|
998
|
+
}
|
|
999
|
+
getOrder() {
|
|
1000
|
+
return this.#stream.getOrder();
|
|
1001
|
+
}
|
|
1002
|
+
getIndexFields() {
|
|
1003
|
+
return this.#stream.getIndexFields();
|
|
1004
|
+
}
|
|
1005
|
+
getEqualityIndexFilter() {
|
|
1006
|
+
return this.#stream.getEqualityIndexFilter();
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
function equalIndexFields(indexFields1, indexFields2) {
|
|
1010
|
+
if (indexFields1.length !== indexFields2.length) {
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
for (let i = 0; i < indexFields1.length; i++) {
|
|
1014
|
+
if (indexFields1[i] !== indexFields2[i]) {
|
|
1015
|
+
return false;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return true;
|
|
1019
|
+
}
|
|
1020
|
+
function getValueAtIndex(v2, index) {
|
|
1021
|
+
if (index >= v2.length) {
|
|
1022
|
+
return void 0;
|
|
1023
|
+
}
|
|
1024
|
+
return { kind: "found", value: v2[index] };
|
|
1025
|
+
}
|
|
1026
|
+
function compareDanglingSuffix(shorterKeyKind, longerKeyKind, shorterKey, longerKey) {
|
|
1027
|
+
if (shorterKeyKind === "exact" && longerKeyKind === "exact") {
|
|
1028
|
+
throw new Error(`Exact keys are not the same length: ${JSON.stringify(shorterKey.value)}, ${JSON.stringify(longerKey.value)}`);
|
|
1029
|
+
}
|
|
1030
|
+
if (shorterKeyKind === "exact") {
|
|
1031
|
+
throw new Error(`Exact key is shorter than prefix: ${JSON.stringify(shorterKey.value)}, ${JSON.stringify(longerKey.value)}`);
|
|
1032
|
+
}
|
|
1033
|
+
if (shorterKeyKind === "predecessor" && longerKeyKind === "successor") {
|
|
1034
|
+
return -1;
|
|
1035
|
+
}
|
|
1036
|
+
if (shorterKeyKind === "successor" && longerKeyKind === "predecessor") {
|
|
1037
|
+
return 1;
|
|
1038
|
+
}
|
|
1039
|
+
if (shorterKeyKind === "predecessor" && longerKeyKind === "predecessor") {
|
|
1040
|
+
return -1;
|
|
1041
|
+
}
|
|
1042
|
+
if (shorterKeyKind === "successor" && longerKeyKind === "successor") {
|
|
1043
|
+
return 1;
|
|
1044
|
+
}
|
|
1045
|
+
if (shorterKeyKind === "predecessor" && longerKeyKind === "exact") {
|
|
1046
|
+
return -1;
|
|
1047
|
+
}
|
|
1048
|
+
if (shorterKeyKind === "successor" && longerKeyKind === "exact") {
|
|
1049
|
+
return 1;
|
|
1050
|
+
}
|
|
1051
|
+
throw new Error(`Unexpected key kinds: ${shorterKeyKind}, ${longerKeyKind}`);
|
|
1052
|
+
}
|
|
1053
|
+
function compareKeys(key1, key2) {
|
|
1054
|
+
let i = 0;
|
|
1055
|
+
while (i < Math.max(key1.value.length, key2.value.length)) {
|
|
1056
|
+
const v1 = getValueAtIndex(key1.value, i);
|
|
1057
|
+
const v2 = getValueAtIndex(key2.value, i);
|
|
1058
|
+
if (v1 === void 0) {
|
|
1059
|
+
return compareDanglingSuffix(key1.kind, key2.kind, key1, key2);
|
|
1060
|
+
}
|
|
1061
|
+
if (v2 === void 0) {
|
|
1062
|
+
return -1 * compareDanglingSuffix(key2.kind, key1.kind, key2, key1);
|
|
1063
|
+
}
|
|
1064
|
+
const result = compareValues(v1.value, v2.value);
|
|
1065
|
+
if (result !== 0) {
|
|
1066
|
+
return result;
|
|
1067
|
+
}
|
|
1068
|
+
i++;
|
|
1069
|
+
}
|
|
1070
|
+
if (key1.kind === key2.kind) {
|
|
1071
|
+
return 0;
|
|
1072
|
+
}
|
|
1073
|
+
if (key1.kind === "exact") {
|
|
1074
|
+
if (key2.kind === "successor") {
|
|
1075
|
+
return -1;
|
|
1076
|
+
} else {
|
|
1077
|
+
return 1;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
if (key1.kind === "predecessor") {
|
|
1081
|
+
return -1;
|
|
1082
|
+
}
|
|
1083
|
+
if (key1.kind === "successor") {
|
|
1084
|
+
return 1;
|
|
1085
|
+
}
|
|
1086
|
+
throw new Error(`Unexpected key kind: ${key1.kind}`);
|
|
1087
|
+
}
|
|
1088
|
+
function serializeCursor(key) {
|
|
1089
|
+
return JSON.stringify(convexToJson(key.map((v2) => v2 === void 0 ? "undefined" : typeof v2 === "string" && v2.endsWith("undefined") ? (
|
|
1090
|
+
// in the unlikely case their string was "undefined"
|
|
1091
|
+
// or "_undefined" etc, we escape it.
|
|
1092
|
+
"_" + v2
|
|
1093
|
+
) : v2)));
|
|
1094
|
+
}
|
|
1095
|
+
function deserializeCursor(cursor) {
|
|
1096
|
+
return jsonToConvex(JSON.parse(cursor)).map((v2) => {
|
|
1097
|
+
if (typeof v2 === "string") {
|
|
1098
|
+
if (v2 === "undefined") {
|
|
1099
|
+
return void 0;
|
|
1100
|
+
}
|
|
1101
|
+
if (v2.endsWith("undefined")) {
|
|
1102
|
+
return v2.slice(1);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return v2;
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
34
1108
|
export {
|
|
35
1109
|
doc as d,
|
|
36
|
-
omit as o
|
|
1110
|
+
omit as o,
|
|
1111
|
+
stream as s
|
|
37
1112
|
};
|