@typicalday/firegraph 0.11.2 → 0.12.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 +38 -5
- package/dist/backend-BsR0lnFL.d.ts +200 -0
- package/dist/backend-Ct-fLlkG.d.cts +200 -0
- package/dist/backend.cjs +143 -2
- package/dist/backend.cjs.map +1 -1
- package/dist/backend.d.cts +3 -3
- package/dist/backend.d.ts +3 -3
- package/dist/backend.js +13 -4
- package/dist/backend.js.map +1 -1
- package/dist/chunk-AWW4MUJ5.js +245 -0
- package/dist/chunk-AWW4MUJ5.js.map +1 -0
- package/dist/{chunk-5753Y42M.js → chunk-C2QMD7RY.js} +6 -10
- package/dist/chunk-C2QMD7RY.js.map +1 -0
- package/dist/chunk-EQJUUVFG.js +14 -0
- package/dist/chunk-EQJUUVFG.js.map +1 -0
- package/dist/{chunk-NJSOD64C.js → chunk-HONQY4HF.js} +80 -17
- package/dist/chunk-HONQY4HF.js.map +1 -0
- package/dist/cloudflare/index.cjs +458 -73
- package/dist/cloudflare/index.cjs.map +1 -1
- package/dist/cloudflare/index.d.cts +8 -5
- package/dist/cloudflare/index.d.ts +8 -5
- package/dist/cloudflare/index.js +234 -56
- 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/index.cjs +271 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -69
- package/dist/index.d.ts +21 -69
- package/dist/index.js +58 -28
- package/dist/index.js.map +1 -1
- package/dist/registry-B1qsVL0E.d.cts +64 -0
- package/dist/registry-Fi074zVa.d.ts +64 -0
- package/dist/{serialization-ZZ7RSDRX.js → serialization-OE2PFZMY.js} +6 -4
- package/dist/{types-BGWxcpI_.d.cts → types-DxYLy8Ol.d.cts} +36 -2
- package/dist/{types-BGWxcpI_.d.ts → types-DxYLy8Ol.d.ts} +36 -2
- package/package.json +1 -1
- package/dist/backend-U-MLShlg.d.ts +0 -97
- package/dist/backend-np4gEVhB.d.cts +0 -97
- package/dist/chunk-5753Y42M.js.map +0 -1
- package/dist/chunk-NJSOD64C.js.map +0 -1
- package/dist/chunk-R7CRGYY4.js +0 -94
- package/dist/chunk-R7CRGYY4.js.map +0 -1
- /package/dist/{serialization-ZZ7RSDRX.js.map → serialization-OE2PFZMY.js.map} +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { W as WritableRecord, U as UpdatePayload, S as StorageBackend, T as TransactionBackend, B as BatchBackend } from '../backend-
|
|
2
|
-
|
|
1
|
+
import { W as WritableRecord, b as WriteMode, U as UpdatePayload, S as StorageBackend, T as TransactionBackend, B as BatchBackend } from '../backend-Ct-fLlkG.cjs';
|
|
2
|
+
export { d as deleteField } from '../backend-Ct-fLlkG.cjs';
|
|
3
|
+
import { e as GraphRegistry, I as IndexSpec, g as QueryFilter, z as QueryOptions, C as CascadeResult, F as FindEdgesParams, m as BulkOptions, o as BulkResult, a as GraphClient, D as DynamicGraphClient, S as StoredGraphRecord, l as GraphReader, G as GraphClientOptions, c as DynamicRegistryConfig } from '../types-DxYLy8Ol.cjs';
|
|
3
4
|
import { DurableObject } from 'cloudflare:workers';
|
|
5
|
+
export { M as META_EDGE_TYPE, a as META_NODE_TYPE, b as createMergedRegistry, d as createRegistry, f as generateId } from '../registry-B1qsVL0E.cjs';
|
|
4
6
|
import '@google-cloud/firestore';
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -124,6 +126,7 @@ type BatchOp = {
|
|
|
124
126
|
kind: 'set';
|
|
125
127
|
docId: string;
|
|
126
128
|
record: WritableRecord;
|
|
129
|
+
mode: WriteMode;
|
|
127
130
|
} | {
|
|
128
131
|
kind: 'update';
|
|
129
132
|
docId: string;
|
|
@@ -185,7 +188,7 @@ declare class FiregraphDO extends DurableObject<unknown> {
|
|
|
185
188
|
constructor(ctx: DurableObjectStateLike, env: unknown, options?: FiregraphDOOptions);
|
|
186
189
|
_fgGetDoc(docId: string): Promise<DORecordWire | null>;
|
|
187
190
|
_fgQuery(filters: QueryFilter[], options?: QueryOptions): Promise<DORecordWire[]>;
|
|
188
|
-
_fgSetDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
191
|
+
_fgSetDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void>;
|
|
189
192
|
_fgUpdateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
190
193
|
_fgDeleteDoc(docId: string): Promise<void>;
|
|
191
194
|
/**
|
|
@@ -257,7 +260,7 @@ interface DurableObjectIdLike {
|
|
|
257
260
|
interface FiregraphStub {
|
|
258
261
|
_fgGetDoc(docId: string): Promise<DORecordWire | null>;
|
|
259
262
|
_fgQuery(filters: QueryFilter[], options?: QueryOptions): Promise<DORecordWire[]>;
|
|
260
|
-
_fgSetDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
263
|
+
_fgSetDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void>;
|
|
261
264
|
_fgUpdateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
262
265
|
_fgDeleteDoc(docId: string): Promise<void>;
|
|
263
266
|
_fgBatch(ops: BatchOp[]): Promise<void>;
|
|
@@ -320,7 +323,7 @@ declare class DORPCBackend implements StorageBackend {
|
|
|
320
323
|
private get stub();
|
|
321
324
|
getDoc(docId: string): Promise<StoredGraphRecord | null>;
|
|
322
325
|
query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;
|
|
323
|
-
setDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
326
|
+
setDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void>;
|
|
324
327
|
updateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
325
328
|
deleteDoc(docId: string): Promise<void>;
|
|
326
329
|
runTransaction<T>(_fn: (tx: TransactionBackend) => Promise<T>): Promise<T>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { W as WritableRecord, U as UpdatePayload, S as StorageBackend, T as TransactionBackend, B as BatchBackend } from '../backend-
|
|
2
|
-
|
|
1
|
+
import { W as WritableRecord, b as WriteMode, U as UpdatePayload, S as StorageBackend, T as TransactionBackend, B as BatchBackend } from '../backend-BsR0lnFL.js';
|
|
2
|
+
export { d as deleteField } from '../backend-BsR0lnFL.js';
|
|
3
|
+
import { e as GraphRegistry, I as IndexSpec, g as QueryFilter, z as QueryOptions, C as CascadeResult, F as FindEdgesParams, m as BulkOptions, o as BulkResult, a as GraphClient, D as DynamicGraphClient, S as StoredGraphRecord, l as GraphReader, G as GraphClientOptions, c as DynamicRegistryConfig } from '../types-DxYLy8Ol.js';
|
|
3
4
|
import { DurableObject } from 'cloudflare:workers';
|
|
5
|
+
export { M as META_EDGE_TYPE, a as META_NODE_TYPE, b as createMergedRegistry, d as createRegistry, f as generateId } from '../registry-Fi074zVa.js';
|
|
4
6
|
import '@google-cloud/firestore';
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -124,6 +126,7 @@ type BatchOp = {
|
|
|
124
126
|
kind: 'set';
|
|
125
127
|
docId: string;
|
|
126
128
|
record: WritableRecord;
|
|
129
|
+
mode: WriteMode;
|
|
127
130
|
} | {
|
|
128
131
|
kind: 'update';
|
|
129
132
|
docId: string;
|
|
@@ -185,7 +188,7 @@ declare class FiregraphDO extends DurableObject<unknown> {
|
|
|
185
188
|
constructor(ctx: DurableObjectStateLike, env: unknown, options?: FiregraphDOOptions);
|
|
186
189
|
_fgGetDoc(docId: string): Promise<DORecordWire | null>;
|
|
187
190
|
_fgQuery(filters: QueryFilter[], options?: QueryOptions): Promise<DORecordWire[]>;
|
|
188
|
-
_fgSetDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
191
|
+
_fgSetDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void>;
|
|
189
192
|
_fgUpdateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
190
193
|
_fgDeleteDoc(docId: string): Promise<void>;
|
|
191
194
|
/**
|
|
@@ -257,7 +260,7 @@ interface DurableObjectIdLike {
|
|
|
257
260
|
interface FiregraphStub {
|
|
258
261
|
_fgGetDoc(docId: string): Promise<DORecordWire | null>;
|
|
259
262
|
_fgQuery(filters: QueryFilter[], options?: QueryOptions): Promise<DORecordWire[]>;
|
|
260
|
-
_fgSetDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
263
|
+
_fgSetDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void>;
|
|
261
264
|
_fgUpdateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
262
265
|
_fgDeleteDoc(docId: string): Promise<void>;
|
|
263
266
|
_fgBatch(ops: BatchOp[]): Promise<void>;
|
|
@@ -320,7 +323,7 @@ declare class DORPCBackend implements StorageBackend {
|
|
|
320
323
|
private get stub();
|
|
321
324
|
getDoc(docId: string): Promise<StoredGraphRecord | null>;
|
|
322
325
|
query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]>;
|
|
323
|
-
setDoc(docId: string, record: WritableRecord): Promise<void>;
|
|
326
|
+
setDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void>;
|
|
324
327
|
updateDoc(docId: string, update: UpdatePayload): Promise<void>;
|
|
325
328
|
deleteDoc(docId: string): Promise<void>;
|
|
326
329
|
runTransaction<T>(_fn: (tx: TransactionBackend) => Promise<T>): Promise<T>;
|
package/dist/cloudflare/index.js
CHANGED
|
@@ -1,14 +1,173 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CORE_INDEXES,
|
|
3
|
+
META_EDGE_TYPE,
|
|
4
|
+
META_NODE_TYPE,
|
|
3
5
|
NODE_RELATION,
|
|
4
6
|
buildEdgeQueryPlan,
|
|
5
7
|
computeEdgeDocId,
|
|
6
8
|
computeNodeDocId,
|
|
7
|
-
createGraphClientFromBackend
|
|
8
|
-
|
|
9
|
+
createGraphClientFromBackend,
|
|
10
|
+
createMergedRegistry,
|
|
11
|
+
createRegistry,
|
|
12
|
+
generateId
|
|
13
|
+
} from "../chunk-HONQY4HF.js";
|
|
9
14
|
import {
|
|
10
|
-
FiregraphError
|
|
11
|
-
|
|
15
|
+
FiregraphError,
|
|
16
|
+
assertUpdatePayloadExclusive,
|
|
17
|
+
deleteField,
|
|
18
|
+
flattenPatch,
|
|
19
|
+
isDeleteSentinel
|
|
20
|
+
} from "../chunk-AWW4MUJ5.js";
|
|
21
|
+
import {
|
|
22
|
+
SERIALIZATION_TAG
|
|
23
|
+
} from "../chunk-EQJUUVFG.js";
|
|
24
|
+
|
|
25
|
+
// src/internal/sqlite-data-ops.ts
|
|
26
|
+
var FIRESTORE_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
27
|
+
"Timestamp",
|
|
28
|
+
"GeoPoint",
|
|
29
|
+
"VectorValue",
|
|
30
|
+
"DocumentReference",
|
|
31
|
+
"FieldValue"
|
|
32
|
+
]);
|
|
33
|
+
function isFirestoreSpecialType(value) {
|
|
34
|
+
const ctorName = value.constructor?.name;
|
|
35
|
+
if (ctorName && FIRESTORE_TYPE_NAMES.has(ctorName)) return ctorName;
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
var JSON_PATH_KEY_RE = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
39
|
+
function validateJsonPathKey(key, backendLabel) {
|
|
40
|
+
if (key.length === 0) {
|
|
41
|
+
throw new FiregraphError(
|
|
42
|
+
`${backendLabel}: empty JSON path component is not allowed`,
|
|
43
|
+
"INVALID_QUERY"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (!JSON_PATH_KEY_RE.test(key)) {
|
|
47
|
+
throw new FiregraphError(
|
|
48
|
+
`${backendLabel}: data field path component "${key}" is not a safe JSON-path identifier. Allowed pattern: /^[A-Za-z_][A-Za-z0-9_-]*$/. Use replaceNode/replaceEdge (full-data overwrite) for keys with reserved characters (whitespace, dots, brackets, quotes, etc.).`,
|
|
49
|
+
"INVALID_QUERY"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function jsonBind(value, backendLabel) {
|
|
54
|
+
if (value === void 0) return "null";
|
|
55
|
+
if (value !== null && typeof value === "object") {
|
|
56
|
+
const firestoreType = isFirestoreSpecialType(value);
|
|
57
|
+
if (firestoreType) {
|
|
58
|
+
throw new FiregraphError(
|
|
59
|
+
`${backendLabel} cannot persist a Firestore ${firestoreType} value. Convert to a primitive before writing (e.g. \`ts.toMillis()\` for Timestamp).`,
|
|
60
|
+
"INVALID_ARGUMENT"
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return JSON.stringify(value);
|
|
65
|
+
}
|
|
66
|
+
function compileDataOpsExpr(ops, base, params, backendLabel) {
|
|
67
|
+
if (ops.length === 0) return null;
|
|
68
|
+
const deletes = [];
|
|
69
|
+
const sets = [];
|
|
70
|
+
for (const op of ops) (op.delete ? deletes : sets).push(op);
|
|
71
|
+
let expr = base;
|
|
72
|
+
if (deletes.length > 0) {
|
|
73
|
+
const placeholders = deletes.map(() => "?").join(", ");
|
|
74
|
+
expr = `json_remove(${expr}, ${placeholders})`;
|
|
75
|
+
for (const op of deletes) {
|
|
76
|
+
for (const seg of op.path) validateJsonPathKey(seg, backendLabel);
|
|
77
|
+
params.push(`$.${op.path.join(".")}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (sets.length > 0) {
|
|
81
|
+
const pieces = sets.map(() => "?, json(?)").join(", ");
|
|
82
|
+
expr = `json_set(${expr}, ${pieces})`;
|
|
83
|
+
for (const op of sets) {
|
|
84
|
+
for (const seg of op.path) validateJsonPathKey(seg, backendLabel);
|
|
85
|
+
params.push(`$.${op.path.join(".")}`);
|
|
86
|
+
params.push(jsonBind(op.value, backendLabel));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return expr;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/internal/sqlite-payload-guard.ts
|
|
93
|
+
var FIRESTORE_TYPE_NAMES2 = /* @__PURE__ */ new Set([
|
|
94
|
+
"Timestamp",
|
|
95
|
+
"GeoPoint",
|
|
96
|
+
"VectorValue",
|
|
97
|
+
"DocumentReference",
|
|
98
|
+
"FieldValue"
|
|
99
|
+
]);
|
|
100
|
+
function assertJsonSafePayload(data, label) {
|
|
101
|
+
walk(data, [], label);
|
|
102
|
+
}
|
|
103
|
+
function walk(node, path, label) {
|
|
104
|
+
if (node === null || node === void 0) return;
|
|
105
|
+
if (isDeleteSentinel(node)) {
|
|
106
|
+
throw new FiregraphError(
|
|
107
|
+
`${label} backend cannot persist a deleteField() sentinel inside a full-data payload (replaceNode/replaceEdge or first-insert). The sentinel is only valid inside an updateNode/updateEdge dataOps patch. Path: ${formatPath(path)}.`,
|
|
108
|
+
"INVALID_ARGUMENT"
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const t = typeof node;
|
|
112
|
+
if (t === "symbol" || t === "function") {
|
|
113
|
+
throw new FiregraphError(
|
|
114
|
+
`${label} backend cannot persist a value of type ${t}. JSON.stringify drops it silently. Path: ${formatPath(path)}.`,
|
|
115
|
+
"INVALID_ARGUMENT"
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (t === "bigint") {
|
|
119
|
+
throw new FiregraphError(
|
|
120
|
+
`${label} backend cannot persist a value of type bigint. JSON.stringify cannot serialize this type (throws TypeError). Path: ${formatPath(path)}.`,
|
|
121
|
+
"INVALID_ARGUMENT"
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (t !== "object") return;
|
|
125
|
+
if (Array.isArray(node)) {
|
|
126
|
+
for (let i = 0; i < node.length; i++) {
|
|
127
|
+
walk(node[i], [...path, String(i)], label);
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const obj = node;
|
|
132
|
+
if (Object.prototype.hasOwnProperty.call(obj, SERIALIZATION_TAG)) {
|
|
133
|
+
const tagValue = obj[SERIALIZATION_TAG];
|
|
134
|
+
throw new FiregraphError(
|
|
135
|
+
`${label} backend cannot persist an object with a \`${SERIALIZATION_TAG}\` key (value: ${formatTagValue(tagValue)}). Recognised tags are valid only on the Firestore backend (migration-sandbox output); a literal \`${SERIALIZATION_TAG}\` field in user data is reserved and not allowed. Path: ${formatPath(path)}.`,
|
|
136
|
+
"INVALID_ARGUMENT"
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const proto = Object.getPrototypeOf(node);
|
|
140
|
+
if (proto !== null && proto !== Object.prototype) {
|
|
141
|
+
const ctor = node.constructor;
|
|
142
|
+
const ctorName = ctor && typeof ctor.name === "string" ? ctor.name : "<anonymous>";
|
|
143
|
+
if (FIRESTORE_TYPE_NAMES2.has(ctorName)) {
|
|
144
|
+
throw new FiregraphError(
|
|
145
|
+
`${label} backend cannot persist a Firestore ${ctorName} value. Convert to a primitive before writing (e.g. \`ts.toMillis()\` for Timestamp, \`{lat,lng}\` for GeoPoint). Path: ${formatPath(path)}.`,
|
|
146
|
+
"INVALID_ARGUMENT"
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (node instanceof Date) return;
|
|
150
|
+
throw new FiregraphError(
|
|
151
|
+
`${label} backend cannot persist a class instance of type ${ctorName}. Only plain objects, arrays, and primitives round-trip safely through JSON storage. Path: ${formatPath(path)}.`,
|
|
152
|
+
"INVALID_ARGUMENT"
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
for (const key of Object.keys(obj)) {
|
|
156
|
+
walk(obj[key], [...path, key], label);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function formatPath(path) {
|
|
160
|
+
return path.length === 0 ? "<root>" : path.map((p) => JSON.stringify(p)).join(" > ");
|
|
161
|
+
}
|
|
162
|
+
function formatTagValue(value) {
|
|
163
|
+
if (value === null) return "null";
|
|
164
|
+
if (value === void 0) return "undefined";
|
|
165
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
166
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
167
|
+
return String(value);
|
|
168
|
+
}
|
|
169
|
+
return typeof value;
|
|
170
|
+
}
|
|
12
171
|
|
|
13
172
|
// src/timestamp.ts
|
|
14
173
|
var GraphTimestampImpl = class _GraphTimestampImpl {
|
|
@@ -37,7 +196,7 @@ var GraphTimestampImpl = class _GraphTimestampImpl {
|
|
|
37
196
|
|
|
38
197
|
// src/internal/sqlite-index-ddl.ts
|
|
39
198
|
var IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
40
|
-
var
|
|
199
|
+
var JSON_PATH_KEY_RE2 = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
41
200
|
function quoteIdent(name) {
|
|
42
201
|
if (!IDENT_RE.test(name)) {
|
|
43
202
|
throw new FiregraphError(
|
|
@@ -85,7 +244,7 @@ function compileFieldExpr(path, fieldToColumn) {
|
|
|
85
244
|
const suffix = path.slice(5);
|
|
86
245
|
const parts = suffix.split(".");
|
|
87
246
|
for (const part of parts) {
|
|
88
|
-
if (!
|
|
247
|
+
if (!JSON_PATH_KEY_RE2.test(part)) {
|
|
89
248
|
throw new FiregraphError(
|
|
90
249
|
`IndexSpec data path "${path}" has invalid component "${part}". Each component must match /^[A-Za-z_][A-Za-z0-9_-]*$/.`,
|
|
91
250
|
"INVALID_INDEX"
|
|
@@ -180,6 +339,8 @@ function buildDOSchemaStatements(table, options = {}) {
|
|
|
180
339
|
}
|
|
181
340
|
|
|
182
341
|
// src/cloudflare/sql.ts
|
|
342
|
+
var DO_BACKEND_LABEL = "DO SQLite";
|
|
343
|
+
var DO_BACKEND_ERR_LABEL = "DO SQLite backend";
|
|
183
344
|
function compileFieldRef(field) {
|
|
184
345
|
const column = DO_FIELD_TO_COLUMN[field];
|
|
185
346
|
if (column) {
|
|
@@ -188,7 +349,7 @@ function compileFieldRef(field) {
|
|
|
188
349
|
if (field.startsWith("data.")) {
|
|
189
350
|
const suffix = field.slice(5);
|
|
190
351
|
for (const part of suffix.split(".")) {
|
|
191
|
-
validateJsonPathKey(part);
|
|
352
|
+
validateJsonPathKey(part, DO_BACKEND_ERR_LABEL);
|
|
192
353
|
}
|
|
193
354
|
return { expr: `json_extract("data", '$.${suffix}')` };
|
|
194
355
|
}
|
|
@@ -200,18 +361,6 @@ function compileFieldRef(field) {
|
|
|
200
361
|
"INVALID_QUERY"
|
|
201
362
|
);
|
|
202
363
|
}
|
|
203
|
-
var FIRESTORE_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
204
|
-
"Timestamp",
|
|
205
|
-
"GeoPoint",
|
|
206
|
-
"VectorValue",
|
|
207
|
-
"DocumentReference",
|
|
208
|
-
"FieldValue"
|
|
209
|
-
]);
|
|
210
|
-
function isFirestoreSpecialType(value) {
|
|
211
|
-
const ctorName = value.constructor?.name;
|
|
212
|
-
if (ctorName && FIRESTORE_TYPE_NAMES.has(ctorName)) return ctorName;
|
|
213
|
-
return null;
|
|
214
|
-
}
|
|
215
364
|
function bindValue(value) {
|
|
216
365
|
if (value === null || value === void 0) return null;
|
|
217
366
|
if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") {
|
|
@@ -230,21 +379,6 @@ function bindValue(value) {
|
|
|
230
379
|
}
|
|
231
380
|
return String(value);
|
|
232
381
|
}
|
|
233
|
-
var JSON_PATH_KEY_RE2 = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
234
|
-
function validateJsonPathKey(key) {
|
|
235
|
-
if (key.length === 0) {
|
|
236
|
-
throw new FiregraphError(
|
|
237
|
-
"DO SQLite backend: empty JSON path component is not allowed",
|
|
238
|
-
"INVALID_QUERY"
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
if (!JSON_PATH_KEY_RE2.test(key)) {
|
|
242
|
-
throw new FiregraphError(
|
|
243
|
-
`DO SQLite backend: data field path component "${key}" is not a safe JSON-path identifier. Allowed pattern: /^[A-Za-z_][A-Za-z0-9_-]*$/. Use replaceData (full-data overwrite) for keys with reserved characters (whitespace, dots, brackets, quotes, etc.).`,
|
|
244
|
-
"INVALID_QUERY"
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
382
|
function compileFilter(filter, params) {
|
|
249
383
|
const { expr } = compileFieldRef(filter.field);
|
|
250
384
|
switch (filter.op) {
|
|
@@ -331,11 +465,27 @@ function compileDOSelectByDocId(table, docId) {
|
|
|
331
465
|
params: [docId]
|
|
332
466
|
};
|
|
333
467
|
}
|
|
334
|
-
function compileDOSet(table, docId, record, nowMillis) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
468
|
+
function compileDOSet(table, docId, record, nowMillis, mode) {
|
|
469
|
+
assertJsonSafePayload(record.data, DO_BACKEND_LABEL);
|
|
470
|
+
if (mode === "replace") {
|
|
471
|
+
const sql2 = `INSERT OR REPLACE INTO ${quoteDOIdent(table)} (
|
|
472
|
+
doc_id, a_type, a_uid, axb_type, b_type, b_uid, data, v, created_at, updated_at
|
|
473
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
474
|
+
const params = [
|
|
475
|
+
docId,
|
|
476
|
+
record.aType,
|
|
477
|
+
record.aUid,
|
|
478
|
+
record.axbType,
|
|
479
|
+
record.bType,
|
|
480
|
+
record.bUid,
|
|
481
|
+
JSON.stringify(record.data ?? {}),
|
|
482
|
+
record.v ?? null,
|
|
483
|
+
nowMillis,
|
|
484
|
+
nowMillis
|
|
485
|
+
];
|
|
486
|
+
return { sql: sql2, params };
|
|
487
|
+
}
|
|
488
|
+
const insertParams = [
|
|
339
489
|
docId,
|
|
340
490
|
record.aType,
|
|
341
491
|
record.aUid,
|
|
@@ -347,22 +497,44 @@ function compileDOSet(table, docId, record, nowMillis) {
|
|
|
347
497
|
nowMillis,
|
|
348
498
|
nowMillis
|
|
349
499
|
];
|
|
350
|
-
|
|
500
|
+
const ops = flattenPatch(record.data ?? {});
|
|
501
|
+
const updateParams = [];
|
|
502
|
+
const dataExpr = compileDataOpsExpr(ops, `COALESCE("data", '{}')`, updateParams, DO_BACKEND_ERR_LABEL) ?? `COALESCE("data", '{}')`;
|
|
503
|
+
const sql = `INSERT INTO ${quoteDOIdent(table)} (
|
|
504
|
+
doc_id, a_type, a_uid, axb_type, b_type, b_uid, data, v, created_at, updated_at
|
|
505
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
506
|
+
ON CONFLICT(doc_id) DO UPDATE SET
|
|
507
|
+
"a_type" = excluded."a_type",
|
|
508
|
+
"a_uid" = excluded."a_uid",
|
|
509
|
+
"axb_type" = excluded."axb_type",
|
|
510
|
+
"b_type" = excluded."b_type",
|
|
511
|
+
"b_uid" = excluded."b_uid",
|
|
512
|
+
"data" = ${dataExpr},
|
|
513
|
+
"v" = COALESCE(excluded."v", "v"),
|
|
514
|
+
"created_at" = excluded."created_at",
|
|
515
|
+
"updated_at" = excluded."updated_at"`;
|
|
516
|
+
return { sql, params: [...insertParams, ...updateParams] };
|
|
351
517
|
}
|
|
352
518
|
function compileDOUpdate(table, docId, update, nowMillis) {
|
|
519
|
+
assertUpdatePayloadExclusive(update);
|
|
353
520
|
const setClauses = [];
|
|
354
521
|
const params = [];
|
|
355
522
|
if (update.replaceData) {
|
|
523
|
+
assertJsonSafePayload(update.replaceData, DO_BACKEND_LABEL);
|
|
356
524
|
setClauses.push(`"data" = ?`);
|
|
357
525
|
params.push(JSON.stringify(update.replaceData));
|
|
358
|
-
} else if (update.
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
params
|
|
526
|
+
} else if (update.dataOps && update.dataOps.length > 0) {
|
|
527
|
+
for (const op of update.dataOps) {
|
|
528
|
+
if (!op.delete) assertJsonSafePayload(op.value, DO_BACKEND_LABEL);
|
|
529
|
+
}
|
|
530
|
+
const expr = compileDataOpsExpr(
|
|
531
|
+
update.dataOps,
|
|
532
|
+
`COALESCE("data", '{}')`,
|
|
533
|
+
params,
|
|
534
|
+
DO_BACKEND_ERR_LABEL
|
|
535
|
+
);
|
|
536
|
+
if (expr !== null) {
|
|
537
|
+
setClauses.push(`"data" = ${expr}`);
|
|
366
538
|
}
|
|
367
539
|
}
|
|
368
540
|
if (update.v !== void 0) {
|
|
@@ -458,8 +630,8 @@ var DORPCBatchBackend = class {
|
|
|
458
630
|
this.getStub = getStub;
|
|
459
631
|
}
|
|
460
632
|
ops = [];
|
|
461
|
-
setDoc(docId, record) {
|
|
462
|
-
this.ops.push({ kind: "set", docId, record });
|
|
633
|
+
setDoc(docId, record, mode) {
|
|
634
|
+
this.ops.push({ kind: "set", docId, record, mode });
|
|
463
635
|
}
|
|
464
636
|
updateDoc(docId, update) {
|
|
465
637
|
this.ops.push({ kind: "update", docId, update });
|
|
@@ -509,8 +681,8 @@ var DORPCBackend = class _DORPCBackend {
|
|
|
509
681
|
return wires.map(hydrateDORecord);
|
|
510
682
|
}
|
|
511
683
|
// --- Writes ---
|
|
512
|
-
async setDoc(docId, record) {
|
|
513
|
-
return this.stub._fgSetDoc(docId, record);
|
|
684
|
+
async setDoc(docId, record, mode) {
|
|
685
|
+
return this.stub._fgSetDoc(docId, record, mode);
|
|
514
686
|
}
|
|
515
687
|
async updateDoc(docId, update) {
|
|
516
688
|
return this.stub._fgUpdateDoc(docId, update);
|
|
@@ -760,8 +932,8 @@ var FiregraphDO = class extends DurableObject {
|
|
|
760
932
|
// ---------------------------------------------------------------------------
|
|
761
933
|
// RPC: writes
|
|
762
934
|
// ---------------------------------------------------------------------------
|
|
763
|
-
async _fgSetDoc(docId, record) {
|
|
764
|
-
const stmt = compileDOSet(this.table, docId, record, Date.now());
|
|
935
|
+
async _fgSetDoc(docId, record, mode) {
|
|
936
|
+
const stmt = compileDOSet(this.table, docId, record, Date.now(), mode);
|
|
765
937
|
this.execRun(stmt);
|
|
766
938
|
}
|
|
767
939
|
async _fgUpdateDoc(docId, update) {
|
|
@@ -791,7 +963,7 @@ var FiregraphDO = class extends DurableObject {
|
|
|
791
963
|
const statements = ops.map((op) => {
|
|
792
964
|
switch (op.kind) {
|
|
793
965
|
case "set":
|
|
794
|
-
return compileDOSet(this.table, op.docId, op.record, now);
|
|
966
|
+
return compileDOSet(this.table, op.docId, op.record, now, op.mode);
|
|
795
967
|
case "update":
|
|
796
968
|
return compileDOUpdate(this.table, op.docId, op.update, now);
|
|
797
969
|
case "delete":
|
|
@@ -940,8 +1112,14 @@ var FiregraphDO = class extends DurableObject {
|
|
|
940
1112
|
export {
|
|
941
1113
|
DORPCBackend,
|
|
942
1114
|
FiregraphDO,
|
|
1115
|
+
META_EDGE_TYPE,
|
|
1116
|
+
META_NODE_TYPE,
|
|
943
1117
|
buildDOSchemaStatements,
|
|
944
1118
|
createDOClient,
|
|
945
|
-
|
|
1119
|
+
createMergedRegistry,
|
|
1120
|
+
createRegistry,
|
|
1121
|
+
createSiblingClient,
|
|
1122
|
+
deleteField,
|
|
1123
|
+
generateId
|
|
946
1124
|
};
|
|
947
1125
|
//# sourceMappingURL=index.js.map
|