kitcn 0.32.1 → 0.33.0
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/CHANGELOG.md +114 -0
- package/dist/aggregate/index.d.ts +2 -2
- package/dist/auth/index.js +1 -1
- package/dist/{capabilities-Ctcw2VRq.d.ts → capabilities-Bxzoofl4.d.ts} +195 -9
- package/dist/orm/aggregate-index/index.d.ts +1 -1
- package/dist/orm/aggregate-index/index.js +226 -96
- package/dist/orm/index.d.ts +2 -2
- package/dist/orm/index.js +440 -113
- package/dist/orm/migrations/index.d.ts +2 -2
- package/dist/{query-context-D4z1CnDH.js → query-context-DQLv58LH.js} +34 -1
- package/dist/react/index.js +4 -3
- package/dist/{schema-Bh7AmJwY.js → schema-BF4P0ZjS.js} +322 -1
- package/dist/{where-clause-compiler-BHGHbfb9.d.ts → where-clause-compiler-DrV6lQg0.d.ts} +126 -126
- package/package.json +1 -1
- package/skills/kitcn/references/features/aggregates.md +13 -0
- package/skills/kitcn/references/features/orm.md +24 -4
|
@@ -1,77 +1,8 @@
|
|
|
1
1
|
import { t as DirectAggregate } from "../../runtime-B-8HKSIE.js";
|
|
2
2
|
import { n as Columns } from "../../symbols-DDNAddkd.js";
|
|
3
3
|
import { d as INTERNAL_CREATION_TIME_FIELD, f as PUBLIC_CREATED_AT_FIELD, m as usesSystemCreatedAtAlias } from "../../index-utils-DvK7P6Q1.js";
|
|
4
|
-
import {
|
|
4
|
+
import { C as createError, _ as createOrmTransactionMemo, a as AGGREGATE_STATE_TABLE, b as COUNT_ERROR, c as getAggregateIndexDefinitions, d as flushOrmWriteBatch, f as isOrmWriteBatchOpen, h as createOrmWriteMemo, i as AGGREGATE_RANK_TREE_TABLE, l as getRankIndexDefinitions, n as AGGREGATE_EXTREMA_TABLE, r as AGGREGATE_MEMBER_TABLE, s as rankAggregateName, st as normalizeTemporalComparableValue, t as AGGREGATE_BUCKET_TABLE, u as enqueueOrmWriteBatch, wt as mapWithConcurrency, y as AGGREGATE_ERROR } from "../../schema-BF4P0ZjS.js";
|
|
5
5
|
|
|
6
|
-
//#region src/orm/transaction-cache.ts
|
|
7
|
-
/**
|
|
8
|
-
* Per-transaction memo storage for the ORM.
|
|
9
|
-
*
|
|
10
|
-
* The ORM already has isolate-, execution-, statement- and row-scoped memos.
|
|
11
|
-
* The lifetime it lacked is the one a hook needs: `prependWriteBarrier` is
|
|
12
|
-
* built inside `createOrmDbLifecycle`, which `createOrm` runs at module scope,
|
|
13
|
-
* so a flag in that closure lives as long as the isolate and would leak an
|
|
14
|
-
* answer from one transaction into the next.
|
|
15
|
-
*
|
|
16
|
-
* Deliberately dependency-free, for the same reason as `write-fanout`:
|
|
17
|
-
* `aggregate-index/runtime` is contractually unreachable from `orm/index`
|
|
18
|
-
* (`import-graph.test.ts`), so importing `lifecycle` here to read one symbol
|
|
19
|
-
* would drag the trigger runtime into the aggregate entry's bundle.
|
|
20
|
-
* `Symbol.for` is registry-based, so re-declaring the key resolves to the same
|
|
21
|
-
* symbol `lifecycle` installs.
|
|
22
|
-
*/
|
|
23
|
-
const ORMLIFECYCLE_INNER_DB = Symbol.for("kitcn:OrmLifecycleInnerDB");
|
|
24
|
-
/**
|
|
25
|
-
* The object whose identity stands in for "this transaction".
|
|
26
|
-
*
|
|
27
|
-
* Convex builds `ctx.db` fresh on every UDF invocation, so it can never be
|
|
28
|
-
* shared by two transactions. `getOrmLifecycleInnerDb` cannot be used on its
|
|
29
|
-
* own: the lifecycle refuses to wrap readers and returns a no-op wrapper for
|
|
30
|
-
* schemas with no triggers and no aggregate indexes, so the inner-db symbol is
|
|
31
|
-
* absent for every query and for most mutations. Resolving through it when it
|
|
32
|
-
* is there, and falling back to the db itself when it is not, converges on the
|
|
33
|
-
* same raw writer from the main scope, `skipRules`, `withoutTriggers` and the
|
|
34
|
-
* scheduled workers.
|
|
35
|
-
*
|
|
36
|
-
* A nested `ctx.runMutation` shares the transaction but gets its own `ctx.db`,
|
|
37
|
-
* so it starts a fresh memo. That direction only costs extra reads.
|
|
38
|
-
*/
|
|
39
|
-
const resolveTransactionAnchor = (db) => {
|
|
40
|
-
if (typeof db !== "object" || db === null) return;
|
|
41
|
-
const inner = db[ORMLIFECYCLE_INNER_DB];
|
|
42
|
-
return typeof inner === "object" && inner !== null ? inner : db;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* One memo namespace with transaction lifetime.
|
|
46
|
-
*
|
|
47
|
-
* The store is a `WeakMap` keyed on the anchor rather than a slot on the db,
|
|
48
|
-
* because `createDatabase` promises not to mutate the `ctx.db` it was handed.
|
|
49
|
-
* Entries die with the transaction's db object.
|
|
50
|
-
*
|
|
51
|
-
* Callers own staleness: only memoize a fact that nothing inside the
|
|
52
|
-
* transaction can invalidate.
|
|
53
|
-
*/
|
|
54
|
-
const createOrmTransactionMemo = () => {
|
|
55
|
-
const byTransaction = /* @__PURE__ */ new WeakMap();
|
|
56
|
-
return {
|
|
57
|
-
get(db, key) {
|
|
58
|
-
const anchor = resolveTransactionAnchor(db);
|
|
59
|
-
return anchor ? byTransaction.get(anchor)?.get(key) : void 0;
|
|
60
|
-
},
|
|
61
|
-
set(db, key, value) {
|
|
62
|
-
const anchor = resolveTransactionAnchor(db);
|
|
63
|
-
if (!anchor) return;
|
|
64
|
-
const existing = byTransaction.get(anchor);
|
|
65
|
-
if (existing) {
|
|
66
|
-
existing.set(key, value);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
byTransaction.set(anchor, new Map([[key, value]]));
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
//#endregion
|
|
75
6
|
//#region src/orm/aggregate-index/runtime.ts
|
|
76
7
|
const UNDEFINED_SENTINEL = "__kitcnUndefined";
|
|
77
8
|
const FLOAT64_SIGN_BIT = 1n << 63n;
|
|
@@ -801,6 +732,54 @@ const listBucketsByHash = async (db, tableName, indexName, keyHash) => await db.
|
|
|
801
732
|
const getBucketByKey = async (db, tableName, indexName, keyParts) => {
|
|
802
733
|
return (await listBucketsByHash(db, tableName, indexName, serializeCountKeyParts(keyParts))).find((bucket) => deepEquals(bucket.keyParts, keyParts)) ?? null;
|
|
803
734
|
};
|
|
735
|
+
const bucketRowByKey = createOrmWriteMemo();
|
|
736
|
+
const memberRowByDoc = createOrmWriteMemo();
|
|
737
|
+
const aggregateRowMemoKey = (...parts) => parts.join("\0");
|
|
738
|
+
const bucketMemoKey = (tableName, indexName, keyHash) => aggregateRowMemoKey(tableName, indexName, keyHash);
|
|
739
|
+
/**
|
|
740
|
+
* `kind` leads, because the member table stores a metric and a rank row for the
|
|
741
|
+
* same document under index names the schema lets collide.
|
|
742
|
+
*/
|
|
743
|
+
const memberMemoKey = (tableName, indexName, docId) => aggregateRowMemoKey(AGGREGATE_STATE_KIND_METRIC, tableName, indexName, docId);
|
|
744
|
+
/**
|
|
745
|
+
* A stored row is the backend's object, and Convex's test backend hands out the
|
|
746
|
+
* document it holds rather than a copy. One shallow clone of the row and of the
|
|
747
|
+
* containers it owns makes the memo entry the memo's own, so an entry means the
|
|
748
|
+
* same thing whatever the backend does with the document afterwards.
|
|
749
|
+
*/
|
|
750
|
+
const cloneStoredRow = (row) => {
|
|
751
|
+
const clone = { ...row };
|
|
752
|
+
for (const [field, value] of Object.entries(clone)) {
|
|
753
|
+
if (Array.isArray(value)) {
|
|
754
|
+
clone[field] = [...value];
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
if (typeof value === "object" && value !== null) clone[field] = { ...value };
|
|
758
|
+
}
|
|
759
|
+
return clone;
|
|
760
|
+
};
|
|
761
|
+
const rememberBucket = (db, memoKey, row) => {
|
|
762
|
+
bucketRowByKey.set(db, memoKey, { row: row === null ? null : cloneStoredRow(row) });
|
|
763
|
+
};
|
|
764
|
+
const rememberMember = (db, memoKey, row) => {
|
|
765
|
+
memberRowByDoc.set(db, memoKey, { row: row === null ? null : cloneStoredRow(row) });
|
|
766
|
+
};
|
|
767
|
+
/** `getBucketByKey` within the current write segment. Write path only. */
|
|
768
|
+
const readBucketForWrite = async (db, tableName, indexName, keyParts, memoKey) => {
|
|
769
|
+
const memoized = bucketRowByKey.get(db, memoKey);
|
|
770
|
+
if (memoized) return memoized.row;
|
|
771
|
+
const bucket = await getBucketByKey(db, tableName, indexName, keyParts);
|
|
772
|
+
rememberBucket(db, memoKey, bucket);
|
|
773
|
+
return bucket;
|
|
774
|
+
};
|
|
775
|
+
/** `getMemberByDoc` within the current write segment. Write path only. */
|
|
776
|
+
const readMemberForWrite = async (db, tableName, indexName, docId, memoKey) => {
|
|
777
|
+
const memoized = memberRowByDoc.get(db, memoKey);
|
|
778
|
+
if (memoized) return memoized.row;
|
|
779
|
+
const member = await getMemberByDoc(db, tableName, indexName, docId);
|
|
780
|
+
rememberMember(db, memoKey, member);
|
|
781
|
+
return member;
|
|
782
|
+
};
|
|
804
783
|
const listBucketsByHashPrefix = async (db, tableName, indexName, scan, limit) => await db.query(AGGREGATE_BUCKET_TABLE).withIndex("by_table_index_hash", (q) => {
|
|
805
784
|
const scoped = q.eq("tableKey", tableName).eq("indexName", indexName);
|
|
806
785
|
return (scan.after === void 0 ? scoped.gte("keyHash", scan.start) : scoped.gt("keyHash", scan.after)).lt("keyHash", scan.end);
|
|
@@ -814,34 +793,45 @@ const takeBucketsForIndex = async (db, tableName, indexName, limit) => await db.
|
|
|
814
793
|
const takeExtremaForIndex = async (db, tableName, indexName, limit) => await db.query(AGGREGATE_EXTREMA_TABLE).withIndex("by_table_index", (q) => q.eq("tableKey", tableName).eq("indexName", indexName)).take(limit);
|
|
815
794
|
const applyBucketDelta = async (db, tableName, indexName, keyParts, deltaCount, deltaSums, deltaNonNullCounts) => {
|
|
816
795
|
if (deltaCount === 0 && Object.keys(deltaSums).length === 0 && Object.keys(deltaNonNullCounts).length === 0) return;
|
|
817
|
-
const
|
|
796
|
+
const keyHash = serializeCountKeyParts(keyParts);
|
|
797
|
+
const memoKey = bucketMemoKey(tableName, indexName, keyHash);
|
|
798
|
+
const existing = await readBucketForWrite(db, tableName, indexName, keyParts, memoKey);
|
|
818
799
|
const now = Date.now();
|
|
819
800
|
if (!existing) {
|
|
820
801
|
if (deltaCount < 0) return;
|
|
821
|
-
|
|
802
|
+
const inserted = {
|
|
822
803
|
tableKey: tableName,
|
|
823
804
|
indexName,
|
|
824
|
-
keyHash
|
|
805
|
+
keyHash,
|
|
825
806
|
keyParts,
|
|
826
807
|
count: deltaCount,
|
|
827
808
|
sumValues: deltaSums,
|
|
828
809
|
nonNullCountValues: deltaNonNullCounts,
|
|
829
810
|
updatedAt: now
|
|
811
|
+
};
|
|
812
|
+
const id = await db.insert(AGGREGATE_BUCKET_TABLE, inserted);
|
|
813
|
+
rememberBucket(db, memoKey, {
|
|
814
|
+
...inserted,
|
|
815
|
+
_id: id
|
|
830
816
|
});
|
|
831
817
|
return;
|
|
832
818
|
}
|
|
833
819
|
const nextCount = existing.count + deltaCount;
|
|
834
820
|
if (nextCount <= 0) {
|
|
835
821
|
await db.delete(AGGREGATE_BUCKET_TABLE, existing._id);
|
|
822
|
+
rememberBucket(db, memoKey, null);
|
|
836
823
|
return;
|
|
837
824
|
}
|
|
838
|
-
const
|
|
839
|
-
const nextNonNullCountValues = mergeCountValues(normalizeNonNullCountValues(existing.nonNullCountValues), deltaNonNullCounts);
|
|
840
|
-
await db.patch(AGGREGATE_BUCKET_TABLE, existing._id, {
|
|
825
|
+
const patch = {
|
|
841
826
|
count: nextCount,
|
|
842
|
-
sumValues:
|
|
843
|
-
nonNullCountValues:
|
|
827
|
+
sumValues: mergeSumValues(normalizeSumValues(existing.sumValues), deltaSums),
|
|
828
|
+
nonNullCountValues: mergeCountValues(normalizeNonNullCountValues(existing.nonNullCountValues), deltaNonNullCounts),
|
|
844
829
|
updatedAt: now
|
|
830
|
+
};
|
|
831
|
+
await db.patch(AGGREGATE_BUCKET_TABLE, existing._id, patch);
|
|
832
|
+
rememberBucket(db, memoKey, {
|
|
833
|
+
...existing,
|
|
834
|
+
...patch
|
|
845
835
|
});
|
|
846
836
|
};
|
|
847
837
|
const encodeNumberSortKey = (value) => {
|
|
@@ -926,6 +916,7 @@ const matchesRangePlanBucket = (options) => {
|
|
|
926
916
|
return true;
|
|
927
917
|
};
|
|
928
918
|
const readPlanBuckets = async (db, plan) => {
|
|
919
|
+
await flushOrmWriteBatch(db);
|
|
929
920
|
if (!plan.rangeConstraint) return (await mapWithConcurrency(plan.keyCandidates ?? buildCandidateKeys(plan.indexFields, plan.fieldValues), AGGREGATE_BUCKET_READ_CONCURRENCY, (keyParts) => getBucketByKey(db, plan.tableName, plan.indexName, keyParts))).filter((bucket) => bucket !== null);
|
|
930
921
|
const prefixCandidates = buildCandidateKeys(plan.rangeConstraint.prefixFields, plan.fieldValues);
|
|
931
922
|
const rangeFieldIndex = plan.indexFields.indexOf(plan.rangeConstraint.fieldName);
|
|
@@ -992,6 +983,7 @@ const getPlanBucketCacheKey = (plan) => serializeStable({
|
|
|
992
983
|
postFieldValues: sortFieldValueRecord(plan.postFieldValues)
|
|
993
984
|
});
|
|
994
985
|
const readPlanBucketsWithCache = async (db, plan, bucketCache) => {
|
|
986
|
+
await flushOrmWriteBatch(db);
|
|
995
987
|
if (!bucketCache) return await readPlanBuckets(db, plan);
|
|
996
988
|
const cacheKey = getPlanBucketCacheKey(plan);
|
|
997
989
|
const existing = bucketCache.get(cacheKey);
|
|
@@ -1053,6 +1045,7 @@ const readKeyExtrema = async (db, params) => {
|
|
|
1053
1045
|
};
|
|
1054
1046
|
const readExtremaFromBuckets = async (db, plan, bucketCache) => {
|
|
1055
1047
|
if (plan.metric.kind !== "min" && plan.metric.kind !== "max") throw new Error("readExtremaFromBuckets() requires a min/max aggregate plan.");
|
|
1048
|
+
await flushOrmWriteBatch(db);
|
|
1056
1049
|
let selected = null;
|
|
1057
1050
|
const buckets = await readPlanBucketsWithCache(db, plan, bucketCache);
|
|
1058
1051
|
const metric = plan.metric;
|
|
@@ -1151,11 +1144,13 @@ const computeMembershipDelta = (existing, params) => {
|
|
|
1151
1144
|
const { tableName, indexName, docId, keyParts, metricValues } = params;
|
|
1152
1145
|
if (!keyParts || !metricValues) {
|
|
1153
1146
|
if (!existing) return {
|
|
1147
|
+
docId,
|
|
1154
1148
|
buckets: [],
|
|
1155
1149
|
extrema: [],
|
|
1156
1150
|
member: { kind: "none" }
|
|
1157
1151
|
};
|
|
1158
1152
|
return {
|
|
1153
|
+
docId,
|
|
1159
1154
|
buckets: [{
|
|
1160
1155
|
keyHash: serializeCountKeyParts(existing.keyParts),
|
|
1161
1156
|
keyParts: existing.keyParts,
|
|
@@ -1177,6 +1172,7 @@ const computeMembershipDelta = (existing, params) => {
|
|
|
1177
1172
|
const normalizedNextNonNullCountValues = normalizeNonNullCountValues(metricValues.nonNullCountValues);
|
|
1178
1173
|
const normalizedNextExtremaValues = normalizeExtremaValues(metricValues.extremaValues);
|
|
1179
1174
|
if (existing && existing.keyHash === keyHash && deepEquals(existing.keyParts, normalizedKeyParts) && deepEquals(normalizeSumValues(existing.sumValues), normalizedNextSumValues) && deepEquals(normalizeNonNullCountValues(existing.nonNullCountValues), normalizedNextNonNullCountValues) && deepEquals(normalizeExtremaValues(existing.extremaValues), normalizedNextExtremaValues)) return {
|
|
1175
|
+
docId,
|
|
1180
1176
|
buckets: [],
|
|
1181
1177
|
extrema: [],
|
|
1182
1178
|
member: { kind: "none" }
|
|
@@ -1210,14 +1206,28 @@ const computeMembershipDelta = (existing, params) => {
|
|
|
1210
1206
|
extremaValues: normalizedNextExtremaValues,
|
|
1211
1207
|
updatedAt: now
|
|
1212
1208
|
};
|
|
1209
|
+
if (existing) {
|
|
1210
|
+
const { _id, ...priorFields } = existing;
|
|
1211
|
+
return {
|
|
1212
|
+
docId,
|
|
1213
|
+
buckets,
|
|
1214
|
+
extrema,
|
|
1215
|
+
member: {
|
|
1216
|
+
kind: "patch",
|
|
1217
|
+
id: _id,
|
|
1218
|
+
doc: memberFields,
|
|
1219
|
+
post: {
|
|
1220
|
+
...priorFields,
|
|
1221
|
+
...memberFields
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1213
1226
|
return {
|
|
1227
|
+
docId,
|
|
1214
1228
|
buckets,
|
|
1215
1229
|
extrema,
|
|
1216
|
-
member:
|
|
1217
|
-
kind: "patch",
|
|
1218
|
-
id: existing._id,
|
|
1219
|
-
doc: memberFields
|
|
1220
|
-
} : {
|
|
1230
|
+
member: {
|
|
1221
1231
|
kind: "insert",
|
|
1222
1232
|
doc: {
|
|
1223
1233
|
...memberFields,
|
|
@@ -1229,14 +1239,14 @@ const computeMembershipDelta = (existing, params) => {
|
|
|
1229
1239
|
};
|
|
1230
1240
|
};
|
|
1231
1241
|
const computeAggregateMembershipDelta = async (db, params) => {
|
|
1232
|
-
return computeMembershipDelta(await
|
|
1242
|
+
return computeMembershipDelta(await readMemberForWrite(db, params.tableName, params.indexName, params.docId, memberMemoKey(params.tableName, params.indexName, params.docId)), params);
|
|
1233
1243
|
};
|
|
1234
1244
|
/**
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1245
|
+
* Folds bucket deltas by key tuple and extrema deltas by
|
|
1246
|
+
* (keyHash, field, value), so each storage document is read and written once
|
|
1247
|
+
* regardless of how many source documents contributed to it.
|
|
1238
1248
|
*/
|
|
1239
|
-
const
|
|
1249
|
+
const foldStorageDeltas = (deltas) => {
|
|
1240
1250
|
const bucketDeltas = /* @__PURE__ */ new Map();
|
|
1241
1251
|
const extremaDeltas = /* @__PURE__ */ new Map();
|
|
1242
1252
|
for (const delta of deltas) {
|
|
@@ -1270,28 +1280,139 @@ const flushAggregateMembershipDeltas = async (db, tableName, indexName, deltas)
|
|
|
1270
1280
|
current.delta += entry.delta;
|
|
1271
1281
|
}
|
|
1272
1282
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1283
|
+
return {
|
|
1284
|
+
buckets: bucketDeltas,
|
|
1285
|
+
extrema: extremaDeltas
|
|
1286
|
+
};
|
|
1287
|
+
};
|
|
1288
|
+
/** Applies a fold to the bucket and extrema documents it names. */
|
|
1289
|
+
const applyFoldedStorageDeltas = async (db, tableName, indexName, folded) => {
|
|
1290
|
+
for (const bucket of folded.buckets.values()) await applyBucketDelta(db, tableName, indexName, bucket.keyParts, bucket.deltaCount, bucket.deltaSums, bucket.deltaNonNullCounts);
|
|
1291
|
+
for (const entry of folded.extrema.values()) await applyExtremaDelta(db, tableName, indexName, entry.keyHash, entry.fieldName, entry.value, entry.delta);
|
|
1292
|
+
};
|
|
1293
|
+
/**
|
|
1294
|
+
* One member row per source document. Nothing folds here — the member table
|
|
1295
|
+
* stores the per-document post-image the next reconciliation of that document
|
|
1296
|
+
* subtracts, so it is written eagerly even when the bucket write is deferred.
|
|
1297
|
+
*/
|
|
1298
|
+
const applyMemberWrites = async (db, tableName, indexName, deltas) => {
|
|
1275
1299
|
for (const delta of deltas) {
|
|
1276
1300
|
const member = delta.member;
|
|
1301
|
+
if (member.kind === "none") continue;
|
|
1302
|
+
const memoKey = memberMemoKey(tableName, indexName, delta.docId);
|
|
1277
1303
|
if (member.kind === "delete") {
|
|
1278
1304
|
await db.delete(AGGREGATE_MEMBER_TABLE, member.id);
|
|
1305
|
+
rememberMember(db, memoKey, null);
|
|
1279
1306
|
continue;
|
|
1280
1307
|
}
|
|
1281
1308
|
if (member.kind === "patch") {
|
|
1282
1309
|
await db.patch(AGGREGATE_MEMBER_TABLE, member.id, member.doc);
|
|
1310
|
+
rememberMember(db, memoKey, {
|
|
1311
|
+
...member.post,
|
|
1312
|
+
_id: member.id
|
|
1313
|
+
});
|
|
1283
1314
|
continue;
|
|
1284
1315
|
}
|
|
1285
|
-
|
|
1316
|
+
const id = await db.insert(AGGREGATE_MEMBER_TABLE, member.doc);
|
|
1317
|
+
rememberMember(db, memoKey, {
|
|
1318
|
+
...member.doc,
|
|
1319
|
+
_id: id
|
|
1320
|
+
});
|
|
1286
1321
|
}
|
|
1287
1322
|
};
|
|
1288
1323
|
/**
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1324
|
+
* Write half of aggregate reconciliation. Folds bucket deltas by key tuple and
|
|
1325
|
+
* extrema deltas by (keyHash, field, value) so each storage document is read and
|
|
1326
|
+
* written once regardless of how many source documents contributed to it.
|
|
1327
|
+
*/
|
|
1328
|
+
const flushAggregateMembershipDeltas = async (db, tableName, indexName, deltas) => {
|
|
1329
|
+
await applyFoldedStorageDeltas(db, tableName, indexName, foldStorageDeltas(deltas));
|
|
1330
|
+
await applyMemberWrites(db, tableName, indexName, deltas);
|
|
1331
|
+
};
|
|
1332
|
+
const PENDING_STORAGE_WRITES_KEY = "aggregateStorageWrites";
|
|
1333
|
+
/**
|
|
1334
|
+
* Bucket and extrema deltas the open write batch has not applied yet, keyed by
|
|
1335
|
+
* the index that owns them.
|
|
1336
|
+
*
|
|
1337
|
+
* Reconciliation runs once per document, so there is nothing for the fold to
|
|
1338
|
+
* collapse inside a single call. Holding the deltas until the statement ends is
|
|
1339
|
+
* what gives the fold something to fold: a 40-row statement over one key tuple
|
|
1340
|
+
* becomes one bucket read and one bucket write instead of forty of each.
|
|
1341
|
+
*/
|
|
1342
|
+
const pendingStorageWrites = createOrmTransactionMemo();
|
|
1343
|
+
/**
|
|
1344
|
+
* Grouped per index, never flat. `serializeCountKeyParts` is `JSON.stringify` of
|
|
1345
|
+
* the key tuple alone, so two indexes on different single string fields both
|
|
1346
|
+
* holding `"a"` produce the identical `keyHash`; a flat fold would write one
|
|
1347
|
+
* index's counts onto the other's bucket.
|
|
1348
|
+
*/
|
|
1349
|
+
const pendingIndexKey = (tableName, indexName) => `${tableName}\u0000${indexName}`;
|
|
1350
|
+
const getPendingStorageWrites = (db) => {
|
|
1351
|
+
const existing = pendingStorageWrites.get(db, PENDING_STORAGE_WRITES_KEY);
|
|
1352
|
+
if (existing) return existing;
|
|
1353
|
+
const created = {
|
|
1354
|
+
byIndex: /* @__PURE__ */ new Map(),
|
|
1355
|
+
flush: async () => {
|
|
1356
|
+
for (;;) {
|
|
1357
|
+
const next = created.byIndex.entries().next();
|
|
1358
|
+
if (next.done) return;
|
|
1359
|
+
const [key, entry] = next.value;
|
|
1360
|
+
created.byIndex.delete(key);
|
|
1361
|
+
await applyFoldedStorageDeltas(db, entry.tableName, entry.indexName, foldStorageDeltas(entry.deltas));
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
pendingStorageWrites.set(db, PENDING_STORAGE_WRITES_KEY, created);
|
|
1366
|
+
return created;
|
|
1367
|
+
};
|
|
1368
|
+
const isEmptyMembershipDelta = (delta) => delta.buckets.length === 0 && delta.extrema.length === 0 && delta.member.kind === "none";
|
|
1369
|
+
/**
|
|
1370
|
+
* Single-document reconciliation.
|
|
1371
|
+
*
|
|
1372
|
+
* The bucket and extrema writes always go on the transaction's write queue,
|
|
1373
|
+
* never straight to storage: `applyBucketDelta` writes an absolute count
|
|
1374
|
+
* computed from the row it just read, so two of them interleaving would be a
|
|
1375
|
+
* lost update, and routing every one of them through a single drain is what
|
|
1376
|
+
* keeps them serialized. Inside a mutation statement the queue is held to the
|
|
1377
|
+
* end of the statement, which is what lets the fold collapse a page of
|
|
1378
|
+
* documents into one write per key tuple; outside one it is drained
|
|
1379
|
+
* immediately, so a raw `ctx.db` write behaves exactly as it did before.
|
|
1380
|
+
*
|
|
1381
|
+
* The member row is written per document either way, because it is the
|
|
1382
|
+
* pre-image the next reconciliation of this document subtracts. Outside a
|
|
1383
|
+
* statement it is still written after the bucket, preserving the previous
|
|
1384
|
+
* order; inside one it necessarily lands first, and a flush that throws
|
|
1385
|
+
* part-way leaves the index needing a backfill — which a partially applied fold
|
|
1386
|
+
* would anyway, whichever order the two halves ran in.
|
|
1387
|
+
*
|
|
1388
|
+
* Deferral is invisible to aggregate readers: every bucket- and extrema-backed
|
|
1389
|
+
* read path drains the queue first, so user code reading a count later in the
|
|
1390
|
+
* same mutation — including from a trigger firing mid-statement — still sees
|
|
1391
|
+
* its own writes.
|
|
1291
1392
|
*/
|
|
1292
1393
|
const reconcileAggregateMembership = async (db, params) => {
|
|
1394
|
+
const { tableName, indexName } = params;
|
|
1293
1395
|
const delta = await computeAggregateMembershipDelta(db, params);
|
|
1294
|
-
|
|
1396
|
+
if (isEmptyMembershipDelta(delta)) return;
|
|
1397
|
+
const pending = getPendingStorageWrites(db);
|
|
1398
|
+
if (!enqueueOrmWriteBatch(db, pending.flush)) {
|
|
1399
|
+
await flushAggregateMembershipDeltas(db, tableName, indexName, [delta]);
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
const key = pendingIndexKey(tableName, indexName);
|
|
1403
|
+
const entry = pending.byIndex.get(key);
|
|
1404
|
+
if (entry) entry.deltas.push(delta);
|
|
1405
|
+
else pending.byIndex.set(key, {
|
|
1406
|
+
tableName,
|
|
1407
|
+
indexName,
|
|
1408
|
+
deltas: [delta]
|
|
1409
|
+
});
|
|
1410
|
+
if (isOrmWriteBatchOpen(db)) {
|
|
1411
|
+
await applyMemberWrites(db, tableName, indexName, [delta]);
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
await flushOrmWriteBatch(db);
|
|
1415
|
+
await applyMemberWrites(db, tableName, indexName, [delta]);
|
|
1295
1416
|
};
|
|
1296
1417
|
const computeCountKeyParts = (doc, fields) => fields.map((field) => normalizeUndefined(doc[field]));
|
|
1297
1418
|
const applyAggregateIndexesForChange = async (db, tableName, aggregateIndexes, change) => {
|
|
@@ -1361,6 +1482,7 @@ const assertAggregateIndexesWritable = async (db, tableName, metricIndexNames, r
|
|
|
1361
1482
|
* writing anything.
|
|
1362
1483
|
*/
|
|
1363
1484
|
const isIndexStateDrained = async (db, kind, tableName, indexName) => {
|
|
1485
|
+
await flushOrmWriteBatch(db);
|
|
1364
1486
|
if (await db.query(AGGREGATE_MEMBER_TABLE).withIndex("by_kind_table_index", (q) => q.eq("kind", kind).eq("tableKey", tableName).eq("indexName", indexName)).first()) return false;
|
|
1365
1487
|
if (kind === AGGREGATE_STATE_KIND_RANK) return await db.query(AGGREGATE_RANK_TREE_TABLE).withIndex("by_aggregate_name", (q) => q.eq("aggregateName", rankAggregateName(tableName, indexName))).first() === null;
|
|
1366
1488
|
const [bucket, extrema] = await Promise.all([db.query(AGGREGATE_BUCKET_TABLE).withIndex("by_table_index", (q) => q.eq("tableKey", tableName).eq("indexName", indexName)).first(), db.query(AGGREGATE_EXTREMA_TABLE).withIndex("by_table_index", (q) => q.eq("tableKey", tableName).eq("indexName", indexName)).first()]);
|
|
@@ -1423,9 +1545,13 @@ const setCountStateError = async (db, tableName, indexName, error, kind = AGGREG
|
|
|
1423
1545
|
* CLEARING write barrier keeps concurrent writers out of the index.
|
|
1424
1546
|
*/
|
|
1425
1547
|
const clearCountIndexChunk = async (db, tableName, indexName, batchSize) => {
|
|
1548
|
+
await flushOrmWriteBatch(db);
|
|
1426
1549
|
const members = await takeMembersForIndex(db, tableName, indexName, batchSize);
|
|
1427
1550
|
if (members.length > 0) {
|
|
1428
|
-
for (const member of members)
|
|
1551
|
+
for (const member of members) {
|
|
1552
|
+
await db.delete(AGGREGATE_MEMBER_TABLE, member._id);
|
|
1553
|
+
rememberMember(db, memberMemoKey(member.tableKey, member.indexName, member.docId), null);
|
|
1554
|
+
}
|
|
1429
1555
|
return {
|
|
1430
1556
|
done: false,
|
|
1431
1557
|
processed: members.length
|
|
@@ -1433,7 +1559,10 @@ const clearCountIndexChunk = async (db, tableName, indexName, batchSize) => {
|
|
|
1433
1559
|
}
|
|
1434
1560
|
const buckets = await takeBucketsForIndex(db, tableName, indexName, batchSize);
|
|
1435
1561
|
if (buckets.length > 0) {
|
|
1436
|
-
for (const bucket of buckets)
|
|
1562
|
+
for (const bucket of buckets) {
|
|
1563
|
+
await db.delete(AGGREGATE_BUCKET_TABLE, bucket._id);
|
|
1564
|
+
rememberBucket(db, bucketMemoKey(bucket.tableKey, bucket.indexName, bucket.keyHash), null);
|
|
1565
|
+
}
|
|
1437
1566
|
return {
|
|
1438
1567
|
done: false,
|
|
1439
1568
|
processed: buckets.length
|
|
@@ -1882,6 +2011,7 @@ function createCountBackfillHandlers(schema, getChunkRef) {
|
|
|
1882
2011
|
if (args.tableName && args.indexName) {
|
|
1883
2012
|
const tableName = args.tableName;
|
|
1884
2013
|
const indexName = args.indexName;
|
|
2014
|
+
await flushOrmWriteBatch(ctx.db);
|
|
1885
2015
|
const [bucket, extrema, metricMember, rankMember] = await Promise.all([
|
|
1886
2016
|
ctx.db.query(AGGREGATE_BUCKET_TABLE).withIndex("by_table_index", (q) => q.eq("tableKey", tableName).eq("indexName", indexName)).first(),
|
|
1887
2017
|
ctx.db.query(AGGREGATE_EXTREMA_TABLE).withIndex("by_table_index", (q) => q.eq("tableKey", tableName).eq("indexName", indexName)).first(),
|
package/dist/orm/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $n as TableName, $t as OrmLifecycleChange, An as ConvexCheckBuilder, At as UpdateSet, Bn as ConvexTextBuilder, Br as IsPrimaryKey, Bt as RelationsBuilderColumnBase, C as MigrationStep, Cn as ConvexVectorIndexConfig, Cr as not, Ct as OrderByClause, D as defineMigration, Dn as searchIndex, Dr as startsWith, Dt as ReturningAll, E as buildMigrationPlan, En as rankIndex, Er as or, Et as PredicateWhereIndexConfig, Fn as ConvexUniqueConstraintBuilderOn, Fr as ColumnBuilderTypeConfig, Ft as ExtractTablesFromSchema, Gn as Columns, Gt as TablesRelationalConfig, H as RlsMode, Hn as text, Hr as NotNull, In as ConvexUniqueConstraintConfig, Ir as ColumnBuilderWithTableName, It as ExtractTablesWithRelations, Jn as OrmSchemaExtensionTables, Jt as ConvexDeletionBuilder, Kt as defineRelations, Ln as check, Lr as ColumnDataType, Lt as ManyConfig, M as DatabaseWithQuery, Mn as ConvexForeignKeyBuilder, Mr as ColumnBuilder, Mt as VectorSearchProvider, N as OrmReader$1, Nn as ConvexForeignKeyConfig, Nr as ColumnBuilderBaseConfig, Nt as unsetToken, O as defineMigrationSet, On as uniqueIndex, Ot as ReturningResult, P as OrmWriter$1, Pn as ConvexUniqueConstraintBuilder, Pr as ColumnBuilderRuntimeConfig, Qn as OrmSchemaTriggers, Qt as DiscriminatorBuilderConfig, Rn as foreignKey, Rr as DrizzleEntity, Rt as OneConfig, S as MigrationStateMap, Sn as ConvexVectorIndexBuilderOn, Sr as ne, St as MutationRunMode, T as MigrationWriteMode, Tn as index, Tr as notInArray, Tt as PaginatedResult, U as EdgeMetadata, V as RlsContext, Vn as ConvexTextBuilderInitial, Vr as IsUnique, Vt as RelationsBuilderColumnConfig, W as extractRelationsConfig, Wn as Brand, Wt as TableRelationalConfig, Xn as OrmSchemaExtensions, Xt as ConvexTable, Yt as ConvexDeletionConfig, Zn as OrmSchemaRelations, Zt as ConvexTableWithColumns, _ as MigrationManifestEntry, _n as ConvexRankIndexBuilderOn, _r as isNotNull, _t as MutationExecutionMode, an as RlsPolicy, ar as UnaryExpression, at as BuildRelationResult, b as MigrationRunStatus, bn as ConvexSearchIndexConfig, br as lt, bt as MutationResult, cn as rlsPolicy, cr as contains, ct as DBQueryConfig, d as MigrationAppliedState, dn as rlsRole, dr as fieldRef, dt as InferInsertModel, en as OrmLifecycleOperation, er as BinaryExpression, f as MigrationDefinition, fn as ConvexAggregateIndexBuilder, fr as gt, ft as InferModelFromColumns, g as MigrationDriftIssue, gn as ConvexRankIndexBuilder, gr as isFieldReference, gt as MutationExecuteResult, h as MigrationDocContext, hn as ConvexIndexBuilderOn, hr as inArray, ht as MutationExecuteConfig, i as OrmMigrationCapability, in as discriminator, ir as LogicalExpression, it as BuildQueryResult, j as DatabaseWithMutations, jn as ConvexCheckConfig, jr as AnyColumn, jt as VectorQueryConfig, k as detectMigrationDrift, kn as vectorIndex, kr as SystemFields, kt as ReturningSelection, ln as RlsRole, lr as endsWith, lt as FilterOperators, m as MigrationDoc, mn as ConvexIndexBuilder, mr as ilike, mt as InsertValue, n as OrmCapabilities, nn as convexTable, nr as FieldReference, nt as AggregateFieldValue, on as RlsPolicyConfig, or as and, ot as CountConfig, p as MigrationDirection, pn as ConvexAggregateIndexBuilderOn, pr as gte, pt as InferSelectModel, qt as defineRelationsPart, r as OrmCapability, rn as deletion, rr as FilterExpression, rt as AggregateResult, sn as RlsPolicyToOption, sr as between, st as CountResult, t as OrmAggregateCapability, tn as TableConfig, tr as ExpressionVisitor, tt as AggregateConfig, un as RlsRoleConfig, ur as eq, ut as GetColumnData, v as MigrationMigrateOne, vn as ConvexSearchIndexBuilder, vr as isNull, vt as MutationPaginateConfig, w as MigrationTableName, wn as aggregateIndex, wr as notBetween, wt as OrderDirection, x as MigrationSet, xn as ConvexVectorIndexBuilder, xr as lte, xt as MutationReturning, y as MigrationPlan, yn as ConvexSearchIndexBuilderOn, yr as like, yt as MutationPaginatedResult, zn as unique, zr as HasDefault, zt as RelationsBuilder } from "../capabilities-
|
|
2
|
-
import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-
|
|
1
|
+
import { $n as TableName, $t as OrmLifecycleChange, An as ConvexCheckBuilder, At as UpdateSet, Bn as ConvexTextBuilder, Br as IsPrimaryKey, Bt as RelationsBuilderColumnBase, C as MigrationStep, Cn as ConvexVectorIndexConfig, Cr as not, Ct as OrderByClause, D as defineMigration, Dn as searchIndex, Dr as startsWith, Dt as ReturningAll, E as buildMigrationPlan, En as rankIndex, Er as or, Et as PredicateWhereIndexConfig, Fn as ConvexUniqueConstraintBuilderOn, Fr as ColumnBuilderTypeConfig, Ft as ExtractTablesFromSchema, Gn as Columns, Gt as TablesRelationalConfig, H as RlsMode, Hn as text, Hr as NotNull, In as ConvexUniqueConstraintConfig, Ir as ColumnBuilderWithTableName, It as ExtractTablesWithRelations, Jn as OrmSchemaExtensionTables, Jt as ConvexDeletionBuilder, Kt as defineRelations, Ln as check, Lr as ColumnDataType, Lt as ManyConfig, M as DatabaseWithQuery, Mn as ConvexForeignKeyBuilder, Mr as ColumnBuilder, Mt as VectorSearchProvider, N as OrmReader$1, Nn as ConvexForeignKeyConfig, Nr as ColumnBuilderBaseConfig, Nt as unsetToken, O as defineMigrationSet, On as uniqueIndex, Ot as ReturningResult, P as OrmWriter$1, Pn as ConvexUniqueConstraintBuilder, Pr as ColumnBuilderRuntimeConfig, Qn as OrmSchemaTriggers, Qt as DiscriminatorBuilderConfig, Rn as foreignKey, Rr as DrizzleEntity, Rt as OneConfig, S as MigrationStateMap, Sn as ConvexVectorIndexBuilderOn, Sr as ne, St as MutationRunMode, T as MigrationWriteMode, Tn as index, Tr as notInArray, Tt as PaginatedResult, U as EdgeMetadata, V as RlsContext, Vn as ConvexTextBuilderInitial, Vr as IsUnique, Vt as RelationsBuilderColumnConfig, W as extractRelationsConfig, Wn as Brand, Wt as TableRelationalConfig, Xn as OrmSchemaExtensions, Xt as ConvexTable, Yt as ConvexDeletionConfig, Zn as OrmSchemaRelations, Zt as ConvexTableWithColumns, _ as MigrationManifestEntry, _n as ConvexRankIndexBuilderOn, _r as isNotNull, _t as MutationExecutionMode, an as RlsPolicy, ar as UnaryExpression, at as BuildRelationResult, b as MigrationRunStatus, bn as ConvexSearchIndexConfig, br as lt, bt as MutationResult, cn as rlsPolicy, cr as contains, ct as DBQueryConfig, d as MigrationAppliedState, dn as rlsRole, dr as fieldRef, dt as InferInsertModel, en as OrmLifecycleOperation, er as BinaryExpression, f as MigrationDefinition, fn as ConvexAggregateIndexBuilder, fr as gt, ft as InferModelFromColumns, g as MigrationDriftIssue, gn as ConvexRankIndexBuilder, gr as isFieldReference, gt as MutationExecuteResult, h as MigrationDocContext, hn as ConvexIndexBuilderOn, hr as inArray, ht as MutationExecuteConfig, i as OrmMigrationCapability, in as discriminator, ir as LogicalExpression, it as BuildQueryResult, j as DatabaseWithMutations, jn as ConvexCheckConfig, jr as AnyColumn, jt as VectorQueryConfig, k as detectMigrationDrift, kn as vectorIndex, kr as SystemFields, kt as ReturningSelection, ln as RlsRole, lr as endsWith, lt as FilterOperators, m as MigrationDoc, mn as ConvexIndexBuilder, mr as ilike, mt as InsertValue, n as OrmCapabilities, nn as convexTable, nr as FieldReference, nt as AggregateFieldValue, on as RlsPolicyConfig, or as and, ot as CountConfig, p as MigrationDirection, pn as ConvexAggregateIndexBuilderOn, pr as gte, pt as InferSelectModel, qt as defineRelationsPart, r as OrmCapability, rn as deletion, rr as FilterExpression, rt as AggregateResult, sn as RlsPolicyToOption, sr as between, st as CountResult, t as OrmAggregateCapability, tn as TableConfig, tr as ExpressionVisitor, tt as AggregateConfig, un as RlsRoleConfig, ur as eq, ut as GetColumnData, v as MigrationMigrateOne, vn as ConvexSearchIndexBuilder, vr as isNull, vt as MutationPaginateConfig, w as MigrationTableName, wn as aggregateIndex, wr as notBetween, wt as OrderDirection, x as MigrationSet, xn as ConvexVectorIndexBuilder, xr as lte, xt as MutationReturning, y as MigrationPlan, yn as ConvexSearchIndexBuilderOn, yr as like, yt as MutationPaginatedResult, zn as unique, zr as HasDefault, zt as RelationsBuilder } from "../capabilities-Bxzoofl4.js";
|
|
2
|
+
import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-DrV6lQg0.js";
|
|
3
3
|
import { i as pretendRequired, n as deprecated, r as pretend } from "../validators-0I-Ik1EN.js";
|
|
4
4
|
import { a as QueryCtxWithPreferredOrmQueryTable, i as QueryCtxWithOrmQueryTable, n as LookupByIdResultByCtx, o as getByIdWithOrmQueryFallback, r as QueryCtxWithOptionalOrmQueryTable, t as DocByCtx } from "../query-context-BkNjkDCk.js";
|
|
5
5
|
import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchemaDefinition } from "convex/server";
|