js-bao 0.5.1 → 0.5.2
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/README.md +124 -30
- package/dist/browser.cjs +586 -265
- package/dist/browser.d.cts +21 -0
- package/dist/browser.d.ts +21 -0
- package/dist/browser.js +588 -263
- package/dist/client.cjs +42 -6
- package/dist/client.d.cts +71 -0
- package/dist/client.d.ts +71 -0
- package/dist/client.js +39 -4
- package/dist/cloudflare-do.cjs +462 -215
- package/dist/cloudflare-do.d.cts +111 -1
- package/dist/cloudflare-do.d.ts +111 -1
- package/dist/cloudflare-do.js +459 -213
- package/dist/cloudflare.cjs +270 -23
- package/dist/cloudflare.d.cts +276 -1
- package/dist/cloudflare.d.ts +276 -1
- package/dist/cloudflare.js +267 -21
- package/dist/codegen-v2.cjs +77 -19
- package/dist/codegen.cjs +2 -1
- package/dist/index.cjs +551 -224
- package/dist/index.d.cts +57 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +549 -221
- package/dist/node.cjs +775 -291
- package/dist/node.d.cts +179 -1
- package/dist/node.d.ts +179 -1
- package/dist/node.js +762 -288
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -366,21 +366,36 @@ var init_CursorManager = __esm({
|
|
|
366
366
|
return fields;
|
|
367
367
|
}
|
|
368
368
|
/**
|
|
369
|
-
* Build ORDER BY clause from sort specification
|
|
369
|
+
* Build ORDER BY clause from sort specification.
|
|
370
|
+
*
|
|
371
|
+
* `direction` is the pagination direction (1 = forward, -1 = backward).
|
|
372
|
+
* For backward pagination each field's effective ORDER BY direction is
|
|
373
|
+
* reversed so the cursor's flipped inequality (built by
|
|
374
|
+
* `buildPaginationConditions`) returns the page adjacent to the cursor,
|
|
375
|
+
* not the globally smallest/largest window. Without this,
|
|
376
|
+
* `field < cursor ... ORDER BY field ASC LIMIT n` returns the n smallest
|
|
377
|
+
* rows overall instead of the n rows just below the cursor.
|
|
378
|
+
*
|
|
379
|
+
* The returned `directions` array carries the *declared* per-field sort
|
|
380
|
+
* directions (unaffected by `direction`) — `buildPaginationConditions`
|
|
381
|
+
* needs the declared directions to pick each field's comparison operator.
|
|
370
382
|
*/
|
|
371
|
-
static buildOrderClause(sort, fieldFormatter = (field) => field) {
|
|
383
|
+
static buildOrderClause(sort, fieldFormatter = (field) => field, direction = 1) {
|
|
372
384
|
const fields = this.extractSortFields(sort);
|
|
373
385
|
const clauses = [];
|
|
374
386
|
const directions = [];
|
|
387
|
+
const sqlDir = (declared) => {
|
|
388
|
+
const effective = direction === -1 ? declared === 1 ? -1 : 1 : declared;
|
|
389
|
+
return effective === 1 ? "ASC" : "DESC";
|
|
390
|
+
};
|
|
375
391
|
if (sort && Object.keys(sort).length > 0) {
|
|
376
392
|
for (const [field, dir] of Object.entries(sort)) {
|
|
377
|
-
|
|
378
|
-
clauses.push(`${fieldFormatter(field)} ${sqlDirection}`);
|
|
393
|
+
clauses.push(`${fieldFormatter(field)} ${sqlDir(dir)}`);
|
|
379
394
|
directions.push(dir);
|
|
380
395
|
}
|
|
381
396
|
}
|
|
382
397
|
if (!sort || !sort.hasOwnProperty("id")) {
|
|
383
|
-
clauses.push(`${fieldFormatter("id")}
|
|
398
|
+
clauses.push(`${fieldFormatter("id")} ${sqlDir(1)}`);
|
|
384
399
|
directions.push(1);
|
|
385
400
|
} else if (sort && sort.hasOwnProperty("id")) {
|
|
386
401
|
directions.push(sort["id"]);
|
|
@@ -403,18 +418,27 @@ var init_CursorManager = __esm({
|
|
|
403
418
|
/**
|
|
404
419
|
* Generate next and previous cursors from result set
|
|
405
420
|
*/
|
|
406
|
-
static generateResultCursors(results, sortFields,
|
|
421
|
+
static generateResultCursors(results, sortFields, requestedDirection, hasMore, isFirstPage = false) {
|
|
407
422
|
if (results.length === 0) {
|
|
408
423
|
return {};
|
|
409
424
|
}
|
|
410
425
|
const cursors = {};
|
|
411
426
|
if (hasMore && results.length > 0) {
|
|
412
427
|
const lastResult = results[results.length - 1];
|
|
413
|
-
cursors.nextCursor = this.generateCursor(
|
|
428
|
+
cursors.nextCursor = this.generateCursor(
|
|
429
|
+
lastResult,
|
|
430
|
+
sortFields,
|
|
431
|
+
requestedDirection
|
|
432
|
+
);
|
|
414
433
|
}
|
|
415
434
|
if (results.length > 0 && !isFirstPage) {
|
|
416
435
|
const firstResult = results[0];
|
|
417
|
-
|
|
436
|
+
const opposite = requestedDirection === 1 ? -1 : 1;
|
|
437
|
+
cursors.prevCursor = this.generateCursor(
|
|
438
|
+
firstResult,
|
|
439
|
+
sortFields,
|
|
440
|
+
opposite
|
|
441
|
+
);
|
|
418
442
|
}
|
|
419
443
|
return cursors;
|
|
420
444
|
}
|
|
@@ -547,7 +571,8 @@ var init_DocumentQueryTranslator = __esm({
|
|
|
547
571
|
const whereClause = this.translateFilter(filter);
|
|
548
572
|
const orderClause = CursorManager.buildOrderClause(
|
|
549
573
|
options?.sort,
|
|
550
|
-
(field) => this.getQuotedField(field)
|
|
574
|
+
(field) => this.getQuotedField(field),
|
|
575
|
+
options?.direction || 1
|
|
551
576
|
);
|
|
552
577
|
const limitClause = this.buildLimitClause(options);
|
|
553
578
|
const paginationClause = this.buildPaginationClause(
|
|
@@ -1220,6 +1245,69 @@ var init_yjsValues = __esm({
|
|
|
1220
1245
|
}
|
|
1221
1246
|
});
|
|
1222
1247
|
|
|
1248
|
+
// src/models/writeLifecycle.ts
|
|
1249
|
+
function ensureStringSetYMap(rm, fieldName) {
|
|
1250
|
+
const nested = rm.get(fieldName);
|
|
1251
|
+
if (nested instanceof Y2.Map) return nested;
|
|
1252
|
+
const fresh = new Y2.Map();
|
|
1253
|
+
if (nested && typeof nested === "object") {
|
|
1254
|
+
for (const [member, marker] of Object.entries(
|
|
1255
|
+
nested
|
|
1256
|
+
)) {
|
|
1257
|
+
if (Boolean(marker)) fresh.set(member, true);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
rm.set(fieldName, fresh);
|
|
1261
|
+
return fresh;
|
|
1262
|
+
}
|
|
1263
|
+
function applyStringSetDelta(target, delta) {
|
|
1264
|
+
if (delta.clear) {
|
|
1265
|
+
for (const member of Array.from(target.keys())) target.delete(member);
|
|
1266
|
+
}
|
|
1267
|
+
if (delta.remove) {
|
|
1268
|
+
for (const member of delta.remove) target.delete(String(member));
|
|
1269
|
+
}
|
|
1270
|
+
if (delta.add) {
|
|
1271
|
+
for (const member of delta.add) {
|
|
1272
|
+
const key = String(member);
|
|
1273
|
+
if (target.get(key) !== true) target.set(key, true);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
function applyStringSetChange(recordYMap, fieldName, change) {
|
|
1278
|
+
const target = ensureStringSetYMap(recordYMap, fieldName);
|
|
1279
|
+
applyStringSetDelta(target, {
|
|
1280
|
+
add: change.additions,
|
|
1281
|
+
remove: change.removals
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
function registerFunctionDefaultGenerator(name, fn) {
|
|
1285
|
+
FUNCTION_DEFAULT_GENERATORS.set(name, fn);
|
|
1286
|
+
}
|
|
1287
|
+
function resolveLiteralOrFunctionDefault(rawDefault) {
|
|
1288
|
+
return typeof rawDefault === "function" ? rawDefault() : rawDefault;
|
|
1289
|
+
}
|
|
1290
|
+
var Y2, import_ulid, KNOWN_FIELD_TYPE_MAP, KNOWN_FIELD_TYPES, FUNCTION_DEFAULT_GENERATORS, UNKNOWN_FUNCTION_DEFAULT;
|
|
1291
|
+
var init_writeLifecycle = __esm({
|
|
1292
|
+
"src/models/writeLifecycle.ts"() {
|
|
1293
|
+
"use strict";
|
|
1294
|
+
Y2 = __toESM(require("yjs"), 1);
|
|
1295
|
+
import_ulid = require("ulid");
|
|
1296
|
+
KNOWN_FIELD_TYPE_MAP = {
|
|
1297
|
+
string: true,
|
|
1298
|
+
number: true,
|
|
1299
|
+
boolean: true,
|
|
1300
|
+
date: true,
|
|
1301
|
+
id: true,
|
|
1302
|
+
stringset: true
|
|
1303
|
+
};
|
|
1304
|
+
KNOWN_FIELD_TYPES = new Set(Object.keys(KNOWN_FIELD_TYPE_MAP));
|
|
1305
|
+
FUNCTION_DEFAULT_GENERATORS = /* @__PURE__ */ new Map();
|
|
1306
|
+
registerFunctionDefaultGenerator("generate_ulid", () => (0, import_ulid.ulid)());
|
|
1307
|
+
UNKNOWN_FUNCTION_DEFAULT = "$unknown_function";
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1223
1311
|
// src/models/metaSync.ts
|
|
1224
1312
|
function inferFieldType(value) {
|
|
1225
1313
|
if (isStringSetYMap(value)) return "stringset";
|
|
@@ -1241,7 +1329,10 @@ function encodeDefault(value) {
|
|
|
1241
1329
|
if (value === void 0 || value === null) return void 0;
|
|
1242
1330
|
if (typeof value === "function") {
|
|
1243
1331
|
const name = KNOWN_FUNCTION_DEFAULTS.get(value);
|
|
1244
|
-
return name ? `$${name}` :
|
|
1332
|
+
return name ? `$${name}` : UNKNOWN_FUNCTION_DEFAULT;
|
|
1333
|
+
}
|
|
1334
|
+
if (typeof value === "string" && value.startsWith("$")) {
|
|
1335
|
+
return `$${value}`;
|
|
1245
1336
|
}
|
|
1246
1337
|
return value;
|
|
1247
1338
|
}
|
|
@@ -1267,7 +1358,7 @@ function syncModelMeta(yDoc, modelName, schema) {
|
|
|
1267
1358
|
if (compoundConstraints.length > 0) {
|
|
1268
1359
|
let constraints = meta.get("_constraints");
|
|
1269
1360
|
if (!constraints) {
|
|
1270
|
-
constraints = new
|
|
1361
|
+
constraints = new Y3.Map();
|
|
1271
1362
|
meta.set("_constraints", constraints);
|
|
1272
1363
|
}
|
|
1273
1364
|
for (const constraint of compoundConstraints) {
|
|
@@ -1278,7 +1369,7 @@ function syncModelMeta(yDoc, modelName, schema) {
|
|
|
1278
1369
|
if (relationships && Object.keys(relationships).length > 0) {
|
|
1279
1370
|
let rels = meta.get("_relationships");
|
|
1280
1371
|
if (!rels) {
|
|
1281
|
-
rels = new
|
|
1372
|
+
rels = new Y3.Map();
|
|
1282
1373
|
meta.set("_relationships", rels);
|
|
1283
1374
|
}
|
|
1284
1375
|
for (const [relName, relConfig] of Object.entries(relationships)) {
|
|
@@ -1290,7 +1381,7 @@ function syncModelMeta(yDoc, modelName, schema) {
|
|
|
1290
1381
|
function syncFieldMeta(metaMap, fieldName, fieldOpts) {
|
|
1291
1382
|
let fieldMeta = metaMap.get(fieldName);
|
|
1292
1383
|
if (!fieldMeta) {
|
|
1293
|
-
fieldMeta = new
|
|
1384
|
+
fieldMeta = new Y3.Map();
|
|
1294
1385
|
metaMap.set(fieldName, fieldMeta);
|
|
1295
1386
|
}
|
|
1296
1387
|
setIfChanged(fieldMeta, "type", fieldOpts.type);
|
|
@@ -1307,7 +1398,7 @@ function syncFieldMeta(metaMap, fieldName, fieldOpts) {
|
|
|
1307
1398
|
function syncConstraintMeta(constraintsMap, constraint) {
|
|
1308
1399
|
let cMeta = constraintsMap.get(constraint.name);
|
|
1309
1400
|
if (!cMeta) {
|
|
1310
|
-
cMeta = new
|
|
1401
|
+
cMeta = new Y3.Map();
|
|
1311
1402
|
constraintsMap.set(constraint.name, cMeta);
|
|
1312
1403
|
}
|
|
1313
1404
|
setIfChanged(cMeta, "type", "unique");
|
|
@@ -1317,7 +1408,7 @@ function syncConstraintMeta(constraintsMap, constraint) {
|
|
|
1317
1408
|
function syncRelationshipMeta(relsMap, relName, relConfig) {
|
|
1318
1409
|
let relMeta = relsMap.get(relName);
|
|
1319
1410
|
if (!relMeta) {
|
|
1320
|
-
relMeta = new
|
|
1411
|
+
relMeta = new Y3.Map();
|
|
1321
1412
|
relsMap.set(relName, relMeta);
|
|
1322
1413
|
}
|
|
1323
1414
|
for (const [key, value] of Object.entries(relConfig)) {
|
|
@@ -1332,7 +1423,7 @@ function syncInferredMeta(yDoc, modelName, recordData) {
|
|
|
1332
1423
|
if (fieldName.startsWith("_")) continue;
|
|
1333
1424
|
let fieldMeta = meta.get(fieldName);
|
|
1334
1425
|
if (!fieldMeta) {
|
|
1335
|
-
fieldMeta = new
|
|
1426
|
+
fieldMeta = new Y3.Map();
|
|
1336
1427
|
meta.set(fieldName, fieldMeta);
|
|
1337
1428
|
}
|
|
1338
1429
|
if (!fieldMeta.has("type")) {
|
|
@@ -1348,17 +1439,44 @@ function setIfChanged(map, key, value) {
|
|
|
1348
1439
|
map.set(key, value);
|
|
1349
1440
|
}
|
|
1350
1441
|
}
|
|
1351
|
-
var
|
|
1442
|
+
var Y3, KNOWN_FUNCTION_DEFAULTS, _syncedCache;
|
|
1352
1443
|
var init_metaSync = __esm({
|
|
1353
1444
|
"src/models/metaSync.ts"() {
|
|
1354
1445
|
"use strict";
|
|
1355
|
-
|
|
1446
|
+
Y3 = __toESM(require("yjs"), 1);
|
|
1356
1447
|
init_yjsValues();
|
|
1448
|
+
init_writeLifecycle();
|
|
1357
1449
|
KNOWN_FUNCTION_DEFAULTS = /* @__PURE__ */ new WeakMap();
|
|
1358
1450
|
_syncedCache = /* @__PURE__ */ new WeakMap();
|
|
1359
1451
|
}
|
|
1360
1452
|
});
|
|
1361
1453
|
|
|
1454
|
+
// src/utils/uniqueIndex.ts
|
|
1455
|
+
function buildUniqueKey(recordData, fields) {
|
|
1456
|
+
const keyParts = [];
|
|
1457
|
+
for (const field of fields) {
|
|
1458
|
+
const value = recordData instanceof Y4.Map ? recordData.get(field) : recordData[field];
|
|
1459
|
+
if (value === null || value === void 0) {
|
|
1460
|
+
return null;
|
|
1461
|
+
}
|
|
1462
|
+
keyParts.push(String(value));
|
|
1463
|
+
}
|
|
1464
|
+
return keyParts.join("|");
|
|
1465
|
+
}
|
|
1466
|
+
function uniqueIndexMapName(modelName, constraintName) {
|
|
1467
|
+
return `_uniqueIdx_${modelName}_${constraintName}`;
|
|
1468
|
+
}
|
|
1469
|
+
function fieldUniqueConstraintName(modelName, fieldName) {
|
|
1470
|
+
return `${modelName}_${fieldName}_unique`;
|
|
1471
|
+
}
|
|
1472
|
+
var Y4;
|
|
1473
|
+
var init_uniqueIndex = __esm({
|
|
1474
|
+
"src/utils/uniqueIndex.ts"() {
|
|
1475
|
+
"use strict";
|
|
1476
|
+
Y4 = __toESM(require("yjs"), 1);
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
|
|
1362
1480
|
// src/query/IncludeResolver.ts
|
|
1363
1481
|
var IncludeResolver_exports = {};
|
|
1364
1482
|
__export(IncludeResolver_exports, {
|
|
@@ -1717,7 +1835,13 @@ var init_IncludeResolver = __esm({
|
|
|
1717
1835
|
}
|
|
1718
1836
|
return null;
|
|
1719
1837
|
}
|
|
1720
|
-
/**
|
|
1838
|
+
/**
|
|
1839
|
+
* Apply a projection to a single record. Assumes the projection was already
|
|
1840
|
+
* validated upstream (mixed inclusion+exclusion rejected by the translator):
|
|
1841
|
+
* `isInclusion` treats "any value === 1" as inclusion mode. `id` and `type`
|
|
1842
|
+
* are system-identity fields and are always kept in BOTH modes (mirrors the
|
|
1843
|
+
* DatabaseDO `_applyProjection`); `_meta` stays excludable.
|
|
1844
|
+
*/
|
|
1721
1845
|
_applyProjection(record, projection) {
|
|
1722
1846
|
const fields = Object.entries(projection);
|
|
1723
1847
|
if (fields.length === 0) return record;
|
|
@@ -1736,7 +1860,7 @@ var init_IncludeResolver = __esm({
|
|
|
1736
1860
|
} else {
|
|
1737
1861
|
const result = { ...record };
|
|
1738
1862
|
for (const [f, v] of fields) {
|
|
1739
|
-
if (v === 0) delete result[f];
|
|
1863
|
+
if (v === 0 && f !== "id" && f !== "type") delete result[f];
|
|
1740
1864
|
}
|
|
1741
1865
|
return result;
|
|
1742
1866
|
}
|
|
@@ -1756,21 +1880,23 @@ __export(BaseModel_exports, {
|
|
|
1756
1880
|
generateULID: () => generateULID
|
|
1757
1881
|
});
|
|
1758
1882
|
function generateULID() {
|
|
1759
|
-
return (0,
|
|
1883
|
+
return (0, import_ulid2.ulid)();
|
|
1760
1884
|
}
|
|
1761
|
-
var
|
|
1885
|
+
var Y5, import_ulid2, LogLevel, Logger, UniqueConstraintViolationError, RecordNotFoundError, SCHEMA_ACCESSORS_KEY, BaseModel;
|
|
1762
1886
|
var init_BaseModel = __esm({
|
|
1763
1887
|
"src/models/BaseModel.ts"() {
|
|
1764
1888
|
"use strict";
|
|
1765
|
-
|
|
1766
|
-
|
|
1889
|
+
Y5 = __toESM(require("yjs"), 1);
|
|
1890
|
+
import_ulid2 = require("ulid");
|
|
1767
1891
|
init_StringSet();
|
|
1768
1892
|
init_documentTypes();
|
|
1769
1893
|
init_DocumentQueryTranslator();
|
|
1770
1894
|
init_CursorManager();
|
|
1771
1895
|
init_sql();
|
|
1772
1896
|
init_metaSync();
|
|
1897
|
+
init_writeLifecycle();
|
|
1773
1898
|
init_yjsValues();
|
|
1899
|
+
init_uniqueIndex();
|
|
1774
1900
|
LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
1775
1901
|
LogLevel2[LogLevel2["SILENT"] = 0] = "SILENT";
|
|
1776
1902
|
LogLevel2[LogLevel2["ERROR"] = 1] = "ERROR";
|
|
@@ -2155,7 +2281,9 @@ var init_BaseModel = __esm({
|
|
|
2155
2281
|
this.setValue(fieldKey, data[fieldKey]);
|
|
2156
2282
|
this._constructorProvidedFields.add(fieldKey);
|
|
2157
2283
|
} else if (fieldOptions.default !== void 0) {
|
|
2158
|
-
const defaultValue =
|
|
2284
|
+
const defaultValue = resolveLiteralOrFunctionDefault(
|
|
2285
|
+
fieldOptions.default
|
|
2286
|
+
);
|
|
2159
2287
|
this.setValue(fieldKey, defaultValue);
|
|
2160
2288
|
}
|
|
2161
2289
|
}
|
|
@@ -2447,7 +2575,7 @@ var init_BaseModel = __esm({
|
|
|
2447
2575
|
}
|
|
2448
2576
|
getStringSetFromYjs(fieldName) {
|
|
2449
2577
|
const yjsData = this.getFromYjs(fieldName);
|
|
2450
|
-
if (yjsData instanceof
|
|
2578
|
+
if (yjsData instanceof Y5.Map) {
|
|
2451
2579
|
return Array.from(yjsData.keys());
|
|
2452
2580
|
}
|
|
2453
2581
|
if (yjsData && typeof yjsData === "object") {
|
|
@@ -2555,7 +2683,7 @@ var init_BaseModel = __esm({
|
|
|
2555
2683
|
}
|
|
2556
2684
|
const extractStringSetValues = (value) => {
|
|
2557
2685
|
if (!value) return [];
|
|
2558
|
-
if (value instanceof
|
|
2686
|
+
if (value instanceof Y5.Map) {
|
|
2559
2687
|
return Array.from(value.entries()).filter(([, isMember]) => Boolean(isMember)).map(([key]) => key);
|
|
2560
2688
|
}
|
|
2561
2689
|
if (Array.isArray(value)) {
|
|
@@ -2572,7 +2700,7 @@ var init_BaseModel = __esm({
|
|
|
2572
2700
|
if (!recordId) continue;
|
|
2573
2701
|
let itemData;
|
|
2574
2702
|
const stringSetValuesByField = {};
|
|
2575
|
-
if (recordData instanceof
|
|
2703
|
+
if (recordData instanceof Y5.Map) {
|
|
2576
2704
|
itemData = {};
|
|
2577
2705
|
const unknownFields = [];
|
|
2578
2706
|
for (const [fieldKey, value] of recordData.entries()) {
|
|
@@ -2688,20 +2816,10 @@ var init_BaseModel = __esm({
|
|
|
2688
2816
|
Logger.verbose(
|
|
2689
2817
|
`[${this.name}] Setting up YMap observer for document ${docId}/${modelName}...`
|
|
2690
2818
|
);
|
|
2691
|
-
const
|
|
2692
|
-
const keyParts = [];
|
|
2693
|
-
for (const field of fields) {
|
|
2694
|
-
const value = recordData instanceof Y3.Map ? recordData.get(field) : recordData[field];
|
|
2695
|
-
if (value === null || value === void 0) {
|
|
2696
|
-
return null;
|
|
2697
|
-
}
|
|
2698
|
-
keyParts.push(String(value));
|
|
2699
|
-
}
|
|
2700
|
-
return keyParts.join("|");
|
|
2701
|
-
};
|
|
2819
|
+
const buildUniqueKey2 = (recordData, fields) => buildUniqueKey(recordData, fields);
|
|
2702
2820
|
const extractItemData = (key, recordData) => {
|
|
2703
2821
|
let itemData;
|
|
2704
|
-
if (recordData instanceof
|
|
2822
|
+
if (recordData instanceof Y5.Map) {
|
|
2705
2823
|
itemData = {};
|
|
2706
2824
|
const unknownFields = [];
|
|
2707
2825
|
for (const [fieldKey, value] of recordData.entries()) {
|
|
@@ -2785,7 +2903,7 @@ var init_BaseModel = __esm({
|
|
|
2785
2903
|
const recordsByUniqueKey = /* @__PURE__ */ new Map();
|
|
2786
2904
|
for (const [recordId, recordData] of allRecords.entries()) {
|
|
2787
2905
|
if (recordIdsToDiscard.has(recordId)) continue;
|
|
2788
|
-
const uniqueKey =
|
|
2906
|
+
const uniqueKey = buildUniqueKey2(recordData, constraint.fields);
|
|
2789
2907
|
if (uniqueKey === null) continue;
|
|
2790
2908
|
if (!recordsByUniqueKey.has(uniqueKey)) {
|
|
2791
2909
|
recordsByUniqueKey.set(uniqueKey, []);
|
|
@@ -2831,7 +2949,7 @@ var init_BaseModel = __esm({
|
|
|
2831
2949
|
if (!recordData || !key) continue;
|
|
2832
2950
|
const itemData = extractItemData(key, recordData);
|
|
2833
2951
|
if (!itemData) continue;
|
|
2834
|
-
if (change.action === "add" && recordData instanceof
|
|
2952
|
+
if (change.action === "add" && recordData instanceof Y5.Map) {
|
|
2835
2953
|
Logger.verbose(
|
|
2836
2954
|
`[${this.name}] Setting up observer on newly added nested YMap for record ${key} in document ${docId}`
|
|
2837
2955
|
);
|
|
@@ -2929,9 +3047,12 @@ var init_BaseModel = __esm({
|
|
|
2929
3047
|
const recordData = documentYMap.get(idToDiscard);
|
|
2930
3048
|
if (!recordData) continue;
|
|
2931
3049
|
for (const constraint of schema.resolvedUniqueConstraints) {
|
|
2932
|
-
const uniqueKey =
|
|
3050
|
+
const uniqueKey = buildUniqueKey2(recordData, constraint.fields);
|
|
2933
3051
|
if (uniqueKey === null) continue;
|
|
2934
|
-
const constraintMapName =
|
|
3052
|
+
const constraintMapName = uniqueIndexMapName(
|
|
3053
|
+
modelName,
|
|
3054
|
+
constraint.name
|
|
3055
|
+
);
|
|
2935
3056
|
const constraintMap = yDoc.getMap(constraintMapName);
|
|
2936
3057
|
const currentIndexValue = constraintMap.get(uniqueKey);
|
|
2937
3058
|
if (currentIndexValue === idToDiscard) {
|
|
@@ -2949,11 +3070,14 @@ var init_BaseModel = __esm({
|
|
|
2949
3070
|
}, `conflict-resolution-${modelName}-${docId}`);
|
|
2950
3071
|
yDoc.transact(() => {
|
|
2951
3072
|
for (const constraint of schema.resolvedUniqueConstraints) {
|
|
2952
|
-
const constraintMapName =
|
|
3073
|
+
const constraintMapName = uniqueIndexMapName(
|
|
3074
|
+
modelName,
|
|
3075
|
+
constraint.name
|
|
3076
|
+
);
|
|
2953
3077
|
const constraintMap = yDoc.getMap(constraintMapName);
|
|
2954
3078
|
for (const [recordId, recordData] of documentYMap.entries()) {
|
|
2955
3079
|
if (!recordData) continue;
|
|
2956
|
-
const uniqueKey =
|
|
3080
|
+
const uniqueKey = buildUniqueKey2(recordData, constraint.fields);
|
|
2957
3081
|
if (uniqueKey === null) continue;
|
|
2958
3082
|
const currentIndexValue = constraintMap.get(uniqueKey);
|
|
2959
3083
|
if (currentIndexValue !== recordId) {
|
|
@@ -2976,7 +3100,7 @@ var init_BaseModel = __esm({
|
|
|
2976
3100
|
`[${this.name}] Setting up observers on existing nested YMaps for ${modelName}/${docId}...`
|
|
2977
3101
|
);
|
|
2978
3102
|
for (const [recordId, recordData] of documentYMap.entries()) {
|
|
2979
|
-
if (recordData instanceof
|
|
3103
|
+
if (recordData instanceof Y5.Map) {
|
|
2980
3104
|
Logger.verbose(
|
|
2981
3105
|
`[${this.name}] Setting up observer on existing nested YMap for record ${recordId} in document ${docId}`
|
|
2982
3106
|
);
|
|
@@ -3202,26 +3326,7 @@ var init_BaseModel = __esm({
|
|
|
3202
3326
|
* if the field hasn't been touched since the wire-format change in #561.
|
|
3203
3327
|
*/
|
|
3204
3328
|
applyStringSetChangeToYMap(recordYMap, fieldName, change) {
|
|
3205
|
-
|
|
3206
|
-
if (!(nested instanceof Y3.Map)) {
|
|
3207
|
-
const migrated = new Y3.Map();
|
|
3208
|
-
if (nested && typeof nested === "object") {
|
|
3209
|
-
for (const [member, marker] of Object.entries(
|
|
3210
|
-
nested
|
|
3211
|
-
)) {
|
|
3212
|
-
if (Boolean(marker)) migrated.set(member, true);
|
|
3213
|
-
}
|
|
3214
|
-
}
|
|
3215
|
-
recordYMap.set(fieldName, migrated);
|
|
3216
|
-
nested = migrated;
|
|
3217
|
-
}
|
|
3218
|
-
const target = nested;
|
|
3219
|
-
for (const member of change.additions) {
|
|
3220
|
-
target.set(member, true);
|
|
3221
|
-
}
|
|
3222
|
-
for (const member of change.removals) {
|
|
3223
|
-
target.delete(member);
|
|
3224
|
-
}
|
|
3329
|
+
applyStringSetChange(recordYMap, fieldName, change);
|
|
3225
3330
|
}
|
|
3226
3331
|
/**
|
|
3227
3332
|
* Deep equality check for comparing field values
|
|
@@ -3423,6 +3528,34 @@ var init_BaseModel = __esm({
|
|
|
3423
3528
|
`[${modelName}.save] getCurrentJSState() returned:`,
|
|
3424
3529
|
dataToSave
|
|
3425
3530
|
);
|
|
3531
|
+
const uniqueMissConflicts = /* @__PURE__ */ new Map();
|
|
3532
|
+
for (const constraint of schema.resolvedUniqueConstraints) {
|
|
3533
|
+
const newUniqueKey = this._buildUniqueKey(
|
|
3534
|
+
constraint.fields,
|
|
3535
|
+
dataToSave,
|
|
3536
|
+
modelName,
|
|
3537
|
+
constraint.name
|
|
3538
|
+
);
|
|
3539
|
+
if (newUniqueKey === null) {
|
|
3540
|
+
continue;
|
|
3541
|
+
}
|
|
3542
|
+
const constraintMap = yDoc.getMap(
|
|
3543
|
+
uniqueIndexMapName(modelName, constraint.name)
|
|
3544
|
+
);
|
|
3545
|
+
if (!constraintMap.get(newUniqueKey)) {
|
|
3546
|
+
const constraintKeyValues = constraint.fields.map(
|
|
3547
|
+
(field) => dataToSave[field]
|
|
3548
|
+
);
|
|
3549
|
+
const conflictingRecord = await modelConstructor._resolveByUniqueFallback(
|
|
3550
|
+
constraint,
|
|
3551
|
+
constraintKeyValues,
|
|
3552
|
+
{ excludeId: this.id }
|
|
3553
|
+
);
|
|
3554
|
+
if (conflictingRecord) {
|
|
3555
|
+
uniqueMissConflicts.set(constraint.name, conflictingRecord.id);
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3426
3559
|
await yDoc.transact(async () => {
|
|
3427
3560
|
if (upsertOnConstraint && upsertOnKey) {
|
|
3428
3561
|
const constraintMapName = `_uniqueIdx_${modelName}_${upsertOnConstraint.name}`;
|
|
@@ -3464,7 +3597,7 @@ var init_BaseModel = __esm({
|
|
|
3464
3597
|
Logger.debug(`[${modelName}.save] isUpdate: ${isUpdate}`);
|
|
3465
3598
|
Logger.debug(`[${modelName}.save] recordYMap exists: ${!!recordYMap}`);
|
|
3466
3599
|
if (!recordYMap) {
|
|
3467
|
-
recordYMap = new
|
|
3600
|
+
recordYMap = new Y5.Map();
|
|
3468
3601
|
Logger.verbose(
|
|
3469
3602
|
`[${modelName}] Creating new nested YMap for record ${this.id} in document ${targetDocId || "legacy"}`
|
|
3470
3603
|
);
|
|
@@ -3516,7 +3649,10 @@ var init_BaseModel = __esm({
|
|
|
3516
3649
|
);
|
|
3517
3650
|
continue;
|
|
3518
3651
|
}
|
|
3519
|
-
const constraintMapName =
|
|
3652
|
+
const constraintMapName = uniqueIndexMapName(
|
|
3653
|
+
modelName,
|
|
3654
|
+
constraint.name
|
|
3655
|
+
);
|
|
3520
3656
|
const constraintMap = yDoc.getMap(constraintMapName);
|
|
3521
3657
|
Logger.verbose(
|
|
3522
3658
|
`[${modelName}] Save Check (Item '${this.id}'): GET from '${constraintMapName}' with Key '${newUniqueKey.substring(
|
|
@@ -3545,6 +3681,26 @@ var init_BaseModel = __esm({
|
|
|
3545
3681
|
this.id,
|
|
3546
3682
|
existingRecordIdWithNewKey
|
|
3547
3683
|
);
|
|
3684
|
+
} else if (!existingRecordIdWithNewKey) {
|
|
3685
|
+
const conflictingRecordId = uniqueMissConflicts.get(constraint.name);
|
|
3686
|
+
if (conflictingRecordId && conflictingRecordId !== this.id) {
|
|
3687
|
+
Logger.verbose(
|
|
3688
|
+
`[${modelName}] Save Check (Item '${this.id}'): index miss for '${constraint.name}', but engine fallback found conflicting index-less record ${conflictingRecordId}.`
|
|
3689
|
+
);
|
|
3690
|
+
throw new UniqueConstraintViolationError(
|
|
3691
|
+
`Unique constraint '${constraint.name}' violated for model '${modelName}' on fields [${constraint.fields.join(
|
|
3692
|
+
", "
|
|
3693
|
+
)}]. Attempted ID: ${this.id}. Value(s) starting with '${newUniqueKey.substring(
|
|
3694
|
+
0,
|
|
3695
|
+
50
|
|
3696
|
+
)}...' already exist for index-less record ID ${conflictingRecordId}.`,
|
|
3697
|
+
modelName,
|
|
3698
|
+
constraint.name,
|
|
3699
|
+
constraint.fields,
|
|
3700
|
+
this.id,
|
|
3701
|
+
conflictingRecordId
|
|
3702
|
+
);
|
|
3703
|
+
}
|
|
3548
3704
|
}
|
|
3549
3705
|
}
|
|
3550
3706
|
if (isUpdate && oldData) {
|
|
@@ -3888,34 +4044,46 @@ var init_BaseModel = __esm({
|
|
|
3888
4044
|
const modelName = schema.options.name;
|
|
3889
4045
|
Logger.verbose(`[${modelName}] Executing query:`, { filter, options });
|
|
3890
4046
|
const hasIncludes = options?.include && options.include.length > 0;
|
|
3891
|
-
const
|
|
4047
|
+
const requestedLimit = options?.limit;
|
|
4048
|
+
const overFetch = typeof requestedLimit === "number" && requestedLimit > 0;
|
|
4049
|
+
let translatorOptions = hasIncludes && options?.projection ? { ...options, projection: void 0 } : options;
|
|
4050
|
+
if (overFetch) {
|
|
4051
|
+
translatorOptions = {
|
|
4052
|
+
...translatorOptions || {},
|
|
4053
|
+
limit: requestedLimit + 1
|
|
4054
|
+
};
|
|
4055
|
+
}
|
|
3892
4056
|
const translator = new DocumentQueryTranslator(modelName, schema.fields);
|
|
3893
4057
|
const translatedQuery = translator.translateFind(filter, translatorOptions);
|
|
3894
4058
|
Logger.verbose(`[${modelName}] Translated SQL:`, translatedQuery.sql);
|
|
3895
4059
|
Logger.verbose(`[${modelName}] SQL params:`, translatedQuery.params);
|
|
3896
|
-
|
|
4060
|
+
let results = await _BaseModel.dbInstance.query(
|
|
3897
4061
|
translatedQuery.sql,
|
|
3898
4062
|
translatedQuery.params
|
|
3899
4063
|
);
|
|
3900
4064
|
Logger.verbose(`[${modelName}] Query returned ${results.length} results`);
|
|
4065
|
+
let hasMore = false;
|
|
4066
|
+
if (overFetch && results.length > requestedLimit) {
|
|
4067
|
+
hasMore = true;
|
|
4068
|
+
results = results.slice(0, requestedLimit);
|
|
4069
|
+
}
|
|
3901
4070
|
if (options?.include && options.include.length > 0) {
|
|
3902
4071
|
const { IncludeResolver: IncludeResolver2 } = await Promise.resolve().then(() => (init_IncludeResolver(), IncludeResolver_exports));
|
|
3903
4072
|
const resolver = new IncludeResolver2(_BaseModel.dbInstance);
|
|
3904
4073
|
await resolver.resolve(results, options.include, 0, modelName);
|
|
3905
4074
|
}
|
|
3906
|
-
const requestedLimit = options?.limit;
|
|
3907
|
-
const hasMore = CursorManager.hasMoreResults(
|
|
3908
|
-
requestedLimit,
|
|
3909
|
-
results.length
|
|
3910
|
-
);
|
|
3911
4075
|
const isFirstPage = !options?.uniqueStartKey;
|
|
4076
|
+
const direction = options?.direction || 1;
|
|
3912
4077
|
const cursors = CursorManager.generateResultCursors(
|
|
3913
4078
|
results,
|
|
3914
4079
|
translatedQuery.sortFields,
|
|
3915
|
-
|
|
4080
|
+
direction,
|
|
3916
4081
|
hasMore,
|
|
3917
4082
|
isFirstPage
|
|
3918
4083
|
);
|
|
4084
|
+
if (direction === -1) {
|
|
4085
|
+
results.reverse();
|
|
4086
|
+
}
|
|
3919
4087
|
let transformedData;
|
|
3920
4088
|
if (options?.projection && Object.keys(options.projection).length > 0) {
|
|
3921
4089
|
transformedData = results.map((row) => {
|
|
@@ -4491,7 +4659,7 @@ var init_BaseModel = __esm({
|
|
|
4491
4659
|
);
|
|
4492
4660
|
}
|
|
4493
4661
|
for (const [recordId, recordYMap] of documentYMap.entries()) {
|
|
4494
|
-
if (recordYMap instanceof
|
|
4662
|
+
if (recordYMap instanceof Y5.Map) {
|
|
4495
4663
|
const instance = new this({ id: recordId });
|
|
4496
4664
|
instance._metaDocId = docId;
|
|
4497
4665
|
const connectedDoc = modelConstructor.connectedDocuments.get(docId);
|
|
@@ -4516,6 +4684,50 @@ var init_BaseModel = __esm({
|
|
|
4516
4684
|
}
|
|
4517
4685
|
return allInstances;
|
|
4518
4686
|
}
|
|
4687
|
+
/**
|
|
4688
|
+
* Resolve a record by its unique-constraint field values via an engine query.
|
|
4689
|
+
* Used as a fallback when the `_uniqueIdx_<model>_<constraint>` map has no
|
|
4690
|
+
* entry for a key.
|
|
4691
|
+
*
|
|
4692
|
+
* The index map is a cache over the SQLite projection, not the source of
|
|
4693
|
+
* truth: every record is loaded into the projection on `initializeForDocument`
|
|
4694
|
+
* regardless of index presence, but a record written by a client predating
|
|
4695
|
+
* index maintenance (legacy data) is missing from the index. Such a record
|
|
4696
|
+
* silently escapes both `upsertByUnique` lookups and the `save()` uniqueness
|
|
4697
|
+
* check. A query over the constraint fields finds it reliably.
|
|
4698
|
+
*
|
|
4699
|
+
* Contract: RESOLVE ONLY. Returns the owning record (with `_metaDocId` set to
|
|
4700
|
+
* the document that holds it, via `queryOne`) or `null`. Callers decide
|
|
4701
|
+
* whether to heal the missing index entry (write paths) and do their own
|
|
4702
|
+
* logging — this method never mutates the index, so read paths stay
|
|
4703
|
+
* read-only. Mirrors `buildUniqueKey`: a null/undefined value in any
|
|
4704
|
+
* constraint field means the record does not participate in the constraint,
|
|
4705
|
+
* so no query runs.
|
|
4706
|
+
*/
|
|
4707
|
+
static async _resolveByUniqueFallback(constraint, keyValues, options) {
|
|
4708
|
+
if (!_BaseModel.dbInstance) {
|
|
4709
|
+
return null;
|
|
4710
|
+
}
|
|
4711
|
+
const filter = {};
|
|
4712
|
+
for (let i = 0; i < constraint.fields.length; i++) {
|
|
4713
|
+
const value = keyValues[i];
|
|
4714
|
+
if (value === null || value === void 0) {
|
|
4715
|
+
return null;
|
|
4716
|
+
}
|
|
4717
|
+
filter[constraint.fields[i]] = value;
|
|
4718
|
+
}
|
|
4719
|
+
if (options?.excludeId) {
|
|
4720
|
+
if ("id" in filter) {
|
|
4721
|
+
if (filter.id === options.excludeId) {
|
|
4722
|
+
return null;
|
|
4723
|
+
}
|
|
4724
|
+
} else {
|
|
4725
|
+
filter.id = { $ne: options.excludeId };
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
const found = await this.queryOne(filter);
|
|
4729
|
+
return found ?? null;
|
|
4730
|
+
}
|
|
4519
4731
|
static async findByUnique(constraintName, value) {
|
|
4520
4732
|
const modelConstructor = this;
|
|
4521
4733
|
const schema = modelConstructor.getSchema();
|
|
@@ -4554,7 +4766,10 @@ var init_BaseModel = __esm({
|
|
|
4554
4766
|
const documentInfo = modelConstructor.connectedDocuments.get(docId);
|
|
4555
4767
|
if (!documentInfo) continue;
|
|
4556
4768
|
const yDoc = documentInfo.yDoc;
|
|
4557
|
-
const constraintMapName2 =
|
|
4769
|
+
const constraintMapName2 = uniqueIndexMapName(
|
|
4770
|
+
currentModelName,
|
|
4771
|
+
constraint.name
|
|
4772
|
+
);
|
|
4558
4773
|
const constraintMap2 = yDoc.getMap(constraintMapName2);
|
|
4559
4774
|
const recordId2 = constraintMap2.get(uniqueKeyString);
|
|
4560
4775
|
if (recordId2) {
|
|
@@ -4562,7 +4777,7 @@ var init_BaseModel = __esm({
|
|
|
4562
4777
|
const documentYMap = modelConstructor.documentYMaps.get(documentYMapKey);
|
|
4563
4778
|
if (documentYMap) {
|
|
4564
4779
|
const recordYMap2 = documentYMap.get(recordId2);
|
|
4565
|
-
if (recordYMap2 && recordYMap2 instanceof
|
|
4780
|
+
if (recordYMap2 && recordYMap2 instanceof Y5.Map) {
|
|
4566
4781
|
const instance = new modelConstructor({
|
|
4567
4782
|
id: recordId2
|
|
4568
4783
|
});
|
|
@@ -4576,6 +4791,16 @@ var init_BaseModel = __esm({
|
|
|
4576
4791
|
}
|
|
4577
4792
|
}
|
|
4578
4793
|
}
|
|
4794
|
+
const fallbackRecord = await modelConstructor._resolveByUniqueFallback(
|
|
4795
|
+
constraint,
|
|
4796
|
+
keyValues
|
|
4797
|
+
);
|
|
4798
|
+
if (fallbackRecord) {
|
|
4799
|
+
Logger.verbose(
|
|
4800
|
+
`[${currentModelName}.findByUnique] Index miss for '${constraintName}' resolved via engine fallback to record ${fallbackRecord.id} (legacy index-less record; index left unchanged on read path).`
|
|
4801
|
+
);
|
|
4802
|
+
return fallbackRecord;
|
|
4803
|
+
}
|
|
4579
4804
|
Logger.verbose(
|
|
4580
4805
|
`[${currentModelName}.findByUnique] Record not found in any connected document`
|
|
4581
4806
|
);
|
|
@@ -4589,17 +4814,30 @@ var init_BaseModel = __esm({
|
|
|
4589
4814
|
`[${currentModelName}] No Y.Doc is connected for this model. Connect a document via initJsBao(...).connectDocument or call initializeForDocument(yDoc, db, docId, permissionHint) before using legacy findByUnique.`
|
|
4590
4815
|
);
|
|
4591
4816
|
}
|
|
4592
|
-
const constraintMapName =
|
|
4817
|
+
const constraintMapName = uniqueIndexMapName(
|
|
4818
|
+
currentModelName,
|
|
4819
|
+
constraint.name
|
|
4820
|
+
);
|
|
4593
4821
|
const constraintMap = legacyDocInfo.yDoc.getMap(constraintMapName);
|
|
4594
4822
|
const recordId = constraintMap.get(uniqueKeyString);
|
|
4595
4823
|
if (!recordId) {
|
|
4824
|
+
const fallbackRecord = await modelConstructor._resolveByUniqueFallback(
|
|
4825
|
+
constraint,
|
|
4826
|
+
keyValues
|
|
4827
|
+
);
|
|
4828
|
+
if (fallbackRecord) {
|
|
4829
|
+
Logger.verbose(
|
|
4830
|
+
`[${currentModelName}.findByUnique] Index miss for '${constraintName}' resolved via engine fallback to record ${fallbackRecord.id} (legacy index-less record; index left unchanged on read path).`
|
|
4831
|
+
);
|
|
4832
|
+
return fallbackRecord;
|
|
4833
|
+
}
|
|
4596
4834
|
return null;
|
|
4597
4835
|
}
|
|
4598
4836
|
const recordYMap = legacyDocumentMap.get(recordId);
|
|
4599
4837
|
if (!recordYMap) {
|
|
4600
4838
|
return null;
|
|
4601
4839
|
}
|
|
4602
|
-
if (recordYMap instanceof
|
|
4840
|
+
if (recordYMap instanceof Y5.Map) {
|
|
4603
4841
|
const instance = new modelConstructor({
|
|
4604
4842
|
id: recordId
|
|
4605
4843
|
});
|
|
@@ -4657,7 +4895,10 @@ var init_BaseModel = __esm({
|
|
|
4657
4895
|
`[${currentModelName}] upsertByUnique for '${constraintName}': unique key cannot be built due to null/undefined values. Upsert cannot proceed reliably.`
|
|
4658
4896
|
);
|
|
4659
4897
|
}
|
|
4660
|
-
const constraintMapName =
|
|
4898
|
+
const constraintMapName = uniqueIndexMapName(
|
|
4899
|
+
currentModelName,
|
|
4900
|
+
constraint.name
|
|
4901
|
+
);
|
|
4661
4902
|
let existingRecord = null;
|
|
4662
4903
|
if (connectedDocuments && connectedDocuments.size > 0) {
|
|
4663
4904
|
for (const docId of connectedDocuments.keys()) {
|
|
@@ -4675,6 +4916,33 @@ var init_BaseModel = __esm({
|
|
|
4675
4916
|
}
|
|
4676
4917
|
} else {
|
|
4677
4918
|
}
|
|
4919
|
+
if (!existingRecord) {
|
|
4920
|
+
const fallbackRecord = await modelConstructor._resolveByUniqueFallback(
|
|
4921
|
+
constraint,
|
|
4922
|
+
keyValuesForLookup
|
|
4923
|
+
);
|
|
4924
|
+
if (fallbackRecord) {
|
|
4925
|
+
existingRecord = fallbackRecord;
|
|
4926
|
+
const healDocId = fallbackRecord._metaDocId;
|
|
4927
|
+
const healDocInfo = healDocId ? connectedDocuments.get(healDocId) : void 0;
|
|
4928
|
+
const canHeal = !!healDocInfo && healDocInfo.permissionHint !== "read";
|
|
4929
|
+
if (healDocInfo && canHeal) {
|
|
4930
|
+
healDocInfo.yDoc.transact(() => {
|
|
4931
|
+
const healMap = healDocInfo.yDoc.getMap(constraintMapName);
|
|
4932
|
+
if (healMap.get(uniqueKeyString) !== fallbackRecord.id) {
|
|
4933
|
+
healMap.set(uniqueKeyString, fallbackRecord.id);
|
|
4934
|
+
}
|
|
4935
|
+
}, `heal-unique-index-${currentModelName}-${healDocId}`);
|
|
4936
|
+
Logger.verbose(
|
|
4937
|
+
`[${currentModelName}] upsertByUnique: index miss for '${constraintName}' resolved via engine fallback to record ${fallbackRecord.id}; healed missing index entry (legacy index-less record).`
|
|
4938
|
+
);
|
|
4939
|
+
} else {
|
|
4940
|
+
Logger.verbose(
|
|
4941
|
+
`[${currentModelName}] upsertByUnique: index miss for '${constraintName}' resolved via engine fallback to record ${fallbackRecord.id}; skipped index heal (owning document is read-only or not connected).`
|
|
4942
|
+
);
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
}
|
|
4678
4946
|
if (options?.objectMustExist) {
|
|
4679
4947
|
if (!existingRecord) {
|
|
4680
4948
|
throw new RecordNotFoundError(
|
|
@@ -4831,7 +5099,7 @@ var init_BaseModel = __esm({
|
|
|
4831
5099
|
for (const [fieldKey, fieldOptions] of schema.fields) {
|
|
4832
5100
|
if (fieldOptions?.type !== "stringset") continue;
|
|
4833
5101
|
const value = recordYMap.get(fieldKey);
|
|
4834
|
-
if (value instanceof
|
|
5102
|
+
if (value instanceof Y5.Map) {
|
|
4835
5103
|
this.observeStringSetMapOnce(value);
|
|
4836
5104
|
}
|
|
4837
5105
|
}
|
|
@@ -5017,6 +5285,19 @@ var init_BaseModel = __esm({
|
|
|
5017
5285
|
});
|
|
5018
5286
|
|
|
5019
5287
|
// src/models/relationshipManager.ts
|
|
5288
|
+
function warnIfOrderFieldNullable(modelClass, orderByField, relationshipDescription) {
|
|
5289
|
+
if (ALWAYS_PRESENT_ORDER_FIELDS.has(orderByField)) return;
|
|
5290
|
+
const schema = modelClass.getSchema?.();
|
|
5291
|
+
const fields = schema?.fields;
|
|
5292
|
+
if (!fields || typeof fields.get !== "function") return;
|
|
5293
|
+
const fieldOptions = fields.get(orderByField);
|
|
5294
|
+
if (!fieldOptions) return;
|
|
5295
|
+
if (fieldOptions.required !== true) {
|
|
5296
|
+
Logger.warn(
|
|
5297
|
+
`[RelationshipManager] ${relationshipDescription} orders by '${orderByField}', which is not marked required on ${modelClass.name}. The composite (${orderByField}, id) cursor paginates deterministically, but a row whose '${orderByField}' is actually NULL has no stable cursor position and may drop from the tail. Mark '${orderByField}' as required, or order by a required field such as 'id', to remove the risk. (Full NULL-ordering support is tracked in #1316.)`
|
|
5298
|
+
);
|
|
5299
|
+
}
|
|
5300
|
+
}
|
|
5020
5301
|
function generateRefersToMethod(_sourceModelClass, config, targetModelClass) {
|
|
5021
5302
|
return async function() {
|
|
5022
5303
|
const relatedId = this[config.relatedIdField];
|
|
@@ -5025,6 +5306,16 @@ function generateRefersToMethod(_sourceModelClass, config, targetModelClass) {
|
|
|
5025
5306
|
};
|
|
5026
5307
|
}
|
|
5027
5308
|
function generateHasManyMethod(_sourceModelClass, config, targetModelClass, _dbEngine) {
|
|
5309
|
+
const {
|
|
5310
|
+
relatedIdField,
|
|
5311
|
+
orderByField = "id",
|
|
5312
|
+
orderDirection = "ASC"
|
|
5313
|
+
} = config;
|
|
5314
|
+
warnIfOrderFieldNullable(
|
|
5315
|
+
targetModelClass,
|
|
5316
|
+
orderByField,
|
|
5317
|
+
`hasMany(${targetModelClass.name})`
|
|
5318
|
+
);
|
|
5028
5319
|
return async function(paginationArgs) {
|
|
5029
5320
|
const {
|
|
5030
5321
|
limit,
|
|
@@ -5032,71 +5323,39 @@ function generateHasManyMethod(_sourceModelClass, config, targetModelClass, _dbE
|
|
|
5032
5323
|
beforeCursor,
|
|
5033
5324
|
direction = "forward"
|
|
5034
5325
|
} = paginationArgs || {};
|
|
5035
|
-
const {
|
|
5036
|
-
relatedIdField,
|
|
5037
|
-
orderByField = "id",
|
|
5038
|
-
orderDirection = "ASC"
|
|
5039
|
-
} = config;
|
|
5040
5326
|
const targetSchema = targetModelClass.getSchema();
|
|
5041
5327
|
if (!targetSchema || !targetSchema.options || !targetSchema.options.name) {
|
|
5042
5328
|
Logger.error(
|
|
5043
5329
|
`[RelationshipManager] Target model ${targetModelClass.name} for hasMany relationship has no valid schema name.`
|
|
5044
5330
|
);
|
|
5045
|
-
return { data: [],
|
|
5331
|
+
return { data: [], hasMore: false };
|
|
5046
5332
|
}
|
|
5047
|
-
const
|
|
5333
|
+
const forward = direction !== "backward";
|
|
5334
|
+
const cursor = forward ? afterCursor : beforeCursor;
|
|
5048
5335
|
const queryOptions = {
|
|
5049
|
-
sort: { [orderByField]: orderDirection === "ASC" ? 1 : -1 }
|
|
5336
|
+
sort: { [orderByField]: orderDirection === "ASC" ? 1 : -1 },
|
|
5337
|
+
direction: forward ? 1 : -1
|
|
5050
5338
|
};
|
|
5051
|
-
if (limit !== void 0)
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
};
|
|
5058
|
-
} else if (direction === "backward") {
|
|
5059
|
-
if (beforeCursor) {
|
|
5060
|
-
filter[orderByField] = {
|
|
5061
|
-
[orderDirection === "ASC" ? "$lt" : "$gt"]: beforeCursor
|
|
5062
|
-
};
|
|
5063
|
-
}
|
|
5064
|
-
queryOptions.sort = { [orderByField]: orderDirection === "ASC" ? -1 : 1 };
|
|
5065
|
-
}
|
|
5066
|
-
const result = await targetModelClass.query(filter, queryOptions);
|
|
5067
|
-
const results = result.data;
|
|
5068
|
-
let nextCursor = null;
|
|
5069
|
-
let prevCursor = null;
|
|
5070
|
-
const isFirstPage = direction === "forward" && !afterCursor;
|
|
5071
|
-
if (limit !== void 0) {
|
|
5072
|
-
if (direction === "forward") {
|
|
5073
|
-
if (results.length > limit) {
|
|
5074
|
-
nextCursor = results[limit - 1][orderByField];
|
|
5075
|
-
results.pop();
|
|
5076
|
-
}
|
|
5077
|
-
if (results.length > 0 && !isFirstPage) {
|
|
5078
|
-
prevCursor = results[0][orderByField];
|
|
5079
|
-
}
|
|
5080
|
-
} else {
|
|
5081
|
-
if (results.length > limit) {
|
|
5082
|
-
prevCursor = results[limit - 1][orderByField];
|
|
5083
|
-
results.pop();
|
|
5084
|
-
}
|
|
5085
|
-
results.reverse();
|
|
5086
|
-
if (results.length > 0 && beforeCursor) {
|
|
5087
|
-
nextCursor = results[results.length - 1][orderByField];
|
|
5088
|
-
}
|
|
5089
|
-
if (results.length > 0 && !beforeCursor) {
|
|
5090
|
-
if (results.length === limit) {
|
|
5091
|
-
prevCursor = results[0][orderByField];
|
|
5092
|
-
}
|
|
5093
|
-
}
|
|
5094
|
-
}
|
|
5095
|
-
}
|
|
5096
|
-
return { data: results, nextCursor, prevCursor };
|
|
5339
|
+
if (limit !== void 0) queryOptions.limit = limit;
|
|
5340
|
+
if (cursor != null) queryOptions.uniqueStartKey = cursor;
|
|
5341
|
+
return targetModelClass.query(
|
|
5342
|
+
{ [relatedIdField]: this.id },
|
|
5343
|
+
queryOptions
|
|
5344
|
+
);
|
|
5097
5345
|
};
|
|
5098
5346
|
}
|
|
5099
5347
|
function generateHasManyThroughMethod(_sourceModelClass, config, targetModelClass, joinModelClass, _dbEngine) {
|
|
5348
|
+
const {
|
|
5349
|
+
joinModelLocalField,
|
|
5350
|
+
joinModelRelatedField,
|
|
5351
|
+
joinModelOrderByField = "id",
|
|
5352
|
+
joinModelOrderDirection = "ASC"
|
|
5353
|
+
} = config;
|
|
5354
|
+
warnIfOrderFieldNullable(
|
|
5355
|
+
joinModelClass,
|
|
5356
|
+
joinModelOrderByField,
|
|
5357
|
+
`hasManyThrough(${targetModelClass.name} via ${joinModelClass.name})`
|
|
5358
|
+
);
|
|
5100
5359
|
return async function(paginationArgs) {
|
|
5101
5360
|
const {
|
|
5102
5361
|
limit,
|
|
@@ -5110,87 +5369,42 @@ function generateHasManyThroughMethod(_sourceModelClass, config, targetModelClas
|
|
|
5110
5369
|
Logger.error(
|
|
5111
5370
|
`[RelationshipManager] Join model ${joinModelClass.name} for hasManyThrough relationship has no valid schema name.`
|
|
5112
5371
|
);
|
|
5113
|
-
return { data: [],
|
|
5372
|
+
return { data: [], hasMore: false };
|
|
5114
5373
|
}
|
|
5115
5374
|
if (!targetSchema || !targetSchema.options || !targetSchema.options.name) {
|
|
5116
5375
|
Logger.error(
|
|
5117
5376
|
`[RelationshipManager] Target model ${targetModelClass.name} for hasManyThrough relationship has no valid schema name.`
|
|
5118
5377
|
);
|
|
5119
|
-
return { data: [],
|
|
5378
|
+
return { data: [], hasMore: false };
|
|
5120
5379
|
}
|
|
5121
|
-
const
|
|
5122
|
-
|
|
5123
|
-
joinModelRelatedField,
|
|
5124
|
-
joinModelOrderByField = "id",
|
|
5125
|
-
joinModelOrderDirection = "ASC"
|
|
5126
|
-
} = config;
|
|
5127
|
-
const joinFilter = { [joinModelLocalField]: this.id };
|
|
5380
|
+
const forward = direction !== "backward";
|
|
5381
|
+
const cursor = forward ? afterCursor : beforeCursor;
|
|
5128
5382
|
const joinQueryOptions = {
|
|
5129
5383
|
sort: {
|
|
5130
5384
|
[joinModelOrderByField]: joinModelOrderDirection === "ASC" ? 1 : -1
|
|
5131
5385
|
},
|
|
5132
|
-
projection: { [joinModelRelatedField]: 1, [joinModelOrderByField]: 1 }
|
|
5386
|
+
projection: { [joinModelRelatedField]: 1, [joinModelOrderByField]: 1 },
|
|
5387
|
+
direction: forward ? 1 : -1
|
|
5133
5388
|
};
|
|
5134
|
-
if (limit !== void 0)
|
|
5135
|
-
|
|
5136
|
-
}
|
|
5137
|
-
if (direction === "forward" && afterCursor) {
|
|
5138
|
-
joinFilter[joinModelOrderByField] = {
|
|
5139
|
-
[joinModelOrderDirection === "ASC" ? "$gt" : "$lt"]: afterCursor
|
|
5140
|
-
};
|
|
5141
|
-
} else if (direction === "backward") {
|
|
5142
|
-
if (beforeCursor) {
|
|
5143
|
-
joinFilter[joinModelOrderByField] = {
|
|
5144
|
-
[joinModelOrderDirection === "ASC" ? "$lt" : "$gt"]: beforeCursor
|
|
5145
|
-
};
|
|
5146
|
-
}
|
|
5147
|
-
joinQueryOptions.sort = {
|
|
5148
|
-
[joinModelOrderByField]: joinModelOrderDirection === "ASC" ? -1 : 1
|
|
5149
|
-
};
|
|
5150
|
-
}
|
|
5389
|
+
if (limit !== void 0) joinQueryOptions.limit = limit;
|
|
5390
|
+
if (cursor != null) joinQueryOptions.uniqueStartKey = cursor;
|
|
5151
5391
|
const joinResult = await joinModelClass.query(
|
|
5152
|
-
|
|
5392
|
+
{ [joinModelLocalField]: this.id },
|
|
5153
5393
|
joinQueryOptions
|
|
5154
5394
|
);
|
|
5155
|
-
const
|
|
5156
|
-
let
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
nextCursorFromJoin = joinResults[limit - 1][joinModelOrderByField];
|
|
5163
|
-
joinResults.pop();
|
|
5164
|
-
}
|
|
5165
|
-
if (joinResults.length > 0 && !isFirstPage) {
|
|
5166
|
-
prevCursorFromJoin = joinResults[0][joinModelOrderByField];
|
|
5167
|
-
}
|
|
5168
|
-
} else {
|
|
5169
|
-
if (joinResults.length > limit) {
|
|
5170
|
-
prevCursorFromJoin = joinResults[limit - 1][joinModelOrderByField];
|
|
5171
|
-
joinResults.pop();
|
|
5172
|
-
}
|
|
5173
|
-
joinResults.reverse();
|
|
5174
|
-
if (joinResults.length > 0 && beforeCursor) {
|
|
5175
|
-
nextCursorFromJoin = joinResults[joinResults.length - 1][joinModelOrderByField];
|
|
5176
|
-
}
|
|
5177
|
-
if (joinResults.length > 0 && !beforeCursor) {
|
|
5178
|
-
if (joinResults.length === limit) {
|
|
5179
|
-
prevCursorFromJoin = joinResults[0][joinModelOrderByField];
|
|
5180
|
-
}
|
|
5181
|
-
}
|
|
5182
|
-
}
|
|
5395
|
+
const relatedIds = joinResult.data.map((r) => r[joinModelRelatedField]).filter((id) => id != null && typeof id === "string");
|
|
5396
|
+
let targetData = [];
|
|
5397
|
+
if (relatedIds.length > 0) {
|
|
5398
|
+
const targetResult = await targetModelClass.query({
|
|
5399
|
+
id: { $in: relatedIds }
|
|
5400
|
+
});
|
|
5401
|
+
targetData = targetResult.data;
|
|
5183
5402
|
}
|
|
5184
|
-
const relatedIds = joinResults.map((r) => r[joinModelRelatedField]).filter((id) => id != null && typeof id === "string");
|
|
5185
|
-
if (relatedIds.length === 0)
|
|
5186
|
-
return { data: [], nextCursor: null, prevCursor: null };
|
|
5187
|
-
const targetResult = await targetModelClass.query({
|
|
5188
|
-
id: { $in: relatedIds }
|
|
5189
|
-
});
|
|
5190
5403
|
return {
|
|
5191
|
-
data:
|
|
5192
|
-
nextCursor:
|
|
5193
|
-
prevCursor:
|
|
5404
|
+
data: targetData,
|
|
5405
|
+
nextCursor: joinResult.nextCursor,
|
|
5406
|
+
prevCursor: joinResult.prevCursor,
|
|
5407
|
+
hasMore: joinResult.hasMore
|
|
5194
5408
|
};
|
|
5195
5409
|
};
|
|
5196
5410
|
}
|
|
@@ -5314,10 +5528,12 @@ function generateHasManyThroughRemoveMethod(_sourceModelClass, config, _targetMo
|
|
|
5314
5528
|
}, `remove-join-${config.joinModel}-${this.id}-${targetId}`);
|
|
5315
5529
|
};
|
|
5316
5530
|
}
|
|
5531
|
+
var ALWAYS_PRESENT_ORDER_FIELDS;
|
|
5317
5532
|
var init_relationshipManager = __esm({
|
|
5318
5533
|
"src/models/relationshipManager.ts"() {
|
|
5319
5534
|
"use strict";
|
|
5320
5535
|
init_BaseModel();
|
|
5536
|
+
ALWAYS_PRESENT_ORDER_FIELDS = /* @__PURE__ */ new Set(["id", "type"]);
|
|
5321
5537
|
}
|
|
5322
5538
|
});
|
|
5323
5539
|
|
|
@@ -5785,7 +6001,92 @@ var init_environment = __esm({
|
|
|
5785
6001
|
});
|
|
5786
6002
|
|
|
5787
6003
|
// src/engines/SqljsEngine.ts
|
|
5788
|
-
|
|
6004
|
+
async function resolveNodeWasmPath() {
|
|
6005
|
+
if (!isNode()) {
|
|
6006
|
+
return null;
|
|
6007
|
+
}
|
|
6008
|
+
try {
|
|
6009
|
+
const cjsRequire = typeof require !== "undefined" ? require : void 0;
|
|
6010
|
+
if (cjsRequire) {
|
|
6011
|
+
return cjsRequire.resolve("sql.js/dist/sql-wasm.wasm");
|
|
6012
|
+
}
|
|
6013
|
+
} catch {
|
|
6014
|
+
}
|
|
6015
|
+
try {
|
|
6016
|
+
const metaUrl = import_meta.url;
|
|
6017
|
+
if (metaUrl) {
|
|
6018
|
+
const { createRequire } = await import(
|
|
6019
|
+
/* @vite-ignore */
|
|
6020
|
+
"module"
|
|
6021
|
+
);
|
|
6022
|
+
const req = createRequire(metaUrl);
|
|
6023
|
+
return req.resolve("sql.js/dist/sql-wasm.wasm");
|
|
6024
|
+
}
|
|
6025
|
+
} catch {
|
|
6026
|
+
}
|
|
6027
|
+
return null;
|
|
6028
|
+
}
|
|
6029
|
+
async function preflightNodeWasm(wasmPath) {
|
|
6030
|
+
if (!isNode()) {
|
|
6031
|
+
return;
|
|
6032
|
+
}
|
|
6033
|
+
if (/^[a-z]+:\/\//i.test(wasmPath)) {
|
|
6034
|
+
return;
|
|
6035
|
+
}
|
|
6036
|
+
const { existsSync } = await import(
|
|
6037
|
+
/* @vite-ignore */
|
|
6038
|
+
"fs"
|
|
6039
|
+
);
|
|
6040
|
+
if (!existsSync(wasmPath)) {
|
|
6041
|
+
throw new Error(
|
|
6042
|
+
`[SqljsEngine] sql.js wasm not found at "${wasmPath}". Pass \`locateFile\`/\`wasmURL\` pointing at sql-wasm.wasm, or install \`better-sqlite3\` and use the \`node-sqlite\` engine (see getRecommendedNodeEngine()).`
|
|
6043
|
+
);
|
|
6044
|
+
}
|
|
6045
|
+
}
|
|
6046
|
+
async function loadSqlJsModule(locateFile) {
|
|
6047
|
+
let abortReject;
|
|
6048
|
+
const toError = (reason) => reason instanceof Error ? reason : new Error(
|
|
6049
|
+
`[SqljsEngine] sql.js aborted during initialization: ${String(
|
|
6050
|
+
reason
|
|
6051
|
+
)}`
|
|
6052
|
+
);
|
|
6053
|
+
const nodeProcess = isNode() && typeof process !== "undefined" ? process : void 0;
|
|
6054
|
+
const onUnhandled = (reason) => {
|
|
6055
|
+
const err = toError(reason);
|
|
6056
|
+
if (/Aborted/.test(err.message) || /Aborted/.test(String(reason))) {
|
|
6057
|
+
abortReject?.(err);
|
|
6058
|
+
return;
|
|
6059
|
+
}
|
|
6060
|
+
if (nodeProcess && nodeProcess.listenerCount("unhandledRejection") === 1) {
|
|
6061
|
+
nodeProcess.removeListener("unhandledRejection", onUnhandled);
|
|
6062
|
+
void Promise.reject(reason);
|
|
6063
|
+
}
|
|
6064
|
+
};
|
|
6065
|
+
if (nodeProcess) {
|
|
6066
|
+
nodeProcess.on("unhandledRejection", onUnhandled);
|
|
6067
|
+
}
|
|
6068
|
+
const abortGuard = new Promise((_resolve, reject) => {
|
|
6069
|
+
abortReject = reject;
|
|
6070
|
+
});
|
|
6071
|
+
abortGuard.catch(() => {
|
|
6072
|
+
});
|
|
6073
|
+
try {
|
|
6074
|
+
const initPromise = (0, import_sql4.default)({
|
|
6075
|
+
locateFile,
|
|
6076
|
+
// Layer 1: emscripten onAbort.
|
|
6077
|
+
onAbort: (reason) => abortReject?.(toError(reason))
|
|
6078
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6079
|
+
});
|
|
6080
|
+
return await Promise.race([initPromise, abortGuard]);
|
|
6081
|
+
} finally {
|
|
6082
|
+
if (nodeProcess) {
|
|
6083
|
+
setTimeout(() => {
|
|
6084
|
+
nodeProcess.removeListener("unhandledRejection", onUnhandled);
|
|
6085
|
+
}, 0);
|
|
6086
|
+
}
|
|
6087
|
+
}
|
|
6088
|
+
}
|
|
6089
|
+
var import_sql4, import_async_mutex, import_meta, SQL_WASM_URL, SQL_WASM_FILENAME, TransactionalSQLJSOperations, SqljsEngine;
|
|
5789
6090
|
var init_SqljsEngine = __esm({
|
|
5790
6091
|
"src/engines/SqljsEngine.ts"() {
|
|
5791
6092
|
"use strict";
|
|
@@ -5793,7 +6094,10 @@ var init_SqljsEngine = __esm({
|
|
|
5793
6094
|
init_BaseModel();
|
|
5794
6095
|
import_async_mutex = require("async-mutex");
|
|
5795
6096
|
init_sql();
|
|
6097
|
+
init_environment();
|
|
6098
|
+
import_meta = {};
|
|
5796
6099
|
SQL_WASM_URL = "/sql-wasm.wasm";
|
|
6100
|
+
SQL_WASM_FILENAME = "sql-wasm.wasm";
|
|
5797
6101
|
TransactionalSQLJSOperations = class {
|
|
5798
6102
|
db;
|
|
5799
6103
|
engine;
|
|
@@ -5859,22 +6163,37 @@ var init_SqljsEngine = __esm({
|
|
|
5859
6163
|
}
|
|
5860
6164
|
async initialize(engineOptions) {
|
|
5861
6165
|
Logger.info("[SqljsEngine] Initializing SQL.js engine...");
|
|
6166
|
+
const loadingModuleThisCall = !_SqljsEngine.SQL;
|
|
5862
6167
|
try {
|
|
5863
6168
|
if (!_SqljsEngine.SQL) {
|
|
5864
|
-
|
|
6169
|
+
let locateFileConfig;
|
|
6170
|
+
if (engineOptions?.locateFile) {
|
|
6171
|
+
locateFileConfig = engineOptions.locateFile;
|
|
6172
|
+
} else if (engineOptions?.wasmURL) {
|
|
6173
|
+
const url = engineOptions.wasmURL;
|
|
6174
|
+
locateFileConfig = (_file) => url;
|
|
6175
|
+
} else {
|
|
6176
|
+
const nodeWasmPath = await resolveNodeWasmPath();
|
|
6177
|
+
const resolved = nodeWasmPath ?? SQL_WASM_URL;
|
|
6178
|
+
locateFileConfig = (_file) => resolved;
|
|
6179
|
+
}
|
|
6180
|
+
const wasmPath = locateFileConfig(SQL_WASM_FILENAME);
|
|
5865
6181
|
Logger.debug(
|
|
5866
6182
|
"[SqljsEngine] Attempting to load SQL.js WASM from:",
|
|
5867
|
-
|
|
6183
|
+
wasmPath
|
|
5868
6184
|
);
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
6185
|
+
await preflightNodeWasm(wasmPath);
|
|
6186
|
+
const SQL = await loadSqlJsModule(locateFileConfig);
|
|
6187
|
+
_SqljsEngine.SQL = SQL;
|
|
5872
6188
|
Logger.info("[SqljsEngine] SQL.js WASM loaded successfully.");
|
|
5873
6189
|
}
|
|
5874
6190
|
this.db = new _SqljsEngine.SQL.Database();
|
|
5875
6191
|
Logger.info("[SqljsEngine] SQL.js Database initialized in memory.");
|
|
5876
6192
|
this.updateTableNames();
|
|
5877
6193
|
} catch (error) {
|
|
6194
|
+
if (loadingModuleThisCall) {
|
|
6195
|
+
_SqljsEngine.SQL = null;
|
|
6196
|
+
}
|
|
5878
6197
|
Logger.error("[SqljsEngine] Error during SQL.js initialization:", error);
|
|
5879
6198
|
throw error;
|
|
5880
6199
|
}
|
|
@@ -6856,12 +7175,14 @@ __export(index_exports, {
|
|
|
6856
7175
|
attachAndRegisterModel: () => attachAndRegisterModel,
|
|
6857
7176
|
attachSchemaToClass: () => attachSchemaToClass,
|
|
6858
7177
|
autoRegisterModel: () => autoRegisterModel,
|
|
7178
|
+
buildUniqueKey: () => buildUniqueKey,
|
|
6859
7179
|
clearMetaSyncCache: () => clearMetaSyncCache,
|
|
6860
7180
|
createModelClass: () => createModelClass,
|
|
6861
7181
|
defineModelSchema: () => defineModelSchema,
|
|
6862
7182
|
discoverModelNames: () => discoverModelNames,
|
|
6863
7183
|
discoverSchema: () => discoverSchema,
|
|
6864
7184
|
dumpYDocToPlain: () => dumpYDocToPlain,
|
|
7185
|
+
fieldUniqueConstraintName: () => fieldUniqueConstraintName,
|
|
6865
7186
|
generateULID: () => generateULID,
|
|
6866
7187
|
inferFieldType: () => inferFieldType,
|
|
6867
7188
|
initJsBao: () => initJsBao,
|
|
@@ -6872,7 +7193,8 @@ __export(index_exports, {
|
|
|
6872
7193
|
schemaToToml: () => schemaToToml,
|
|
6873
7194
|
summarizePlainYDoc: () => summarizePlainYDoc,
|
|
6874
7195
|
syncInferredMeta: () => syncInferredMeta,
|
|
6875
|
-
syncModelMeta: () => syncModelMeta
|
|
7196
|
+
syncModelMeta: () => syncModelMeta,
|
|
7197
|
+
uniqueIndexMapName: () => uniqueIndexMapName
|
|
6876
7198
|
});
|
|
6877
7199
|
module.exports = __toCommonJS(index_exports);
|
|
6878
7200
|
|
|
@@ -7095,6 +7417,7 @@ init_StringSet();
|
|
|
7095
7417
|
// src/models/schema.ts
|
|
7096
7418
|
init_BaseModel();
|
|
7097
7419
|
init_ModelRegistry();
|
|
7420
|
+
init_uniqueIndex();
|
|
7098
7421
|
function defineModelSchema(input) {
|
|
7099
7422
|
const { name, fields } = input;
|
|
7100
7423
|
const options = {
|
|
@@ -7167,7 +7490,7 @@ function resolveUniqueConstraints(modelName, fields, customConstraints) {
|
|
|
7167
7490
|
for (const [fieldName, options] of fields.entries()) {
|
|
7168
7491
|
if (options.unique) {
|
|
7169
7492
|
resolved.push({
|
|
7170
|
-
name:
|
|
7493
|
+
name: fieldUniqueConstraintName(modelName, fieldName),
|
|
7171
7494
|
fields: [fieldName]
|
|
7172
7495
|
});
|
|
7173
7496
|
}
|
|
@@ -7494,7 +7817,7 @@ async function loadSchemaFromToml(filePath, options = {}) {
|
|
|
7494
7817
|
}
|
|
7495
7818
|
|
|
7496
7819
|
// src/utils/yDocSchema.ts
|
|
7497
|
-
var
|
|
7820
|
+
var Y6 = __toESM(require("yjs"), 1);
|
|
7498
7821
|
init_yjsValues();
|
|
7499
7822
|
function discoverSchema(yDoc) {
|
|
7500
7823
|
const models = {};
|
|
@@ -7529,7 +7852,7 @@ function discoverModelNames(yDoc) {
|
|
|
7529
7852
|
function materializeMap(yDoc, key) {
|
|
7530
7853
|
try {
|
|
7531
7854
|
const map = yDoc.getMap(key);
|
|
7532
|
-
return map instanceof
|
|
7855
|
+
return map instanceof Y6.Map ? map : null;
|
|
7533
7856
|
} catch {
|
|
7534
7857
|
return null;
|
|
7535
7858
|
}
|
|
@@ -7539,11 +7862,11 @@ function readModelMeta(metaMap) {
|
|
|
7539
7862
|
let constraints;
|
|
7540
7863
|
let relationships;
|
|
7541
7864
|
for (const [key, value] of metaMap.entries()) {
|
|
7542
|
-
if (key === "_constraints" && value instanceof
|
|
7865
|
+
if (key === "_constraints" && value instanceof Y6.Map) {
|
|
7543
7866
|
constraints = readConstraints(value);
|
|
7544
|
-
} else if (key === "_relationships" && value instanceof
|
|
7867
|
+
} else if (key === "_relationships" && value instanceof Y6.Map) {
|
|
7545
7868
|
relationships = readRelationships(value);
|
|
7546
|
-
} else if (value instanceof
|
|
7869
|
+
} else if (value instanceof Y6.Map) {
|
|
7547
7870
|
fields[key] = readFieldMeta(value);
|
|
7548
7871
|
}
|
|
7549
7872
|
}
|
|
@@ -7578,7 +7901,7 @@ function inferModelFromData(dataMap) {
|
|
|
7578
7901
|
const fields = {};
|
|
7579
7902
|
let sampled = 0;
|
|
7580
7903
|
for (const [_recordId, recordValue] of dataMap.entries()) {
|
|
7581
|
-
if (!(recordValue instanceof
|
|
7904
|
+
if (!(recordValue instanceof Y6.Map)) continue;
|
|
7582
7905
|
if (++sampled > 5) break;
|
|
7583
7906
|
for (const [fieldName, value] of recordValue.entries()) {
|
|
7584
7907
|
if (fieldName.startsWith("_")) continue;
|
|
@@ -7606,7 +7929,7 @@ function inferTypeFromValue(value) {
|
|
|
7606
7929
|
function readConstraints(constraintsMap) {
|
|
7607
7930
|
const out = {};
|
|
7608
7931
|
for (const [name, value] of constraintsMap.entries()) {
|
|
7609
|
-
if (!(value instanceof
|
|
7932
|
+
if (!(value instanceof Y6.Map)) continue;
|
|
7610
7933
|
let fields = [];
|
|
7611
7934
|
const rawFields = value.get("fields");
|
|
7612
7935
|
if (typeof rawFields === "string") {
|
|
@@ -7625,7 +7948,7 @@ function readConstraints(constraintsMap) {
|
|
|
7625
7948
|
function readRelationships(relsMap) {
|
|
7626
7949
|
const out = {};
|
|
7627
7950
|
for (const [name, value] of relsMap.entries()) {
|
|
7628
|
-
if (!(value instanceof
|
|
7951
|
+
if (!(value instanceof Y6.Map)) continue;
|
|
7629
7952
|
const rel = {};
|
|
7630
7953
|
for (const [k, v] of value.entries()) {
|
|
7631
7954
|
rel[k] = v;
|
|
@@ -7699,19 +8022,20 @@ function schemaToToml(schema) {
|
|
|
7699
8022
|
}
|
|
7700
8023
|
|
|
7701
8024
|
// src/index.ts
|
|
8025
|
+
init_uniqueIndex();
|
|
7702
8026
|
init_BaseModel();
|
|
7703
8027
|
|
|
7704
8028
|
// src/utils/yDocDump.ts
|
|
7705
|
-
var
|
|
8029
|
+
var Y7 = __toESM(require("yjs"), 1);
|
|
7706
8030
|
function toPlain(value) {
|
|
7707
|
-
if (value instanceof
|
|
8031
|
+
if (value instanceof Y7.Map) {
|
|
7708
8032
|
const obj = {};
|
|
7709
8033
|
value.forEach((v, k) => {
|
|
7710
8034
|
obj[k] = toPlain(v);
|
|
7711
8035
|
});
|
|
7712
8036
|
return obj;
|
|
7713
8037
|
}
|
|
7714
|
-
if (value instanceof
|
|
8038
|
+
if (value instanceof Y7.Array) {
|
|
7715
8039
|
return value.toArray().map((item) => toPlain(item));
|
|
7716
8040
|
}
|
|
7717
8041
|
return value;
|
|
@@ -7720,7 +8044,7 @@ function dumpYDocToPlain(yDoc, options = {}) {
|
|
|
7720
8044
|
const result = {};
|
|
7721
8045
|
const includeIndexes = !!options.includeIndexes;
|
|
7722
8046
|
yDoc.share.forEach((type, name) => {
|
|
7723
|
-
if (!(type instanceof
|
|
8047
|
+
if (!(type instanceof Y7.Map)) return;
|
|
7724
8048
|
if (!includeIndexes && name.startsWith("_uniqueIdx_")) return;
|
|
7725
8049
|
const records = {};
|
|
7726
8050
|
type.forEach((recordValue, recordId) => {
|
|
@@ -7769,12 +8093,14 @@ function summarizePlainYDoc(dump) {
|
|
|
7769
8093
|
attachAndRegisterModel,
|
|
7770
8094
|
attachSchemaToClass,
|
|
7771
8095
|
autoRegisterModel,
|
|
8096
|
+
buildUniqueKey,
|
|
7772
8097
|
clearMetaSyncCache,
|
|
7773
8098
|
createModelClass,
|
|
7774
8099
|
defineModelSchema,
|
|
7775
8100
|
discoverModelNames,
|
|
7776
8101
|
discoverSchema,
|
|
7777
8102
|
dumpYDocToPlain,
|
|
8103
|
+
fieldUniqueConstraintName,
|
|
7778
8104
|
generateULID,
|
|
7779
8105
|
inferFieldType,
|
|
7780
8106
|
initJsBao,
|
|
@@ -7785,5 +8111,6 @@ function summarizePlainYDoc(dump) {
|
|
|
7785
8111
|
schemaToToml,
|
|
7786
8112
|
summarizePlainYDoc,
|
|
7787
8113
|
syncInferredMeta,
|
|
7788
|
-
syncModelMeta
|
|
8114
|
+
syncModelMeta,
|
|
8115
|
+
uniqueIndexMapName
|
|
7789
8116
|
});
|