@typicalday/firegraph 0.14.1 → 0.16.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 +62 -20
- package/dist/backend-CE3pM9-T.d.ts +167 -0
- package/dist/{backend-DuvHGgK1.d.cts → backend-DNzv8KSR.d.cts} +34 -20
- package/dist/{backend-DuvHGgK1.d.ts → backend-DNzv8KSR.d.ts} +34 -20
- package/dist/backend-EjFfw9yO.d.cts +167 -0
- 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-5JBNLH5W.js +732 -0
- package/dist/chunk-5JBNLH5W.js.map +1 -0
- package/dist/{chunk-3AHHXMWX.js → chunk-6IO74NKD.js} +23 -44
- package/dist/chunk-6IO74NKD.js.map +1 -0
- package/dist/{chunk-DJI3VXXA.js → chunk-7IEZ6IYY.js} +2 -2
- package/dist/chunk-7IEZ6IYY.js.map +1 -0
- package/dist/chunk-NGAJCALM.js +34 -0
- package/dist/chunk-NGAJCALM.js.map +1 -0
- package/dist/chunk-NZVSLWNY.js +867 -0
- package/dist/chunk-NZVSLWNY.js.map +1 -0
- package/dist/{chunk-N5HFDWQX.js → chunk-PWIO46RT.js} +1 -1
- package/dist/{chunk-N5HFDWQX.js.map → chunk-PWIO46RT.js.map} +1 -1
- package/dist/{client-BKi3vk0Q.d.ts → client-CNAwJayO.d.ts} +1 -1
- package/dist/{client-BrsaXtDV.d.cts → client-CaXH5D5C.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 +159 -167
- 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 +11 -9
- 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 +6 -4
- package/dist/firestore-enterprise/index.js.map +1 -1
- package/dist/firestore-standard/index.cjs +11 -9
- 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 +4 -3
- package/dist/firestore-standard/index.js.map +1 -1
- package/dist/index.cjs +11 -9
- 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 +6 -4
- 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-C2KUPVZj.d.ts → registry-By1i-zge.d.ts} +2 -2
- package/dist/{registry-Bc7h6WTM.d.cts → registry-CNToyEra.d.cts} +2 -2
- package/dist/sqlite/index.cjs +599 -380
- 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 +2262 -0
- package/dist/sqlite/local.cjs.map +1 -0
- package/dist/sqlite/local.d.cts +109 -0
- package/dist/sqlite/local.d.ts +109 -0
- package/dist/sqlite/local.js +546 -0
- package/dist/sqlite/local.js.map +1 -0
- package/package.json +15 -1
- package/dist/chunk-3AHHXMWX.js.map +0 -1
- package/dist/chunk-DJI3VXXA.js.map +0 -1
- package/dist/chunk-NNBSUOOF.js +0 -289
- package/dist/chunk-NNBSUOOF.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",
|
|
@@ -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
|
//
|
|
@@ -3264,7 +3254,7 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
3264
3254
|
async findNearest(params) {
|
|
3265
3255
|
if (!this.backend.findNearest) {
|
|
3266
3256
|
throw new FiregraphError(
|
|
3267
|
-
"findNearest() is not supported by the current storage backend. Vector search requires a backend that declares `search.vector` (currently Firestore Standard and
|
|
3257
|
+
"findNearest() is not supported by the current storage backend. Vector search requires a backend that declares `search.vector` (currently Firestore Standard, Firestore Enterprise, and the local better-sqlite3 backend). There is no client-side fallback because emulating ANN on top of the generic backend surface does not scale beyond toy datasets.",
|
|
3268
3258
|
"UNSUPPORTED_OPERATION"
|
|
3269
3259
|
);
|
|
3270
3260
|
}
|
|
@@ -3280,13 +3270,15 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
3280
3270
|
* Native full-text search (capability `search.fullText`).
|
|
3281
3271
|
*
|
|
3282
3272
|
* Returns the top-N records by relevance, ordered by the search
|
|
3283
|
-
* index's score.
|
|
3284
|
-
*
|
|
3285
|
-
*
|
|
3286
|
-
*
|
|
3287
|
-
*
|
|
3288
|
-
*
|
|
3289
|
-
*
|
|
3273
|
+
* index's score. Firestore Enterprise declares this capability (via
|
|
3274
|
+
* the Pipelines `search({ query: documentMatches(...) })` stage over
|
|
3275
|
+
* Enterprise's FTS index), as does the local better-sqlite3 backend
|
|
3276
|
+
* (`firegraph/sqlite-local`, via a trigger-synced FTS5 index ranked
|
|
3277
|
+
* by `bm25()`). Standard does not declare the cap (FTS is an
|
|
3278
|
+
* Enterprise-only product feature, not a typed-API gap); D1 and the
|
|
3279
|
+
* Cloudflare DO edition have no FTS trigger infrastructure. Backends
|
|
3280
|
+
* without `search.fullText` throw `UNSUPPORTED_OPERATION` from this
|
|
3281
|
+
* wrapper.
|
|
3290
3282
|
*
|
|
3291
3283
|
* Scan-protection mirrors `findNearest`: a search with no
|
|
3292
3284
|
* identifying filters (`aType` / `axbType` / `bType`) walks every
|
|
@@ -3302,7 +3294,7 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
3302
3294
|
async fullTextSearch(params) {
|
|
3303
3295
|
if (!this.backend.fullTextSearch) {
|
|
3304
3296
|
throw new FiregraphError(
|
|
3305
|
-
"fullTextSearch() is not supported by the current storage backend. Full-text search requires a backend that declares `search.fullText` (currently Firestore Enterprise
|
|
3297
|
+
"fullTextSearch() is not supported by the current storage backend. Full-text search requires a backend that declares `search.fullText` (currently Firestore Enterprise and the local better-sqlite3 backend). There is no client-side fallback because emulating FTS over the generic backend surface would not scale beyond toy datasets.",
|
|
3306
3298
|
"UNSUPPORTED_OPERATION"
|
|
3307
3299
|
);
|
|
3308
3300
|
}
|
|
@@ -3627,7 +3619,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3627
3619
|
super(ctx, env);
|
|
3628
3620
|
this.state = ctx;
|
|
3629
3621
|
const table = options.table ?? DEFAULT_OPTIONS.table;
|
|
3630
|
-
|
|
3622
|
+
validateTableName(table);
|
|
3631
3623
|
this.table = table;
|
|
3632
3624
|
this.registry = options.registry;
|
|
3633
3625
|
this.coreIndexes = options.coreIndexes;
|
|
@@ -3646,12 +3638,12 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3646
3638
|
// `src/cloudflare/backend.ts` calls these directly on the DO stub.
|
|
3647
3639
|
// ---------------------------------------------------------------------------
|
|
3648
3640
|
async _fgGetDoc(docId) {
|
|
3649
|
-
const stmt =
|
|
3641
|
+
const stmt = compileSelectByDocId(this.table, docId);
|
|
3650
3642
|
const rows = this.execAll(stmt);
|
|
3651
3643
|
return rows.length === 0 ? null : rowToDORecord(rows[0]);
|
|
3652
3644
|
}
|
|
3653
3645
|
async _fgQuery(filters, options) {
|
|
3654
|
-
const stmt =
|
|
3646
|
+
const stmt = compileSelect(this.table, filters, options);
|
|
3655
3647
|
const rows = this.execAll(stmt);
|
|
3656
3648
|
return rows.map(rowToDORecord);
|
|
3657
3649
|
}
|
|
@@ -3663,7 +3655,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3663
3655
|
* the wire payload stays a plain row of (alias → number | null).
|
|
3664
3656
|
*/
|
|
3665
3657
|
async _fgAggregate(spec, filters) {
|
|
3666
|
-
const { stmt, aliases } =
|
|
3658
|
+
const { stmt, aliases } = compileAggregate(this.table, spec, filters);
|
|
3667
3659
|
const rows = this.execAll(stmt);
|
|
3668
3660
|
const row = rows[0] ?? {};
|
|
3669
3661
|
const out = {};
|
|
@@ -3680,11 +3672,11 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3680
3672
|
// RPC: writes
|
|
3681
3673
|
// ---------------------------------------------------------------------------
|
|
3682
3674
|
async _fgSetDoc(docId, record, mode) {
|
|
3683
|
-
const stmt =
|
|
3675
|
+
const stmt = compileSet(this.table, docId, record, Date.now(), mode);
|
|
3684
3676
|
this.execRun(stmt);
|
|
3685
3677
|
}
|
|
3686
3678
|
async _fgUpdateDoc(docId, update) {
|
|
3687
|
-
const stmt =
|
|
3679
|
+
const stmt = compileUpdate(this.table, docId, update, Date.now());
|
|
3688
3680
|
const sqlWithReturning = `${stmt.sql} RETURNING "doc_id"`;
|
|
3689
3681
|
const rows = this.state.storage.sql.exec(sqlWithReturning, ...stmt.params).toArray();
|
|
3690
3682
|
if (rows.length === 0) {
|
|
@@ -3692,7 +3684,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3692
3684
|
}
|
|
3693
3685
|
}
|
|
3694
3686
|
async _fgDeleteDoc(docId) {
|
|
3695
|
-
const stmt =
|
|
3687
|
+
const stmt = compileDelete(this.table, docId);
|
|
3696
3688
|
this.execRun(stmt);
|
|
3697
3689
|
}
|
|
3698
3690
|
// ---------------------------------------------------------------------------
|
|
@@ -3710,11 +3702,11 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3710
3702
|
const statements = ops.map((op) => {
|
|
3711
3703
|
switch (op.kind) {
|
|
3712
3704
|
case "set":
|
|
3713
|
-
return
|
|
3705
|
+
return compileSet(this.table, op.docId, op.record, now, op.mode);
|
|
3714
3706
|
case "update":
|
|
3715
|
-
return
|
|
3707
|
+
return compileUpdate(this.table, op.docId, op.update, now);
|
|
3716
3708
|
case "delete":
|
|
3717
|
-
return
|
|
3709
|
+
return compileDelete(this.table, op.docId);
|
|
3718
3710
|
}
|
|
3719
3711
|
});
|
|
3720
3712
|
this.state.storage.transactionSync(() => {
|
|
@@ -3733,8 +3725,8 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3733
3725
|
// Without that topology the DO has no way to enumerate its children.
|
|
3734
3726
|
// ---------------------------------------------------------------------------
|
|
3735
3727
|
async _fgRemoveNodeCascade(uid) {
|
|
3736
|
-
const outgoingStmt =
|
|
3737
|
-
const incomingStmt =
|
|
3728
|
+
const outgoingStmt = compileSelect(this.table, [{ field: "aUid", op: "==", value: uid }]);
|
|
3729
|
+
const incomingStmt = compileSelect(this.table, [{ field: "bUid", op: "==", value: uid }]);
|
|
3738
3730
|
const outgoingRows = this.execAll(outgoingStmt);
|
|
3739
3731
|
const incomingRows = this.execAll(incomingStmt);
|
|
3740
3732
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3754,9 +3746,9 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3754
3746
|
edgeDocIds.push(docId);
|
|
3755
3747
|
}
|
|
3756
3748
|
}
|
|
3757
|
-
const statements = edgeDocIds.map((id) =>
|
|
3749
|
+
const statements = edgeDocIds.map((id) => compileDelete(this.table, id));
|
|
3758
3750
|
if (nodeExists) {
|
|
3759
|
-
statements.push(
|
|
3751
|
+
statements.push(compileDelete(this.table, computeNodeDocId(uid)));
|
|
3760
3752
|
}
|
|
3761
3753
|
if (statements.length === 0) {
|
|
3762
3754
|
return {
|
|
@@ -3795,11 +3787,11 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3795
3787
|
const plan = buildEdgeQueryPlan(params);
|
|
3796
3788
|
let docIds;
|
|
3797
3789
|
if (plan.strategy === "get") {
|
|
3798
|
-
const existsStmt =
|
|
3790
|
+
const existsStmt = compileSelectByDocId(this.table, plan.docId);
|
|
3799
3791
|
const rows = this.execAll(existsStmt);
|
|
3800
3792
|
docIds = rows.length > 0 ? [plan.docId] : [];
|
|
3801
3793
|
} else {
|
|
3802
|
-
const selectStmt =
|
|
3794
|
+
const selectStmt = compileSelect(this.table, plan.filters, plan.options);
|
|
3803
3795
|
const rows = this.execAll(selectStmt);
|
|
3804
3796
|
docIds = rows.map(
|
|
3805
3797
|
(row) => computeEdgeDocId(row.a_uid, row.axb_type, row.b_uid)
|
|
@@ -3808,7 +3800,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3808
3800
|
if (docIds.length === 0) {
|
|
3809
3801
|
return { deleted: 0, batches: 0, errors: [] };
|
|
3810
3802
|
}
|
|
3811
|
-
const deleteStmts = docIds.map((id) =>
|
|
3803
|
+
const deleteStmts = docIds.map((id) => compileDelete(this.table, id));
|
|
3812
3804
|
try {
|
|
3813
3805
|
this.state.storage.transactionSync(() => {
|
|
3814
3806
|
for (const stmt of deleteStmts) {
|
|
@@ -3853,12 +3845,12 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3853
3845
|
"INVALID_ARGUMENT"
|
|
3854
3846
|
);
|
|
3855
3847
|
}
|
|
3856
|
-
const stmt =
|
|
3848
|
+
const stmt = compileBulkDelete(this.table, filters);
|
|
3857
3849
|
return this.execDmlWithReturning(stmt);
|
|
3858
3850
|
}
|
|
3859
3851
|
async _fgBulkUpdate(filters, patch, _options) {
|
|
3860
3852
|
void _options;
|
|
3861
|
-
const stmt =
|
|
3853
|
+
const stmt = compileBulkUpdate(this.table, filters, patch.data, Date.now());
|
|
3862
3854
|
return this.execDmlWithReturning(stmt);
|
|
3863
3855
|
}
|
|
3864
3856
|
// ---------------------------------------------------------------------------
|
|
@@ -3875,7 +3867,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3875
3867
|
if (params.sources.length === 0) {
|
|
3876
3868
|
return params.hydrate ? { edges: [], targets: [] } : { edges: [] };
|
|
3877
3869
|
}
|
|
3878
|
-
const stmt =
|
|
3870
|
+
const stmt = compileExpand(this.table, params);
|
|
3879
3871
|
const rows = this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
3880
3872
|
const edges = rows.map((row) => rowToDORecord(row));
|
|
3881
3873
|
if (!params.hydrate) {
|
|
@@ -3887,7 +3879,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3887
3879
|
if (uniqueTargets.length === 0) {
|
|
3888
3880
|
return { edges, targets: [] };
|
|
3889
3881
|
}
|
|
3890
|
-
const hydrateStmt =
|
|
3882
|
+
const hydrateStmt = compileExpandHydrate(this.table, uniqueTargets);
|
|
3891
3883
|
const hydrateRows = this.state.storage.sql.exec(hydrateStmt.sql, ...hydrateStmt.params).toArray();
|
|
3892
3884
|
const byUid = /* @__PURE__ */ new Map();
|
|
3893
3885
|
for (const row of hydrateRows) {
|
|
@@ -3909,7 +3901,7 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3909
3901
|
// a typical projection); structured clone copes happily.
|
|
3910
3902
|
// ---------------------------------------------------------------------------
|
|
3911
3903
|
async _fgFindEdgesProjected(select, filters, options) {
|
|
3912
|
-
const { stmt, columns } =
|
|
3904
|
+
const { stmt, columns } = compileFindEdgesProjected(this.table, select, filters, options);
|
|
3913
3905
|
const rows = this.state.storage.sql.exec(stmt.sql, ...stmt.params).toArray();
|
|
3914
3906
|
return { rows, columns };
|
|
3915
3907
|
}
|
|
@@ -3947,14 +3939,14 @@ var FiregraphDO = class extends import_cloudflare_workers.DurableObject {
|
|
|
3947
3939
|
* forever), but its storage can be emptied.
|
|
3948
3940
|
*/
|
|
3949
3941
|
async _fgDestroy() {
|
|
3950
|
-
const stmt =
|
|
3942
|
+
const stmt = compileDeleteAll(this.table);
|
|
3951
3943
|
this.execRun(stmt);
|
|
3952
3944
|
}
|
|
3953
3945
|
// ---------------------------------------------------------------------------
|
|
3954
3946
|
// Internals
|
|
3955
3947
|
// ---------------------------------------------------------------------------
|
|
3956
3948
|
runSchema() {
|
|
3957
|
-
const statements =
|
|
3949
|
+
const statements = buildSchemaStatements(this.table, {
|
|
3958
3950
|
coreIndexes: this.coreIndexes,
|
|
3959
3951
|
registry: this.registry
|
|
3960
3952
|
});
|