@typicalday/firegraph 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -3
- package/dist/{backend-DuvHGgK1.d.cts → backend-BpYLdwCW.d.cts} +1 -1
- package/dist/{backend-DuvHGgK1.d.ts → backend-BpYLdwCW.d.ts} +1 -1
- package/dist/backend-CvImIwTY.d.cts +137 -0
- package/dist/backend-YH5HtawN.d.ts +137 -0
- package/dist/backend.cjs +2 -3
- package/dist/backend.cjs.map +1 -1
- package/dist/backend.d.cts +2 -2
- package/dist/backend.d.ts +2 -2
- package/dist/backend.js +1 -1
- package/dist/{chunk-WRTFC5NG.js → chunk-5HIRYV2S.js} +13 -36
- package/dist/chunk-5HIRYV2S.js.map +1 -0
- package/dist/{chunk-PAD7WFFU.js → chunk-7IEZ6IYY.js} +36 -10
- package/dist/chunk-7IEZ6IYY.js.map +1 -0
- package/dist/chunk-FODIMIWY.js +721 -0
- package/dist/chunk-FODIMIWY.js.map +1 -0
- package/dist/chunk-NGAJCALM.js +34 -0
- package/dist/chunk-NGAJCALM.js.map +1 -0
- package/dist/{chunk-TK64DNVK.js → chunk-SIHE4UY4.js} +3 -4
- package/dist/chunk-SIHE4UY4.js.map +1 -0
- package/dist/chunk-ULRDQ6HZ.js +862 -0
- package/dist/chunk-ULRDQ6HZ.js.map +1 -0
- package/dist/{client-BKi3vk0Q.d.ts → client-B5o39X79.d.ts} +1 -1
- package/dist/{client-BrsaXtDV.d.cts → client-BGHwxwPg.d.cts} +1 -1
- package/dist/{client-Bk2Cm6xv.d.cts → client-DoyEdJ5w.d.cts} +1 -1
- package/dist/{client-Bk2Cm6xv.d.ts → client-DoyEdJ5w.d.ts} +1 -1
- package/dist/cloudflare/index.cjs +155 -165
- package/dist/cloudflare/index.cjs.map +1 -1
- package/dist/cloudflare/index.d.cts +73 -70
- package/dist/cloudflare/index.d.ts +73 -70
- package/dist/cloudflare/index.js +54 -589
- package/dist/cloudflare/index.js.map +1 -1
- package/dist/codegen/index.d.cts +1 -1
- package/dist/codegen/index.d.ts +1 -1
- package/dist/firestore-enterprise/index.cjs +42 -40
- package/dist/firestore-enterprise/index.cjs.map +1 -1
- package/dist/firestore-enterprise/index.d.cts +3 -3
- package/dist/firestore-enterprise/index.d.ts +3 -3
- package/dist/firestore-enterprise/index.js +19 -35
- package/dist/firestore-enterprise/index.js.map +1 -1
- package/dist/firestore-standard/index.cjs +34 -37
- package/dist/firestore-standard/index.cjs.map +1 -1
- package/dist/firestore-standard/index.d.cts +3 -3
- package/dist/firestore-standard/index.d.ts +3 -3
- package/dist/firestore-standard/index.js +10 -34
- package/dist/firestore-standard/index.js.map +1 -1
- package/dist/index.cjs +2 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/query-client/index.d.cts +2 -2
- package/dist/query-client/index.d.ts +2 -2
- package/dist/{registry-Bc7h6WTM.d.cts → registry-BGh7Jqpb.d.cts} +2 -2
- package/dist/{registry-C2KUPVZj.d.ts → registry-tKTb5Kx1.d.ts} +2 -2
- package/dist/sqlite/index.cjs +585 -378
- package/dist/sqlite/index.cjs.map +1 -1
- package/dist/sqlite/index.d.cts +4 -110
- package/dist/sqlite/index.d.ts +4 -110
- package/dist/sqlite/index.js +7 -1144
- package/dist/sqlite/index.js.map +1 -1
- package/dist/sqlite/local.cjs +1835 -0
- package/dist/sqlite/local.cjs.map +1 -0
- package/dist/sqlite/local.d.cts +83 -0
- package/dist/sqlite/local.d.ts +83 -0
- package/dist/sqlite/local.js +121 -0
- package/dist/sqlite/local.js.map +1 -0
- package/package.json +15 -1
- package/dist/chunk-4MMQ5W74.js +0 -288
- package/dist/chunk-4MMQ5W74.js.map +0 -1
- package/dist/chunk-PAD7WFFU.js.map +0 -1
- package/dist/chunk-TK64DNVK.js.map +0 -1
- package/dist/chunk-WRTFC5NG.js.map +0 -1
|
@@ -172,7 +172,7 @@ __export(cloudflare_exports, {
|
|
|
172
172
|
FiregraphDO: () => FiregraphDO,
|
|
173
173
|
META_EDGE_TYPE: () => META_EDGE_TYPE,
|
|
174
174
|
META_NODE_TYPE: () => META_NODE_TYPE,
|
|
175
|
-
buildDOSchemaStatements: () =>
|
|
175
|
+
buildDOSchemaStatements: () => buildSchemaStatements,
|
|
176
176
|
createCapabilities: () => createCapabilities,
|
|
177
177
|
createDOClient: () => createDOClient,
|
|
178
178
|
createMergedRegistry: () => createMergedRegistry,
|
|
@@ -281,6 +281,31 @@ var BUILTIN_FIELDS = /* @__PURE__ */ new Set([
|
|
|
281
281
|
]);
|
|
282
282
|
var SHARD_SEPARATOR = ":";
|
|
283
283
|
|
|
284
|
+
// src/timestamp.ts
|
|
285
|
+
var GraphTimestampImpl = class _GraphTimestampImpl {
|
|
286
|
+
constructor(seconds, nanoseconds) {
|
|
287
|
+
this.seconds = seconds;
|
|
288
|
+
this.nanoseconds = nanoseconds;
|
|
289
|
+
}
|
|
290
|
+
toDate() {
|
|
291
|
+
return new Date(this.toMillis());
|
|
292
|
+
}
|
|
293
|
+
toMillis() {
|
|
294
|
+
return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
|
|
295
|
+
}
|
|
296
|
+
toJSON() {
|
|
297
|
+
return { seconds: this.seconds, nanoseconds: this.nanoseconds };
|
|
298
|
+
}
|
|
299
|
+
static fromMillis(ms) {
|
|
300
|
+
const seconds = Math.floor(ms / 1e3);
|
|
301
|
+
const nanoseconds = (ms - seconds * 1e3) * 1e6;
|
|
302
|
+
return new _GraphTimestampImpl(seconds, nanoseconds);
|
|
303
|
+
}
|
|
304
|
+
static now() {
|
|
305
|
+
return _GraphTimestampImpl.fromMillis(Date.now());
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
284
309
|
// src/internal/sqlite-data-ops.ts
|
|
285
310
|
var FIRESTORE_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
286
311
|
"Timestamp",
|
|
@@ -309,6 +334,9 @@ function validateJsonPathKey(key, backendLabel) {
|
|
|
309
334
|
);
|
|
310
335
|
}
|
|
311
336
|
}
|
|
337
|
+
function buildJsonPath(segments) {
|
|
338
|
+
return "$" + segments.map((seg) => "." + JSON.stringify(seg)).join("");
|
|
339
|
+
}
|
|
312
340
|
function jsonBind(value, backendLabel) {
|
|
313
341
|
if (value === void 0) return "null";
|
|
314
342
|
if (value !== null && typeof value === "object") {
|
|
@@ -332,16 +360,14 @@ function compileDataOpsExpr(ops, base, params, backendLabel) {
|
|
|
332
360
|
const placeholders = deletes.map(() => "?").join(", ");
|
|
333
361
|
expr = `json_remove(${expr}, ${placeholders})`;
|
|
334
362
|
for (const op of deletes) {
|
|
335
|
-
|
|
336
|
-
params.push(`$.${op.path.join(".")}`);
|
|
363
|
+
params.push(buildJsonPath(op.path));
|
|
337
364
|
}
|
|
338
365
|
}
|
|
339
366
|
if (sets.length > 0) {
|
|
340
367
|
const pieces = sets.map(() => "?, json(?)").join(", ");
|
|
341
368
|
expr = `json_set(${expr}, ${pieces})`;
|
|
342
369
|
for (const op of sets) {
|
|
343
|
-
|
|
344
|
-
params.push(`$.${op.path.join(".")}`);
|
|
370
|
+
params.push(buildJsonPath(op.path));
|
|
345
371
|
params.push(jsonBind(op.value, backendLabel));
|
|
346
372
|
}
|
|
347
373
|
}
|
|
@@ -384,7 +410,6 @@ function isTerminalValue(value) {
|
|
|
384
410
|
if (ctor && typeof ctor.name === "string" && FIRESTORE_TERMINAL_CTOR.has(ctor.name)) return true;
|
|
385
411
|
return true;
|
|
386
412
|
}
|
|
387
|
-
var SAFE_KEY_RE = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
388
413
|
function assertUpdatePayloadExclusive(update) {
|
|
389
414
|
if (update.replaceData !== void 0 && update.dataOps !== void 0) {
|
|
390
415
|
throw new Error(
|
|
@@ -423,9 +448,9 @@ function walkForDeleteSentinels(node, path, parent, visit) {
|
|
|
423
448
|
}
|
|
424
449
|
function assertSafePath(path) {
|
|
425
450
|
for (const seg of path) {
|
|
426
|
-
if (
|
|
451
|
+
if (seg === "") {
|
|
427
452
|
throw new Error(
|
|
428
|
-
`firegraph:
|
|
453
|
+
`firegraph: empty object key at path ${path.map((p) => JSON.stringify(p)).join(" > ")}. Object keys in update payloads must be non-empty.`
|
|
429
454
|
);
|
|
430
455
|
}
|
|
431
456
|
}
|
|
@@ -571,31 +596,6 @@ function formatTagValue(value) {
|
|
|
571
596
|
return typeof value;
|
|
572
597
|
}
|
|
573
598
|
|
|
574
|
-
// src/timestamp.ts
|
|
575
|
-
var GraphTimestampImpl = class _GraphTimestampImpl {
|
|
576
|
-
constructor(seconds, nanoseconds) {
|
|
577
|
-
this.seconds = seconds;
|
|
578
|
-
this.nanoseconds = nanoseconds;
|
|
579
|
-
}
|
|
580
|
-
toDate() {
|
|
581
|
-
return new Date(this.toMillis());
|
|
582
|
-
}
|
|
583
|
-
toMillis() {
|
|
584
|
-
return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
|
|
585
|
-
}
|
|
586
|
-
toJSON() {
|
|
587
|
-
return { seconds: this.seconds, nanoseconds: this.nanoseconds };
|
|
588
|
-
}
|
|
589
|
-
static fromMillis(ms) {
|
|
590
|
-
const seconds = Math.floor(ms / 1e3);
|
|
591
|
-
const nanoseconds = (ms - seconds * 1e3) * 1e6;
|
|
592
|
-
return new _GraphTimestampImpl(seconds, nanoseconds);
|
|
593
|
-
}
|
|
594
|
-
static now() {
|
|
595
|
-
return _GraphTimestampImpl.fromMillis(Date.now());
|
|
596
|
-
}
|
|
597
|
-
};
|
|
598
|
-
|
|
599
599
|
// src/default-indexes.ts
|
|
600
600
|
var DEFAULT_CORE_INDEXES = Object.freeze([
|
|
601
601
|
{ fields: ["aUid"] },
|
|
@@ -640,9 +640,9 @@ function normalizeFields(fields) {
|
|
|
640
640
|
return { path: f.path, desc: !!f.desc };
|
|
641
641
|
});
|
|
642
642
|
}
|
|
643
|
-
function specFingerprint(spec
|
|
643
|
+
function specFingerprint(spec) {
|
|
644
644
|
const normalized = {
|
|
645
|
-
lead:
|
|
645
|
+
lead: [],
|
|
646
646
|
fields: normalizeFields(spec.fields),
|
|
647
647
|
where: spec.where ?? ""
|
|
648
648
|
};
|
|
@@ -673,17 +673,14 @@ function compileFieldExpr(path, fieldToColumn) {
|
|
|
673
673
|
);
|
|
674
674
|
}
|
|
675
675
|
function buildIndexDDL(spec, options) {
|
|
676
|
-
const { table, fieldToColumn
|
|
676
|
+
const { table, fieldToColumn } = options;
|
|
677
677
|
if (!spec.fields || spec.fields.length === 0) {
|
|
678
678
|
throw new FiregraphError("IndexSpec.fields must be a non-empty array", "INVALID_INDEX");
|
|
679
679
|
}
|
|
680
680
|
const normalized = normalizeFields(spec.fields);
|
|
681
|
-
const hash = specFingerprint(spec
|
|
681
|
+
const hash = specFingerprint(spec);
|
|
682
682
|
const indexName = `${table}_idx_${hash}`;
|
|
683
683
|
const cols = [];
|
|
684
|
-
for (const col of leadingColumns) {
|
|
685
|
-
cols.push(quoteIdent(col));
|
|
686
|
-
}
|
|
687
684
|
for (const f of normalized) {
|
|
688
685
|
const expr = compileFieldExpr(f.path, fieldToColumn);
|
|
689
686
|
cols.push(f.desc ? `${expr} DESC` : expr);
|
|
@@ -694,11 +691,11 @@ function buildIndexDDL(spec, options) {
|
|
|
694
691
|
}
|
|
695
692
|
return ddl;
|
|
696
693
|
}
|
|
697
|
-
function dedupeIndexSpecs(specs
|
|
694
|
+
function dedupeIndexSpecs(specs) {
|
|
698
695
|
const seen = /* @__PURE__ */ new Set();
|
|
699
696
|
const out = [];
|
|
700
697
|
for (const spec of specs) {
|
|
701
|
-
const fp = specFingerprint(spec
|
|
698
|
+
const fp = specFingerprint(spec);
|
|
702
699
|
if (seen.has(fp)) continue;
|
|
703
700
|
seen.add(fp);
|
|
704
701
|
out.push(spec);
|
|
@@ -706,8 +703,8 @@ function dedupeIndexSpecs(specs, leadingColumns = []) {
|
|
|
706
703
|
return out;
|
|
707
704
|
}
|
|
708
705
|
|
|
709
|
-
// src/
|
|
710
|
-
var
|
|
706
|
+
// src/internal/sqlite-schema.ts
|
|
707
|
+
var FIELD_TO_COLUMN = {
|
|
711
708
|
aType: "a_type",
|
|
712
709
|
aUid: "a_uid",
|
|
713
710
|
axbType: "axb_type",
|
|
@@ -717,21 +714,8 @@ var DO_FIELD_TO_COLUMN = {
|
|
|
717
714
|
createdAt: "created_at",
|
|
718
715
|
updatedAt: "updated_at"
|
|
719
716
|
};
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
if (!IDENT_RE2.test(name)) {
|
|
723
|
-
throw new Error(`Invalid SQL identifier: ${name}. Must match /^[A-Za-z_][A-Za-z0-9_]*$/.`);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
function quoteDOIdent(name) {
|
|
727
|
-
validateDOTableName(name);
|
|
728
|
-
return `"${name}"`;
|
|
729
|
-
}
|
|
730
|
-
function quoteDOColumnAlias(label) {
|
|
731
|
-
return `"${label.replace(/"/g, '""')}"`;
|
|
732
|
-
}
|
|
733
|
-
function buildDOSchemaStatements(table, options = {}) {
|
|
734
|
-
const t = quoteDOIdent(table);
|
|
717
|
+
function buildSchemaStatements(table, options = {}) {
|
|
718
|
+
const t = quoteIdent2(table);
|
|
735
719
|
const statements = [
|
|
736
720
|
`CREATE TABLE IF NOT EXISTS ${t} (
|
|
737
721
|
doc_id TEXT NOT NULL PRIMARY KEY,
|
|
@@ -750,33 +734,42 @@ function buildDOSchemaStatements(table, options = {}) {
|
|
|
750
734
|
const fromRegistry = options.registry?.entries().flatMap((e) => e.indexes ?? []) ?? [];
|
|
751
735
|
const deduped = dedupeIndexSpecs([...core, ...fromRegistry]);
|
|
752
736
|
for (const spec of deduped) {
|
|
753
|
-
statements.push(buildIndexDDL(spec, { table, fieldToColumn:
|
|
737
|
+
statements.push(buildIndexDDL(spec, { table, fieldToColumn: FIELD_TO_COLUMN }));
|
|
754
738
|
}
|
|
755
739
|
return statements;
|
|
756
740
|
}
|
|
741
|
+
function quoteIdent2(name) {
|
|
742
|
+
validateTableName(name);
|
|
743
|
+
return `"${name}"`;
|
|
744
|
+
}
|
|
745
|
+
function validateTableName(name) {
|
|
746
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
747
|
+
throw new Error(`Invalid SQL identifier: ${name}. Must match /^[A-Za-z_][A-Za-z0-9_]*$/.`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function quoteColumnAlias(label) {
|
|
751
|
+
return `"${label.replace(/"/g, '""')}"`;
|
|
752
|
+
}
|
|
757
753
|
|
|
758
|
-
// src/
|
|
759
|
-
var
|
|
760
|
-
var
|
|
754
|
+
// src/internal/sqlite-sql.ts
|
|
755
|
+
var BACKEND_LABEL = "SQLite";
|
|
756
|
+
var BACKEND_ERR_LABEL = "SQLite backend";
|
|
761
757
|
function compileFieldRef(field) {
|
|
762
|
-
const column =
|
|
758
|
+
const column = FIELD_TO_COLUMN[field];
|
|
763
759
|
if (column) {
|
|
764
|
-
return { expr:
|
|
760
|
+
return { expr: quoteIdent2(column) };
|
|
765
761
|
}
|
|
766
762
|
if (field.startsWith("data.")) {
|
|
767
763
|
const suffix = field.slice(5);
|
|
768
764
|
for (const part of suffix.split(".")) {
|
|
769
|
-
validateJsonPathKey(part,
|
|
765
|
+
validateJsonPathKey(part, BACKEND_ERR_LABEL);
|
|
770
766
|
}
|
|
771
767
|
return { expr: `json_extract("data", '$.${suffix}')` };
|
|
772
768
|
}
|
|
773
769
|
if (field === "data") {
|
|
774
770
|
return { expr: `json_extract("data", '$')` };
|
|
775
771
|
}
|
|
776
|
-
throw new FiregraphError(
|
|
777
|
-
`DO SQLite backend cannot resolve filter field: ${field}`,
|
|
778
|
-
"INVALID_QUERY"
|
|
779
|
-
);
|
|
772
|
+
throw new FiregraphError(`SQLite backend cannot resolve filter field: ${field}`, "INVALID_QUERY");
|
|
780
773
|
}
|
|
781
774
|
function bindValue(value) {
|
|
782
775
|
if (value === null || value === void 0) return null;
|
|
@@ -788,7 +781,7 @@ function bindValue(value) {
|
|
|
788
781
|
const firestoreType = isFirestoreSpecialType(value);
|
|
789
782
|
if (firestoreType) {
|
|
790
783
|
throw new FiregraphError(
|
|
791
|
-
`
|
|
784
|
+
`SQLite backend cannot bind a Firestore ${firestoreType} value \u2014 JSON serialization would silently drop fields and the resulting bind would never match a stored row. Convert to a primitive (e.g. \`ts.toMillis()\` for Timestamp) before filtering or updating.`,
|
|
792
785
|
"INVALID_QUERY"
|
|
793
786
|
);
|
|
794
787
|
}
|
|
@@ -841,7 +834,7 @@ function compileFilter(filter, params) {
|
|
|
841
834
|
}
|
|
842
835
|
default:
|
|
843
836
|
throw new FiregraphError(
|
|
844
|
-
`
|
|
837
|
+
`SQLite backend does not support filter operator: ${String(filter.op)}`,
|
|
845
838
|
"INVALID_QUERY"
|
|
846
839
|
);
|
|
847
840
|
}
|
|
@@ -864,22 +857,22 @@ function compileLimit(options, params) {
|
|
|
864
857
|
params.push(options.limit);
|
|
865
858
|
return ` LIMIT ?`;
|
|
866
859
|
}
|
|
867
|
-
function
|
|
860
|
+
function compileSelect(table, filters, options) {
|
|
868
861
|
const params = [];
|
|
869
862
|
const conditions = [];
|
|
870
863
|
for (const f of filters) {
|
|
871
864
|
conditions.push(compileFilter(f, params));
|
|
872
865
|
}
|
|
873
866
|
const where = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
874
|
-
let sql = `SELECT * FROM ${
|
|
867
|
+
let sql = `SELECT * FROM ${quoteIdent2(table)}${where}`;
|
|
875
868
|
sql += compileOrderBy(options, params);
|
|
876
869
|
sql += compileLimit(options, params);
|
|
877
870
|
return { sql, params };
|
|
878
871
|
}
|
|
879
|
-
function
|
|
872
|
+
function compileExpand(table, params) {
|
|
880
873
|
if (params.sources.length === 0) {
|
|
881
874
|
throw new FiregraphError(
|
|
882
|
-
"
|
|
875
|
+
"compileExpand requires a non-empty sources list \u2014 empty IN () is invalid SQL.",
|
|
883
876
|
"INVALID_QUERY"
|
|
884
877
|
);
|
|
885
878
|
}
|
|
@@ -906,7 +899,7 @@ function compileDOExpand(table, params) {
|
|
|
906
899
|
if (params.axbType === NODE_RELATION) {
|
|
907
900
|
conditions.push(`${aUidCol} != ${bUidCol}`);
|
|
908
901
|
}
|
|
909
|
-
let sql = `SELECT * FROM ${
|
|
902
|
+
let sql = `SELECT * FROM ${quoteIdent2(table)} WHERE ${conditions.join(" AND ")}`;
|
|
910
903
|
if (params.orderBy) {
|
|
911
904
|
sql += compileOrderBy({ orderBy: params.orderBy }, sqlParams);
|
|
912
905
|
}
|
|
@@ -917,10 +910,10 @@ function compileDOExpand(table, params) {
|
|
|
917
910
|
}
|
|
918
911
|
return { sql, params: sqlParams };
|
|
919
912
|
}
|
|
920
|
-
function
|
|
913
|
+
function compileExpandHydrate(table, targetUids) {
|
|
921
914
|
if (targetUids.length === 0) {
|
|
922
915
|
throw new FiregraphError(
|
|
923
|
-
"
|
|
916
|
+
"compileExpandHydrate requires a non-empty target list \u2014 empty IN () is invalid SQL.",
|
|
924
917
|
"INVALID_QUERY"
|
|
925
918
|
);
|
|
926
919
|
}
|
|
@@ -931,25 +924,25 @@ function compileDOExpandHydrate(table, targetUids) {
|
|
|
931
924
|
const bUidCol = compileFieldRef("bUid").expr;
|
|
932
925
|
const axbTypeCol = compileFieldRef("axbType").expr;
|
|
933
926
|
return {
|
|
934
|
-
sql: `SELECT * FROM ${
|
|
927
|
+
sql: `SELECT * FROM ${quoteIdent2(table)} WHERE ${axbTypeCol} = ? AND ${aUidCol} = ${bUidCol} AND ${bUidCol} IN (${placeholders})`,
|
|
935
928
|
params: sqlParams
|
|
936
929
|
};
|
|
937
930
|
}
|
|
938
|
-
function
|
|
931
|
+
function compileSelectByDocId(table, docId) {
|
|
939
932
|
return {
|
|
940
|
-
sql: `SELECT * FROM ${
|
|
933
|
+
sql: `SELECT * FROM ${quoteIdent2(table)} WHERE "doc_id" = ? LIMIT 1`,
|
|
941
934
|
params: [docId]
|
|
942
935
|
};
|
|
943
936
|
}
|
|
944
|
-
function
|
|
945
|
-
if (field in
|
|
937
|
+
function normalizeProjectionField(field) {
|
|
938
|
+
if (field in FIELD_TO_COLUMN) return field;
|
|
946
939
|
if (field === "data" || field.startsWith("data.")) return field;
|
|
947
940
|
return `data.${field}`;
|
|
948
941
|
}
|
|
949
|
-
function
|
|
942
|
+
function compileFindEdgesProjected(table, select, filters, options) {
|
|
950
943
|
if (select.length === 0) {
|
|
951
944
|
throw new FiregraphError(
|
|
952
|
-
"
|
|
945
|
+
"compileFindEdgesProjected requires a non-empty select list \u2014 an empty projection has no SQL representation distinct from `findEdges`.",
|
|
953
946
|
"INVALID_QUERY"
|
|
954
947
|
);
|
|
955
948
|
}
|
|
@@ -965,9 +958,9 @@ function compileDOFindEdgesProjected(table, select, filters, options) {
|
|
|
965
958
|
const columns = [];
|
|
966
959
|
for (let idx = 0; idx < uniqueFields.length; idx++) {
|
|
967
960
|
const field = uniqueFields[idx];
|
|
968
|
-
const canonical =
|
|
961
|
+
const canonical = normalizeProjectionField(field);
|
|
969
962
|
const { expr } = compileFieldRef(canonical);
|
|
970
|
-
const alias =
|
|
963
|
+
const alias = quoteColumnAlias(field);
|
|
971
964
|
projections.push(`${expr} AS ${alias}`);
|
|
972
965
|
let kind;
|
|
973
966
|
let typeAliasName;
|
|
@@ -976,7 +969,7 @@ function compileDOFindEdgesProjected(table, select, filters, options) {
|
|
|
976
969
|
} else if (canonical.startsWith("data.")) {
|
|
977
970
|
kind = "json";
|
|
978
971
|
typeAliasName = `__fg_t_${idx}`;
|
|
979
|
-
const typeAlias =
|
|
972
|
+
const typeAlias = quoteColumnAlias(typeAliasName);
|
|
980
973
|
projections.push(`json_type("data", '$.${canonical.slice(5)}') AS ${typeAlias}`);
|
|
981
974
|
} else {
|
|
982
975
|
if (canonical === "v") kind = "builtin-int";
|
|
@@ -991,12 +984,12 @@ function compileDOFindEdgesProjected(table, select, filters, options) {
|
|
|
991
984
|
conditions.push(compileFilter(f, params));
|
|
992
985
|
}
|
|
993
986
|
const where = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
994
|
-
let sql = `SELECT ${projections.join(", ")} FROM ${
|
|
987
|
+
let sql = `SELECT ${projections.join(", ")} FROM ${quoteIdent2(table)}${where}`;
|
|
995
988
|
sql += compileOrderBy(options, params);
|
|
996
989
|
sql += compileLimit(options, params);
|
|
997
990
|
return { stmt: { sql, params }, columns };
|
|
998
991
|
}
|
|
999
|
-
function
|
|
992
|
+
function decodeProjectedRow(row, columns) {
|
|
1000
993
|
const out = {};
|
|
1001
994
|
for (const c of columns) {
|
|
1002
995
|
const raw = row[c.field];
|
|
@@ -1016,7 +1009,7 @@ function decodeDOProjectedRow(row, columns) {
|
|
|
1016
1009
|
}
|
|
1017
1010
|
break;
|
|
1018
1011
|
case "builtin-timestamp": {
|
|
1019
|
-
const ms =
|
|
1012
|
+
const ms = rowTimestampToMillis(raw);
|
|
1020
1013
|
out[c.field] = GraphTimestampImpl.fromMillis(ms);
|
|
1021
1014
|
break;
|
|
1022
1015
|
}
|
|
@@ -1044,7 +1037,7 @@ function decodeDOProjectedRow(row, columns) {
|
|
|
1044
1037
|
}
|
|
1045
1038
|
return out;
|
|
1046
1039
|
}
|
|
1047
|
-
function
|
|
1040
|
+
function compileAggregate(table, spec, filters) {
|
|
1048
1041
|
const aliases = Object.keys(spec);
|
|
1049
1042
|
if (aliases.length === 0) {
|
|
1050
1043
|
throw new FiregraphError(
|
|
@@ -1055,7 +1048,7 @@ function compileDOAggregate(table, spec, filters) {
|
|
|
1055
1048
|
const projections = [];
|
|
1056
1049
|
for (const alias of aliases) {
|
|
1057
1050
|
const { op, field } = spec[alias];
|
|
1058
|
-
validateJsonPathKey(alias,
|
|
1051
|
+
validateJsonPathKey(alias, BACKEND_ERR_LABEL);
|
|
1059
1052
|
if (op === "count") {
|
|
1060
1053
|
if (field !== void 0) {
|
|
1061
1054
|
throw new FiregraphError(
|
|
@@ -1063,7 +1056,7 @@ function compileDOAggregate(table, spec, filters) {
|
|
|
1063
1056
|
"INVALID_QUERY"
|
|
1064
1057
|
);
|
|
1065
1058
|
}
|
|
1066
|
-
projections.push(`COUNT(*) AS ${
|
|
1059
|
+
projections.push(`COUNT(*) AS ${quoteIdent2(alias)}`);
|
|
1067
1060
|
continue;
|
|
1068
1061
|
}
|
|
1069
1062
|
if (!field) {
|
|
@@ -1074,13 +1067,13 @@ function compileDOAggregate(table, spec, filters) {
|
|
|
1074
1067
|
}
|
|
1075
1068
|
const { expr } = compileFieldRef(field);
|
|
1076
1069
|
const numeric = `CAST(${expr} AS REAL)`;
|
|
1077
|
-
if (op === "sum") projections.push(`SUM(${numeric}) AS ${
|
|
1078
|
-
else if (op === "avg") projections.push(`AVG(${numeric}) AS ${
|
|
1079
|
-
else if (op === "min") projections.push(`MIN(${numeric}) AS ${
|
|
1080
|
-
else if (op === "max") projections.push(`MAX(${numeric}) AS ${
|
|
1070
|
+
if (op === "sum") projections.push(`SUM(${numeric}) AS ${quoteIdent2(alias)}`);
|
|
1071
|
+
else if (op === "avg") projections.push(`AVG(${numeric}) AS ${quoteIdent2(alias)}`);
|
|
1072
|
+
else if (op === "min") projections.push(`MIN(${numeric}) AS ${quoteIdent2(alias)}`);
|
|
1073
|
+
else if (op === "max") projections.push(`MAX(${numeric}) AS ${quoteIdent2(alias)}`);
|
|
1081
1074
|
else
|
|
1082
1075
|
throw new FiregraphError(
|
|
1083
|
-
`
|
|
1076
|
+
`SQLite backend does not support aggregate op: ${String(op)}`,
|
|
1084
1077
|
"INVALID_QUERY"
|
|
1085
1078
|
);
|
|
1086
1079
|
}
|
|
@@ -1090,13 +1083,13 @@ function compileDOAggregate(table, spec, filters) {
|
|
|
1090
1083
|
conditions.push(compileFilter(f, params));
|
|
1091
1084
|
}
|
|
1092
1085
|
const where = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
1093
|
-
const sql = `SELECT ${projections.join(", ")} FROM ${
|
|
1086
|
+
const sql = `SELECT ${projections.join(", ")} FROM ${quoteIdent2(table)}${where}`;
|
|
1094
1087
|
return { stmt: { sql, params }, aliases };
|
|
1095
1088
|
}
|
|
1096
|
-
function
|
|
1097
|
-
assertJsonSafePayload(record.data,
|
|
1089
|
+
function compileSet(table, docId, record, nowMillis, mode) {
|
|
1090
|
+
assertJsonSafePayload(record.data, BACKEND_LABEL);
|
|
1098
1091
|
if (mode === "replace") {
|
|
1099
|
-
const sql2 = `INSERT OR REPLACE INTO ${
|
|
1092
|
+
const sql2 = `INSERT OR REPLACE INTO ${quoteIdent2(table)} (
|
|
1100
1093
|
doc_id, a_type, a_uid, axb_type, b_type, b_uid, data, v, created_at, updated_at
|
|
1101
1094
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
1102
1095
|
const params = [
|
|
@@ -1127,8 +1120,8 @@ function compileDOSet(table, docId, record, nowMillis, mode) {
|
|
|
1127
1120
|
];
|
|
1128
1121
|
const ops = flattenPatch(record.data ?? {});
|
|
1129
1122
|
const updateParams = [];
|
|
1130
|
-
const dataExpr = compileDataOpsExpr(ops, `COALESCE("data", '{}')`, updateParams,
|
|
1131
|
-
const sql = `INSERT INTO ${
|
|
1123
|
+
const dataExpr = compileDataOpsExpr(ops, `COALESCE("data", '{}')`, updateParams, BACKEND_ERR_LABEL) ?? `COALESCE("data", '{}')`;
|
|
1124
|
+
const sql = `INSERT INTO ${quoteIdent2(table)} (
|
|
1132
1125
|
doc_id, a_type, a_uid, axb_type, b_type, b_uid, data, v, created_at, updated_at
|
|
1133
1126
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1134
1127
|
ON CONFLICT(doc_id) DO UPDATE SET
|
|
@@ -1143,23 +1136,23 @@ function compileDOSet(table, docId, record, nowMillis, mode) {
|
|
|
1143
1136
|
"updated_at" = excluded."updated_at"`;
|
|
1144
1137
|
return { sql, params: [...insertParams, ...updateParams] };
|
|
1145
1138
|
}
|
|
1146
|
-
function
|
|
1139
|
+
function compileUpdate(table, docId, update, nowMillis) {
|
|
1147
1140
|
assertUpdatePayloadExclusive(update);
|
|
1148
1141
|
const setClauses = [];
|
|
1149
1142
|
const params = [];
|
|
1150
1143
|
if (update.replaceData) {
|
|
1151
|
-
assertJsonSafePayload(update.replaceData,
|
|
1144
|
+
assertJsonSafePayload(update.replaceData, BACKEND_LABEL);
|
|
1152
1145
|
setClauses.push(`"data" = ?`);
|
|
1153
1146
|
params.push(JSON.stringify(update.replaceData));
|
|
1154
1147
|
} else if (update.dataOps && update.dataOps.length > 0) {
|
|
1155
1148
|
for (const op of update.dataOps) {
|
|
1156
|
-
if (!op.delete) assertJsonSafePayload(op.value,
|
|
1149
|
+
if (!op.delete) assertJsonSafePayload(op.value, BACKEND_LABEL);
|
|
1157
1150
|
}
|
|
1158
1151
|
const expr = compileDataOpsExpr(
|
|
1159
1152
|
update.dataOps,
|
|
1160
1153
|
`COALESCE("data", '{}')`,
|
|
1161
1154
|
params,
|
|
1162
|
-
|
|
1155
|
+
BACKEND_ERR_LABEL
|
|
1163
1156
|
);
|
|
1164
1157
|
if (expr !== null) {
|
|
1165
1158
|
setClauses.push(`"data" = ${expr}`);
|
|
@@ -1173,17 +1166,17 @@ function compileDOUpdate(table, docId, update, nowMillis) {
|
|
|
1173
1166
|
params.push(nowMillis);
|
|
1174
1167
|
params.push(docId);
|
|
1175
1168
|
return {
|
|
1176
|
-
sql: `UPDATE ${
|
|
1169
|
+
sql: `UPDATE ${quoteIdent2(table)} SET ${setClauses.join(", ")} WHERE "doc_id" = ?`,
|
|
1177
1170
|
params
|
|
1178
1171
|
};
|
|
1179
1172
|
}
|
|
1180
|
-
function
|
|
1173
|
+
function compileDelete(table, docId) {
|
|
1181
1174
|
return {
|
|
1182
|
-
sql: `DELETE FROM ${
|
|
1175
|
+
sql: `DELETE FROM ${quoteIdent2(table)} WHERE "doc_id" = ?`,
|
|
1183
1176
|
params: [docId]
|
|
1184
1177
|
};
|
|
1185
1178
|
}
|
|
1186
|
-
function
|
|
1179
|
+
function compileBulkDelete(table, filters) {
|
|
1187
1180
|
const params = [];
|
|
1188
1181
|
const conditions = [];
|
|
1189
1182
|
for (const f of filters) {
|
|
@@ -1191,11 +1184,11 @@ function compileDOBulkDelete(table, filters) {
|
|
|
1191
1184
|
}
|
|
1192
1185
|
const where = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
1193
1186
|
return {
|
|
1194
|
-
sql: `DELETE FROM ${
|
|
1187
|
+
sql: `DELETE FROM ${quoteIdent2(table)}${where}`,
|
|
1195
1188
|
params
|
|
1196
1189
|
};
|
|
1197
1190
|
}
|
|
1198
|
-
function
|
|
1191
|
+
function compileBulkUpdate(table, filters, patchData, nowMillis) {
|
|
1199
1192
|
const dataOps = flattenPatch(patchData);
|
|
1200
1193
|
if (dataOps.length === 0) {
|
|
1201
1194
|
throw new FiregraphError(
|
|
@@ -1204,15 +1197,10 @@ function compileDOBulkUpdate(table, filters, patchData, nowMillis) {
|
|
|
1204
1197
|
);
|
|
1205
1198
|
}
|
|
1206
1199
|
for (const op of dataOps) {
|
|
1207
|
-
if (!op.delete) assertJsonSafePayload(op.value,
|
|
1200
|
+
if (!op.delete) assertJsonSafePayload(op.value, BACKEND_LABEL);
|
|
1208
1201
|
}
|
|
1209
1202
|
const setParams = [];
|
|
1210
|
-
const expr = compileDataOpsExpr(
|
|
1211
|
-
dataOps,
|
|
1212
|
-
`COALESCE("data", '{}')`,
|
|
1213
|
-
setParams,
|
|
1214
|
-
DO_BACKEND_ERR_LABEL
|
|
1215
|
-
);
|
|
1203
|
+
const expr = compileDataOpsExpr(dataOps, `COALESCE("data", '{}')`, setParams, BACKEND_ERR_LABEL);
|
|
1216
1204
|
if (expr === null) {
|
|
1217
1205
|
throw new FiregraphError(
|
|
1218
1206
|
"bulkUpdate() patch produced no SQL operations \u2014 internal invariant violated.",
|
|
@@ -1228,21 +1216,35 @@ function compileDOBulkUpdate(table, filters, patchData, nowMillis) {
|
|
|
1228
1216
|
}
|
|
1229
1217
|
const where = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
1230
1218
|
return {
|
|
1231
|
-
sql: `UPDATE ${
|
|
1219
|
+
sql: `UPDATE ${quoteIdent2(table)} SET ${setClauses.join(", ")}${where}`,
|
|
1232
1220
|
params: [...setParams, ...whereParams]
|
|
1233
1221
|
};
|
|
1234
1222
|
}
|
|
1235
|
-
function
|
|
1223
|
+
function compileDeleteAll(table) {
|
|
1236
1224
|
return {
|
|
1237
|
-
sql: `DELETE FROM ${
|
|
1225
|
+
sql: `DELETE FROM ${quoteIdent2(table)}`,
|
|
1238
1226
|
params: []
|
|
1239
1227
|
};
|
|
1240
1228
|
}
|
|
1229
|
+
function rowTimestampToMillis(value) {
|
|
1230
|
+
if (typeof value === "number") return value;
|
|
1231
|
+
if (typeof value === "bigint") return Number(value);
|
|
1232
|
+
if (typeof value === "string") {
|
|
1233
|
+
const n = Number(value);
|
|
1234
|
+
if (Number.isFinite(n)) return n;
|
|
1235
|
+
}
|
|
1236
|
+
throw new FiregraphError(
|
|
1237
|
+
`SQLite row has non-numeric timestamp column: ${typeof value} (${String(value)})`,
|
|
1238
|
+
"INVALID_QUERY"
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// src/cloudflare/sql.ts
|
|
1241
1243
|
function rowToDORecord(row) {
|
|
1242
1244
|
const dataString = row.data;
|
|
1243
1245
|
const data = dataString ? JSON.parse(dataString) : {};
|
|
1244
|
-
const createdAtMs =
|
|
1245
|
-
const updatedAtMs =
|
|
1246
|
+
const createdAtMs = rowTimestampToMillis(row.created_at);
|
|
1247
|
+
const updatedAtMs = rowTimestampToMillis(row.updated_at);
|
|
1246
1248
|
const record = {
|
|
1247
1249
|
aType: row.a_type,
|
|
1248
1250
|
aUid: row.a_uid,
|
|
@@ -1274,18 +1276,6 @@ function hydrateDORecord(wire) {
|
|
|
1274
1276
|
}
|
|
1275
1277
|
return record;
|
|
1276
1278
|
}
|
|
1277
|
-
function toMillis(value) {
|
|
1278
|
-
if (typeof value === "number") return value;
|
|
1279
|
-
if (typeof value === "bigint") return Number(value);
|
|
1280
|
-
if (typeof value === "string") {
|
|
1281
|
-
const n = Number(value);
|
|
1282
|
-
if (Number.isFinite(n)) return n;
|
|
1283
|
-
}
|
|
1284
|
-
throw new FiregraphError(
|
|
1285
|
-
`DO SQLite row has non-numeric timestamp column: ${typeof value} (${String(value)})`,
|
|
1286
|
-
"INVALID_QUERY"
|
|
1287
|
-
);
|
|
1288
|
-
}
|
|
1289
1279
|
|
|
1290
1280
|
// src/cloudflare/backend.ts
|
|
1291
1281
|
function validateSegment(value, label) {
|
|
@@ -1549,7 +1539,7 @@ var DORPCBackend = class _DORPCBackend {
|
|
|
1549
1539
|
);
|
|
1550
1540
|
}
|
|
1551
1541
|
const { rows, columns } = await stub._fgFindEdgesProjected(select, filters, options);
|
|
1552
|
-
return rows.map((row) =>
|
|
1542
|
+
return rows.map((row) => decodeProjectedRow(row, columns));
|
|
1553
1543
|
}
|
|
1554
1544
|
// --- Cross-scope queries ---
|
|
1555
1545
|
//
|
|
@@ -3627,7 +3617,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3627
3617
|
super(ctx, env);
|
|
3628
3618
|
this.state = ctx;
|
|
3629
3619
|
const table = options.table ?? DEFAULT_OPTIONS.table;
|
|
3630
|
-
|
|
3620
|
+
validateTableName(table);
|
|
3631
3621
|
this.table = table;
|
|
3632
3622
|
this.registry = options.registry;
|
|
3633
3623
|
this.coreIndexes = options.coreIndexes;
|
|
@@ -3646,12 +3636,12 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3646
3636
|
// `src/cloudflare/backend.ts` calls these directly on the DO stub.
|
|
3647
3637
|
// ---------------------------------------------------------------------------
|
|
3648
3638
|
async _fgGetDoc(docId) {
|
|
3649
|
-
const stmt =
|
|
3639
|
+
const stmt = compileSelectByDocId(this.table, docId);
|
|
3650
3640
|
const rows = this.execAll(stmt);
|
|
3651
3641
|
return rows.length === 0 ? null : rowToDORecord(rows[0]);
|
|
3652
3642
|
}
|
|
3653
3643
|
async _fgQuery(filters, options) {
|
|
3654
|
-
const stmt =
|
|
3644
|
+
const stmt = compileSelect(this.table, filters, options);
|
|
3655
3645
|
const rows = this.execAll(stmt);
|
|
3656
3646
|
return rows.map(rowToDORecord);
|
|
3657
3647
|
}
|
|
@@ -3663,7 +3653,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3663
3653
|
* the wire payload stays a plain row of (alias → number | null).
|
|
3664
3654
|
*/
|
|
3665
3655
|
async _fgAggregate(spec, filters) {
|
|
3666
|
-
const { stmt, aliases } =
|
|
3656
|
+
const { stmt, aliases } = compileAggregate(this.table, spec, filters);
|
|
3667
3657
|
const rows = this.execAll(stmt);
|
|
3668
3658
|
const row = rows[0] ?? {};
|
|
3669
3659
|
const out = {};
|
|
@@ -3680,11 +3670,11 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3680
3670
|
// RPC: writes
|
|
3681
3671
|
// ---------------------------------------------------------------------------
|
|
3682
3672
|
async _fgSetDoc(docId, record, mode) {
|
|
3683
|
-
const stmt =
|
|
3673
|
+
const stmt = compileSet(this.table, docId, record, Date.now(), mode);
|
|
3684
3674
|
this.execRun(stmt);
|
|
3685
3675
|
}
|
|
3686
3676
|
async _fgUpdateDoc(docId, update) {
|
|
3687
|
-
const stmt =
|
|
3677
|
+
const stmt = compileUpdate(this.table, docId, update, Date.now());
|
|
3688
3678
|
const sqlWithReturning = `${stmt.sql} RETURNING "doc_id"`;
|
|
3689
3679
|
const rows = this.state.storage.sql.exec(sqlWithReturning, ...stmt.params).toArray();
|
|
3690
3680
|
if (rows.length === 0) {
|
|
@@ -3692,7 +3682,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3692
3682
|
}
|
|
3693
3683
|
}
|
|
3694
3684
|
async _fgDeleteDoc(docId) {
|
|
3695
|
-
const stmt =
|
|
3685
|
+
const stmt = compileDelete(this.table, docId);
|
|
3696
3686
|
this.execRun(stmt);
|
|
3697
3687
|
}
|
|
3698
3688
|
// ---------------------------------------------------------------------------
|
|
@@ -3710,11 +3700,11 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3710
3700
|
const statements = ops.map((op) => {
|
|
3711
3701
|
switch (op.kind) {
|
|
3712
3702
|
case "set":
|
|
3713
|
-
return
|
|
3703
|
+
return compileSet(this.table, op.docId, op.record, now, op.mode);
|
|
3714
3704
|
case "update":
|
|
3715
|
-
return
|
|
3705
|
+
return compileUpdate(this.table, op.docId, op.update, now);
|
|
3716
3706
|
case "delete":
|
|
3717
|
-
return
|
|
3707
|
+
return compileDelete(this.table, op.docId);
|
|
3718
3708
|
}
|
|
3719
3709
|
});
|
|
3720
3710
|
this.state.storage.transactionSync(() => {
|
|
@@ -3733,8 +3723,8 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3733
3723
|
// Without that topology the DO has no way to enumerate its children.
|
|
3734
3724
|
// ---------------------------------------------------------------------------
|
|
3735
3725
|
async _fgRemoveNodeCascade(uid) {
|
|
3736
|
-
const outgoingStmt =
|
|
3737
|
-
const incomingStmt =
|
|
3726
|
+
const outgoingStmt = compileSelect(this.table, [{ field: "aUid", op: "==", value: uid }]);
|
|
3727
|
+
const incomingStmt = compileSelect(this.table, [{ field: "bUid", op: "==", value: uid }]);
|
|
3738
3728
|
const outgoingRows = this.execAll(outgoingStmt);
|
|
3739
3729
|
const incomingRows = this.execAll(incomingStmt);
|
|
3740
3730
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3754,9 +3744,9 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3754
3744
|
edgeDocIds.push(docId);
|
|
3755
3745
|
}
|
|
3756
3746
|
}
|
|
3757
|
-
const statements = edgeDocIds.map((id) =>
|
|
3747
|
+
const statements = edgeDocIds.map((id) => compileDelete(this.table, id));
|
|
3758
3748
|
if (nodeExists) {
|
|
3759
|
-
statements.push(
|
|
3749
|
+
statements.push(compileDelete(this.table, computeNodeDocId(uid)));
|
|
3760
3750
|
}
|
|
3761
3751
|
if (statements.length === 0) {
|
|
3762
3752
|
return {
|
|
@@ -3795,11 +3785,11 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3795
3785
|
const plan = buildEdgeQueryPlan(params);
|
|
3796
3786
|
let docIds;
|
|
3797
3787
|
if (plan.strategy === "get") {
|
|
3798
|
-
const existsStmt =
|
|
3788
|
+
const existsStmt = compileSelectByDocId(this.table, plan.docId);
|
|
3799
3789
|
const rows = this.execAll(existsStmt);
|
|
3800
3790
|
docIds = rows.length > 0 ? [plan.docId] : [];
|
|
3801
3791
|
} else {
|
|
3802
|
-
const selectStmt =
|
|
3792
|
+
const selectStmt = compileSelect(this.table, plan.filters, plan.options);
|
|
3803
3793
|
const rows = this.execAll(selectStmt);
|
|
3804
3794
|
docIds = rows.map(
|
|
3805
3795
|
(row) => computeEdgeDocId(row.a_uid, row.axb_type, row.b_uid)
|
|
@@ -3808,7 +3798,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3808
3798
|
if (docIds.length === 0) {
|
|
3809
3799
|
return { deleted: 0, batches: 0, errors: [] };
|
|
3810
3800
|
}
|
|
3811
|
-
const deleteStmts = docIds.map((id) =>
|
|
3801
|
+
const deleteStmts = docIds.map((id) => compileDelete(this.table, id));
|
|
3812
3802
|
try {
|
|
3813
3803
|
this.state.storage.transactionSync(() => {
|
|
3814
3804
|
for (const stmt of deleteStmts) {
|
|
@@ -3853,12 +3843,12 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3853
3843
|
"INVALID_ARGUMENT"
|
|
3854
3844
|
);
|
|
3855
3845
|
}
|
|
3856
|
-
const stmt =
|
|
3846
|
+
const stmt = compileBulkDelete(this.table, filters);
|
|
3857
3847
|
return this.execDmlWithReturning(stmt);
|
|
3858
3848
|
}
|
|
3859
3849
|
async _fgBulkUpdate(filters, patch, _options) {
|
|
3860
3850
|
void _options;
|
|
3861
|
-
const stmt =
|
|
3851
|
+
const stmt = compileBulkUpdate(this.table, filters, patch.data, Date.now());
|
|
3862
3852
|
return this.execDmlWithReturning(stmt);
|
|
3863
3853
|
}
|
|
3864
3854
|
// ---------------------------------------------------------------------------
|
|
@@ -3875,7 +3865,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3875
3865
|
if (params.sources.length === 0) {
|
|
3876
3866
|
return params.hydrate ? { edges: [], targets: [] } : { edges: [] };
|
|
3877
3867
|
}
|
|
3878
|
-
const stmt =
|
|
3868
|
+
const stmt = compileExpand(this.table, params);
|
|
3879
3869
|
const rows = this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
3880
3870
|
const edges = rows.map((row) => rowToDORecord(row));
|
|
3881
3871
|
if (!params.hydrate) {
|
|
@@ -3887,7 +3877,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3887
3877
|
if (uniqueTargets.length === 0) {
|
|
3888
3878
|
return { edges, targets: [] };
|
|
3889
3879
|
}
|
|
3890
|
-
const hydrateStmt =
|
|
3880
|
+
const hydrateStmt = compileExpandHydrate(this.table, uniqueTargets);
|
|
3891
3881
|
const hydrateRows = this.state.storage.sql.exec(hydrateStmt.sql, ...hydrateStmt.params).toArray();
|
|
3892
3882
|
const byUid = /* @__PURE__ */ new Map();
|
|
3893
3883
|
for (const row of hydrateRows) {
|
|
@@ -3909,7 +3899,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3909
3899
|
// a typical projection); structured clone copes happily.
|
|
3910
3900
|
// ---------------------------------------------------------------------------
|
|
3911
3901
|
async _fgFindEdgesProjected(select, filters, options) {
|
|
3912
|
-
const { stmt, columns } =
|
|
3902
|
+
const { stmt, columns } = compileFindEdgesProjected(this.table, select, filters, options);
|
|
3913
3903
|
const rows = this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
3914
3904
|
return { rows, columns };
|
|
3915
3905
|
}
|
|
@@ -3947,14 +3937,14 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3947
3937
|
* forever), but its storage can be emptied.
|
|
3948
3938
|
*/
|
|
3949
3939
|
async _fgDestroy() {
|
|
3950
|
-
const stmt =
|
|
3940
|
+
const stmt = compileDeleteAll(this.table);
|
|
3951
3941
|
this.execRun(stmt);
|
|
3952
3942
|
}
|
|
3953
3943
|
// ---------------------------------------------------------------------------
|
|
3954
3944
|
// Internals
|
|
3955
3945
|
// ---------------------------------------------------------------------------
|
|
3956
3946
|
runSchema() {
|
|
3957
|
-
const statements =
|
|
3947
|
+
const statements = buildSchemaStatements(this.table, {
|
|
3958
3948
|
coreIndexes: this.coreIndexes,
|
|
3959
3949
|
registry: this.registry
|
|
3960
3950
|
});
|