@lunora/do 1.0.0-alpha.2 → 1.0.0-alpha.21
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/__assets__/package-og.svg +1 -1
- package/dist/index.d.mts +1162 -114
- package/dist/index.d.ts +1162 -114
- package/dist/index.mjs +27 -22
- package/dist/packem_shared/{ADMIN_FUNCTION_PREFIX-Dzdqq5J2.mjs → ADMIN_FUNCTIONS-DSUQ5fX9.mjs} +49 -3
- package/dist/packem_shared/{applyCdcChanges-Ctdmxmrv.mjs → CDC_LOG_TABLE-DSycmnDf.mjs} +5 -1
- package/dist/packem_shared/{DATA_MIGRATION_STATE_TABLE-PTtTiQ7U.mjs → DATA_MIGRATION_STATE_TABLE-DfPxn8I0.mjs} +5 -1
- package/dist/packem_shared/{assertFlatPredicate-DyVYReuT.mjs → DEFAULT_MAX_RELATION_KEYS-DU-Y4-LJ.mjs} +51 -2
- package/dist/packem_shared/{assertValidClientId-CBZ1zC96.mjs → NotUniqueError-Do5h_jiW.mjs} +127 -37
- package/dist/packem_shared/{rank-CrkEIpF4.mjs → RANK_TIEBREAK-CXhdcA1o.mjs} +2 -13
- package/dist/packem_shared/{guardWriter-u3UlnCH5.mjs → RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs} +6 -2
- package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-DQkmGiCS.mjs → ROOT_DO_SIZE_WARN_BYTES-BfPNp3Jh.mjs} +2342 -200
- package/dist/packem_shared/{ReactiveCache-ByVzgH3d.mjs → ReactiveCache-BYlSGY0N.mjs} +1 -28
- package/dist/packem_shared/{applyOnDelete-CMif2RKw.mjs → applyOnDelete-BQ-8ZlZ1.mjs} +19 -9
- package/dist/packem_shared/{buildSeekWhere-lVsNXSLy.mjs → applySelect-BvZdFUBT.mjs} +18 -1
- package/dist/packem_shared/{backfillAggregateIndexes-BF5eL7kW.mjs → backfillAggregateIndexes-BZsOqDXP.mjs} +3 -2
- package/dist/packem_shared/{compileWhereSql-CXrhFA3G.mjs → compileWhereSql-MW_Lk8nJ.mjs} +3 -2
- package/dist/packem_shared/ctx-db-idempotency-BdcNpvY4.mjs +108 -0
- package/dist/packem_shared/ctx-db-shapes-0RaIOy7J.mjs +53 -0
- package/dist/packem_shared/diffExternalSource-Cx9HUPJj.mjs +44 -0
- package/dist/packem_shared/isSourceDue-9mJRJ9Ld.mjs +40 -0
- package/dist/packem_shared/materializeExternalRows-Bj6EXy50.mjs +23 -0
- package/dist/packem_shared/{runShardMigrations-C3bn5r93.mjs → runShardMigrations-nIwoQeOK.mjs} +6 -4
- package/dist/packem_shared/serialize-sql-BlRUoiQe.mjs +14 -0
- package/dist/packem_shared/{serveRelationFanout-Clr1a05L.mjs → serveRelationFanout-C5axmGDj.mjs} +1 -1
- package/dist/packem_shared/stableStringify-MydiuScU.mjs +40 -0
- package/dist/packem_shared/subscription-delivery-CK8qga-k.mjs +347 -0
- package/dist/packem_shared/subscriptionListDeltas-BxygQlXT.mjs +1 -0
- package/package.json +2 -2
- package/dist/packem_shared/ctx-db-idempotency-DkC9rP91.mjs +0 -35
- package/dist/packem_shared/encodePartitionKey-C6blLR5K.mjs +0 -1
- /package/dist/packem_shared/{matchesStaticWhere-CFk6adSu.mjs → AGGREGATE_SQL_FUNCTION-CFk6adSu.mjs} +0 -0
- /package/dist/packem_shared/{AUTH_METRICS_BUCKET_MS-CiHHYeJi.mjs → AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs} +0 -0
- /package/dist/packem_shared/{ensureFunctionMetricsTables-UDNVD7FS.mjs → FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs} +0 -0
- /package/dist/packem_shared/{clearCapturedMail-CPpgl-dX.mjs → MAIL_RETENTION-CPpgl-dX.mjs} +0 -0
- /package/dist/packem_shared/{assertReadonly-dDcFE1YZ.mjs → MAX_SQL_ROWS-dDcFE1YZ.mjs} +0 -0
- /package/dist/packem_shared/{buildSecurityAudit-CCAvoFlr.mjs → MIN_ADMIN_TOKEN_LENGTH-CCAvoFlr.mjs} +0 -0
- /package/dist/packem_shared/{ftsTableName-BLEMawrp.mjs → buildFtsMatch-BLEMawrp.mjs} +0 -0
- /package/dist/packem_shared/{runTriggers-5N6_Fx0A.mjs → hasTrigger-5N6_Fx0A.mjs} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
export { exportShardRows, exportShardTable, importShardRows, parseExportShardArgs, parseImportShardArgs, selectExportTables, validateImportRow } from './packem_shared/exportShardRows-DZEhUeyI.mjs';
|
|
2
|
-
export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, normalizeCountArgument, throwingScheduler } from './packem_shared/
|
|
2
|
+
export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, normalizeCountArgument, throwingScheduler } from './packem_shared/AGGREGATE_SQL_FUNCTION-CFk6adSu.mjs';
|
|
3
3
|
export { aggregateTableName, coerceAggregateNumber, encodeAggregateKey, foldAggregateTally, readAggregateValue } from './packem_shared/aggregateTableName-CxNqY1Sl.mjs';
|
|
4
4
|
export { CountRlsUnsupportedError, mergeWhere, planAggregateLookup, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy } from './packem_shared/CountRlsUnsupportedError-28ZvvwKS.mjs';
|
|
5
|
-
export { AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, ensureAuthMetricsTables, readAuthMetrics, recordAuthEvent } from './packem_shared/
|
|
6
|
-
export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/
|
|
7
|
-
export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-
|
|
5
|
+
export { AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, ensureAuthMetricsTables, readAuthMetrics, recordAuthEvent } from './packem_shared/AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs';
|
|
6
|
+
export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/NotUniqueError-Do5h_jiW.mjs';
|
|
7
|
+
export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-DfPxn8I0.mjs';
|
|
8
8
|
export { SCAN_DEP, createDependencyTracker, depKey } from './packem_shared/SCAN_DEP-DLJF8dsj.mjs';
|
|
9
9
|
export { renderSql } from './packem_shared/renderSql-D6eUcn2N.mjs';
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
10
|
+
export { diffExternalSource } from './packem_shared/diffExternalSource-Cx9HUPJj.mjs';
|
|
11
|
+
export { materializeExternalRows, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-Bj6EXy50.mjs';
|
|
12
|
+
export { isSourceDue, liftSourceId, pullExternalSourceTick } from './packem_shared/isSourceDue-9mJRJ9Ld.mjs';
|
|
13
|
+
export { FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_TABLE, ensureFunctionMetricsTables, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetrics, readFunctionMetricsTotals, recordFunctionMetric } from './packem_shared/FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
|
|
14
|
+
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, FLAGS_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, facetColumn, listTables, readTablePage, selectMatchingIds } from './packem_shared/ADMIN_FUNCTIONS-DSUQ5fX9.mjs';
|
|
12
15
|
export { LogBuffer } from './packem_shared/LogBuffer-B_Ezju_N.mjs';
|
|
13
|
-
export { MAIL_RETENTION, MAIL_TABLE, clearCapturedMail, ensureMailTable, readCapturedMail, recordCapturedMail } from './packem_shared/
|
|
16
|
+
export { MAIL_RETENTION, MAIL_TABLE, clearCapturedMail, ensureMailTable, readCapturedMail, recordCapturedMail } from './packem_shared/MAIL_RETENTION-CPpgl-dX.mjs';
|
|
14
17
|
export { default as NotFoundError } from './packem_shared/NotFoundError-CMuMZt81.mjs';
|
|
15
18
|
export { armRestore, readBookmark } from './packem_shared/armRestore-BJk53Ro8.mjs';
|
|
16
|
-
export { buildSeekWhere, decodeCursor, encodeCursor, normalizeOrderKeys } from './packem_shared/
|
|
17
|
-
export {
|
|
18
|
-
export { ReactiveCache, reactiveCacheKey
|
|
19
|
-
export { serveRelationFanout } from './packem_shared/serveRelationFanout-
|
|
20
|
-
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/
|
|
21
|
-
export { applyOnDelete, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-
|
|
22
|
-
export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/
|
|
23
|
-
export { buildFtsMatch, ftsTableName, scoreDocument, stringifySearchText, tokenizeSearch } from './packem_shared/
|
|
19
|
+
export { applySelect, buildSeekWhere, decodeCursor, encodeCursor, normalizeOrderKeys, softDeleteScope } from './packem_shared/applySelect-BvZdFUBT.mjs';
|
|
20
|
+
export { RANK_TIEBREAK, encodePartitionKey, matchesRankStaticWhere, rankTableName, resolveRankPartition, sortColumnName } from './packem_shared/RANK_TIEBREAK-CXhdcA1o.mjs';
|
|
21
|
+
export { ReactiveCache, reactiveCacheKey } from './packem_shared/ReactiveCache-BYlSGY0N.mjs';
|
|
22
|
+
export { serveRelationFanout } from './packem_shared/serveRelationFanout-C5axmGDj.mjs';
|
|
23
|
+
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/DEFAULT_MAX_RELATION_KEYS-DU-Y4-LJ.mjs';
|
|
24
|
+
export { applyOnDelete, fanOutScalarCounts, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-BQ-8ZlZ1.mjs';
|
|
25
|
+
export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs';
|
|
26
|
+
export { buildFtsMatch, ftsTableName, scoreDocument, stringifySearchText, tokenizeSearch } from './packem_shared/buildFtsMatch-BLEMawrp.mjs';
|
|
24
27
|
export { M as MIN_ADMIN_TOKEN_LENGTH, a as MIN_AUTH_SECRET_LENGTH, b as buildSecurityAudit } from './packem_shared/security-audit-CucgBice.mjs';
|
|
25
28
|
export { SESSION_DO_TTL_DEFAULT, SessionDO } from './packem_shared/SESSION_DO_TTL_DEFAULT-ilPZsVwu.mjs';
|
|
26
|
-
export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO
|
|
29
|
+
export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-BfPNp3Jh.mjs';
|
|
27
30
|
export { SHARD_REGISTRY_DO_NAME, ShardRegistryDO } from './packem_shared/SHARD_REGISTRY_DO_NAME-BsAbi5Mn.mjs';
|
|
28
|
-
export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/
|
|
31
|
+
export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/MAX_SQL_ROWS-dDcFE1YZ.mjs';
|
|
29
32
|
export { createSystemReader } from './packem_shared/createSystemReader-8CzSZP9V.mjs';
|
|
30
33
|
export { ConflictError } from './packem_shared/ConflictError-C0STs6bU.mjs';
|
|
31
|
-
export { hasTrigger, runTriggers } from './packem_shared/
|
|
32
|
-
export { compileWhereSql } from './packem_shared/compileWhereSql-
|
|
33
|
-
export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/
|
|
34
|
-
export { backfillAggregateIndexes, backfillRankIndexes } from './packem_shared/backfillAggregateIndexes-
|
|
35
|
-
export { runShardMigrations } from './packem_shared/runShardMigrations-
|
|
34
|
+
export { hasTrigger, runTriggers } from './packem_shared/hasTrigger-5N6_Fx0A.mjs';
|
|
35
|
+
export { compileWhereSql } from './packem_shared/compileWhereSql-MW_Lk8nJ.mjs';
|
|
36
|
+
export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/CDC_LOG_TABLE-DSycmnDf.mjs';
|
|
37
|
+
export { backfillAggregateIndexes, backfillRankIndexes } from './packem_shared/backfillAggregateIndexes-BZsOqDXP.mjs';
|
|
38
|
+
export { runShardMigrations } from './packem_shared/runShardMigrations-nIwoQeOK.mjs';
|
|
39
|
+
export { stableStringify } from './packem_shared/stableStringify-MydiuScU.mjs';
|
|
40
|
+
export { s as subscriptionListDeltas } from './packem_shared/subscription-delivery-CK8qga-k.mjs';
|
package/dist/packem_shared/{ADMIN_FUNCTION_PREFIX-Dzdqq5J2.mjs → ADMIN_FUNCTIONS-DSUQ5fX9.mjs}
RENAMED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
const quoteIdentifier = (name) => `"${name.replaceAll('"', '""')}"`;
|
|
2
|
+
|
|
1
3
|
const ADMIN_FUNCTION_PREFIX = "__lunora_admin__:";
|
|
2
4
|
const RELATION_FUNCTION_PREFIX = "__lunora_relation__:";
|
|
5
|
+
const FLAGS_FUNCTION_PREFIX = "__lunora_flags__:";
|
|
3
6
|
const ADMIN_FUNCTIONS = {
|
|
4
7
|
applyCdc: "__lunora_admin__:applyCdc",
|
|
5
8
|
cdcSync: "__lunora_admin__:cdcSync",
|
|
@@ -15,6 +18,7 @@ const ADMIN_FUNCTIONS = {
|
|
|
15
18
|
getAuditLog: "__lunora_admin__:getAuditLog",
|
|
16
19
|
getAuthMetrics: "__lunora_admin__:getAuthMetrics",
|
|
17
20
|
getCapturedMail: "__lunora_admin__:getCapturedMail",
|
|
21
|
+
getFanoutMetrics: "__lunora_admin__:getFanoutMetrics",
|
|
18
22
|
getFunctionStats: "__lunora_admin__:getFunctionStats",
|
|
19
23
|
listSubscriptions: "__lunora_admin__:listSubscriptions",
|
|
20
24
|
listTableIndexes: "__lunora_admin__:listTableIndexes",
|
|
@@ -27,6 +31,8 @@ const ADMIN_FUNCTIONS = {
|
|
|
27
31
|
// eslint-disable-next-line no-secrets/no-secrets -- reserved admin RPC path constant, not a credential
|
|
28
32
|
getWorkflowInstanceStatus: "__lunora_admin__:getWorkflowInstanceStatus",
|
|
29
33
|
importShard: "__lunora_admin__:importShard",
|
|
34
|
+
listFlags: "__lunora_admin__:listFlags",
|
|
35
|
+
listQueues: "__lunora_admin__:listQueues",
|
|
30
36
|
listTables: "__lunora_admin__:listTables",
|
|
31
37
|
listWorkflows: "__lunora_admin__:listWorkflows",
|
|
32
38
|
maskPolicies: "__lunora_admin__:maskPolicies",
|
|
@@ -91,7 +97,6 @@ const expandDocumentRows = (columns, rows) => {
|
|
|
91
97
|
};
|
|
92
98
|
const escapeLike = (value) => value.replaceAll(/[\\%_]/g, (character) => `\\${character}`);
|
|
93
99
|
const isInternalTable = (name) => name.startsWith("sqlite_") || name.startsWith("_cf_") || name.startsWith("__miniflare") || name.startsWith("__lunora") || name.includes("__fts_");
|
|
94
|
-
const quoteIdentifier = (name) => `"${name.replaceAll('"', '""')}"`;
|
|
95
100
|
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
96
101
|
const countRows = (sql, quotedTable) => {
|
|
97
102
|
const row = sql.exec(`SELECT COUNT(*) AS c FROM ${quotedTable}`).one();
|
|
@@ -195,7 +200,10 @@ const readTablePage = (sql, options) => {
|
|
|
195
200
|
const orderSql = order === void 0 ? "" : ` ORDER BY ${order.sql}`;
|
|
196
201
|
const whereParams = predicate?.parameters ?? [];
|
|
197
202
|
const orderParams = order?.params ?? [];
|
|
198
|
-
|
|
203
|
+
let total;
|
|
204
|
+
if (!options.skipCount) {
|
|
205
|
+
total = predicate === void 0 ? countRows(sql, quoted) : Number(sql.exec(`SELECT COUNT(*) AS c FROM ${quoted}${whereSql}`, ...whereParams).one().c);
|
|
206
|
+
}
|
|
199
207
|
const rawRows = sql.exec(`SELECT * FROM ${quoted}${whereSql}${orderSql} LIMIT ? OFFSET ?`, ...whereParams, ...orderParams, limit, offset).toArray();
|
|
200
208
|
return withReferences({ ...expandDocumentRows(columns, rawRows), total });
|
|
201
209
|
};
|
|
@@ -309,5 +317,43 @@ const summarizeSubscriptions = (attachments) => {
|
|
|
309
317
|
const totalSubscriptions = connections.reduce((sum, connection) => sum + connection.subscriptions.length, 0);
|
|
310
318
|
return { connections, totalConnections: connections.length, totalSubscriptions };
|
|
311
319
|
};
|
|
320
|
+
const DEFAULT_FANOUT_TOPIC_LIMIT = 20;
|
|
321
|
+
const createFanoutCounters = () => {
|
|
322
|
+
return { maxMs: 0, passes: 0, peakSocketsIterated: 0, socketsDelivered: 0, socketsIterated: 0, totalMs: 0 };
|
|
323
|
+
};
|
|
324
|
+
const recordFanoutPass = (counters, iterated, delivered, ms) => {
|
|
325
|
+
return {
|
|
326
|
+
maxMs: Math.max(counters.maxMs, ms),
|
|
327
|
+
passes: counters.passes + 1,
|
|
328
|
+
peakSocketsIterated: Math.max(counters.peakSocketsIterated, iterated),
|
|
329
|
+
socketsDelivered: counters.socketsDelivered + delivered,
|
|
330
|
+
socketsIterated: counters.socketsIterated + iterated,
|
|
331
|
+
totalMs: counters.totalMs + ms
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
const summarizeFanoutTopics = (attachments, limit = DEFAULT_FANOUT_TOPIC_LIMIT) => {
|
|
335
|
+
const shapeCounts = /* @__PURE__ */ new Map();
|
|
336
|
+
const whisperCounts = /* @__PURE__ */ new Map();
|
|
337
|
+
for (const attachment of attachments) {
|
|
338
|
+
for (const shape of Object.values(attachment.shapes ?? {})) {
|
|
339
|
+
const key = shape.name ?? "(unknown shape)";
|
|
340
|
+
shapeCounts.set(key, (shapeCounts.get(key) ?? 0) + 1);
|
|
341
|
+
}
|
|
342
|
+
for (const topic of attachment.whispers ?? []) {
|
|
343
|
+
whisperCounts.set(topic, (whisperCounts.get(topic) ?? 0) + 1);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
const topics = [
|
|
347
|
+
...[...shapeCounts].map(([topic, subscribers]) => {
|
|
348
|
+
return { kind: "shape", subscribers, topic };
|
|
349
|
+
}),
|
|
350
|
+
...[...whisperCounts].map(([topic, subscribers]) => {
|
|
351
|
+
return { kind: "whisper", subscribers, topic };
|
|
352
|
+
})
|
|
353
|
+
];
|
|
354
|
+
topics.sort((a, b) => b.subscribers - a.subscribers || a.topic.localeCompare(b.topic));
|
|
355
|
+
const peakSubscribers = topics[0]?.subscribers ?? 0;
|
|
356
|
+
return { peakSubscribers, topics: topics.slice(0, limit), totalConnections: attachments.length };
|
|
357
|
+
};
|
|
312
358
|
|
|
313
|
-
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, MAX_PAGE_SIZE, RELATION_FUNCTION_PREFIX, facetColumn, findStorageReferences, listTables, readTablePage, selectMatchingIds, summarizeSubscriptions };
|
|
359
|
+
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, DEFAULT_FANOUT_TOPIC_LIMIT, FLAGS_FUNCTION_PREFIX, MAX_PAGE_SIZE, RELATION_FUNCTION_PREFIX, createFanoutCounters, facetColumn, findStorageReferences, listTables, readTablePage, recordFanoutPass, selectMatchingIds, summarizeFanoutTopics, summarizeSubscriptions };
|
|
@@ -26,9 +26,13 @@ const appendCdcChange = (sql$1, ts, table, id, op, doc) => {
|
|
|
26
26
|
const readCdcChanges = (sql$1, options = {}) => {
|
|
27
27
|
const sinceSeq = options.sinceSeq ?? 0;
|
|
28
28
|
const limit = Math.max(1, Math.min(options.limit ?? 1e3, 1e4));
|
|
29
|
+
const tableFilter = options.tables && options.tables.size > 0 ? sql` AND ${sql.identifier("table")} IN (${sql.join(
|
|
30
|
+
[...options.tables].map((table) => sql`${table}`),
|
|
31
|
+
sql`, `
|
|
32
|
+
)})` : sql``;
|
|
29
33
|
const rows = runDrizzle(
|
|
30
34
|
sql$1,
|
|
31
|
-
sql`SELECT seq, ts, ${sql.identifier("table")}, id, op, doc FROM ${sql.identifier(CDC_LOG_TABLE)} WHERE seq > ${sinceSeq} ORDER BY seq ASC LIMIT ${limit}`
|
|
35
|
+
sql`SELECT seq, ts, ${sql.identifier("table")}, id, op, doc FROM ${sql.identifier(CDC_LOG_TABLE)} WHERE seq > ${sinceSeq}${tableFilter} ORDER BY seq ASC LIMIT ${limit}`
|
|
32
36
|
).toArray();
|
|
33
37
|
const changes = rows.map((row) => {
|
|
34
38
|
const base = { id: row.id, op: row.op, seq: row.seq, table: row.table, ts: row.ts };
|
|
@@ -229,7 +229,11 @@ const runDataMigration = async (options) => {
|
|
|
229
229
|
throw error;
|
|
230
230
|
}
|
|
231
231
|
if (!dryRun && !isDone) {
|
|
232
|
-
|
|
232
|
+
try {
|
|
233
|
+
releaseClaim(sql, migration.id);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.warn(`data migration "${migration.id}": releaseClaim failed`, error);
|
|
236
|
+
}
|
|
233
237
|
}
|
|
234
238
|
return { changed, cursor: isDone ? null : cursor, direction, dryRun, id: migration.id, processed, status: isDone ? "completed" : "in_progress" };
|
|
235
239
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { distinctValues } from './applyOnDelete-
|
|
1
|
+
import { distinctValues } from './applyOnDelete-BQ-8ZlZ1.mjs';
|
|
2
2
|
|
|
3
3
|
const RELATION_EXISTS_KEY = "__relationExists";
|
|
4
4
|
|
|
@@ -156,5 +156,54 @@ const resolveRelationPredicates = async (where, options) => {
|
|
|
156
156
|
schema: options.schema
|
|
157
157
|
});
|
|
158
158
|
};
|
|
159
|
+
const firstShardedHit = (branches, schema, tableName) => {
|
|
160
|
+
for (const branch of branches) {
|
|
161
|
+
const hit = findShardedRelationTarget(branch, schema, tableName);
|
|
162
|
+
if (hit) {
|
|
163
|
+
return hit;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return void 0;
|
|
167
|
+
};
|
|
168
|
+
const inspectKey = (key, value, schema, tableName) => {
|
|
169
|
+
if (key === "AND" || key === "OR") {
|
|
170
|
+
return firstShardedHit(branchesOf(value), schema, tableName);
|
|
171
|
+
}
|
|
172
|
+
if (key === "NOT") {
|
|
173
|
+
return firstShardedHit([value ?? {}], schema, tableName);
|
|
174
|
+
}
|
|
175
|
+
const relation = schema.tables[tableName]?.relationMap?.[key];
|
|
176
|
+
if (!relation || !isRelationPredicate(value)) {
|
|
177
|
+
return void 0;
|
|
178
|
+
}
|
|
179
|
+
if (schema.tables[relation.table]?.shardMode?.kind === "shardBy") {
|
|
180
|
+
return { relation: key, target: relation.table };
|
|
181
|
+
}
|
|
182
|
+
return firstShardedHit(Object.values(value), schema, relation.table);
|
|
183
|
+
};
|
|
184
|
+
const findShardedRelationTarget = (where, schema, tableName) => {
|
|
185
|
+
for (const key of Object.keys(where)) {
|
|
186
|
+
const hit = inspectKey(key, where[key], schema, tableName);
|
|
187
|
+
if (hit) {
|
|
188
|
+
return hit;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return void 0;
|
|
192
|
+
};
|
|
193
|
+
const assertShapeShardable = (effectiveWhere, schema, table) => {
|
|
194
|
+
if (!effectiveWhere) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const offending = findShardedRelationTarget(effectiveWhere, schema, table);
|
|
198
|
+
if (!offending) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
throw Object.assign(
|
|
202
|
+
new Error(
|
|
203
|
+
`shape on "${table}" joins the sharded table "${offending.target}" via relation "${offending.relation}" — a live shape cannot replicate rows that live in another shard's Durable Object. Fix it by (a) denormalizing the joined columns into "${table}", or (b) moving "${offending.target}" to .global() so it is served through the latency-tiered D1 shape tier.`
|
|
204
|
+
),
|
|
205
|
+
{ code: "SHAPE_CROSS_SHARD_JOIN", name: "LunoraError", status: 400 }
|
|
206
|
+
);
|
|
207
|
+
};
|
|
159
208
|
|
|
160
|
-
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates };
|
|
209
|
+
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates };
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import { sql } from 'drizzle-orm';
|
|
2
|
-
import { matchesStaticWhere, aggregateSqlFunction, normalizeCountArgument, throwingScheduler } from './
|
|
2
|
+
import { matchesStaticWhere, aggregateSqlFunction, normalizeCountArgument, throwingScheduler } from './AGGREGATE_SQL_FUNCTION-CFk6adSu.mjs';
|
|
3
3
|
import { encodeAggregateKey, foldAggregateTally, aggregateTableName, coerceAggregateNumber, readAggregateValue } from './aggregateTableName-CxNqY1Sl.mjs';
|
|
4
4
|
import { mergeWhere, CountRlsUnsupportedError, selectIndexForGroupBy, selectIndexForCount, selectIndexForAggregate } from './CountRlsUnsupportedError-28ZvvwKS.mjs';
|
|
5
|
-
import { appendCdcChange } from './
|
|
6
|
-
export { CDC_LOG_TABLE,
|
|
5
|
+
import { appendCdcChange } from './CDC_LOG_TABLE-DSycmnDf.mjs';
|
|
6
|
+
export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-DSycmnDf.mjs';
|
|
7
7
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
8
8
|
import { i as isFtsAvailable, D as DOC_COLUMN$1, r as rowToDocument, A as AGG_KEY, a as AGG_VALUE, b as AGG_COUNT, d as aggUpsertSql, j as jsonPathSql, q as quoteIdentifier, t as tableColumns, e as qualifiedJsonPathSql } from './do-sql-BCHCWtrD.mjs';
|
|
9
9
|
import { param } from './renderSql-D6eUcn2N.mjs';
|
|
10
|
-
import {
|
|
11
|
-
import { stringifySearchText, ftsTableName, tokenizeSearch, buildFtsMatch, scoreDocument } from './
|
|
10
|
+
import { sortColumnName, matchesRankStaticWhere, encodePartitionKey, rankTableName, resolveRankPartition, RANK_TIEBREAK } from './RANK_TIEBREAK-CXhdcA1o.mjs';
|
|
11
|
+
import { stringifySearchText, ftsTableName, tokenizeSearch, buildFtsMatch, scoreDocument } from './buildFtsMatch-BLEMawrp.mjs';
|
|
12
|
+
import { s as serializeSqlValue } from './serialize-sql-BlRUoiQe.mjs';
|
|
12
13
|
import { SCAN_DEP } from './SCAN_DEP-DLJF8dsj.mjs';
|
|
13
|
-
import { decodeCursor, normalizeOrderKeys, buildSeekWhere, encodeCursor, buildSeekBeforeWhere } from './
|
|
14
|
+
import { decodeCursor, normalizeOrderKeys, buildSeekWhere, applySelect, encodeCursor, softDeleteScope, buildSeekBeforeWhere } from './applySelect-BvZdFUBT.mjs';
|
|
14
15
|
import NotFoundError from './NotFoundError-CMuMZt81.mjs';
|
|
15
|
-
import { assertFlatPredicate, resolveRelationPredicates } from './
|
|
16
|
-
import { runRowValidators, resolveWith, applyOnDelete } from './applyOnDelete-
|
|
17
|
-
import { guardWriter } from './
|
|
16
|
+
import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-DU-Y4-LJ.mjs';
|
|
17
|
+
import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-BQ-8ZlZ1.mjs';
|
|
18
|
+
import { guardWriter } from './RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs';
|
|
18
19
|
import { createSystemReader } from './createSystemReader-8CzSZP9V.mjs';
|
|
19
20
|
import { ConflictError } from './ConflictError-C0STs6bU.mjs';
|
|
20
|
-
import { runTriggers } from './
|
|
21
|
-
import { compileWhereSql } from './compileWhereSql-
|
|
22
|
-
export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-
|
|
23
|
-
export { I as IDEMPOTENCY_TABLE, m as
|
|
24
|
-
export { runShardMigrations } from './runShardMigrations-
|
|
21
|
+
import { runTriggers } from './hasTrigger-5N6_Fx0A.mjs';
|
|
22
|
+
import { compileWhereSql } from './compileWhereSql-MW_Lk8nJ.mjs';
|
|
23
|
+
export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-BZsOqDXP.mjs';
|
|
24
|
+
export { C as CLIENT_WATERMARK_TABLE, G as GLOBAL_SHAPE_SNAPSHOT_TABLE, I as IDEMPOTENCY_TABLE, c as advanceClientWatermark, d as deleteGlobalShapeSnapshot, e as deleteGlobalShapeSnapshotsForConnection, m as migrateClientWatermark, b as migrateGlobalShapeSnapshot, r as readClientWatermark, f as readGlobalShapeSnapshot, g as readIdempotent, t as trimIdempotent, w as writeGlobalShapeSnapshot, h as writeIdempotent } from './ctx-db-idempotency-BdcNpvY4.mjs';
|
|
25
|
+
export { runShardMigrations } from './runShardMigrations-nIwoQeOK.mjs';
|
|
26
|
+
export { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-0RaIOy7J.mjs';
|
|
25
27
|
|
|
26
28
|
const rankIndexFieldsUnchanged = (index, previous, next) => {
|
|
27
29
|
const fields = [...index.partitionBy ?? [], ...index.sortBy.map((key) => key.field), ...index.where ? Object.keys(index.where) : []];
|
|
@@ -534,7 +536,7 @@ const createSearchBuilder = (search, tableName) => {
|
|
|
534
536
|
};
|
|
535
537
|
return builder;
|
|
536
538
|
};
|
|
537
|
-
const searchViaFts = (sql$1, tableName, search, limit) => {
|
|
539
|
+
const searchViaFts = (sql$1, tableName, search, limit, scopeCondition) => {
|
|
538
540
|
const tokens = tokenizeSearch(search.query);
|
|
539
541
|
if (tokens.length === 0) {
|
|
540
542
|
return [];
|
|
@@ -544,6 +546,9 @@ const searchViaFts = (sql$1, tableName, search, limit) => {
|
|
|
544
546
|
for (const filter of search.filters) {
|
|
545
547
|
whereClauses.push(sql`${jsonPathSql(filter.field)} = ${serializeSqlValue(filter.value)}`);
|
|
546
548
|
}
|
|
549
|
+
if (scopeCondition) {
|
|
550
|
+
whereClauses.push(scopeCondition);
|
|
551
|
+
}
|
|
547
552
|
let query = sql`SELECT m.id, m._creationTime, m.${sql.identifier(DOC_COLUMN$1)} FROM ${sql.identifier(ftName)} f JOIN ${sql.identifier(tableName)} m ON m.id = f.${sql.identifier("__id__")} WHERE ${sql.join(whereClauses, sql` AND `)} ORDER BY f.rank, m._creationTime DESC`;
|
|
548
553
|
if (typeof limit === "number") {
|
|
549
554
|
query = sql`${query} LIMIT ${sql.raw(String(Math.max(0, Math.floor(limit))))}`;
|
|
@@ -558,7 +563,7 @@ const searchViaFts = (sql$1, tableName, search, limit) => {
|
|
|
558
563
|
}
|
|
559
564
|
return docs;
|
|
560
565
|
};
|
|
561
|
-
const searchViaScan = (sql$1, tableName, search, limit) => {
|
|
566
|
+
const searchViaScan = (sql$1, tableName, search, limit, scopeCondition) => {
|
|
562
567
|
const tokens = tokenizeSearch(search.query);
|
|
563
568
|
if (tokens.length === 0) {
|
|
564
569
|
return [];
|
|
@@ -567,6 +572,9 @@ const searchViaScan = (sql$1, tableName, search, limit) => {
|
|
|
567
572
|
for (const filter of search.filters) {
|
|
568
573
|
whereClauses.push(sql`${jsonPathSql(filter.field)} = ${serializeSqlValue(filter.value)}`);
|
|
569
574
|
}
|
|
575
|
+
if (scopeCondition) {
|
|
576
|
+
whereClauses.push(scopeCondition);
|
|
577
|
+
}
|
|
570
578
|
let query = sql`SELECT id, _creationTime, ${sql.identifier(DOC_COLUMN$1)} FROM ${sql.identifier(tableName)}`;
|
|
571
579
|
if (whereClauses.length > 0) {
|
|
572
580
|
query = sql`${query} WHERE ${sql.join(whereClauses, sql` AND `)}`;
|
|
@@ -660,11 +668,12 @@ const scanDocs = (rows, filters, cap) => {
|
|
|
660
668
|
}
|
|
661
669
|
return docs;
|
|
662
670
|
};
|
|
663
|
-
const paginateStage = (sql$1, tableName, stage, options) => {
|
|
671
|
+
const paginateStage = (sql$1, tableName, stage, options, scopeCondition) => {
|
|
664
672
|
const numberItems = Math.max(0, Math.floor(options.numItems));
|
|
665
673
|
const orderKeys = paginateOrderKeys(stage);
|
|
666
674
|
const bounded = typeof options.endCursor === "string";
|
|
667
|
-
const
|
|
675
|
+
const pageWhere = compileWhereSql(paginateWhere(stage, orderKeys, options.cursor, options.endCursor), doWhereSqlStrategy);
|
|
676
|
+
const whereCondition = scopeCondition && pageWhere ? sql`${pageWhere} AND ${scopeCondition}` : scopeCondition ?? pageWhere;
|
|
668
677
|
let query = sql`SELECT id, _creationTime, ${sql.identifier(DOC_COLUMN$1)} FROM ${sql.identifier(tableName)}`;
|
|
669
678
|
if (whereCondition) {
|
|
670
679
|
query = sql`${query} WHERE ${whereCondition}`;
|
|
@@ -721,6 +730,8 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
721
730
|
if (!tableDefinition) {
|
|
722
731
|
throw new Error(`unknown table: ${tableName}`);
|
|
723
732
|
}
|
|
733
|
+
const scopeWhere = softDeleteScope(tableDefinition.softDeleteMode, void 0);
|
|
734
|
+
const scopeCondition = scopeWhere ? compileWhereSql(scopeWhere, doWhereSqlStrategy) : void 0;
|
|
724
735
|
const stage = {
|
|
725
736
|
indexFields: [],
|
|
726
737
|
indexName: void 0,
|
|
@@ -735,7 +746,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
735
746
|
}
|
|
736
747
|
const filtered = stage.inMemoryFilters.length > 0;
|
|
737
748
|
const engineLimit = filtered ? void 0 : limit;
|
|
738
|
-
const docs = isFtsAvailable(sql$1) ? searchViaFts(sql$1, tableName, search, engineLimit) : searchViaScan(sql$1, tableName, search, engineLimit);
|
|
749
|
+
const docs = isFtsAvailable(sql$1) ? searchViaFts(sql$1, tableName, search, engineLimit, scopeCondition) : searchViaScan(sql$1, tableName, search, engineLimit, scopeCondition);
|
|
739
750
|
if (!filtered) {
|
|
740
751
|
return docs;
|
|
741
752
|
}
|
|
@@ -766,6 +777,9 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
766
777
|
for (const condition of stage.sqlConditions) {
|
|
767
778
|
whereClauses.push(sql`${jsonPathSql(condition.field)} ${sql.raw(condition.comparator)} ${serializeSqlValue(condition.value)}`);
|
|
768
779
|
}
|
|
780
|
+
if (scopeCondition) {
|
|
781
|
+
whereClauses.push(scopeCondition);
|
|
782
|
+
}
|
|
769
783
|
let query = sql`SELECT id, _creationTime, ${sql.identifier(DOC_COLUMN$1)} FROM ${sql.identifier(tableName)}`;
|
|
770
784
|
if (whereClauses.length > 0) {
|
|
771
785
|
query = sql`${query} WHERE ${sql.join(whereClauses, sql` AND `)}`;
|
|
@@ -813,7 +827,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
813
827
|
if (stage.search) {
|
|
814
828
|
throw new Error("pagination is not supported on search queries; use .take(n) or .collect()");
|
|
815
829
|
}
|
|
816
|
-
return paginateStage(sql$1, tableName, stage, options);
|
|
830
|
+
return paginateStage(sql$1, tableName, stage, options, scopeCondition);
|
|
817
831
|
},
|
|
818
832
|
// eslint-disable-next-line @typescript-eslint/require-await -- TableReaderLike returns Promises (the D1 twin awaits real I/O); the DO impl is synchronous over local SQLite
|
|
819
833
|
async take(limit) {
|
|
@@ -997,7 +1011,6 @@ const createShardCtxDb = (options) => {
|
|
|
997
1011
|
};
|
|
998
1012
|
const globalFallback = () => globalDb;
|
|
999
1013
|
const relationFetcher = (relationTable, relationArgs) => routeBackend(relationTable, "relation load").findMany(relationTable, relationArgs);
|
|
1000
|
-
const relationCounter = (relationTable, relationWhere) => routeBackend(relationTable, "relation load").count(relationTable, relationWhere);
|
|
1001
1014
|
const relationPredicateFetcher = (relationTable, relationArgs) => {
|
|
1002
1015
|
if (isGlobalTable(relationTable)) {
|
|
1003
1016
|
onRead(relationTable, SCAN_DEP);
|
|
@@ -1015,6 +1028,31 @@ const createShardCtxDb = (options) => {
|
|
|
1015
1028
|
schema,
|
|
1016
1029
|
tableName: predicateTable
|
|
1017
1030
|
});
|
|
1031
|
+
const relationGroupedCounter = async (relationTable, whereField, values, policyWhere) => {
|
|
1032
|
+
const globalWriter = globalWriterFor(relationTable, "relation grouped count");
|
|
1033
|
+
if (globalWriter) {
|
|
1034
|
+
onRead(relationTable, SCAN_DEP);
|
|
1035
|
+
return fanOutScalarCounts((t, w) => globalWriter.count(t, w), relationTable, whereField, values, policyWhere);
|
|
1036
|
+
}
|
|
1037
|
+
const definition = schema.tables[relationTable];
|
|
1038
|
+
if (!definition) {
|
|
1039
|
+
throw new Error(`unknown table: ${relationTable}`);
|
|
1040
|
+
}
|
|
1041
|
+
onRead(relationTable, SCAN_DEP);
|
|
1042
|
+
const softScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
1043
|
+
const inFilter = { [whereField]: { in: values } };
|
|
1044
|
+
const combined = mergeWhere(mergeWhere(inFilter, policyWhere), softScope);
|
|
1045
|
+
const resolvedCombined = await resolveAggregateRelations(combined, relationTable, void 0);
|
|
1046
|
+
const whereCondition = compileWhereSql(resolvedCombined, doWhereSqlStrategy);
|
|
1047
|
+
const fieldSql = jsonPathSql(whereField);
|
|
1048
|
+
let query = sql`SELECT ${fieldSql} AS __fk__, COUNT(*) AS count FROM ${sql.identifier(relationTable)}`;
|
|
1049
|
+
if (whereCondition) {
|
|
1050
|
+
query = sql`${query} WHERE ${whereCondition}`;
|
|
1051
|
+
}
|
|
1052
|
+
query = sql`${query} GROUP BY ${fieldSql}`;
|
|
1053
|
+
const rows = runDrizzle(sql$1, query).toArray();
|
|
1054
|
+
return new Map(rows.map((row) => [row["__fk__"], row.count]));
|
|
1055
|
+
};
|
|
1018
1056
|
let triggerDepth = 0;
|
|
1019
1057
|
const triggerMatchers = /* @__PURE__ */ new Set();
|
|
1020
1058
|
for (const [tableName, definition] of Object.entries(schema.tables)) {
|
|
@@ -1130,10 +1168,11 @@ const createShardCtxDb = (options) => {
|
|
|
1130
1168
|
throw new Error(`aggregate(${tableName}, { op: "${aggOptions.op}" }): "field" is required for non-count reducers`);
|
|
1131
1169
|
}
|
|
1132
1170
|
onRead(tableName, SCAN_DEP);
|
|
1133
|
-
const
|
|
1171
|
+
const aggScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
1172
|
+
const effective = mergeWhere(mergeWhere(aggOptions.baseWhere, aggOptions.where), aggScope);
|
|
1134
1173
|
const resolved = await resolveAggregateRelations(effective, tableName, aggOptions.relationBaseWhere);
|
|
1135
1174
|
const hasRelation = resolved !== effective;
|
|
1136
|
-
if (definition.aggregateIndexes && !aggOptions.baseWhere && !hasRelation) {
|
|
1175
|
+
if (definition.aggregateIndexes && !aggOptions.baseWhere && !hasRelation && !aggScope) {
|
|
1137
1176
|
const planned = selectIndexForAggregate(definition.aggregateIndexes, aggOptions.op, aggOptions.field, aggOptions.where);
|
|
1138
1177
|
if (planned) {
|
|
1139
1178
|
ensureBackfilled(tableName, planned.index);
|
|
@@ -1175,10 +1214,11 @@ const createShardCtxDb = (options) => {
|
|
|
1175
1214
|
throw new CountRlsUnsupportedError(tableName);
|
|
1176
1215
|
}
|
|
1177
1216
|
onRead(tableName, SCAN_DEP);
|
|
1178
|
-
const
|
|
1217
|
+
const countScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
1218
|
+
const effective = mergeWhere(mergeWhere(countOptions.baseWhere, countOptions.where), countScope);
|
|
1179
1219
|
const resolved = await resolveAggregateRelations(effective, tableName, countOptions.relationBaseWhere);
|
|
1180
1220
|
const hasRelation = resolved !== effective;
|
|
1181
|
-
if (definition.aggregateIndexes && !countOptions.baseWhere && !hasRelation) {
|
|
1221
|
+
if (definition.aggregateIndexes && !countOptions.baseWhere && !hasRelation && !countScope) {
|
|
1182
1222
|
const planned = selectIndexForCount(definition.aggregateIndexes, countOptions.where);
|
|
1183
1223
|
if (planned) {
|
|
1184
1224
|
ensureBackfilled(tableName, planned.index);
|
|
@@ -1199,16 +1239,22 @@ const createShardCtxDb = (options) => {
|
|
|
1199
1239
|
const row = runDrizzle(sql$1, query).one();
|
|
1200
1240
|
return row.count;
|
|
1201
1241
|
},
|
|
1202
|
-
async delete(id, expectedTable) {
|
|
1242
|
+
async delete(id, expectedTable, deleteOptions) {
|
|
1203
1243
|
const located = locateRowById(id, expectedTable);
|
|
1204
1244
|
if (!located) {
|
|
1205
1245
|
const global = expectedTable === void 0 ? globalFallback() : void 0;
|
|
1206
1246
|
if (global) {
|
|
1207
|
-
await global.delete(id);
|
|
1247
|
+
await global.delete(id, void 0, deleteOptions);
|
|
1208
1248
|
}
|
|
1209
1249
|
return;
|
|
1210
1250
|
}
|
|
1211
1251
|
const { docJson: existingJson, row: existing, tableName } = located;
|
|
1252
|
+
const definition = schema.tables[tableName];
|
|
1253
|
+
const hard = deleteOptions?.hard === true;
|
|
1254
|
+
const softField = !hard && definition?.softDeleteMode ? definition.softDeleteMode.field : void 0;
|
|
1255
|
+
if (softField && existing[softField] !== null && existing[softField] !== void 0) {
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1212
1258
|
if (hasMatchingTrigger(tableName, "before", "delete")) {
|
|
1213
1259
|
await fireTriggers("before", "delete", { id, op: "delete", previous: existing, table: tableName });
|
|
1214
1260
|
}
|
|
@@ -1216,10 +1262,10 @@ const createShardCtxDb = (options) => {
|
|
|
1216
1262
|
deletedId: id,
|
|
1217
1263
|
deletedReference: (references) => existing[references],
|
|
1218
1264
|
findHolders: async (holderTable, field, value) => {
|
|
1219
|
-
const holders = await routeForHolder(holderTable).findMany(holderTable, { where: { [field]: value } });
|
|
1265
|
+
const holders = await routeForHolder(holderTable).findMany(holderTable, { includeDeleted: hard, where: { [field]: value } });
|
|
1220
1266
|
return holders.page;
|
|
1221
1267
|
},
|
|
1222
|
-
onCascade: (holderTable, holderId) => routeForHolder(holderTable).delete(holderId),
|
|
1268
|
+
onCascade: (holderTable, holderId) => routeForHolder(holderTable).delete(holderId, void 0, deleteOptions),
|
|
1223
1269
|
onRestrict: (message) => {
|
|
1224
1270
|
throw new ConflictError(message, "restrict");
|
|
1225
1271
|
},
|
|
@@ -1230,6 +1276,25 @@ const createShardCtxDb = (options) => {
|
|
|
1230
1276
|
});
|
|
1231
1277
|
ensureBackfilledForTable(tableName);
|
|
1232
1278
|
ensureRankBackfilledForTable(tableName);
|
|
1279
|
+
if (softField) {
|
|
1280
|
+
const merged = { ...existing, [softField]: clock(), _id: id };
|
|
1281
|
+
runGuardedWrite(
|
|
1282
|
+
sql$1,
|
|
1283
|
+
tableName,
|
|
1284
|
+
sql`UPDATE ${sql.identifier(tableName)} SET ${sql.identifier(DOC_COLUMN$1)} = ${JSON.stringify(merged)} WHERE id = ${id} AND ${sql.identifier(DOC_COLUMN$1)} = ${existingJson}`
|
|
1285
|
+
);
|
|
1286
|
+
syncSearch(tableName, id, merged);
|
|
1287
|
+
syncAggregates(tableName, existing, merged);
|
|
1288
|
+
syncRanks(tableName, id, existing, void 0);
|
|
1289
|
+
cache?.invalidate(tableName, id);
|
|
1290
|
+
recordCdc(tableName, id, "update", merged);
|
|
1291
|
+
broadcast({ key: id, op: "update", row: merged, table: tableName });
|
|
1292
|
+
if (hasMatchingTrigger(tableName, "after", "delete")) {
|
|
1293
|
+
await fireTriggers("after", "delete", { id, op: "delete", previous: existing, table: tableName });
|
|
1294
|
+
}
|
|
1295
|
+
await onWrite({ id, op: "delete", table: tableName });
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1233
1298
|
runGuardedWrite(
|
|
1234
1299
|
sql$1,
|
|
1235
1300
|
tableName,
|
|
@@ -1271,7 +1336,8 @@ const createShardCtxDb = (options) => {
|
|
|
1271
1336
|
onRead(tableName, SCAN_DEP);
|
|
1272
1337
|
return global.findMany(tableName, args);
|
|
1273
1338
|
}
|
|
1274
|
-
|
|
1339
|
+
const findManyDefinition = schema.tables[tableName];
|
|
1340
|
+
if (!findManyDefinition) {
|
|
1275
1341
|
throw new Error(`unknown table: ${tableName}`);
|
|
1276
1342
|
}
|
|
1277
1343
|
const isFullScan = !args.where && !args.baseWhere;
|
|
@@ -1283,6 +1349,7 @@ const createShardCtxDb = (options) => {
|
|
|
1283
1349
|
const orderKeys = normalizeOrderKeys(args.orderBy);
|
|
1284
1350
|
const seek = args.cursor ? buildSeekWhere(orderKeys, decodeCursor(args.cursor)) : void 0;
|
|
1285
1351
|
let predicate = mergeWhere(args.baseWhere, args.where);
|
|
1352
|
+
predicate = mergeWhere(predicate, softDeleteScope(findManyDefinition.softDeleteMode, args.includeDeleted));
|
|
1286
1353
|
predicate = await resolveRelationPredicates(predicate, {
|
|
1287
1354
|
canPushExists: relationExistsPushDownEnabled ? canPushRelationExists : void 0,
|
|
1288
1355
|
existsPushMode: relationExistsPushDown === "always" ? "always" : "auto",
|
|
@@ -1320,7 +1387,7 @@ const createShardCtxDb = (options) => {
|
|
|
1320
1387
|
if (limit === void 0) {
|
|
1321
1388
|
if (args.with) {
|
|
1322
1389
|
await resolveWith({
|
|
1323
|
-
|
|
1390
|
+
groupedCounter: relationGroupedCounter,
|
|
1324
1391
|
fetcher: relationFetcher,
|
|
1325
1392
|
parents: docs,
|
|
1326
1393
|
relationBaseWhere: args.relationBaseWhere,
|
|
@@ -1329,15 +1396,15 @@ const createShardCtxDb = (options) => {
|
|
|
1329
1396
|
with: args.with
|
|
1330
1397
|
});
|
|
1331
1398
|
}
|
|
1332
|
-
return { continueCursor: null, isDone: true, page: docs };
|
|
1399
|
+
return { continueCursor: null, isDone: true, page: applySelect(docs, args.select, args.with) };
|
|
1333
1400
|
}
|
|
1334
1401
|
const hasMore = docs.length > limit;
|
|
1335
1402
|
const page = hasMore ? docs.slice(0, limit) : docs;
|
|
1336
1403
|
const last = page.at(-1);
|
|
1337
1404
|
if (args.with) {
|
|
1338
1405
|
await resolveWith({
|
|
1339
|
-
counter: relationCounter,
|
|
1340
1406
|
fetcher: relationFetcher,
|
|
1407
|
+
groupedCounter: relationGroupedCounter,
|
|
1341
1408
|
parents: page,
|
|
1342
1409
|
relationBaseWhere: args.relationBaseWhere,
|
|
1343
1410
|
schema,
|
|
@@ -1346,10 +1413,12 @@ const createShardCtxDb = (options) => {
|
|
|
1346
1413
|
});
|
|
1347
1414
|
}
|
|
1348
1415
|
return {
|
|
1416
|
+
// The cursor is encoded from `last` (the full, unprojected row) above,
|
|
1417
|
+
// so `applySelect` only trims the returned payload — paging is intact.
|
|
1349
1418
|
// eslint-disable-next-line unicorn/no-null -- QueryPage.continueCursor is `null | string`: null is the documented "no further page" cursor on the wire
|
|
1350
1419
|
continueCursor: hasMore && last ? encodeCursor(last, orderKeys) : null,
|
|
1351
1420
|
isDone: !hasMore,
|
|
1352
|
-
page
|
|
1421
|
+
page: applySelect(page, args.select, args.with)
|
|
1353
1422
|
};
|
|
1354
1423
|
},
|
|
1355
1424
|
async get(id, expectedTable) {
|
|
@@ -1390,10 +1459,11 @@ const createShardCtxDb = (options) => {
|
|
|
1390
1459
|
if (agg.op !== "count" && !agg.field) {
|
|
1391
1460
|
throw new Error(`groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
|
|
1392
1461
|
}
|
|
1393
|
-
const
|
|
1462
|
+
const groupScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
1463
|
+
const effective = mergeWhere(mergeWhere(groupOptions.baseWhere, groupOptions.where), groupScope);
|
|
1394
1464
|
const resolved = await resolveAggregateRelations(effective, tableName, groupOptions.relationBaseWhere);
|
|
1395
1465
|
const hasRelation = resolved !== effective;
|
|
1396
|
-
if (definition.aggregateIndexes && !groupOptions.baseWhere && !hasRelation) {
|
|
1466
|
+
if (definition.aggregateIndexes && !groupOptions.baseWhere && !hasRelation && !groupScope) {
|
|
1397
1467
|
const planned = selectIndexForGroupBy(definition.aggregateIndexes, agg.op, agg.field, groupOptions.by, groupOptions.where);
|
|
1398
1468
|
if (planned) {
|
|
1399
1469
|
ensureBackfilled(tableName, planned.index);
|
|
@@ -1696,6 +1766,26 @@ const createShardCtxDb = (options) => {
|
|
|
1696
1766
|
const { directions, hasMore, rows } = computeRankPage(rankPageDeps, tableName, indexName, rankPageOptions);
|
|
1697
1767
|
return { directions, hasMore, rows };
|
|
1698
1768
|
},
|
|
1769
|
+
async restore(id, expectedTable) {
|
|
1770
|
+
const located = locateRowById(id, expectedTable);
|
|
1771
|
+
if (!located) {
|
|
1772
|
+
const global = expectedTable === void 0 ? globalFallback() : void 0;
|
|
1773
|
+
if (global?.restore) {
|
|
1774
|
+
await global.restore(id);
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
throw new Error(`document not found: ${id}`);
|
|
1778
|
+
}
|
|
1779
|
+
const field = schema.tables[located.tableName]?.softDeleteMode?.field;
|
|
1780
|
+
if (!field) {
|
|
1781
|
+
throw new Error(`ctx.db.restore: table "${located.tableName}" is not a .softDelete() table`);
|
|
1782
|
+
}
|
|
1783
|
+
const wasDeleted = located.row[field] !== null && located.row[field] !== void 0;
|
|
1784
|
+
await writer.patch(id, { [field]: null }, expectedTable);
|
|
1785
|
+
if (wasDeleted) {
|
|
1786
|
+
syncRanks(located.tableName, id, void 0, located.row);
|
|
1787
|
+
}
|
|
1788
|
+
},
|
|
1699
1789
|
async replace(id, document, expectedTable) {
|
|
1700
1790
|
const located = locateRowById(id, expectedTable);
|
|
1701
1791
|
if (!located) {
|
|
@@ -1742,4 +1832,4 @@ const createShardCtxDb = (options) => {
|
|
|
1742
1832
|
return options.enforceRls === true ? guardWriter(writer, schema, (id, expectedTable) => locateRowById(id, expectedTable)?.tableName) : writer;
|
|
1743
1833
|
};
|
|
1744
1834
|
|
|
1745
|
-
export { NotUniqueError,
|
|
1835
|
+
export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally };
|
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
if (typeof value === "boolean") {
|
|
3
|
-
return value ? 1 : 0;
|
|
4
|
-
}
|
|
5
|
-
if (value === null || typeof value === "string" || typeof value === "number") {
|
|
6
|
-
return value;
|
|
7
|
-
}
|
|
8
|
-
if (typeof value === "bigint") {
|
|
9
|
-
return value.toString();
|
|
10
|
-
}
|
|
11
|
-
return JSON.stringify(value);
|
|
12
|
-
};
|
|
1
|
+
import { s as serializeSqlValue } from './serialize-sql-BlRUoiQe.mjs';
|
|
13
2
|
|
|
14
3
|
const compareStrings = (a, b) => {
|
|
15
4
|
if (a < b) {
|
|
@@ -99,4 +88,4 @@ const rankKeyFromDocument = (index, document_) => {
|
|
|
99
88
|
};
|
|
100
89
|
};
|
|
101
90
|
|
|
102
|
-
export { RANK_TIEBREAK
|
|
91
|
+
export { RANK_TIEBREAK, encodePartitionKey, matchesRankStaticWhere, rankKeyFromDocument as rankKeyFromDoc, rankTableName, resolveRankPartition, sortColumnName };
|