@nicia-ai/typegraph 0.13.0 → 0.14.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/dist/backend/postgres/index.cjs +28 -28
- package/dist/backend/postgres/index.d.cts +1 -1
- package/dist/backend/postgres/index.d.ts +1 -1
- package/dist/backend/postgres/index.js +4 -4
- package/dist/backend/sqlite/index.cjs +14 -14
- package/dist/backend/sqlite/index.d.cts +1 -1
- package/dist/backend/sqlite/index.d.ts +1 -1
- package/dist/backend/sqlite/index.js +4 -4
- package/dist/backend/sqlite/local.cjs +7 -7
- package/dist/backend/sqlite/local.d.cts +1 -1
- package/dist/backend/sqlite/local.d.ts +1 -1
- package/dist/backend/sqlite/local.js +4 -4
- package/dist/{chunk-U3452TEU.js → chunk-6GWJH6AR.js} +15 -27
- package/dist/chunk-6GWJH6AR.js.map +1 -0
- package/dist/{chunk-52WSY6G5.js → chunk-BNIBR5U2.js} +70 -31
- package/dist/chunk-BNIBR5U2.js.map +1 -0
- package/dist/{chunk-54WJF3DW.js → chunk-GNIYZKBI.js} +29 -3
- package/dist/chunk-GNIYZKBI.js.map +1 -0
- package/dist/{chunk-2XPKLHHH.cjs → chunk-KE2BL3JZ.cjs} +74 -35
- package/dist/chunk-KE2BL3JZ.cjs.map +1 -0
- package/dist/{chunk-PYV4ADC6.js → chunk-KLOSTZDQ.js} +141 -13
- package/dist/chunk-KLOSTZDQ.js.map +1 -0
- package/dist/{chunk-JQDWEX6V.cjs → chunk-LELLOHJK.cjs} +22 -34
- package/dist/chunk-LELLOHJK.cjs.map +1 -0
- package/dist/{chunk-2WVFEIHR.cjs → chunk-MME3H4ZF.cjs} +40 -2
- package/dist/chunk-MME3H4ZF.cjs.map +1 -0
- package/dist/{chunk-NZMKJHE2.cjs → chunk-OEKH5PWL.cjs} +15 -15
- package/dist/{chunk-NZMKJHE2.cjs.map → chunk-OEKH5PWL.cjs.map} +1 -1
- package/dist/{chunk-7VITUTRA.cjs → chunk-QFZ5QB2J.cjs} +140 -12
- package/dist/chunk-QFZ5QB2J.cjs.map +1 -0
- package/dist/{chunk-J4SICP3X.js → chunk-RVUEBUBH.js} +3 -3
- package/dist/{chunk-J4SICP3X.js.map → chunk-RVUEBUBH.js.map} +1 -1
- package/dist/index.cjs +432 -578
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -9
- package/dist/index.d.ts +12 -9
- package/dist/index.js +393 -539
- package/dist/index.js.map +1 -1
- package/dist/indexes/index.cjs +16 -16
- package/dist/indexes/index.js +2 -2
- package/dist/interchange/index.d.cts +3 -3
- package/dist/interchange/index.d.ts +3 -3
- package/dist/{manager-DGSnJa1v.d.cts → manager-oh2mTMvy.d.cts} +1 -1
- package/dist/{manager-BCLhWysp.d.ts → manager-qRSdnKEO.d.ts} +1 -1
- package/dist/profiler/index.cjs +6 -6
- package/dist/profiler/index.cjs.map +1 -1
- package/dist/profiler/index.d.cts +3 -3
- package/dist/profiler/index.d.ts +3 -3
- package/dist/profiler/index.js +6 -6
- package/dist/profiler/index.js.map +1 -1
- package/dist/schema/index.cjs +20 -20
- package/dist/schema/index.d.cts +4 -4
- package/dist/schema/index.d.ts +4 -4
- package/dist/schema/index.js +2 -2
- package/dist/{store-6-vH0ZIj.d.ts → store-B9ItxA-Q.d.ts} +37 -17
- package/dist/{store-Bmdt_dS6.d.cts → store-BJPIoe8u.d.cts} +37 -17
- package/dist/{types-1YJKodRv.d.ts → types-5t_MIcvv.d.ts} +12 -6
- package/dist/{types-GLkwvQvS.d.cts → types-Ckfwgv9l.d.cts} +12 -6
- package/package.json +1 -1
- package/dist/chunk-2WVFEIHR.cjs.map +0 -1
- package/dist/chunk-2XPKLHHH.cjs.map +0 -1
- package/dist/chunk-52WSY6G5.js.map +0 -1
- package/dist/chunk-54WJF3DW.js.map +0 -1
- package/dist/chunk-7VITUTRA.cjs.map +0 -1
- package/dist/chunk-JQDWEX6V.cjs.map +0 -1
- package/dist/chunk-PYV4ADC6.js.map +0 -1
- package/dist/chunk-U3452TEU.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,18 +1,68 @@
|
|
|
1
|
-
import { META_EDGE_BRAND, META_EDGE_SUB_CLASS_OF, META_EDGE_NARROWER, META_EDGE_BROADER, META_EDGE_RELATED_TO, META_EDGE_EQUIVALENT_TO, META_EDGE_SAME_AS, META_EDGE_DIFFERENT_FROM, META_EDGE_DISJOINT_WITH, META_EDGE_HAS_PART, META_EDGE_PART_OF, META_EDGE_INVERSE_OF, META_EDGE_IMPLIES, ensureSchema, computeClosuresFromOntology, createEmptyClosures, KindRegistry, validateNodeProps, validateEdgeProps } from './chunk-
|
|
2
|
-
export { isMetaEdge } from './chunk-
|
|
1
|
+
import { META_EDGE_BRAND, META_EDGE_SUB_CLASS_OF, META_EDGE_NARROWER, META_EDGE_BROADER, META_EDGE_RELATED_TO, META_EDGE_EQUIVALENT_TO, META_EDGE_SAME_AS, META_EDGE_DIFFERENT_FROM, META_EDGE_DISJOINT_WITH, META_EDGE_HAS_PART, META_EDGE_PART_OF, META_EDGE_INVERSE_OF, META_EDGE_IMPLIES, ensureSchema, computeClosuresFromOntology, createEmptyClosures, KindRegistry, validateNodeProps, validateEdgeProps } from './chunk-KLOSTZDQ.js';
|
|
2
|
+
export { isMetaEdge } from './chunk-KLOSTZDQ.js';
|
|
3
3
|
import { NODE_TYPE_BRAND, EDGE_TYPE_BRAND, nowIso, validateOptionalIsoDate, getNodeKinds, getEdgeKinds } from './chunk-IRFD3MEU.js';
|
|
4
4
|
export { defineGraph, getEdgeKinds, getNodeKinds, isEdgeType, isEdgeTypeWithEndpoints, isGraphDef, isNodeType } from './chunk-IRFD3MEU.js';
|
|
5
|
-
import { ConfigurationError, UnsupportedPredicateError, ValidationError, CompilerInvariantError, KindNotFoundError,
|
|
5
|
+
import { ConfigurationError, UnsupportedPredicateError, ValidationError, CompilerInvariantError, KindNotFoundError, DatabaseOperationError, EdgeNotFoundError, NodeConstraintNotFoundError, RestrictedDeleteError, NodeNotFoundError, EndpointNotFoundError, UniquenessError, CardinalityError, EndpointError, DisjointError } from './chunk-SJ2QMDXY.js';
|
|
6
6
|
export { CardinalityError, CompilerInvariantError, ConfigurationError, DatabaseOperationError, DisjointError, EdgeNotFoundError, EndpointError, EndpointNotFoundError, KindNotFoundError, MigrationError, NodeConstraintNotFoundError, NodeNotFoundError, RestrictedDeleteError, SchemaMismatchError, TypeGraphError, UniquenessError, UnsupportedPredicateError, ValidationError, VersionConflictError, getErrorSuggestion, isConstraintError, isSystemError, isTypeGraphError, isUserRecoverable } from './chunk-SJ2QMDXY.js';
|
|
7
|
-
import { getDialect, NODE_META_KEYS, EDGE_META_KEYS } from './chunk-
|
|
7
|
+
import { MAX_PG_IDENTIFIER_LENGTH, DEFAULT_PAGINATION_LIMIT, getDialect, DEFAULT_STREAM_BATCH_SIZE, NODE_META_KEYS, EDGE_META_KEYS, SQLITE_PATH_DELIMITER, PG_ARRAY_START, PG_ARRAY_END, PG_PATH_ELEMENT_SEPARATOR, fnv1aBase36 } from './chunk-GNIYZKBI.js';
|
|
8
8
|
import { jsonPointer, parseJsonPointer, createSchemaIntrospector, normalizeJsonPointer, joinJsonPointers, resolveFieldTypeInfoAtJsonPointer, getEmbeddingDimensions, isEmbeddingSchema } from './chunk-K7SQ3SWP.js';
|
|
9
9
|
export { MAX_JSON_POINTER_DEPTH, embedding, getEmbeddingDimensions, isEmbeddingSchema, joinJsonPointers, jsonPointer, normalizeJsonPointer, parseJsonPointer } from './chunk-K7SQ3SWP.js';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { sql, Placeholder } from 'drizzle-orm';
|
|
12
12
|
import { nanoid } from 'nanoid';
|
|
13
13
|
|
|
14
|
+
// src/store/reserved-keys.ts
|
|
15
|
+
var RESERVED_NODE_KEYS = /* @__PURE__ */ new Set([
|
|
16
|
+
"id",
|
|
17
|
+
"kind",
|
|
18
|
+
"meta"
|
|
19
|
+
]);
|
|
20
|
+
var RESERVED_EDGE_KEYS = /* @__PURE__ */ new Set([
|
|
21
|
+
"id",
|
|
22
|
+
"kind",
|
|
23
|
+
"meta",
|
|
24
|
+
"fromKind",
|
|
25
|
+
"fromId",
|
|
26
|
+
"toKind",
|
|
27
|
+
"toId"
|
|
28
|
+
]);
|
|
29
|
+
var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
30
|
+
"__proto__",
|
|
31
|
+
"constructor",
|
|
32
|
+
"prototype"
|
|
33
|
+
]);
|
|
34
|
+
function validateProjectionField(field2, entityType, kind) {
|
|
35
|
+
const reserved = entityType === "node" ? RESERVED_NODE_KEYS : RESERVED_EDGE_KEYS;
|
|
36
|
+
if (reserved.has(field2)) {
|
|
37
|
+
throw new ConfigurationError(
|
|
38
|
+
`Projection field "${field2}" on ${entityType} kind "${kind}" conflicts with a reserved structural key`,
|
|
39
|
+
{ field: field2, kind, entityType, reservedKeys: [...reserved] },
|
|
40
|
+
{
|
|
41
|
+
suggestion: `Remove "${field2}" from the projection. Structural fields (${[...reserved].join(", ")}) are included automatically when relevant.`
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(field2)) {
|
|
46
|
+
throw new ConfigurationError(
|
|
47
|
+
`Projection field "${field2}" on ${entityType} kind "${kind}" is not allowed`,
|
|
48
|
+
{ field: field2, kind, entityType },
|
|
49
|
+
{
|
|
50
|
+
suggestion: `"${field2}" cannot be used as a projection field name.`
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function filterReservedKeys(props, reservedKeys) {
|
|
56
|
+
const filtered = {};
|
|
57
|
+
for (const [key, value] of Object.entries(props)) {
|
|
58
|
+
if (!reservedKeys.has(key)) {
|
|
59
|
+
filtered[key] = value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return filtered;
|
|
63
|
+
}
|
|
64
|
+
|
|
14
65
|
// src/core/node.ts
|
|
15
|
-
var RESERVED_NODE_KEYS = /* @__PURE__ */ new Set(["id", "kind", "meta"]);
|
|
16
66
|
function validateSchemaKeys(schema, name) {
|
|
17
67
|
const shape = schema.shape;
|
|
18
68
|
const conflicts = Object.keys(shape).filter(
|
|
@@ -37,15 +87,6 @@ function defineNode(name, options) {
|
|
|
37
87
|
description: options.description
|
|
38
88
|
});
|
|
39
89
|
}
|
|
40
|
-
var RESERVED_EDGE_KEYS = /* @__PURE__ */ new Set([
|
|
41
|
-
"id",
|
|
42
|
-
"kind",
|
|
43
|
-
"meta",
|
|
44
|
-
"fromKind",
|
|
45
|
-
"fromId",
|
|
46
|
-
"toKind",
|
|
47
|
-
"toId"
|
|
48
|
-
]);
|
|
49
90
|
var EMPTY_SCHEMA = z.object({});
|
|
50
91
|
function validateSchemaKeys2(schema, name) {
|
|
51
92
|
const shape = schema.shape;
|
|
@@ -1376,14 +1417,14 @@ function extractVectorSimilarityPredicates(predicates) {
|
|
|
1376
1417
|
break;
|
|
1377
1418
|
}
|
|
1378
1419
|
case "and": {
|
|
1379
|
-
for (const
|
|
1380
|
-
visit(
|
|
1420
|
+
for (const predicate2 of expr.predicates) {
|
|
1421
|
+
visit(predicate2, inDisallowedBranch);
|
|
1381
1422
|
}
|
|
1382
1423
|
break;
|
|
1383
1424
|
}
|
|
1384
1425
|
case "or": {
|
|
1385
|
-
for (const
|
|
1386
|
-
visit(
|
|
1426
|
+
for (const predicate2 of expr.predicates) {
|
|
1427
|
+
visit(predicate2, true);
|
|
1387
1428
|
}
|
|
1388
1429
|
break;
|
|
1389
1430
|
}
|
|
@@ -2406,6 +2447,9 @@ function compileTemporalFilter(options) {
|
|
|
2406
2447
|
return sql`${deletedAt} IS NULL AND (${validFrom} IS NULL OR ${validFrom} <= ${now}) AND (${validTo} IS NULL OR ${validTo} > ${now})`;
|
|
2407
2448
|
}
|
|
2408
2449
|
case "asOf": {
|
|
2450
|
+
if (asOf === void 0) {
|
|
2451
|
+
throw new Error(`asOf timestamp is required for temporal mode "asOf"`);
|
|
2452
|
+
}
|
|
2409
2453
|
const timestamp = asOf;
|
|
2410
2454
|
return sql`${deletedAt} IS NULL AND (${validFrom} IS NULL OR ${validFrom} <= ${timestamp}) AND (${validTo} IS NULL OR ${validTo} > ${timestamp})`;
|
|
2411
2455
|
}
|
|
@@ -2813,7 +2857,7 @@ function lowerSetOperationToLogicalPlan(input) {
|
|
|
2813
2857
|
}
|
|
2814
2858
|
|
|
2815
2859
|
// src/query/compiler/recursive.ts
|
|
2816
|
-
var MAX_RECURSIVE_DEPTH =
|
|
2860
|
+
var MAX_RECURSIVE_DEPTH = 10;
|
|
2817
2861
|
var MAX_EXPLICIT_RECURSIVE_DEPTH = 1e3;
|
|
2818
2862
|
var NO_ALWAYS_REQUIRED_COLUMNS = /* @__PURE__ */ new Set();
|
|
2819
2863
|
function runRecursiveQueryPassPipeline(ast, graphId, ctx) {
|
|
@@ -3306,15 +3350,14 @@ var DEFAULT_TABLE_NAMES = {
|
|
|
3306
3350
|
edges: "typegraph_edges",
|
|
3307
3351
|
embeddings: "typegraph_node_embeddings"
|
|
3308
3352
|
};
|
|
3309
|
-
var MAX_IDENTIFIER_LENGTH = 63;
|
|
3310
3353
|
var VALID_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_$]*$/i;
|
|
3311
3354
|
function validateTableName(name, label) {
|
|
3312
3355
|
if (!name || name.length === 0) {
|
|
3313
3356
|
throw new ConfigurationError(`${label} table name cannot be empty`);
|
|
3314
3357
|
}
|
|
3315
|
-
if (name.length >
|
|
3358
|
+
if (name.length > MAX_PG_IDENTIFIER_LENGTH) {
|
|
3316
3359
|
throw new ConfigurationError(
|
|
3317
|
-
`${label} table name exceeds maximum length of ${
|
|
3360
|
+
`${label} table name exceeds maximum length of ${MAX_PG_IDENTIFIER_LENGTH} characters`
|
|
3318
3361
|
);
|
|
3319
3362
|
}
|
|
3320
3363
|
if (!VALID_IDENTIFIER_PATTERN.test(name)) {
|
|
@@ -3397,64 +3440,13 @@ function decodeByValueType(value, valueType) {
|
|
|
3397
3440
|
}
|
|
3398
3441
|
}
|
|
3399
3442
|
|
|
3400
|
-
// src/store/reserved-keys.ts
|
|
3401
|
-
var RESERVED_NODE_KEYS2 = /* @__PURE__ */ new Set([
|
|
3402
|
-
"id",
|
|
3403
|
-
"kind",
|
|
3404
|
-
"meta"
|
|
3405
|
-
]);
|
|
3406
|
-
var RESERVED_EDGE_KEYS2 = /* @__PURE__ */ new Set([
|
|
3407
|
-
"id",
|
|
3408
|
-
"kind",
|
|
3409
|
-
"meta",
|
|
3410
|
-
"fromKind",
|
|
3411
|
-
"fromId",
|
|
3412
|
-
"toKind",
|
|
3413
|
-
"toId"
|
|
3414
|
-
]);
|
|
3415
|
-
var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
3416
|
-
"__proto__",
|
|
3417
|
-
"constructor",
|
|
3418
|
-
"prototype"
|
|
3419
|
-
]);
|
|
3420
|
-
function validateProjectionField(field2, entityType, kind) {
|
|
3421
|
-
const reserved = entityType === "node" ? RESERVED_NODE_KEYS2 : RESERVED_EDGE_KEYS2;
|
|
3422
|
-
if (reserved.has(field2)) {
|
|
3423
|
-
throw new ConfigurationError(
|
|
3424
|
-
`Projection field "${field2}" on ${entityType} kind "${kind}" conflicts with a reserved structural key`,
|
|
3425
|
-
{ field: field2, kind, entityType, reservedKeys: [...reserved] },
|
|
3426
|
-
{
|
|
3427
|
-
suggestion: `Remove "${field2}" from the projection. Structural fields (${[...reserved].join(", ")}) are included automatically when relevant.`
|
|
3428
|
-
}
|
|
3429
|
-
);
|
|
3430
|
-
}
|
|
3431
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(field2)) {
|
|
3432
|
-
throw new ConfigurationError(
|
|
3433
|
-
`Projection field "${field2}" on ${entityType} kind "${kind}" is not allowed`,
|
|
3434
|
-
{ field: field2, kind, entityType },
|
|
3435
|
-
{
|
|
3436
|
-
suggestion: `"${field2}" cannot be used as a projection field name.`
|
|
3437
|
-
}
|
|
3438
|
-
);
|
|
3439
|
-
}
|
|
3440
|
-
}
|
|
3441
|
-
function filterReservedKeys(props, reservedKeys) {
|
|
3442
|
-
const filtered = {};
|
|
3443
|
-
for (const [key, value] of Object.entries(props)) {
|
|
3444
|
-
if (!reservedKeys.has(key)) {
|
|
3445
|
-
filtered[key] = value;
|
|
3446
|
-
}
|
|
3447
|
-
}
|
|
3448
|
-
return filtered;
|
|
3449
|
-
}
|
|
3450
|
-
|
|
3451
3443
|
// src/store/row-mappers.ts
|
|
3452
3444
|
function nullToUndefined2(value) {
|
|
3453
3445
|
return value === null ? void 0 : value;
|
|
3454
3446
|
}
|
|
3455
3447
|
function rowToNode(row) {
|
|
3456
3448
|
const rawProps = JSON.parse(row.props);
|
|
3457
|
-
const props = filterReservedKeys(rawProps,
|
|
3449
|
+
const props = filterReservedKeys(rawProps, RESERVED_NODE_KEYS);
|
|
3458
3450
|
return {
|
|
3459
3451
|
kind: row.kind,
|
|
3460
3452
|
id: row.id,
|
|
@@ -3474,7 +3466,7 @@ function rowToNodeMeta(row) {
|
|
|
3474
3466
|
}
|
|
3475
3467
|
function rowToEdge(row) {
|
|
3476
3468
|
const rawProps = JSON.parse(row.props);
|
|
3477
|
-
const props = filterReservedKeys(rawProps,
|
|
3469
|
+
const props = filterReservedKeys(rawProps, RESERVED_EDGE_KEYS);
|
|
3478
3470
|
return {
|
|
3479
3471
|
id: row.id,
|
|
3480
3472
|
kind: row.kind,
|
|
@@ -3498,17 +3490,6 @@ function rowToEdgeMeta(row) {
|
|
|
3498
3490
|
|
|
3499
3491
|
// src/store/subgraph.ts
|
|
3500
3492
|
var DEFAULT_SUBGRAPH_MAX_DEPTH = 10;
|
|
3501
|
-
var MAX_PG_IDENTIFIER_LENGTH = 63;
|
|
3502
|
-
function fnv1aBase36(input) {
|
|
3503
|
-
let hash = 2166136261;
|
|
3504
|
-
for (const character of input) {
|
|
3505
|
-
const codePoint = character.codePointAt(0);
|
|
3506
|
-
if (codePoint === void 0) continue;
|
|
3507
|
-
hash ^= codePoint;
|
|
3508
|
-
hash = Math.imul(hash, 16777619);
|
|
3509
|
-
}
|
|
3510
|
-
return (hash >>> 0).toString(36);
|
|
3511
|
-
}
|
|
3512
3493
|
var TEXT_ENCODER = new TextEncoder();
|
|
3513
3494
|
function truncateToBytes(value, maxBytes) {
|
|
3514
3495
|
const encoded = TEXT_ENCODER.encode(value);
|
|
@@ -3540,7 +3521,7 @@ async function executeSubgraph(params) {
|
|
|
3540
3521
|
}
|
|
3541
3522
|
const maxDepth = Math.min(
|
|
3542
3523
|
options.maxDepth ?? DEFAULT_SUBGRAPH_MAX_DEPTH,
|
|
3543
|
-
|
|
3524
|
+
MAX_EXPLICIT_RECURSIVE_DEPTH
|
|
3544
3525
|
);
|
|
3545
3526
|
const ctx = {
|
|
3546
3527
|
graphId: params.graphId,
|
|
@@ -4224,6 +4205,7 @@ function compileFieldColumnForSetOp(field2, prefix, dialect) {
|
|
|
4224
4205
|
updated_at: "_updated_at",
|
|
4225
4206
|
deleted_at: "_deleted_at"
|
|
4226
4207
|
};
|
|
4208
|
+
if (columnName === void 0) return sql.raw(`${cteName}.${alias}_props`);
|
|
4227
4209
|
const suffix = columnMap[columnName];
|
|
4228
4210
|
if (suffix) {
|
|
4229
4211
|
return sql.raw(`${cteName}.${alias}${suffix}`);
|
|
@@ -4302,18 +4284,18 @@ function buildSetOperationSuffixClauses(op, dialect) {
|
|
|
4302
4284
|
);
|
|
4303
4285
|
}
|
|
4304
4286
|
const orderParts = [];
|
|
4305
|
-
for (const
|
|
4306
|
-
const projected = matchFieldToProjection(
|
|
4287
|
+
for (const orderSpec of op.orderBy) {
|
|
4288
|
+
const projected = matchFieldToProjection(orderSpec.field, projection);
|
|
4307
4289
|
if (!projected) {
|
|
4308
|
-
const fieldDesc =
|
|
4290
|
+
const fieldDesc = orderSpec.field.jsonPointer ? `${orderSpec.field.alias}.props${orderSpec.field.jsonPointer}` : `${orderSpec.field.alias}.${orderSpec.field.path.join(".")}`;
|
|
4309
4291
|
const availableFields = projection.fields.map((f) => f.outputName).join(", ");
|
|
4310
4292
|
throw new UnsupportedPredicateError(
|
|
4311
4293
|
`Set operation ORDER BY field "${fieldDesc}" is not in the projection. ORDER BY for UNION/INTERSECT/EXCEPT must reference projected columns. Available columns: ${availableFields}`
|
|
4312
4294
|
);
|
|
4313
4295
|
}
|
|
4314
4296
|
const columnRef = sql.raw(dialect.quoteIdentifier(projected.outputName));
|
|
4315
|
-
const dir = sql.raw(
|
|
4316
|
-
const nulls =
|
|
4297
|
+
const dir = sql.raw(orderSpec.direction.toUpperCase());
|
|
4298
|
+
const nulls = orderSpec.nulls ?? (orderSpec.direction === "asc" ? "last" : "first");
|
|
4317
4299
|
const nullsDir = sql.raw(nulls === "first" ? "DESC" : "ASC");
|
|
4318
4300
|
orderParts.push(
|
|
4319
4301
|
sql`(${columnRef} IS NULL) ${nullsDir}`,
|
|
@@ -5180,13 +5162,14 @@ function generateId() {
|
|
|
5180
5162
|
|
|
5181
5163
|
// src/utils/path.ts
|
|
5182
5164
|
function parseSqlitePath(path) {
|
|
5183
|
-
|
|
5165
|
+
const emptyPath = `${SQLITE_PATH_DELIMITER}${SQLITE_PATH_DELIMITER}`;
|
|
5166
|
+
if (!path || path === emptyPath) return [];
|
|
5184
5167
|
const trimmed = path.slice(1, -1);
|
|
5185
5168
|
if (trimmed === "") return [];
|
|
5186
|
-
return trimmed.split(
|
|
5169
|
+
return trimmed.split(SQLITE_PATH_DELIMITER);
|
|
5187
5170
|
}
|
|
5188
5171
|
function isSqlitePath(value) {
|
|
5189
|
-
return typeof value === "string" && value.startsWith(
|
|
5172
|
+
return typeof value === "string" && value.startsWith(SQLITE_PATH_DELIMITER) && value.endsWith(SQLITE_PATH_DELIMITER);
|
|
5190
5173
|
}
|
|
5191
5174
|
function normalizePath(value) {
|
|
5192
5175
|
if (Array.isArray(value)) {
|
|
@@ -5201,20 +5184,20 @@ function normalizePath(value) {
|
|
|
5201
5184
|
return [];
|
|
5202
5185
|
}
|
|
5203
5186
|
function isPostgresTextArray(value) {
|
|
5204
|
-
return typeof value === "string" && value.startsWith(
|
|
5187
|
+
return typeof value === "string" && value.startsWith(PG_ARRAY_START) && value.endsWith(PG_ARRAY_END);
|
|
5205
5188
|
}
|
|
5206
5189
|
function parsePostgresTextArray(value) {
|
|
5207
5190
|
const inner = value.slice(1, -1);
|
|
5208
5191
|
if (inner === "") return [];
|
|
5209
|
-
return inner.split(
|
|
5192
|
+
return inner.split(PG_PATH_ELEMENT_SEPARATOR);
|
|
5210
5193
|
}
|
|
5211
5194
|
|
|
5212
5195
|
// src/query/execution/result-mapper.ts
|
|
5213
5196
|
function transformPathColumns(rows, state, _dialect) {
|
|
5214
5197
|
const pathAliases = [];
|
|
5215
|
-
for (const
|
|
5216
|
-
if (
|
|
5217
|
-
pathAliases.push(
|
|
5198
|
+
for (const traversal of state.traversals) {
|
|
5199
|
+
if (traversal.variableLength?.pathAlias !== void 0) {
|
|
5200
|
+
pathAliases.push(traversal.variableLength.pathAlias);
|
|
5218
5201
|
}
|
|
5219
5202
|
}
|
|
5220
5203
|
if (pathAliases.length === 0) return rows;
|
|
@@ -5238,8 +5221,8 @@ function transformPathColumns(rows, state, _dialect) {
|
|
|
5238
5221
|
}
|
|
5239
5222
|
return changed ? result : rows;
|
|
5240
5223
|
}
|
|
5241
|
-
var
|
|
5242
|
-
var
|
|
5224
|
+
var RESERVED_NODE_KEYS2 = /* @__PURE__ */ new Set(["id", "kind", "meta"]);
|
|
5225
|
+
var RESERVED_EDGE_KEYS2 = /* @__PURE__ */ new Set(["id", "kind", "fromId", "toId", "meta"]);
|
|
5243
5226
|
function nullToUndefined3(value) {
|
|
5244
5227
|
return value === null ? void 0 : value;
|
|
5245
5228
|
}
|
|
@@ -5277,7 +5260,7 @@ function buildSelectableNode(row, alias) {
|
|
|
5277
5260
|
deletedAt
|
|
5278
5261
|
}
|
|
5279
5262
|
};
|
|
5280
|
-
assignPropsExcludingReserved(result, rawProps,
|
|
5263
|
+
assignPropsExcludingReserved(result, rawProps, RESERVED_NODE_KEYS2);
|
|
5281
5264
|
return result;
|
|
5282
5265
|
}
|
|
5283
5266
|
function buildSelectableNodeOrUndefined(row, alias) {
|
|
@@ -5319,7 +5302,7 @@ function buildSelectableEdge(row, alias) {
|
|
|
5319
5302
|
deletedAt
|
|
5320
5303
|
}
|
|
5321
5304
|
};
|
|
5322
|
-
assignPropsExcludingReserved(result, rawProps,
|
|
5305
|
+
assignPropsExcludingReserved(result, rawProps, RESERVED_EDGE_KEYS2);
|
|
5323
5306
|
return result;
|
|
5324
5307
|
}
|
|
5325
5308
|
function buildSelectContext(row, startAlias, traversals) {
|
|
@@ -5447,7 +5430,7 @@ async function* createStreamIterable(batchSize, paginate) {
|
|
|
5447
5430
|
}
|
|
5448
5431
|
}
|
|
5449
5432
|
function getStreamBatchSize(options) {
|
|
5450
|
-
return options?.batchSize ??
|
|
5433
|
+
return options?.batchSize ?? DEFAULT_STREAM_BATCH_SIZE;
|
|
5451
5434
|
}
|
|
5452
5435
|
|
|
5453
5436
|
// src/query/ast.ts
|
|
@@ -5859,6 +5842,9 @@ function buildSelectiveContext(row, plans, traversals) {
|
|
|
5859
5842
|
return context;
|
|
5860
5843
|
}
|
|
5861
5844
|
function buildOptionalAliasValue(row, plan) {
|
|
5845
|
+
if (plan.idOutputName === void 0) {
|
|
5846
|
+
return void 0;
|
|
5847
|
+
}
|
|
5862
5848
|
const idValue = row[plan.idOutputName];
|
|
5863
5849
|
if (idValue === null || idValue === void 0) {
|
|
5864
5850
|
return void 0;
|
|
@@ -7335,7 +7321,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7335
7321
|
);
|
|
7336
7322
|
}
|
|
7337
7323
|
const isBackward = options.last !== void 0 || options.before !== void 0;
|
|
7338
|
-
const limit = options.first ?? options.last ??
|
|
7324
|
+
const limit = options.first ?? options.last ?? DEFAULT_PAGINATION_LIMIT;
|
|
7339
7325
|
const cursor = options.after ?? options.before;
|
|
7340
7326
|
let cursorData;
|
|
7341
7327
|
if (cursor) {
|
|
@@ -7658,7 +7644,8 @@ var TraversalBuilder = class _TraversalBuilder {
|
|
|
7658
7644
|
}
|
|
7659
7645
|
/**
|
|
7660
7646
|
* Enables variable-length (recursive) traversal.
|
|
7661
|
-
*
|
|
7647
|
+
* Defaults to MAX_RECURSIVE_DEPTH (10) hops with cycle prevention.
|
|
7648
|
+
* Use `maxHops` to override (up to MAX_EXPLICIT_RECURSIVE_DEPTH).
|
|
7662
7649
|
*/
|
|
7663
7650
|
recursive(options) {
|
|
7664
7651
|
const minDepth = options?.minHops ?? this.#variableLength.minDepth;
|
|
@@ -10432,6 +10419,9 @@ async function executeEdgeGetOrCreateByEndpoints(ctx, kind, fromKind, fromId, to
|
|
|
10432
10419
|
return { edge: edge2, action: "updated" };
|
|
10433
10420
|
}
|
|
10434
10421
|
const cardinality = registration.cardinality ?? "many";
|
|
10422
|
+
if (deletedRow === void 0) {
|
|
10423
|
+
throw new Error("Expected deletedRow to be defined");
|
|
10424
|
+
}
|
|
10435
10425
|
const matchedDeletedRow = deletedRow;
|
|
10436
10426
|
const effectiveValidTo = matchedDeletedRow.valid_to;
|
|
10437
10427
|
const constraintContext = {
|
|
@@ -10551,6 +10541,9 @@ async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend,
|
|
|
10551
10541
|
});
|
|
10552
10542
|
} else {
|
|
10553
10543
|
const bestRow = liveRow ?? deletedRow;
|
|
10544
|
+
if (bestRow === void 0) {
|
|
10545
|
+
throw new Error("Expected at least one of liveRow or deletedRow");
|
|
10546
|
+
}
|
|
10554
10547
|
toFetch.push({
|
|
10555
10548
|
index,
|
|
10556
10549
|
row: bestRow,
|
|
@@ -10851,11 +10844,12 @@ function getNodeRegistration(graph, kind) {
|
|
|
10851
10844
|
if (registration === void 0) throw new KindNotFoundError(kind, "node");
|
|
10852
10845
|
return registration;
|
|
10853
10846
|
}
|
|
10847
|
+
var CACHE_KEY_SEPARATOR = "\0";
|
|
10854
10848
|
function buildNodeCacheKey(graphId, kind, id) {
|
|
10855
|
-
return `${graphId}
|
|
10849
|
+
return `${graphId}${CACHE_KEY_SEPARATOR}${kind}${CACHE_KEY_SEPARATOR}${id}`;
|
|
10856
10850
|
}
|
|
10857
10851
|
function buildUniqueCacheKey(graphId, nodeKind, constraintName, key) {
|
|
10858
|
-
return `${graphId}
|
|
10852
|
+
return `${graphId}${CACHE_KEY_SEPARATOR}${nodeKind}${CACHE_KEY_SEPARATOR}${constraintName}${CACHE_KEY_SEPARATOR}${key}`;
|
|
10859
10853
|
}
|
|
10860
10854
|
function createNodeAlreadyExistsError(kind, id) {
|
|
10861
10855
|
return new ValidationError(
|
|
@@ -10892,6 +10886,23 @@ function createPendingUniqueRow(graphId, nodeKind, constraintName, key, nodeId)
|
|
|
10892
10886
|
deleted_at: void 0
|
|
10893
10887
|
};
|
|
10894
10888
|
}
|
|
10889
|
+
function resolveConstraint(graph, kind, constraintName) {
|
|
10890
|
+
const registration = getNodeRegistration(graph, kind);
|
|
10891
|
+
const constraints = registration.unique ?? [];
|
|
10892
|
+
const constraint = constraints.find(
|
|
10893
|
+
(candidate) => candidate.name === constraintName
|
|
10894
|
+
);
|
|
10895
|
+
if (constraint === void 0) {
|
|
10896
|
+
throw new NodeConstraintNotFoundError(constraintName, kind);
|
|
10897
|
+
}
|
|
10898
|
+
return constraint;
|
|
10899
|
+
}
|
|
10900
|
+
function createUniquenessContext(graphId, registry, backend) {
|
|
10901
|
+
return { graphId, registry, backend };
|
|
10902
|
+
}
|
|
10903
|
+
function createEmbeddingSyncContext(graphId, nodeKind, nodeId, backend) {
|
|
10904
|
+
return { graphId, nodeKind, nodeId, backend };
|
|
10905
|
+
}
|
|
10895
10906
|
function createNodeBatchValidationBackend(graphId, registry, backend) {
|
|
10896
10907
|
const nodeCache = /* @__PURE__ */ new Map();
|
|
10897
10908
|
const pendingNodes = /* @__PURE__ */ new Map();
|
|
@@ -10900,12 +10911,8 @@ function createNodeBatchValidationBackend(graphId, registry, backend) {
|
|
|
10900
10911
|
async function getNodeCached(lookupGraphId, kind, id) {
|
|
10901
10912
|
const cacheKey = buildNodeCacheKey(lookupGraphId, kind, id);
|
|
10902
10913
|
const pendingNode = pendingNodes.get(cacheKey);
|
|
10903
|
-
if (pendingNode !== void 0)
|
|
10904
|
-
|
|
10905
|
-
}
|
|
10906
|
-
if (nodeCache.has(cacheKey)) {
|
|
10907
|
-
return nodeCache.get(cacheKey);
|
|
10908
|
-
}
|
|
10914
|
+
if (pendingNode !== void 0) return pendingNode;
|
|
10915
|
+
if (nodeCache.has(cacheKey)) return nodeCache.get(cacheKey);
|
|
10909
10916
|
const existing = await backend.getNode(lookupGraphId, kind, id);
|
|
10910
10917
|
nodeCache.set(cacheKey, existing);
|
|
10911
10918
|
return existing;
|
|
@@ -10927,16 +10934,14 @@ function createNodeBatchValidationBackend(graphId, registry, backend) {
|
|
|
10927
10934
|
pendingOwner
|
|
10928
10935
|
);
|
|
10929
10936
|
}
|
|
10930
|
-
if (uniqueCache.has(cacheKey))
|
|
10931
|
-
return uniqueCache.get(cacheKey);
|
|
10932
|
-
}
|
|
10937
|
+
if (uniqueCache.has(cacheKey)) return uniqueCache.get(cacheKey);
|
|
10933
10938
|
const existing = await backend.checkUnique(params);
|
|
10934
10939
|
uniqueCache.set(cacheKey, existing);
|
|
10935
10940
|
return existing;
|
|
10936
10941
|
}
|
|
10937
10942
|
function registerPendingNode(params) {
|
|
10938
10943
|
const cacheKey = buildNodeCacheKey(params.graphId, params.kind, params.id);
|
|
10939
|
-
|
|
10944
|
+
pendingNodes.set(cacheKey, {
|
|
10940
10945
|
graph_id: params.graphId,
|
|
10941
10946
|
kind: params.kind,
|
|
10942
10947
|
id: params.id,
|
|
@@ -10947,14 +10952,11 @@ function createNodeBatchValidationBackend(graphId, registry, backend) {
|
|
|
10947
10952
|
created_at: "",
|
|
10948
10953
|
updated_at: "",
|
|
10949
10954
|
deleted_at: void 0
|
|
10950
|
-
};
|
|
10951
|
-
pendingNodes.set(cacheKey, pendingNode);
|
|
10955
|
+
});
|
|
10952
10956
|
}
|
|
10953
10957
|
function registerPendingUniqueEntries(kind, id, props, constraints) {
|
|
10954
10958
|
for (const constraint of constraints) {
|
|
10955
|
-
if (!checkWherePredicate(constraint, props))
|
|
10956
|
-
continue;
|
|
10957
|
-
}
|
|
10959
|
+
if (!checkWherePredicate(constraint, props)) continue;
|
|
10958
10960
|
const key = computeUniqueKey(
|
|
10959
10961
|
props,
|
|
10960
10962
|
constraint.fields,
|
|
@@ -11016,14 +11018,9 @@ async function validateAndPrepareNodeCreate(ctx, input, id, backend) {
|
|
|
11016
11018
|
backend
|
|
11017
11019
|
};
|
|
11018
11020
|
await checkDisjointnessConstraint(constraintContext, kind, id);
|
|
11019
|
-
const uniquenessContext = {
|
|
11020
|
-
graphId: ctx.graphId,
|
|
11021
|
-
registry: ctx.registry,
|
|
11022
|
-
backend
|
|
11023
|
-
};
|
|
11024
11021
|
const uniqueConstraints = registration.unique ?? [];
|
|
11025
11022
|
await checkUniquenessConstraints(
|
|
11026
|
-
|
|
11023
|
+
createUniquenessContext(ctx.graphId, ctx.registry, backend),
|
|
11027
11024
|
kind,
|
|
11028
11025
|
id,
|
|
11029
11026
|
validatedProps,
|
|
@@ -11046,64 +11043,99 @@ async function validateAndPrepareNodeCreate(ctx, input, id, backend) {
|
|
|
11046
11043
|
};
|
|
11047
11044
|
}
|
|
11048
11045
|
async function finalizeNodeCreate(ctx, prepared, backend) {
|
|
11049
|
-
const uniquenessContext = {
|
|
11050
|
-
graphId: ctx.graphId,
|
|
11051
|
-
registry: ctx.registry,
|
|
11052
|
-
backend
|
|
11053
|
-
};
|
|
11054
11046
|
await insertUniquenessEntries(
|
|
11055
|
-
|
|
11047
|
+
createUniquenessContext(ctx.graphId, ctx.registry, backend),
|
|
11056
11048
|
prepared.kind,
|
|
11057
11049
|
prepared.id,
|
|
11058
11050
|
prepared.validatedProps,
|
|
11059
11051
|
prepared.uniqueConstraints
|
|
11060
11052
|
);
|
|
11061
|
-
const embeddingSyncContext = {
|
|
11062
|
-
graphId: ctx.graphId,
|
|
11063
|
-
nodeKind: prepared.kind,
|
|
11064
|
-
nodeId: prepared.id,
|
|
11065
|
-
backend
|
|
11066
|
-
};
|
|
11067
11053
|
await syncEmbeddings(
|
|
11068
|
-
|
|
11054
|
+
createEmbeddingSyncContext(
|
|
11055
|
+
ctx.graphId,
|
|
11056
|
+
prepared.kind,
|
|
11057
|
+
prepared.id,
|
|
11058
|
+
backend
|
|
11059
|
+
),
|
|
11069
11060
|
prepared.nodeKind.schema,
|
|
11070
11061
|
prepared.validatedProps
|
|
11071
11062
|
);
|
|
11072
11063
|
}
|
|
11073
|
-
async function
|
|
11074
|
-
const kind = input
|
|
11075
|
-
const
|
|
11076
|
-
const
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
}
|
|
11088
|
-
await finalizeNodeCreate(ctx, prepared, backend);
|
|
11089
|
-
if (row === void 0) return;
|
|
11090
|
-
return rowToNode(row);
|
|
11064
|
+
async function performNodeUpdate(ctx, input, backend, options) {
|
|
11065
|
+
const { kind, id } = input;
|
|
11066
|
+
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11067
|
+
const existing = await backend.getNode(ctx.graphId, kind, id);
|
|
11068
|
+
if (!existing || existing.deleted_at && !options?.clearDeleted) {
|
|
11069
|
+
throw new NodeNotFoundError(kind, id);
|
|
11070
|
+
}
|
|
11071
|
+
const existingProps = JSON.parse(existing.props);
|
|
11072
|
+
const mergedProps = { ...existingProps, ...input.props };
|
|
11073
|
+
const nodeKind = registration.type;
|
|
11074
|
+
const validatedProps = validateNodeProps(nodeKind.schema, mergedProps, {
|
|
11075
|
+
kind,
|
|
11076
|
+
operation: "update",
|
|
11077
|
+
id
|
|
11091
11078
|
});
|
|
11079
|
+
const validTo = validateOptionalIsoDate(input.validTo, "validTo");
|
|
11080
|
+
await updateUniquenessEntries(
|
|
11081
|
+
createUniquenessContext(ctx.graphId, ctx.registry, backend),
|
|
11082
|
+
kind,
|
|
11083
|
+
id,
|
|
11084
|
+
existingProps,
|
|
11085
|
+
validatedProps,
|
|
11086
|
+
registration.unique ?? []
|
|
11087
|
+
);
|
|
11088
|
+
const updateParams = {
|
|
11089
|
+
graphId: ctx.graphId,
|
|
11090
|
+
kind,
|
|
11091
|
+
id,
|
|
11092
|
+
props: validatedProps,
|
|
11093
|
+
incrementVersion: true
|
|
11094
|
+
};
|
|
11095
|
+
if (validTo !== void 0) updateParams.validTo = validTo;
|
|
11096
|
+
if (options?.clearDeleted) updateParams.clearDeleted = true;
|
|
11097
|
+
const row = await backend.updateNode(updateParams);
|
|
11098
|
+
await syncEmbeddings(
|
|
11099
|
+
createEmbeddingSyncContext(ctx.graphId, kind, id, backend),
|
|
11100
|
+
nodeKind.schema,
|
|
11101
|
+
validatedProps
|
|
11102
|
+
);
|
|
11103
|
+
return rowToNode(row);
|
|
11092
11104
|
}
|
|
11093
|
-
async function
|
|
11094
|
-
const
|
|
11095
|
-
|
|
11096
|
-
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
|
|
11105
|
+
async function enforceDeleteBehavior(ctx, kind, id, mode, backend, registration) {
|
|
11106
|
+
const deleteBehavior = registration.onDelete ?? "restrict";
|
|
11107
|
+
const connectedEdges = await backend.findEdgesConnectedTo({
|
|
11108
|
+
graphId: ctx.graphId,
|
|
11109
|
+
nodeKind: kind,
|
|
11110
|
+
nodeId: id
|
|
11111
|
+
});
|
|
11112
|
+
if (connectedEdges.length === 0) return;
|
|
11113
|
+
switch (deleteBehavior) {
|
|
11114
|
+
case "restrict": {
|
|
11115
|
+
const edgeKinds = [...new Set(connectedEdges.map((edge) => edge.kind))];
|
|
11116
|
+
throw new RestrictedDeleteError({
|
|
11117
|
+
nodeKind: kind,
|
|
11118
|
+
nodeId: id,
|
|
11119
|
+
edgeCount: connectedEdges.length,
|
|
11120
|
+
edgeKinds
|
|
11121
|
+
});
|
|
11122
|
+
}
|
|
11123
|
+
case "cascade":
|
|
11124
|
+
case "disconnect": {
|
|
11125
|
+
for (const edge of connectedEdges) {
|
|
11126
|
+
await (mode === "hard" ? backend.hardDeleteEdge({
|
|
11127
|
+
graphId: ctx.graphId,
|
|
11128
|
+
id: edge.id
|
|
11129
|
+
}) : backend.deleteEdge({
|
|
11130
|
+
graphId: ctx.graphId,
|
|
11131
|
+
id: edge.id
|
|
11132
|
+
}));
|
|
11133
|
+
}
|
|
11134
|
+
break;
|
|
11135
|
+
}
|
|
11100
11136
|
}
|
|
11101
|
-
return result;
|
|
11102
11137
|
}
|
|
11103
|
-
async function
|
|
11104
|
-
if (inputs.length === 0) {
|
|
11105
|
-
return;
|
|
11106
|
-
}
|
|
11138
|
+
async function prepareBatchCreates(ctx, inputs, backend) {
|
|
11107
11139
|
const {
|
|
11108
11140
|
backend: validationBackend,
|
|
11109
11141
|
registerPendingNode,
|
|
@@ -11130,46 +11162,109 @@ async function executeNodeCreateNoReturnBatch(ctx, inputs, backend) {
|
|
|
11130
11162
|
const batchInsertParams = preparedCreates.map(
|
|
11131
11163
|
(prepared) => prepared.insertParams
|
|
11132
11164
|
);
|
|
11133
|
-
|
|
11134
|
-
for (const insertParams of batchInsertParams) {
|
|
11135
|
-
await (backend.insertNodeNoReturn?.(insertParams) ?? backend.insertNode(insertParams));
|
|
11136
|
-
}
|
|
11137
|
-
} else {
|
|
11138
|
-
await backend.insertNodesBatch(batchInsertParams);
|
|
11139
|
-
}
|
|
11140
|
-
for (const prepared of preparedCreates) {
|
|
11141
|
-
await finalizeNodeCreate(ctx, prepared, backend);
|
|
11142
|
-
}
|
|
11165
|
+
return { preparedCreates, batchInsertParams };
|
|
11143
11166
|
}
|
|
11144
|
-
async function
|
|
11145
|
-
|
|
11146
|
-
|
|
11167
|
+
async function findUniqueRowAcrossKinds(backend, graphId, constraintName, key, kindsToCheck, includeDeleted) {
|
|
11168
|
+
for (const kindToCheck of kindsToCheck) {
|
|
11169
|
+
const row = await backend.checkUnique({
|
|
11170
|
+
graphId,
|
|
11171
|
+
nodeKind: kindToCheck,
|
|
11172
|
+
constraintName,
|
|
11173
|
+
key,
|
|
11174
|
+
includeDeleted
|
|
11175
|
+
});
|
|
11176
|
+
if (row !== void 0) return row;
|
|
11147
11177
|
}
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
|
|
11151
|
-
|
|
11152
|
-
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11178
|
+
return void 0;
|
|
11179
|
+
}
|
|
11180
|
+
async function batchCheckUniqueAcrossKinds(backend, graphId, constraintName, uniqueKeys, kindsToCheck, includeDeleted) {
|
|
11181
|
+
const existingByKey = /* @__PURE__ */ new Map();
|
|
11182
|
+
for (const kindToCheck of kindsToCheck) {
|
|
11183
|
+
if (backend.checkUniqueBatch === void 0) {
|
|
11184
|
+
for (const key of uniqueKeys) {
|
|
11185
|
+
if (existingByKey.has(key)) continue;
|
|
11186
|
+
const row = await backend.checkUnique({
|
|
11187
|
+
graphId,
|
|
11188
|
+
nodeKind: kindToCheck,
|
|
11189
|
+
constraintName,
|
|
11190
|
+
key,
|
|
11191
|
+
includeDeleted
|
|
11192
|
+
});
|
|
11193
|
+
if (row !== void 0) {
|
|
11194
|
+
existingByKey.set(row.key, row);
|
|
11195
|
+
}
|
|
11196
|
+
}
|
|
11197
|
+
} else {
|
|
11198
|
+
const rows = await backend.checkUniqueBatch({
|
|
11199
|
+
graphId,
|
|
11200
|
+
nodeKind: kindToCheck,
|
|
11201
|
+
constraintName,
|
|
11202
|
+
keys: uniqueKeys,
|
|
11203
|
+
includeDeleted
|
|
11204
|
+
});
|
|
11205
|
+
for (const row of rows) {
|
|
11206
|
+
if (!existingByKey.has(row.key)) {
|
|
11207
|
+
existingByKey.set(row.key, row);
|
|
11208
|
+
}
|
|
11209
|
+
}
|
|
11210
|
+
}
|
|
11211
|
+
}
|
|
11212
|
+
return existingByKey;
|
|
11213
|
+
}
|
|
11214
|
+
async function executeNodeCreateInternal(ctx, input, backend, options) {
|
|
11215
|
+
const kind = input.kind;
|
|
11216
|
+
const id = input.id ?? generateId();
|
|
11217
|
+
const opContext = ctx.createOperationContext("create", "node", kind, id);
|
|
11218
|
+
return ctx.withOperationHooks(opContext, async () => {
|
|
11219
|
+
const prepared = await validateAndPrepareNodeCreate(
|
|
11220
|
+
ctx,
|
|
11158
11221
|
input,
|
|
11159
11222
|
id,
|
|
11160
|
-
|
|
11223
|
+
backend
|
|
11161
11224
|
);
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11225
|
+
let row;
|
|
11226
|
+
{
|
|
11227
|
+
row = await backend.insertNode(prepared.insertParams);
|
|
11228
|
+
}
|
|
11229
|
+
await finalizeNodeCreate(ctx, prepared, backend);
|
|
11230
|
+
if (row === void 0) return;
|
|
11231
|
+
return rowToNode(row);
|
|
11232
|
+
});
|
|
11233
|
+
}
|
|
11234
|
+
async function executeNodeCreate(ctx, input, backend) {
|
|
11235
|
+
const result = await executeNodeCreateInternal(ctx, input, backend);
|
|
11236
|
+
if (!result) {
|
|
11237
|
+
throw new DatabaseOperationError(
|
|
11238
|
+
"Node create failed: expected created node row",
|
|
11239
|
+
{ operation: "insert", entity: "node" }
|
|
11169
11240
|
);
|
|
11170
11241
|
}
|
|
11171
|
-
|
|
11172
|
-
|
|
11242
|
+
return result;
|
|
11243
|
+
}
|
|
11244
|
+
async function executeNodeCreateNoReturnBatch(ctx, inputs, backend) {
|
|
11245
|
+
if (inputs.length === 0) return;
|
|
11246
|
+
const { preparedCreates, batchInsertParams } = await prepareBatchCreates(
|
|
11247
|
+
ctx,
|
|
11248
|
+
inputs,
|
|
11249
|
+
backend
|
|
11250
|
+
);
|
|
11251
|
+
if (backend.insertNodesBatch === void 0) {
|
|
11252
|
+
for (const insertParams of batchInsertParams) {
|
|
11253
|
+
await (backend.insertNodeNoReturn?.(insertParams) ?? backend.insertNode(insertParams));
|
|
11254
|
+
}
|
|
11255
|
+
} else {
|
|
11256
|
+
await backend.insertNodesBatch(batchInsertParams);
|
|
11257
|
+
}
|
|
11258
|
+
for (const prepared of preparedCreates) {
|
|
11259
|
+
await finalizeNodeCreate(ctx, prepared, backend);
|
|
11260
|
+
}
|
|
11261
|
+
}
|
|
11262
|
+
async function executeNodeCreateBatch(ctx, inputs, backend) {
|
|
11263
|
+
if (inputs.length === 0) return [];
|
|
11264
|
+
const { preparedCreates, batchInsertParams } = await prepareBatchCreates(
|
|
11265
|
+
ctx,
|
|
11266
|
+
inputs,
|
|
11267
|
+
backend
|
|
11173
11268
|
);
|
|
11174
11269
|
let rows;
|
|
11175
11270
|
if (backend.insertNodesBatchReturning === void 0) {
|
|
@@ -11187,170 +11282,40 @@ async function executeNodeCreateBatch(ctx, inputs, backend) {
|
|
|
11187
11282
|
return rows.map((row) => rowToNode(row));
|
|
11188
11283
|
}
|
|
11189
11284
|
async function executeNodeUpdate(ctx, input, backend, options) {
|
|
11190
|
-
const
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
const mergedProps = { ...existingProps, ...input.props };
|
|
11201
|
-
const nodeKind = registration.type;
|
|
11202
|
-
const validatedProps = validateNodeProps(nodeKind.schema, mergedProps, {
|
|
11203
|
-
kind,
|
|
11204
|
-
operation: "update",
|
|
11205
|
-
id
|
|
11206
|
-
});
|
|
11207
|
-
const validTo = validateOptionalIsoDate(input.validTo, "validTo");
|
|
11208
|
-
const uniquenessContext = {
|
|
11209
|
-
graphId: ctx.graphId,
|
|
11210
|
-
registry: ctx.registry,
|
|
11211
|
-
backend
|
|
11212
|
-
};
|
|
11213
|
-
await updateUniquenessEntries(
|
|
11214
|
-
uniquenessContext,
|
|
11215
|
-
kind,
|
|
11216
|
-
id,
|
|
11217
|
-
existingProps,
|
|
11218
|
-
validatedProps,
|
|
11219
|
-
registration.unique ?? []
|
|
11220
|
-
);
|
|
11221
|
-
const updateParams = {
|
|
11222
|
-
graphId: ctx.graphId,
|
|
11223
|
-
kind,
|
|
11224
|
-
id,
|
|
11225
|
-
props: validatedProps,
|
|
11226
|
-
incrementVersion: true
|
|
11227
|
-
};
|
|
11228
|
-
if (validTo !== void 0) updateParams.validTo = validTo;
|
|
11229
|
-
if (options?.clearDeleted) updateParams.clearDeleted = true;
|
|
11230
|
-
const row = await backend.updateNode(updateParams);
|
|
11231
|
-
const embeddingSyncContext = {
|
|
11232
|
-
graphId: ctx.graphId,
|
|
11233
|
-
nodeKind: kind,
|
|
11234
|
-
nodeId: id,
|
|
11235
|
-
backend
|
|
11236
|
-
};
|
|
11237
|
-
await syncEmbeddings(embeddingSyncContext, nodeKind.schema, validatedProps);
|
|
11238
|
-
return rowToNode(row);
|
|
11239
|
-
});
|
|
11285
|
+
const opContext = ctx.createOperationContext(
|
|
11286
|
+
"update",
|
|
11287
|
+
"node",
|
|
11288
|
+
input.kind,
|
|
11289
|
+
input.id
|
|
11290
|
+
);
|
|
11291
|
+
return ctx.withOperationHooks(
|
|
11292
|
+
opContext,
|
|
11293
|
+
() => performNodeUpdate(ctx, input, backend, options)
|
|
11294
|
+
);
|
|
11240
11295
|
}
|
|
11241
11296
|
async function executeNodeUpsertUpdate(ctx, input, backend, options) {
|
|
11242
|
-
|
|
11243
|
-
const id = input.id;
|
|
11244
|
-
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11245
|
-
const existing = await backend.getNode(ctx.graphId, kind, id);
|
|
11246
|
-
if (!existing || existing.deleted_at && !options?.clearDeleted) {
|
|
11247
|
-
throw new NodeNotFoundError(kind, id);
|
|
11248
|
-
}
|
|
11249
|
-
const existingProps = JSON.parse(existing.props);
|
|
11250
|
-
const mergedProps = { ...existingProps, ...input.props };
|
|
11251
|
-
const nodeKind = registration.type;
|
|
11252
|
-
const validatedProps = validateNodeProps(nodeKind.schema, mergedProps, {
|
|
11253
|
-
kind,
|
|
11254
|
-
operation: "update",
|
|
11255
|
-
id
|
|
11256
|
-
});
|
|
11257
|
-
const validTo = validateOptionalIsoDate(input.validTo, "validTo");
|
|
11258
|
-
const uniquenessContext = {
|
|
11259
|
-
graphId: ctx.graphId,
|
|
11260
|
-
registry: ctx.registry,
|
|
11261
|
-
backend
|
|
11262
|
-
};
|
|
11263
|
-
await updateUniquenessEntries(
|
|
11264
|
-
uniquenessContext,
|
|
11265
|
-
kind,
|
|
11266
|
-
id,
|
|
11267
|
-
existingProps,
|
|
11268
|
-
validatedProps,
|
|
11269
|
-
registration.unique ?? []
|
|
11270
|
-
);
|
|
11271
|
-
const updateParams = {
|
|
11272
|
-
graphId: ctx.graphId,
|
|
11273
|
-
kind,
|
|
11274
|
-
id,
|
|
11275
|
-
props: validatedProps,
|
|
11276
|
-
incrementVersion: true
|
|
11277
|
-
};
|
|
11278
|
-
if (validTo !== void 0) updateParams.validTo = validTo;
|
|
11279
|
-
if (options?.clearDeleted) updateParams.clearDeleted = true;
|
|
11280
|
-
const row = await backend.updateNode(updateParams);
|
|
11281
|
-
const embeddingSyncContext = {
|
|
11282
|
-
graphId: ctx.graphId,
|
|
11283
|
-
nodeKind: kind,
|
|
11284
|
-
nodeId: id,
|
|
11285
|
-
backend
|
|
11286
|
-
};
|
|
11287
|
-
await syncEmbeddings(embeddingSyncContext, nodeKind.schema, validatedProps);
|
|
11288
|
-
return rowToNode(row);
|
|
11297
|
+
return performNodeUpdate(ctx, input, backend, options);
|
|
11289
11298
|
}
|
|
11290
11299
|
async function executeNodeDelete(ctx, kind, id, backend) {
|
|
11291
11300
|
const opContext = ctx.createOperationContext("delete", "node", kind, id);
|
|
11292
11301
|
return ctx.withOperationHooks(opContext, async () => {
|
|
11293
11302
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11294
11303
|
const existing = await backend.getNode(ctx.graphId, kind, id);
|
|
11295
|
-
if (!existing || existing.deleted_at)
|
|
11296
|
-
return;
|
|
11297
|
-
}
|
|
11304
|
+
if (!existing || existing.deleted_at) return;
|
|
11298
11305
|
const existingProps = JSON.parse(existing.props);
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
graphId: ctx.graphId,
|
|
11302
|
-
nodeKind: kind,
|
|
11303
|
-
nodeId: id
|
|
11304
|
-
});
|
|
11305
|
-
if (connectedEdges.length > 0) {
|
|
11306
|
-
switch (deleteBehavior) {
|
|
11307
|
-
case "restrict": {
|
|
11308
|
-
const edgeKinds = [
|
|
11309
|
-
...new Set(connectedEdges.map((edge) => edge.kind))
|
|
11310
|
-
];
|
|
11311
|
-
throw new RestrictedDeleteError({
|
|
11312
|
-
nodeKind: kind,
|
|
11313
|
-
nodeId: id,
|
|
11314
|
-
edgeCount: connectedEdges.length,
|
|
11315
|
-
edgeKinds
|
|
11316
|
-
});
|
|
11317
|
-
}
|
|
11318
|
-
case "cascade":
|
|
11319
|
-
case "disconnect": {
|
|
11320
|
-
for (const edge of connectedEdges) {
|
|
11321
|
-
await backend.deleteEdge({
|
|
11322
|
-
graphId: ctx.graphId,
|
|
11323
|
-
id: edge.id
|
|
11324
|
-
});
|
|
11325
|
-
}
|
|
11326
|
-
break;
|
|
11327
|
-
}
|
|
11328
|
-
}
|
|
11329
|
-
}
|
|
11330
|
-
await backend.deleteNode({
|
|
11331
|
-
graphId: ctx.graphId,
|
|
11332
|
-
kind,
|
|
11333
|
-
id
|
|
11334
|
-
});
|
|
11335
|
-
const uniquenessContext = {
|
|
11336
|
-
graphId: ctx.graphId,
|
|
11337
|
-
registry: ctx.registry,
|
|
11338
|
-
backend
|
|
11339
|
-
};
|
|
11306
|
+
await enforceDeleteBehavior(ctx, kind, id, "soft", backend, registration);
|
|
11307
|
+
await backend.deleteNode({ graphId: ctx.graphId, kind, id });
|
|
11340
11308
|
await deleteUniquenessEntries(
|
|
11341
|
-
|
|
11309
|
+
createUniquenessContext(ctx.graphId, ctx.registry, backend),
|
|
11342
11310
|
kind,
|
|
11343
11311
|
existingProps,
|
|
11344
11312
|
registration.unique ?? []
|
|
11345
11313
|
);
|
|
11346
11314
|
const nodeKind = registration.type;
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
nodeKind
|
|
11350
|
-
|
|
11351
|
-
backend
|
|
11352
|
-
};
|
|
11353
|
-
await deleteNodeEmbeddings(embeddingSyncContext, nodeKind.schema);
|
|
11315
|
+
await deleteNodeEmbeddings(
|
|
11316
|
+
createEmbeddingSyncContext(ctx.graphId, kind, id, backend),
|
|
11317
|
+
nodeKind.schema
|
|
11318
|
+
);
|
|
11354
11319
|
});
|
|
11355
11320
|
}
|
|
11356
11321
|
async function executeNodeHardDelete(ctx, kind, id, backend) {
|
|
@@ -11358,59 +11323,14 @@ async function executeNodeHardDelete(ctx, kind, id, backend) {
|
|
|
11358
11323
|
return ctx.withOperationHooks(opContext, async () => {
|
|
11359
11324
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11360
11325
|
const existing = await backend.getNode(ctx.graphId, kind, id);
|
|
11361
|
-
if (!existing)
|
|
11362
|
-
|
|
11363
|
-
}
|
|
11364
|
-
const deleteBehavior = registration.onDelete ?? "restrict";
|
|
11365
|
-
const connectedEdges = await backend.findEdgesConnectedTo({
|
|
11366
|
-
graphId: ctx.graphId,
|
|
11367
|
-
nodeKind: kind,
|
|
11368
|
-
nodeId: id
|
|
11369
|
-
});
|
|
11370
|
-
if (connectedEdges.length > 0) {
|
|
11371
|
-
switch (deleteBehavior) {
|
|
11372
|
-
case "restrict": {
|
|
11373
|
-
const edgeKinds = [
|
|
11374
|
-
...new Set(connectedEdges.map((edge) => edge.kind))
|
|
11375
|
-
];
|
|
11376
|
-
throw new RestrictedDeleteError({
|
|
11377
|
-
nodeKind: kind,
|
|
11378
|
-
nodeId: id,
|
|
11379
|
-
edgeCount: connectedEdges.length,
|
|
11380
|
-
edgeKinds
|
|
11381
|
-
});
|
|
11382
|
-
}
|
|
11383
|
-
case "cascade":
|
|
11384
|
-
case "disconnect": {
|
|
11385
|
-
for (const edge of connectedEdges) {
|
|
11386
|
-
await backend.hardDeleteEdge({
|
|
11387
|
-
graphId: ctx.graphId,
|
|
11388
|
-
id: edge.id
|
|
11389
|
-
});
|
|
11390
|
-
}
|
|
11391
|
-
break;
|
|
11392
|
-
}
|
|
11393
|
-
}
|
|
11394
|
-
}
|
|
11326
|
+
if (!existing) return;
|
|
11327
|
+
await enforceDeleteBehavior(ctx, kind, id, "hard", backend, registration);
|
|
11395
11328
|
const hardDelete = async (target) => {
|
|
11396
|
-
await target.hardDeleteNode({
|
|
11397
|
-
graphId: ctx.graphId,
|
|
11398
|
-
kind,
|
|
11399
|
-
id
|
|
11400
|
-
});
|
|
11329
|
+
await target.hardDeleteNode({ graphId: ctx.graphId, kind, id });
|
|
11401
11330
|
};
|
|
11402
11331
|
await ("transaction" in backend && backend.capabilities.transactions ? backend.transaction(async (tx) => hardDelete(tx)) : hardDelete(backend));
|
|
11403
11332
|
});
|
|
11404
11333
|
}
|
|
11405
|
-
function resolveConstraint(graph, kind, constraintName) {
|
|
11406
|
-
const registration = getNodeRegistration(graph, kind);
|
|
11407
|
-
const constraints = registration.unique ?? [];
|
|
11408
|
-
const constraint = constraints.find((c) => c.name === constraintName);
|
|
11409
|
-
if (constraint === void 0) {
|
|
11410
|
-
throw new NodeConstraintNotFoundError(constraintName, kind);
|
|
11411
|
-
}
|
|
11412
|
-
return constraint;
|
|
11413
|
-
}
|
|
11414
11334
|
async function executeNodeGetOrCreateByConstraint(ctx, kind, constraintName, props, backend, options) {
|
|
11415
11335
|
const ifExists = options?.ifExists ?? "return";
|
|
11416
11336
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
@@ -11421,8 +11341,11 @@ async function executeNodeGetOrCreateByConstraint(ctx, kind, constraintName, pro
|
|
|
11421
11341
|
});
|
|
11422
11342
|
const constraint = resolveConstraint(ctx.graph, kind, constraintName);
|
|
11423
11343
|
if (!checkWherePredicate(constraint, validatedProps)) {
|
|
11424
|
-
const
|
|
11425
|
-
|
|
11344
|
+
const node = await executeNodeCreate(
|
|
11345
|
+
ctx,
|
|
11346
|
+
{ kind, props: validatedProps },
|
|
11347
|
+
backend
|
|
11348
|
+
);
|
|
11426
11349
|
return { node, action: "created" };
|
|
11427
11350
|
}
|
|
11428
11351
|
const key = computeUniqueKey(
|
|
@@ -11435,23 +11358,20 @@ async function executeNodeGetOrCreateByConstraint(ctx, kind, constraintName, pro
|
|
|
11435
11358
|
constraint.scope,
|
|
11436
11359
|
ctx.registry
|
|
11437
11360
|
);
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
});
|
|
11447
|
-
if (row !== void 0) {
|
|
11448
|
-
existingUniqueRow = row;
|
|
11449
|
-
break;
|
|
11450
|
-
}
|
|
11451
|
-
}
|
|
11361
|
+
const existingUniqueRow = await findUniqueRowAcrossKinds(
|
|
11362
|
+
backend,
|
|
11363
|
+
ctx.graphId,
|
|
11364
|
+
constraint.name,
|
|
11365
|
+
key,
|
|
11366
|
+
kindsToCheck,
|
|
11367
|
+
true
|
|
11368
|
+
);
|
|
11452
11369
|
if (existingUniqueRow === void 0) {
|
|
11453
|
-
const
|
|
11454
|
-
|
|
11370
|
+
const node = await executeNodeCreate(
|
|
11371
|
+
ctx,
|
|
11372
|
+
{ kind, props: validatedProps },
|
|
11373
|
+
backend
|
|
11374
|
+
);
|
|
11455
11375
|
return { node, action: "created" };
|
|
11456
11376
|
}
|
|
11457
11377
|
const existingRow = await backend.getNode(
|
|
@@ -11460,8 +11380,11 @@ async function executeNodeGetOrCreateByConstraint(ctx, kind, constraintName, pro
|
|
|
11460
11380
|
existingUniqueRow.node_id
|
|
11461
11381
|
);
|
|
11462
11382
|
if (existingRow === void 0) {
|
|
11463
|
-
const
|
|
11464
|
-
|
|
11383
|
+
const node = await executeNodeCreate(
|
|
11384
|
+
ctx,
|
|
11385
|
+
{ kind, props: validatedProps },
|
|
11386
|
+
backend
|
|
11387
|
+
);
|
|
11465
11388
|
return { node, action: "created" };
|
|
11466
11389
|
}
|
|
11467
11390
|
const isSoftDeleted = existingRow.deleted_at !== void 0;
|
|
@@ -11500,20 +11423,14 @@ async function executeNodeFindByConstraint(ctx, kind, constraintName, props, bac
|
|
|
11500
11423
|
constraint.scope,
|
|
11501
11424
|
ctx.registry
|
|
11502
11425
|
);
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
});
|
|
11512
|
-
if (row !== void 0) {
|
|
11513
|
-
existingUniqueRow = row;
|
|
11514
|
-
break;
|
|
11515
|
-
}
|
|
11516
|
-
}
|
|
11426
|
+
const existingUniqueRow = await findUniqueRowAcrossKinds(
|
|
11427
|
+
backend,
|
|
11428
|
+
ctx.graphId,
|
|
11429
|
+
constraint.name,
|
|
11430
|
+
key,
|
|
11431
|
+
kindsToCheck,
|
|
11432
|
+
false
|
|
11433
|
+
);
|
|
11517
11434
|
if (existingUniqueRow === void 0) return void 0;
|
|
11518
11435
|
const existingRow = await backend.getNode(
|
|
11519
11436
|
ctx.graphId,
|
|
@@ -11524,11 +11441,7 @@ async function executeNodeFindByConstraint(ctx, kind, constraintName, props, bac
|
|
|
11524
11441
|
return void 0;
|
|
11525
11442
|
return rowToNode(existingRow);
|
|
11526
11443
|
}
|
|
11527
|
-
|
|
11528
|
-
if (items.length === 0) return [];
|
|
11529
|
-
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11530
|
-
const nodeKind = registration.type;
|
|
11531
|
-
const constraint = resolveConstraint(ctx.graph, kind, constraintName);
|
|
11444
|
+
function validateAndComputeKeys(nodeKind, kind, constraint, items) {
|
|
11532
11445
|
const validated = [];
|
|
11533
11446
|
for (const item of items) {
|
|
11534
11447
|
const validatedProps = validateNodeProps(nodeKind.schema, item.props, {
|
|
@@ -11543,49 +11456,35 @@ async function executeNodeBulkFindByConstraint(ctx, kind, constraintName, items,
|
|
|
11543
11456
|
) : void 0;
|
|
11544
11457
|
validated.push({ validatedProps, key });
|
|
11545
11458
|
}
|
|
11546
|
-
|
|
11459
|
+
return validated;
|
|
11460
|
+
}
|
|
11461
|
+
function collectUniqueKeys(validated) {
|
|
11462
|
+
return [
|
|
11547
11463
|
...new Set(
|
|
11548
|
-
validated.map((
|
|
11464
|
+
validated.map((entry) => entry.key).filter((key) => key !== void 0)
|
|
11549
11465
|
)
|
|
11550
11466
|
];
|
|
11467
|
+
}
|
|
11468
|
+
async function executeNodeBulkFindByConstraint(ctx, kind, constraintName, items, backend) {
|
|
11469
|
+
if (items.length === 0) return [];
|
|
11470
|
+
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11471
|
+
const nodeKind = registration.type;
|
|
11472
|
+
const constraint = resolveConstraint(ctx.graph, kind, constraintName);
|
|
11473
|
+
const validated = validateAndComputeKeys(nodeKind, kind, constraint, items);
|
|
11474
|
+
const uniqueKeys = collectUniqueKeys(validated);
|
|
11551
11475
|
const kindsToCheck = getKindsForUniquenessCheck(
|
|
11552
11476
|
kind,
|
|
11553
11477
|
constraint.scope,
|
|
11554
11478
|
ctx.registry
|
|
11555
11479
|
);
|
|
11556
|
-
const existingByKey =
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
nodeKind: kindToCheck,
|
|
11565
|
-
constraintName: constraint.name,
|
|
11566
|
-
key,
|
|
11567
|
-
includeDeleted: false
|
|
11568
|
-
});
|
|
11569
|
-
if (row !== void 0) {
|
|
11570
|
-
existingByKey.set(row.key, row);
|
|
11571
|
-
}
|
|
11572
|
-
}
|
|
11573
|
-
} else {
|
|
11574
|
-
const rows = await backend.checkUniqueBatch({
|
|
11575
|
-
graphId: ctx.graphId,
|
|
11576
|
-
nodeKind: kindToCheck,
|
|
11577
|
-
constraintName: constraint.name,
|
|
11578
|
-
keys: uniqueKeys,
|
|
11579
|
-
includeDeleted: false
|
|
11580
|
-
});
|
|
11581
|
-
for (const row of rows) {
|
|
11582
|
-
if (!existingByKey.has(row.key)) {
|
|
11583
|
-
existingByKey.set(row.key, row);
|
|
11584
|
-
}
|
|
11585
|
-
}
|
|
11586
|
-
}
|
|
11587
|
-
}
|
|
11588
|
-
}
|
|
11480
|
+
const existingByKey = uniqueKeys.length > 0 ? await batchCheckUniqueAcrossKinds(
|
|
11481
|
+
backend,
|
|
11482
|
+
ctx.graphId,
|
|
11483
|
+
constraint.name,
|
|
11484
|
+
uniqueKeys,
|
|
11485
|
+
kindsToCheck,
|
|
11486
|
+
false
|
|
11487
|
+
) : /* @__PURE__ */ new Map();
|
|
11589
11488
|
const results = Array.from({ length: items.length });
|
|
11590
11489
|
const seenKeys = /* @__PURE__ */ new Map();
|
|
11591
11490
|
for (const [index, { key }] of validated.entries()) {
|
|
@@ -11623,73 +11522,28 @@ async function executeNodeBulkGetOrCreateByConstraint(ctx, kind, constraintName,
|
|
|
11623
11522
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11624
11523
|
const nodeKind = registration.type;
|
|
11625
11524
|
const constraint = resolveConstraint(ctx.graph, kind, constraintName);
|
|
11626
|
-
const validated =
|
|
11627
|
-
|
|
11628
|
-
const validatedProps = validateNodeProps(nodeKind.schema, item.props, {
|
|
11629
|
-
kind,
|
|
11630
|
-
operation: "create"
|
|
11631
|
-
});
|
|
11632
|
-
const applies = checkWherePredicate(constraint, validatedProps);
|
|
11633
|
-
const key = applies ? computeUniqueKey(
|
|
11634
|
-
validatedProps,
|
|
11635
|
-
constraint.fields,
|
|
11636
|
-
constraint.collation
|
|
11637
|
-
) : void 0;
|
|
11638
|
-
validated.push({ validatedProps, key });
|
|
11639
|
-
}
|
|
11640
|
-
const uniqueKeys = [
|
|
11641
|
-
...new Set(
|
|
11642
|
-
validated.map((v) => v.key).filter((k) => k !== void 0)
|
|
11643
|
-
)
|
|
11644
|
-
];
|
|
11525
|
+
const validated = validateAndComputeKeys(nodeKind, kind, constraint, items);
|
|
11526
|
+
const uniqueKeys = collectUniqueKeys(validated);
|
|
11645
11527
|
const kindsToCheck = getKindsForUniquenessCheck(
|
|
11646
11528
|
kind,
|
|
11647
11529
|
constraint.scope,
|
|
11648
11530
|
ctx.registry
|
|
11649
11531
|
);
|
|
11650
|
-
const existingByKey =
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
|
|
11654
|
-
|
|
11655
|
-
|
|
11656
|
-
|
|
11657
|
-
|
|
11658
|
-
nodeKind: kindToCheck,
|
|
11659
|
-
constraintName: constraint.name,
|
|
11660
|
-
key,
|
|
11661
|
-
includeDeleted: true
|
|
11662
|
-
});
|
|
11663
|
-
if (row !== void 0) {
|
|
11664
|
-
existingByKey.set(row.key, row);
|
|
11665
|
-
}
|
|
11666
|
-
}
|
|
11667
|
-
} else {
|
|
11668
|
-
const rows = await backend.checkUniqueBatch({
|
|
11669
|
-
graphId: ctx.graphId,
|
|
11670
|
-
nodeKind: kindToCheck,
|
|
11671
|
-
constraintName: constraint.name,
|
|
11672
|
-
keys: uniqueKeys,
|
|
11673
|
-
includeDeleted: true
|
|
11674
|
-
});
|
|
11675
|
-
for (const row of rows) {
|
|
11676
|
-
if (!existingByKey.has(row.key)) {
|
|
11677
|
-
existingByKey.set(row.key, row);
|
|
11678
|
-
}
|
|
11679
|
-
}
|
|
11680
|
-
}
|
|
11681
|
-
}
|
|
11682
|
-
}
|
|
11532
|
+
const existingByKey = uniqueKeys.length > 0 ? await batchCheckUniqueAcrossKinds(
|
|
11533
|
+
backend,
|
|
11534
|
+
ctx.graphId,
|
|
11535
|
+
constraint.name,
|
|
11536
|
+
uniqueKeys,
|
|
11537
|
+
kindsToCheck,
|
|
11538
|
+
true
|
|
11539
|
+
) : /* @__PURE__ */ new Map();
|
|
11683
11540
|
const toCreate = [];
|
|
11684
11541
|
const toFetch = [];
|
|
11685
11542
|
const duplicateOf = [];
|
|
11686
11543
|
const seenKeys = /* @__PURE__ */ new Map();
|
|
11687
11544
|
for (const [index, { validatedProps, key }] of validated.entries()) {
|
|
11688
11545
|
if (key === void 0) {
|
|
11689
|
-
toCreate.push({
|
|
11690
|
-
index,
|
|
11691
|
-
input: { kind, props: validatedProps }
|
|
11692
|
-
});
|
|
11546
|
+
toCreate.push({ index, input: { kind, props: validatedProps } });
|
|
11693
11547
|
continue;
|
|
11694
11548
|
}
|
|
11695
11549
|
const previousIndex = seenKeys.get(key);
|
|
@@ -11700,10 +11554,7 @@ async function executeNodeBulkGetOrCreateByConstraint(ctx, kind, constraintName,
|
|
|
11700
11554
|
seenKeys.set(key, index);
|
|
11701
11555
|
const existing = existingByKey.get(key);
|
|
11702
11556
|
if (existing === void 0) {
|
|
11703
|
-
toCreate.push({
|
|
11704
|
-
index,
|
|
11705
|
-
input: { kind, props: validatedProps }
|
|
11706
|
-
});
|
|
11557
|
+
toCreate.push({ index, input: { kind, props: validatedProps } });
|
|
11707
11558
|
} else {
|
|
11708
11559
|
toFetch.push({
|
|
11709
11560
|
index,
|
|
@@ -11737,8 +11588,11 @@ async function executeNodeBulkGetOrCreateByConstraint(ctx, kind, constraintName,
|
|
|
11737
11588
|
nodeId
|
|
11738
11589
|
);
|
|
11739
11590
|
if (existingRow === void 0) {
|
|
11740
|
-
const
|
|
11741
|
-
|
|
11591
|
+
const node = await executeNodeCreate(
|
|
11592
|
+
ctx,
|
|
11593
|
+
{ kind, props: validatedProps },
|
|
11594
|
+
backend
|
|
11595
|
+
);
|
|
11742
11596
|
results[index] = { node, action: "created" };
|
|
11743
11597
|
continue;
|
|
11744
11598
|
}
|