@lunora/sql-store 1.0.0-alpha.21 → 1.0.0-alpha.23
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/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createSqlCtxDb, decodeGlobalRow, readSqlCdcChanges, runSqlAggregateMigrations, runSqlCdcMigration, runSqlGlobalTableMigrations, runSqlRankMigrations, runSqlSearchMigrations, trimSqlCdcChanges } from './packem_shared/createSqlCtxDb-
|
|
1
|
+
export { createSqlCtxDb, decodeGlobalRow, readSqlCdcChanges, runSqlAggregateMigrations, runSqlCdcMigration, runSqlGlobalTableMigrations, runSqlRankMigrations, runSqlSearchMigrations, trimSqlCdcChanges } from './packem_shared/createSqlCtxDb-CuoIlIqO.mjs';
|
|
2
2
|
export { decodeBigint, effectiveColumnKind, sqliteDecode, sqliteEncode, tryJsonParse } from './packem_shared/decodeBigint-Dedu92k4.mjs';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { aggregateTableName, rankTableName, ftsTableName, hasTrigger, runRowValidators, assertFlatPredicate, mergeWhere, sortColumnName, resolveRankPartition, encodePartitionKey, decodeCursor, RANK_TIEBREAK, CountRlsUnsupportedError, normalizeIdStructurally, assertValidClientId, aggregateSqlFunction, softDeleteScope, compileWhereSql, normalizeOrderKeys, buildSeekWhere, resolveRelationPredicates, resolveWith, applySelect, encodeCursor, NotFoundError, applyOnDelete, ConflictError, normalizeCountArgument, selectIndexForCount, encodeAggregateKey, selectIndexForAggregate, readAggregateValue, renderSql, runTriggers, matchesRankStaticWhere, stringifySearchText, selectIndexForGroupBy, fanOutScalarCounts, matchesStaticWhere, coerceAggregateNumber, foldAggregateTally, NotUniqueError, throwingScheduler, tokenizeSearch, buildFtsMatch, scoreDocument } from '@lunora/do';
|
|
2
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
3
|
import { sql } from 'drizzle-orm';
|
|
3
4
|
import { sqliteDecode, sqliteEncode, effectiveColumnKind } from './decodeBigint-Dedu92k4.mjs';
|
|
4
5
|
|
|
@@ -260,14 +261,17 @@ const createSearchBuilder = (search, tableName) => {
|
|
|
260
261
|
const builder = {
|
|
261
262
|
eq: (field, value) => {
|
|
262
263
|
if (!search.definition.filterFields?.includes(field)) {
|
|
263
|
-
throw new
|
|
264
|
+
throw new LunoraError("INTERNAL", `field "${field}" is not a filter field of search index "${search.indexName}" on table "${tableName}"`);
|
|
264
265
|
}
|
|
265
266
|
search.filters.push({ field, value });
|
|
266
267
|
return builder;
|
|
267
268
|
},
|
|
268
269
|
search: (field, query) => {
|
|
269
270
|
if (field !== search.definition.field) {
|
|
270
|
-
throw new
|
|
271
|
+
throw new LunoraError(
|
|
272
|
+
"INTERNAL",
|
|
273
|
+
`search index "${search.indexName}" on table "${tableName}" indexes "${search.definition.field}", not "${field}"`
|
|
274
|
+
);
|
|
271
275
|
}
|
|
272
276
|
const stage = search;
|
|
273
277
|
stage.field = field;
|
|
@@ -315,7 +319,7 @@ const buildRankCursorSeek = (engine, columns, decoded) => {
|
|
|
315
319
|
};
|
|
316
320
|
const rankPageColumns = (index, sortColumns) => {
|
|
317
321
|
if (index.sortBy.length === 0) {
|
|
318
|
-
throw new
|
|
322
|
+
throw new LunoraError("INTERNAL", `rankIndex "${index.name}" requires at least one "sortBy" column for stable pagination`);
|
|
319
323
|
}
|
|
320
324
|
const columns = [{ column: "__partition__", direction: "asc" }];
|
|
321
325
|
for (const [i, sortKey] of index.sortBy.entries()) {
|
|
@@ -1105,7 +1109,8 @@ const createSqlCtxDb = (options) => {
|
|
|
1105
1109
|
return kind === "shardBy" || kind === "root";
|
|
1106
1110
|
};
|
|
1107
1111
|
const crossBackendUnsupported = (childTable) => {
|
|
1108
|
-
throw new
|
|
1112
|
+
throw new LunoraError(
|
|
1113
|
+
"INTERNAL",
|
|
1109
1114
|
`cross-backend relation: a global table cannot load the shard-local relation '${childTable}' (it spans every shard) — wire a cross-shard reader to support it`
|
|
1110
1115
|
);
|
|
1111
1116
|
};
|
|
@@ -1127,7 +1132,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1127
1132
|
async aggregate(tableName, aggOptions) {
|
|
1128
1133
|
const definition = schema.tables[tableName];
|
|
1129
1134
|
if (!definition) {
|
|
1130
|
-
throw new
|
|
1135
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1131
1136
|
}
|
|
1132
1137
|
await ensureMigrated();
|
|
1133
1138
|
aggregateSqlFunction(aggOptions.op);
|
|
@@ -1140,7 +1145,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1140
1145
|
});
|
|
1141
1146
|
}
|
|
1142
1147
|
if (!aggOptions.field) {
|
|
1143
|
-
throw new
|
|
1148
|
+
throw new LunoraError("INTERNAL", `aggregate(${tableName}, { op: "${aggOptions.op}" }): "field" is required for non-count reducers`);
|
|
1144
1149
|
}
|
|
1145
1150
|
const aggScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
1146
1151
|
const effective = mergeWhere(mergeWhere(aggOptions.baseWhere, aggOptions.where), aggScope);
|
|
@@ -1173,7 +1178,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1173
1178
|
async count(tableName, whereOrOptions) {
|
|
1174
1179
|
const definition = schema.tables[tableName];
|
|
1175
1180
|
if (!definition) {
|
|
1176
|
-
throw new
|
|
1181
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1177
1182
|
}
|
|
1178
1183
|
await ensureMigrated();
|
|
1179
1184
|
const countOptions = normalizeCountArgument(whereOrOptions);
|
|
@@ -1229,7 +1234,8 @@ const createSqlCtxDb = (options) => {
|
|
|
1229
1234
|
deletedReference: (references) => existing?.[references],
|
|
1230
1235
|
findHolders: async (holderTable, field, value) => {
|
|
1231
1236
|
if (schema.tables[holderTable]?.shardMode?.kind === "shardBy") {
|
|
1232
|
-
throw new
|
|
1237
|
+
throw new LunoraError(
|
|
1238
|
+
"INTERNAL",
|
|
1233
1239
|
`cross-backend cascade from global '${tableName}' into shardBy '${holderTable}' is not supported — would require Query Coordinator fan-out across shards`
|
|
1234
1240
|
);
|
|
1235
1241
|
}
|
|
@@ -1288,7 +1294,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1288
1294
|
async findMany(tableName, args = {}) {
|
|
1289
1295
|
const definition = schema.tables[tableName];
|
|
1290
1296
|
if (!definition) {
|
|
1291
|
-
throw new
|
|
1297
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1292
1298
|
}
|
|
1293
1299
|
await ensureMigrated();
|
|
1294
1300
|
const orderKeys = normalizeOrderKeys(args.orderBy);
|
|
@@ -1303,7 +1309,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1303
1309
|
}
|
|
1304
1310
|
const childDefinition = schema.tables[childTable];
|
|
1305
1311
|
if (!childDefinition) {
|
|
1306
|
-
throw new
|
|
1312
|
+
throw new LunoraError("INTERNAL", `unknown table: ${childTable}`);
|
|
1307
1313
|
}
|
|
1308
1314
|
const softScope = softDeleteScope(childDefinition.softDeleteMode, void 0);
|
|
1309
1315
|
const inFilter = { [whereField]: { in: values } };
|
|
@@ -1391,13 +1397,13 @@ const createSqlCtxDb = (options) => {
|
|
|
1391
1397
|
async groupBy(tableName, groupOptions) {
|
|
1392
1398
|
const definition = schema.tables[tableName];
|
|
1393
1399
|
if (!definition) {
|
|
1394
|
-
throw new
|
|
1400
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1395
1401
|
}
|
|
1396
1402
|
await ensureMigrated();
|
|
1397
1403
|
const agg = groupOptions.agg ?? { op: "count" };
|
|
1398
1404
|
aggregateSqlFunction(agg.op);
|
|
1399
1405
|
if (agg.op !== "count" && !agg.field) {
|
|
1400
|
-
throw new
|
|
1406
|
+
throw new LunoraError("INTERNAL", `groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
|
|
1401
1407
|
}
|
|
1402
1408
|
const groupScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
1403
1409
|
const effective = mergeWhere(mergeWhere(groupOptions.baseWhere, groupOptions.where), groupScope);
|
|
@@ -1415,7 +1421,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1415
1421
|
select.push(sql`COUNT(*) AS value`);
|
|
1416
1422
|
} else {
|
|
1417
1423
|
if (!agg.field) {
|
|
1418
|
-
throw new
|
|
1424
|
+
throw new LunoraError("INTERNAL", `groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
|
|
1419
1425
|
}
|
|
1420
1426
|
select.push(sql`${sql.raw(aggregateSqlFunction(agg.op))}(${columnRefSql(agg.field)}) AS value`);
|
|
1421
1427
|
}
|
|
@@ -1445,7 +1451,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1445
1451
|
async insert(tableName, document, insertOptions) {
|
|
1446
1452
|
const definition = schema.tables[tableName];
|
|
1447
1453
|
if (!definition) {
|
|
1448
|
-
throw new
|
|
1454
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1449
1455
|
}
|
|
1450
1456
|
await ensureMigrated();
|
|
1451
1457
|
const withDefaults = applyInsertDefaults(definition, document, auth);
|
|
@@ -1496,16 +1502,16 @@ const createSqlCtxDb = (options) => {
|
|
|
1496
1502
|
async patch(id, patch, expectedTable) {
|
|
1497
1503
|
const tableName = await resolveTableName(id, expectedTable);
|
|
1498
1504
|
if (!tableName) {
|
|
1499
|
-
throw new
|
|
1505
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1500
1506
|
}
|
|
1501
1507
|
const definition = schema.tables[tableName];
|
|
1502
1508
|
if (!definition) {
|
|
1503
|
-
throw new
|
|
1509
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1504
1510
|
}
|
|
1505
1511
|
const snapshot = await rawRow(tableName, id);
|
|
1506
1512
|
const existing = decodeRow(definition, snapshot);
|
|
1507
1513
|
if (!existing) {
|
|
1508
|
-
throw new
|
|
1514
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1509
1515
|
}
|
|
1510
1516
|
const merged = { ...existing, ...patch, _id: id };
|
|
1511
1517
|
applyOnUpdate(definition, patch, merged, auth);
|
|
@@ -1533,12 +1539,12 @@ const createSqlCtxDb = (options) => {
|
|
|
1533
1539
|
async restore(id, expectedTable) {
|
|
1534
1540
|
const tableName = await resolveTableName(id, expectedTable);
|
|
1535
1541
|
if (!tableName) {
|
|
1536
|
-
throw new
|
|
1542
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1537
1543
|
}
|
|
1538
1544
|
const definition = schema.tables[tableName];
|
|
1539
1545
|
const field = definition?.softDeleteMode?.field;
|
|
1540
1546
|
if (!definition || !field) {
|
|
1541
|
-
throw new
|
|
1547
|
+
throw new LunoraError("INTERNAL", `ctx.db.restore: table "${tableName}" is not a .softDelete() table`);
|
|
1542
1548
|
}
|
|
1543
1549
|
const snapshot = await rawRow(tableName, id);
|
|
1544
1550
|
const wasDeleted = snapshot?.[field] !== null && snapshot?.[field] !== void 0;
|
|
@@ -1553,7 +1559,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1553
1559
|
query(tableName) {
|
|
1554
1560
|
const definition = schema.tables[tableName];
|
|
1555
1561
|
if (!definition) {
|
|
1556
|
-
throw new
|
|
1562
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1557
1563
|
}
|
|
1558
1564
|
const LEGACY_READER_ERROR = "the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany";
|
|
1559
1565
|
const runSearch = async (stage, limit) => {
|
|
@@ -1564,16 +1570,16 @@ const createSqlCtxDb = (options) => {
|
|
|
1564
1570
|
const reader = {
|
|
1565
1571
|
async collect() {
|
|
1566
1572
|
if (!stage) {
|
|
1567
|
-
throw new
|
|
1573
|
+
throw new LunoraError("INTERNAL", LEGACY_READER_ERROR);
|
|
1568
1574
|
}
|
|
1569
1575
|
return runSearch(stage, void 0);
|
|
1570
1576
|
},
|
|
1571
1577
|
filter() {
|
|
1572
|
-
throw new
|
|
1578
|
+
throw new LunoraError("INTERNAL", LEGACY_READER_ERROR);
|
|
1573
1579
|
},
|
|
1574
1580
|
async first() {
|
|
1575
1581
|
if (!stage) {
|
|
1576
|
-
throw new
|
|
1582
|
+
throw new LunoraError("INTERNAL", LEGACY_READER_ERROR);
|
|
1577
1583
|
}
|
|
1578
1584
|
const rows = await runSearch(stage, 1);
|
|
1579
1585
|
return rows[0] ?? null;
|
|
@@ -1584,19 +1590,19 @@ const createSqlCtxDb = (options) => {
|
|
|
1584
1590
|
// eslint-disable-next-line @typescript-eslint/require-await -- TableReaderLike.paginate returns a Promise; search queries don't support pagination on either backend
|
|
1585
1591
|
async paginate() {
|
|
1586
1592
|
if (stage) {
|
|
1587
|
-
throw new
|
|
1593
|
+
throw new LunoraError("INTERNAL", "pagination is not supported on search queries; use .take(n) or .collect()");
|
|
1588
1594
|
}
|
|
1589
|
-
throw new
|
|
1595
|
+
throw new LunoraError("INTERNAL", LEGACY_READER_ERROR);
|
|
1590
1596
|
},
|
|
1591
1597
|
async take(limit) {
|
|
1592
1598
|
if (!stage) {
|
|
1593
|
-
throw new
|
|
1599
|
+
throw new LunoraError("INTERNAL", LEGACY_READER_ERROR);
|
|
1594
1600
|
}
|
|
1595
1601
|
return runSearch(stage, limit);
|
|
1596
1602
|
},
|
|
1597
1603
|
async unique() {
|
|
1598
1604
|
if (!stage) {
|
|
1599
|
-
throw new
|
|
1605
|
+
throw new LunoraError("INTERNAL", LEGACY_READER_ERROR);
|
|
1600
1606
|
}
|
|
1601
1607
|
const rows = await runSearch(stage, 2);
|
|
1602
1608
|
if (rows.length > 1) {
|
|
@@ -1605,12 +1611,12 @@ const createSqlCtxDb = (options) => {
|
|
|
1605
1611
|
return rows[0] ?? null;
|
|
1606
1612
|
},
|
|
1607
1613
|
withIndex() {
|
|
1608
|
-
throw new
|
|
1614
|
+
throw new LunoraError("INTERNAL", LEGACY_READER_ERROR);
|
|
1609
1615
|
},
|
|
1610
1616
|
withSearchIndex(indexName, search) {
|
|
1611
1617
|
const searchDefinition = (definition.searchIndexes ?? []).find((index) => index.name === indexName);
|
|
1612
1618
|
if (!searchDefinition) {
|
|
1613
|
-
throw new
|
|
1619
|
+
throw new LunoraError("INTERNAL", `unknown search index "${indexName}" on table "${tableName}"`);
|
|
1614
1620
|
}
|
|
1615
1621
|
const searchStage = {
|
|
1616
1622
|
definition: searchDefinition,
|
|
@@ -1622,7 +1628,7 @@ const createSqlCtxDb = (options) => {
|
|
|
1622
1628
|
};
|
|
1623
1629
|
search(createSearchBuilder(searchStage, tableName));
|
|
1624
1630
|
if (!searchStage.hasQuery) {
|
|
1625
|
-
throw new
|
|
1631
|
+
throw new LunoraError("INTERNAL", `search index "${indexName}" on table "${tableName}" requires a .search(field, query) call`);
|
|
1626
1632
|
}
|
|
1627
1633
|
return buildReader(searchStage);
|
|
1628
1634
|
}
|
|
@@ -1634,11 +1640,11 @@ const createSqlCtxDb = (options) => {
|
|
|
1634
1640
|
async rank(tableName, indexName, rankOptions) {
|
|
1635
1641
|
const definition = schema.tables[tableName];
|
|
1636
1642
|
if (!definition) {
|
|
1637
|
-
throw new
|
|
1643
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1638
1644
|
}
|
|
1639
1645
|
const index = definition.rankIndexes?.find((i) => i.name === indexName);
|
|
1640
1646
|
if (!index) {
|
|
1641
|
-
throw new
|
|
1647
|
+
throw new LunoraError("INTERNAL", `unknown rankIndex "${indexName}" on table "${tableName}"`);
|
|
1642
1648
|
}
|
|
1643
1649
|
if (rankOptions.restrictsCounts) {
|
|
1644
1650
|
throw new CountRlsUnsupportedError(tableName);
|
|
@@ -1691,11 +1697,11 @@ const createSqlCtxDb = (options) => {
|
|
|
1691
1697
|
assertFlatPredicate(mergeWhere(rankPageOptions.baseWhere, rankPageOptions.where), schema, tableName, "rankPage");
|
|
1692
1698
|
const definition = schema.tables[tableName];
|
|
1693
1699
|
if (!definition) {
|
|
1694
|
-
throw new
|
|
1700
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1695
1701
|
}
|
|
1696
1702
|
const index = definition.rankIndexes?.find((i) => i.name === indexName);
|
|
1697
1703
|
if (!index) {
|
|
1698
|
-
throw new
|
|
1704
|
+
throw new LunoraError("INTERNAL", `unknown rankIndex "${indexName}" on table "${tableName}"`);
|
|
1699
1705
|
}
|
|
1700
1706
|
await ensureMigrated();
|
|
1701
1707
|
const counterReady = await ensureRankBackfilled(tableName, index);
|
|
@@ -1751,15 +1757,15 @@ const createSqlCtxDb = (options) => {
|
|
|
1751
1757
|
async replace(id, document, expectedTable) {
|
|
1752
1758
|
const tableName = await resolveTableName(id, expectedTable);
|
|
1753
1759
|
if (!tableName) {
|
|
1754
|
-
throw new
|
|
1760
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1755
1761
|
}
|
|
1756
1762
|
const definition = schema.tables[tableName];
|
|
1757
1763
|
if (!definition) {
|
|
1758
|
-
throw new
|
|
1764
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1759
1765
|
}
|
|
1760
1766
|
const snapshot = await rawRow(tableName, id);
|
|
1761
1767
|
if (snapshot === void 0) {
|
|
1762
|
-
throw new
|
|
1768
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1763
1769
|
}
|
|
1764
1770
|
const needsPrevious = hasTrigger(schema, tableName, "update") || (definition.aggregateIndexes ?? []).length > 0 || (definition.rankIndexes ?? []).length > 0;
|
|
1765
1771
|
const previous = needsPrevious ? decodeRow(definition, snapshot) ?? void 0 : void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/sql-store",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.23",
|
|
4
4
|
"description": "Internal dialect-parameterized SQL store core for Lunora .global() backends (D1, PlanetScale)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@lunora/do": "1.0.0-alpha.
|
|
53
|
+
"@lunora/do": "1.0.0-alpha.23",
|
|
54
|
+
"@lunora/errors": "1.0.0-alpha.1",
|
|
54
55
|
"drizzle-orm": "^0.45.2"
|
|
55
56
|
},
|
|
56
57
|
"engines": {
|