@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
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,21 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
+
// src/internal/serialization-tag.ts
|
|
34
|
+
function isTaggedValue(value) {
|
|
35
|
+
if (value === null || typeof value !== "object") return false;
|
|
36
|
+
const tag = value[SERIALIZATION_TAG];
|
|
37
|
+
return typeof tag === "string" && KNOWN_TYPES.has(tag);
|
|
38
|
+
}
|
|
39
|
+
var SERIALIZATION_TAG, KNOWN_TYPES;
|
|
40
|
+
var init_serialization_tag = __esm({
|
|
41
|
+
"src/internal/serialization-tag.ts"() {
|
|
42
|
+
"use strict";
|
|
43
|
+
SERIALIZATION_TAG = "__firegraph_ser__";
|
|
44
|
+
KNOWN_TYPES = /* @__PURE__ */ new Set(["Timestamp", "GeoPoint", "VectorValue", "DocumentReference"]);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
33
48
|
// src/serialization.ts
|
|
34
49
|
var serialization_exports = {};
|
|
35
50
|
__export(serialization_exports, {
|
|
@@ -38,11 +53,6 @@ __export(serialization_exports, {
|
|
|
38
53
|
isTaggedValue: () => isTaggedValue,
|
|
39
54
|
serializeFirestoreTypes: () => serializeFirestoreTypes
|
|
40
55
|
});
|
|
41
|
-
function isTaggedValue(value) {
|
|
42
|
-
if (value === null || typeof value !== "object") return false;
|
|
43
|
-
const tag = value[SERIALIZATION_TAG];
|
|
44
|
-
return typeof tag === "string" && KNOWN_TYPES.has(tag);
|
|
45
|
-
}
|
|
46
56
|
function isTimestamp(value) {
|
|
47
57
|
return value instanceof import_firestore.Timestamp;
|
|
48
58
|
}
|
|
@@ -143,13 +153,13 @@ function deserializeValue(value, db) {
|
|
|
143
153
|
}
|
|
144
154
|
return result;
|
|
145
155
|
}
|
|
146
|
-
var import_firestore,
|
|
156
|
+
var import_firestore, _docRefWarned;
|
|
147
157
|
var init_serialization = __esm({
|
|
148
158
|
"src/serialization.ts"() {
|
|
149
159
|
"use strict";
|
|
150
160
|
import_firestore = require("@google-cloud/firestore");
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
init_serialization_tag();
|
|
162
|
+
init_serialization_tag();
|
|
153
163
|
_docRefWarned = false;
|
|
154
164
|
}
|
|
155
165
|
});
|
|
@@ -202,6 +212,7 @@ __export(index_exports, {
|
|
|
202
212
|
defaultExecutor: () => defaultExecutor,
|
|
203
213
|
defineConfig: () => defineConfig,
|
|
204
214
|
defineViews: () => defineViews,
|
|
215
|
+
deleteField: () => deleteField,
|
|
205
216
|
deserializeFirestoreTypes: () => deserializeFirestoreTypes,
|
|
206
217
|
destroySandboxWorker: () => destroySandboxWorker,
|
|
207
218
|
discoverEntities: () => discoverEntities,
|
|
@@ -255,6 +266,146 @@ function computeEdgeDocId(aUid, axbType, bUid) {
|
|
|
255
266
|
return `${shard}${SHARD_SEPARATOR}${aUid}${SHARD_SEPARATOR}${axbType}${SHARD_SEPARATOR}${bUid}`;
|
|
256
267
|
}
|
|
257
268
|
|
|
269
|
+
// src/internal/write-plan.ts
|
|
270
|
+
init_serialization_tag();
|
|
271
|
+
var DELETE_FIELD = /* @__PURE__ */ Symbol.for("firegraph.deleteField");
|
|
272
|
+
function deleteField() {
|
|
273
|
+
return DELETE_FIELD;
|
|
274
|
+
}
|
|
275
|
+
function isDeleteSentinel(value) {
|
|
276
|
+
return value === DELETE_FIELD;
|
|
277
|
+
}
|
|
278
|
+
var FIRESTORE_TERMINAL_CTOR = /* @__PURE__ */ new Set([
|
|
279
|
+
"Timestamp",
|
|
280
|
+
"GeoPoint",
|
|
281
|
+
"VectorValue",
|
|
282
|
+
"DocumentReference",
|
|
283
|
+
"FieldValue",
|
|
284
|
+
"NumericIncrementTransform",
|
|
285
|
+
"ArrayUnionTransform",
|
|
286
|
+
"ArrayRemoveTransform",
|
|
287
|
+
"ServerTimestampTransform",
|
|
288
|
+
"DeleteTransform"
|
|
289
|
+
]);
|
|
290
|
+
function isTerminalValue(value) {
|
|
291
|
+
if (value === null) return true;
|
|
292
|
+
const t = typeof value;
|
|
293
|
+
if (t !== "object") return true;
|
|
294
|
+
if (Array.isArray(value)) return true;
|
|
295
|
+
if (isTaggedValue(value)) return true;
|
|
296
|
+
const proto = Object.getPrototypeOf(value);
|
|
297
|
+
if (proto === null || proto === Object.prototype) return false;
|
|
298
|
+
const ctor = value.constructor;
|
|
299
|
+
if (ctor && typeof ctor.name === "string" && FIRESTORE_TERMINAL_CTOR.has(ctor.name)) return true;
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
var SAFE_KEY_RE = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
303
|
+
function assertUpdatePayloadExclusive(update) {
|
|
304
|
+
if (update.replaceData !== void 0 && update.dataOps !== void 0) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
"firegraph: UpdatePayload cannot specify both `replaceData` and `dataOps`. Use one or the other \u2014 `replaceData` is the migration-write-back form, `dataOps` is the standard partial-update form."
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function assertNoDeleteSentinels(data, callerLabel) {
|
|
311
|
+
walkForDeleteSentinels(data, [], { kind: "root" }, ({ path }) => {
|
|
312
|
+
const where = path.length === 0 ? "<root>" : path.map((p) => JSON.stringify(p)).join(" > ");
|
|
313
|
+
throw new Error(
|
|
314
|
+
`firegraph: ${callerLabel} payload contains a deleteField() sentinel at ${where}. deleteField() is only valid inside updateNode/updateEdge \u2014 full-data writes (put*, replace*) cannot delete individual fields. Use updateNode with a deleteField() value, or omit the field from the replace payload.`
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
function walkForDeleteSentinels(node, path, parent, visit) {
|
|
319
|
+
if (node === null || node === void 0) return;
|
|
320
|
+
if (isDeleteSentinel(node)) {
|
|
321
|
+
visit({ path, parent });
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (typeof node !== "object") return;
|
|
325
|
+
if (isTaggedValue(node)) return;
|
|
326
|
+
if (Array.isArray(node)) {
|
|
327
|
+
for (let i = 0; i < node.length; i++) {
|
|
328
|
+
walkForDeleteSentinels(node[i], [...path, String(i)], { kind: "array", index: i }, visit);
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const proto = Object.getPrototypeOf(node);
|
|
333
|
+
if (proto !== null && proto !== Object.prototype) return;
|
|
334
|
+
const obj = node;
|
|
335
|
+
for (const key of Object.keys(obj)) {
|
|
336
|
+
walkForDeleteSentinels(obj[key], [...path, key], { kind: "object" }, visit);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function assertSafePath(path) {
|
|
340
|
+
for (const seg of path) {
|
|
341
|
+
if (!SAFE_KEY_RE.test(seg)) {
|
|
342
|
+
throw new Error(
|
|
343
|
+
`firegraph: unsafe object key ${JSON.stringify(seg)} at path ${path.map((p) => JSON.stringify(p)).join(" > ")}. Keys used inside update payloads must match /^[A-Za-z_][A-Za-z0-9_-]*$/ so they can be embedded safely in SQLite JSON paths.`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function flattenPatch(data) {
|
|
349
|
+
const ops = [];
|
|
350
|
+
walk(data, [], ops);
|
|
351
|
+
return ops;
|
|
352
|
+
}
|
|
353
|
+
function assertNoDeleteSentinelsInArrayValue(arr, arrayPath) {
|
|
354
|
+
walkForDeleteSentinels(arr, arrayPath, { kind: "root" }, ({ parent }) => {
|
|
355
|
+
const arrayPathStr = arrayPath.length === 0 ? "<root>" : arrayPath.map((p) => JSON.stringify(p)).join(" > ");
|
|
356
|
+
if (parent.kind === "array") {
|
|
357
|
+
throw new Error(
|
|
358
|
+
`firegraph: deleteField() sentinel at index ${parent.index} inside an array at path ${arrayPathStr}. Arrays are terminal in update payloads (replaced as a unit), so the sentinel would be silently dropped by JSON serialization. To remove the field entirely, pass deleteField() in place of the whole array.`
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
throw new Error(
|
|
362
|
+
`firegraph: deleteField() sentinel inside an array element at path ${arrayPathStr}. Arrays are terminal in update payloads \u2014 the sentinel would be silently dropped by JSON serialization.`
|
|
363
|
+
);
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
function walk(node, path, out) {
|
|
367
|
+
if (node === void 0) return;
|
|
368
|
+
if (isDeleteSentinel(node)) {
|
|
369
|
+
if (path.length === 0) {
|
|
370
|
+
throw new Error("firegraph: deleteField() cannot be the entire update payload.");
|
|
371
|
+
}
|
|
372
|
+
assertSafePath(path);
|
|
373
|
+
out.push({ path: [...path], value: void 0, delete: true });
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (isTerminalValue(node)) {
|
|
377
|
+
if (path.length === 0) {
|
|
378
|
+
throw new Error(
|
|
379
|
+
"firegraph: update payload must be a plain object. Got " + (node === null ? "null" : Array.isArray(node) ? "array" : typeof node) + "."
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
if (Array.isArray(node)) {
|
|
383
|
+
assertNoDeleteSentinelsInArrayValue(node, path);
|
|
384
|
+
}
|
|
385
|
+
assertSafePath(path);
|
|
386
|
+
out.push({ path: [...path], value: node, delete: false });
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const obj = node;
|
|
390
|
+
const keys = Object.keys(obj);
|
|
391
|
+
if (keys.length === 0) {
|
|
392
|
+
if (path.length > 0) {
|
|
393
|
+
assertSafePath(path);
|
|
394
|
+
out.push({ path: [...path], value: {}, delete: false });
|
|
395
|
+
}
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
for (const key of keys) {
|
|
399
|
+
if (key === SERIALIZATION_TAG) {
|
|
400
|
+
const where = path.length === 0 ? "<root>" : path.map((p) => JSON.stringify(p)).join(" > ");
|
|
401
|
+
throw new Error(
|
|
402
|
+
`firegraph: update payload contains a literal \`${SERIALIZATION_TAG}\` key at ${where}. That key is reserved for firegraph's serialization envelope and cannot appear on a plain object in user data. Use a different field name, or pass a recognized tagged value through replaceNode/replaceEdge instead.`
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
walk(obj[key], [...path, key], out);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
258
409
|
// src/batch.ts
|
|
259
410
|
function buildWritableNodeRecord(aType, uid, data) {
|
|
260
411
|
return { aType, aUid: uid, axbType: NODE_RELATION, bType: aType, bUid: uid, data };
|
|
@@ -269,6 +420,19 @@ var GraphBatchImpl = class {
|
|
|
269
420
|
this.scopePath = scopePath;
|
|
270
421
|
}
|
|
271
422
|
async putNode(aType, uid, data) {
|
|
423
|
+
this.writeNode(aType, uid, data, "merge");
|
|
424
|
+
}
|
|
425
|
+
async putEdge(aType, aUid, axbType, bType, bUid, data) {
|
|
426
|
+
this.writeEdge(aType, aUid, axbType, bType, bUid, data, "merge");
|
|
427
|
+
}
|
|
428
|
+
async replaceNode(aType, uid, data) {
|
|
429
|
+
this.writeNode(aType, uid, data, "replace");
|
|
430
|
+
}
|
|
431
|
+
async replaceEdge(aType, aUid, axbType, bType, bUid, data) {
|
|
432
|
+
this.writeEdge(aType, aUid, axbType, bType, bUid, data, "replace");
|
|
433
|
+
}
|
|
434
|
+
writeNode(aType, uid, data, mode) {
|
|
435
|
+
assertNoDeleteSentinels(data, mode === "replace" ? "replaceNode" : "putNode");
|
|
272
436
|
if (this.registry) {
|
|
273
437
|
this.registry.validate(aType, NODE_RELATION, aType, data, this.scopePath);
|
|
274
438
|
}
|
|
@@ -280,9 +444,10 @@ var GraphBatchImpl = class {
|
|
|
280
444
|
record.v = entry.schemaVersion;
|
|
281
445
|
}
|
|
282
446
|
}
|
|
283
|
-
this.backend.setDoc(docId, record);
|
|
447
|
+
this.backend.setDoc(docId, record, mode);
|
|
284
448
|
}
|
|
285
|
-
|
|
449
|
+
writeEdge(aType, aUid, axbType, bType, bUid, data, mode) {
|
|
450
|
+
assertNoDeleteSentinels(data, mode === "replace" ? "replaceEdge" : "putEdge");
|
|
286
451
|
if (this.registry) {
|
|
287
452
|
this.registry.validate(aType, axbType, bType, data, this.scopePath);
|
|
288
453
|
}
|
|
@@ -294,11 +459,15 @@ var GraphBatchImpl = class {
|
|
|
294
459
|
record.v = entry.schemaVersion;
|
|
295
460
|
}
|
|
296
461
|
}
|
|
297
|
-
this.backend.setDoc(docId, record);
|
|
462
|
+
this.backend.setDoc(docId, record, mode);
|
|
298
463
|
}
|
|
299
464
|
async updateNode(uid, data) {
|
|
300
465
|
const docId = computeNodeDocId(uid);
|
|
301
|
-
this.backend.updateDoc(docId, {
|
|
466
|
+
this.backend.updateDoc(docId, { dataOps: flattenPatch(data) });
|
|
467
|
+
}
|
|
468
|
+
async updateEdge(aUid, axbType, bUid, data) {
|
|
469
|
+
const docId = computeEdgeDocId(aUid, axbType, bUid);
|
|
470
|
+
this.backend.updateDoc(docId, { dataOps: flattenPatch(data) });
|
|
302
471
|
}
|
|
303
472
|
async removeNode(uid) {
|
|
304
473
|
const docId = computeNodeDocId(uid);
|
|
@@ -1409,6 +1578,19 @@ var GraphTransactionImpl = class {
|
|
|
1409
1578
|
return results.map((r) => r.record);
|
|
1410
1579
|
}
|
|
1411
1580
|
async putNode(aType, uid, data) {
|
|
1581
|
+
await this.writeNode(aType, uid, data, "merge");
|
|
1582
|
+
}
|
|
1583
|
+
async putEdge(aType, aUid, axbType, bType, bUid, data) {
|
|
1584
|
+
await this.writeEdge(aType, aUid, axbType, bType, bUid, data, "merge");
|
|
1585
|
+
}
|
|
1586
|
+
async replaceNode(aType, uid, data) {
|
|
1587
|
+
await this.writeNode(aType, uid, data, "replace");
|
|
1588
|
+
}
|
|
1589
|
+
async replaceEdge(aType, aUid, axbType, bType, bUid, data) {
|
|
1590
|
+
await this.writeEdge(aType, aUid, axbType, bType, bUid, data, "replace");
|
|
1591
|
+
}
|
|
1592
|
+
async writeNode(aType, uid, data, mode) {
|
|
1593
|
+
assertNoDeleteSentinels(data, mode === "replace" ? "replaceNode" : "putNode");
|
|
1412
1594
|
if (this.registry) {
|
|
1413
1595
|
this.registry.validate(aType, NODE_RELATION, aType, data, this.scopePath);
|
|
1414
1596
|
}
|
|
@@ -1420,9 +1602,10 @@ var GraphTransactionImpl = class {
|
|
|
1420
1602
|
record.v = entry.schemaVersion;
|
|
1421
1603
|
}
|
|
1422
1604
|
}
|
|
1423
|
-
await this.backend.setDoc(docId, record);
|
|
1605
|
+
await this.backend.setDoc(docId, record, mode);
|
|
1424
1606
|
}
|
|
1425
|
-
async
|
|
1607
|
+
async writeEdge(aType, aUid, axbType, bType, bUid, data, mode) {
|
|
1608
|
+
assertNoDeleteSentinels(data, mode === "replace" ? "replaceEdge" : "putEdge");
|
|
1426
1609
|
if (this.registry) {
|
|
1427
1610
|
this.registry.validate(aType, axbType, bType, data, this.scopePath);
|
|
1428
1611
|
}
|
|
@@ -1434,11 +1617,15 @@ var GraphTransactionImpl = class {
|
|
|
1434
1617
|
record.v = entry.schemaVersion;
|
|
1435
1618
|
}
|
|
1436
1619
|
}
|
|
1437
|
-
await this.backend.setDoc(docId, record);
|
|
1620
|
+
await this.backend.setDoc(docId, record, mode);
|
|
1438
1621
|
}
|
|
1439
1622
|
async updateNode(uid, data) {
|
|
1440
1623
|
const docId = computeNodeDocId(uid);
|
|
1441
|
-
await this.backend.updateDoc(docId, {
|
|
1624
|
+
await this.backend.updateDoc(docId, { dataOps: flattenPatch(data) });
|
|
1625
|
+
}
|
|
1626
|
+
async updateEdge(aUid, axbType, bUid, data) {
|
|
1627
|
+
const docId = computeEdgeDocId(aUid, axbType, bUid);
|
|
1628
|
+
await this.backend.updateDoc(docId, { dataOps: flattenPatch(data) });
|
|
1442
1629
|
}
|
|
1443
1630
|
async removeNode(uid) {
|
|
1444
1631
|
const docId = computeNodeDocId(uid);
|
|
@@ -1637,6 +1824,19 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
1637
1824
|
// GraphWriter
|
|
1638
1825
|
// ---------------------------------------------------------------------------
|
|
1639
1826
|
async putNode(aType, uid, data) {
|
|
1827
|
+
await this.writeNode(aType, uid, data, "merge");
|
|
1828
|
+
}
|
|
1829
|
+
async putEdge(aType, aUid, axbType, bType, bUid, data) {
|
|
1830
|
+
await this.writeEdge(aType, aUid, axbType, bType, bUid, data, "merge");
|
|
1831
|
+
}
|
|
1832
|
+
async replaceNode(aType, uid, data) {
|
|
1833
|
+
await this.writeNode(aType, uid, data, "replace");
|
|
1834
|
+
}
|
|
1835
|
+
async replaceEdge(aType, aUid, axbType, bType, bUid, data) {
|
|
1836
|
+
await this.writeEdge(aType, aUid, axbType, bType, bUid, data, "replace");
|
|
1837
|
+
}
|
|
1838
|
+
async writeNode(aType, uid, data, mode) {
|
|
1839
|
+
assertNoDeleteSentinels(data, mode === "replace" ? "replaceNode" : "putNode");
|
|
1640
1840
|
const registry = this.getRegistryForType(aType);
|
|
1641
1841
|
if (registry) {
|
|
1642
1842
|
registry.validate(aType, NODE_RELATION, aType, data, this.backend.scopePath);
|
|
@@ -1650,9 +1850,10 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
1650
1850
|
record.v = entry.schemaVersion;
|
|
1651
1851
|
}
|
|
1652
1852
|
}
|
|
1653
|
-
await backend.setDoc(docId, record);
|
|
1853
|
+
await backend.setDoc(docId, record, mode);
|
|
1654
1854
|
}
|
|
1655
|
-
async
|
|
1855
|
+
async writeEdge(aType, aUid, axbType, bType, bUid, data, mode) {
|
|
1856
|
+
assertNoDeleteSentinels(data, mode === "replace" ? "replaceEdge" : "putEdge");
|
|
1656
1857
|
const registry = this.getRegistryForType(aType);
|
|
1657
1858
|
if (registry) {
|
|
1658
1859
|
registry.validate(aType, axbType, bType, data, this.backend.scopePath);
|
|
@@ -1666,11 +1867,15 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
1666
1867
|
record.v = entry.schemaVersion;
|
|
1667
1868
|
}
|
|
1668
1869
|
}
|
|
1669
|
-
await backend.setDoc(docId, record);
|
|
1870
|
+
await backend.setDoc(docId, record, mode);
|
|
1670
1871
|
}
|
|
1671
1872
|
async updateNode(uid, data) {
|
|
1672
1873
|
const docId = computeNodeDocId(uid);
|
|
1673
|
-
await this.backend.updateDoc(docId, {
|
|
1874
|
+
await this.backend.updateDoc(docId, { dataOps: flattenPatch(data) });
|
|
1875
|
+
}
|
|
1876
|
+
async updateEdge(aUid, axbType, bUid, data) {
|
|
1877
|
+
const docId = computeEdgeDocId(aUid, axbType, bUid);
|
|
1878
|
+
await this.backend.updateDoc(docId, { dataOps: flattenPatch(data) });
|
|
1674
1879
|
}
|
|
1675
1880
|
async removeNode(uid) {
|
|
1676
1881
|
const docId = computeNodeDocId(uid);
|
|
@@ -2344,8 +2549,12 @@ function createFirestoreAdapter(db, collectionPath) {
|
|
|
2344
2549
|
if (!snap.exists) return null;
|
|
2345
2550
|
return snap.data();
|
|
2346
2551
|
},
|
|
2347
|
-
async setDoc(docId, data) {
|
|
2348
|
-
|
|
2552
|
+
async setDoc(docId, data, options) {
|
|
2553
|
+
if (options?.merge) {
|
|
2554
|
+
await collectionRef.doc(docId).set(data, { merge: true });
|
|
2555
|
+
} else {
|
|
2556
|
+
await collectionRef.doc(docId).set(data);
|
|
2557
|
+
}
|
|
2349
2558
|
},
|
|
2350
2559
|
async updateDoc(docId, data) {
|
|
2351
2560
|
await collectionRef.doc(docId).update(data);
|
|
@@ -2377,8 +2586,12 @@ function createTransactionAdapter(db, collectionPath, tx) {
|
|
|
2377
2586
|
if (!snap.exists) return null;
|
|
2378
2587
|
return snap.data();
|
|
2379
2588
|
},
|
|
2380
|
-
setDoc(docId, data) {
|
|
2381
|
-
|
|
2589
|
+
setDoc(docId, data, options) {
|
|
2590
|
+
if (options?.merge) {
|
|
2591
|
+
tx.set(collectionRef.doc(docId), data, { merge: true });
|
|
2592
|
+
} else {
|
|
2593
|
+
tx.set(collectionRef.doc(docId), data);
|
|
2594
|
+
}
|
|
2382
2595
|
},
|
|
2383
2596
|
updateDoc(docId, data) {
|
|
2384
2597
|
tx.update(collectionRef.doc(docId), data);
|
|
@@ -2406,8 +2619,12 @@ function createBatchAdapter(db, collectionPath) {
|
|
|
2406
2619
|
const collectionRef = db.collection(collectionPath);
|
|
2407
2620
|
const batch = db.batch();
|
|
2408
2621
|
return {
|
|
2409
|
-
setDoc(docId, data) {
|
|
2410
|
-
|
|
2622
|
+
setDoc(docId, data, options) {
|
|
2623
|
+
if (options?.merge) {
|
|
2624
|
+
batch.set(collectionRef.doc(docId), data, { merge: true });
|
|
2625
|
+
} else {
|
|
2626
|
+
batch.set(collectionRef.doc(docId), data);
|
|
2627
|
+
}
|
|
2411
2628
|
},
|
|
2412
2629
|
updateDoc(docId, data) {
|
|
2413
2630
|
batch.update(collectionRef.doc(docId), data);
|
|
@@ -2483,16 +2700,21 @@ function createPipelineQueryAdapter(db, collectionPath) {
|
|
|
2483
2700
|
}
|
|
2484
2701
|
|
|
2485
2702
|
// src/internal/firestore-backend.ts
|
|
2703
|
+
function dottedDataPath(op) {
|
|
2704
|
+
assertSafePath(op.path);
|
|
2705
|
+
return `data.${op.path.join(".")}`;
|
|
2706
|
+
}
|
|
2486
2707
|
function buildFirestoreUpdate(update, db) {
|
|
2708
|
+
assertUpdatePayloadExclusive(update);
|
|
2487
2709
|
const out = {
|
|
2488
2710
|
updatedAt: import_firestore2.FieldValue.serverTimestamp()
|
|
2489
2711
|
};
|
|
2490
2712
|
if (update.replaceData) {
|
|
2491
2713
|
out.data = deserializeFirestoreTypes(update.replaceData, db);
|
|
2492
|
-
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
out[
|
|
2714
|
+
} else if (update.dataOps) {
|
|
2715
|
+
for (const op of update.dataOps) {
|
|
2716
|
+
const key = dottedDataPath(op);
|
|
2717
|
+
out[key] = op.delete ? import_firestore2.FieldValue.delete() : op.value;
|
|
2496
2718
|
}
|
|
2497
2719
|
}
|
|
2498
2720
|
if (update.v !== void 0) {
|
|
@@ -2526,8 +2748,12 @@ var FirestoreTransactionBackend = class {
|
|
|
2526
2748
|
query(filters, options) {
|
|
2527
2749
|
return this.adapter.query(filters, options);
|
|
2528
2750
|
}
|
|
2529
|
-
async setDoc(docId, record) {
|
|
2530
|
-
this.adapter.setDoc(
|
|
2751
|
+
async setDoc(docId, record, mode) {
|
|
2752
|
+
this.adapter.setDoc(
|
|
2753
|
+
docId,
|
|
2754
|
+
stampWritableRecord(record),
|
|
2755
|
+
mode === "merge" ? { merge: true } : void 0
|
|
2756
|
+
);
|
|
2531
2757
|
}
|
|
2532
2758
|
async updateDoc(docId, update) {
|
|
2533
2759
|
this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
|
|
@@ -2541,8 +2767,12 @@ var FirestoreBatchBackend = class {
|
|
|
2541
2767
|
this.adapter = adapter;
|
|
2542
2768
|
this.db = db;
|
|
2543
2769
|
}
|
|
2544
|
-
setDoc(docId, record) {
|
|
2545
|
-
this.adapter.setDoc(
|
|
2770
|
+
setDoc(docId, record, mode) {
|
|
2771
|
+
this.adapter.setDoc(
|
|
2772
|
+
docId,
|
|
2773
|
+
stampWritableRecord(record),
|
|
2774
|
+
mode === "merge" ? { merge: true } : void 0
|
|
2775
|
+
);
|
|
2546
2776
|
}
|
|
2547
2777
|
updateDoc(docId, update) {
|
|
2548
2778
|
this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
|
|
@@ -2580,8 +2810,12 @@ var FirestoreBackendImpl = class _FirestoreBackendImpl {
|
|
|
2580
2810
|
return this.adapter.query(filters, options);
|
|
2581
2811
|
}
|
|
2582
2812
|
// --- Writes ---
|
|
2583
|
-
setDoc(docId, record) {
|
|
2584
|
-
return this.adapter.setDoc(
|
|
2813
|
+
setDoc(docId, record, mode) {
|
|
2814
|
+
return this.adapter.setDoc(
|
|
2815
|
+
docId,
|
|
2816
|
+
stampWritableRecord(record),
|
|
2817
|
+
mode === "merge" ? { merge: true } : void 0
|
|
2818
|
+
);
|
|
2585
2819
|
}
|
|
2586
2820
|
updateDoc(docId, update) {
|
|
2587
2821
|
return this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
|
|
@@ -3441,6 +3675,7 @@ function defineViews(input) {
|
|
|
3441
3675
|
defaultExecutor,
|
|
3442
3676
|
defineConfig,
|
|
3443
3677
|
defineViews,
|
|
3678
|
+
deleteField,
|
|
3444
3679
|
deserializeFirestoreTypes,
|
|
3445
3680
|
destroySandboxWorker,
|
|
3446
3681
|
discoverEntities,
|