grafeo-ogm 2.4.5 → 2.4.7
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/CHANGELOG.md +37 -0
- package/dist/cjs/cli/introspect.d.ts.map +1 -1
- package/dist/cjs/cli/introspect.js +26 -1
- package/dist/cjs/cli/introspect.js.map +1 -1
- package/dist/cjs/cli/push-planner.d.ts +4 -0
- package/dist/cjs/cli/push-planner.d.ts.map +1 -1
- package/dist/cjs/cli/push-planner.js +22 -15
- package/dist/cjs/cli/push-planner.js.map +1 -1
- package/dist/cjs/compilers/mutation.compiler.d.ts.map +1 -1
- package/dist/cjs/compilers/mutation.compiler.js +48 -14
- package/dist/cjs/compilers/mutation.compiler.js.map +1 -1
- package/dist/esm/cli/introspect.d.ts.map +1 -1
- package/dist/esm/cli/introspect.js +26 -1
- package/dist/esm/cli/introspect.js.map +1 -1
- package/dist/esm/cli/push-planner.d.ts +4 -0
- package/dist/esm/cli/push-planner.d.ts.map +1 -1
- package/dist/esm/cli/push-planner.js +23 -16
- package/dist/esm/cli/push-planner.js.map +1 -1
- package/dist/esm/compilers/mutation.compiler.d.ts.map +1 -1
- package/dist/esm/compilers/mutation.compiler.js +48 -14
- package/dist/esm/compilers/mutation.compiler.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.4.7 (2026-10-18) — `db push --force-drop` only drops constraints grafeo created
|
|
4
|
+
|
|
5
|
+
### 🐛 `--force-drop` could drop constraints on labels grafeo doesn't manage
|
|
6
|
+
|
|
7
|
+
`db push` decided whether a live constraint was grafeo's from its **name alone**: any name that started with a known label and ended in `_unique` qualified. With `type Book` in the SDL, a DBA's `Book_Archive_code_unique` constraint on the **unrelated** label `Book_Archive` looked like "label `Book`, property `Archive_code`". `db push --force-drop --yes` then dropped it. A NODE KEY or existence constraint that happened to share the naming shape qualified too.
|
|
8
|
+
|
|
9
|
+
A constraint is now treated as a droppable orphan only when its **definition** proves grafeo would have created it:
|
|
10
|
+
|
|
11
|
+
- the type is `UNIQUENESS`
|
|
12
|
+
- it covers exactly one label, and that label is in the schema
|
|
13
|
+
- it covers exactly one property
|
|
14
|
+
- its name is exactly `{Label}_{prop}_unique` for that label and property
|
|
15
|
+
|
|
16
|
+
`db push` now reads `labelsOrTypes` and `properties` from `SHOW CONSTRAINTS` to check this. If a server doesn't report those columns, nothing is treated as droppable: a missed orphan only means "kept", while a wrong drop can lose a constraint. The set of constraints `--force-drop` can drop only ever shrinks.
|
|
17
|
+
|
|
18
|
+
## 2.4.6 (2026-10-18) — `createMany` writes every item's fields
|
|
19
|
+
|
|
20
|
+
### 🐛 `createMany` took its columns from the first item only
|
|
21
|
+
|
|
22
|
+
The column list came from `data[0]`'s keys, so with mixed items:
|
|
23
|
+
|
|
24
|
+
- **Fields only later items supplied were silently dropped.** `createMany({ data: [{ email: 'a' }, { email: 'b', name: 'B', age: 4 }] })` stored `b` without `name` or `age`.
|
|
25
|
+
- **An `@id` supplied by some items left the others with a null id.**
|
|
26
|
+
- **A `@default` column overwrote values that later items supplied** (`status: 'banned'` was stored as the default `'active'`).
|
|
27
|
+
|
|
28
|
+
The column set is now the union of every item's keys. An item that omits a field gets what `create()` would give it, which is what the README documents for `@default`:
|
|
29
|
+
|
|
30
|
+
- a generated `@id`, if the field is an `@id`
|
|
31
|
+
- the `@default` value, if the field has one
|
|
32
|
+
- nothing, otherwise
|
|
33
|
+
|
|
34
|
+
An explicit `null` stays `null`. With `skipDuplicates`, the `MERGE` key is now the `@id`/`@unique` fields that **every** item supplies, so no item ever merges on a null. Batches where every item has the same keys emit the same Cypher as before.
|
|
35
|
+
|
|
36
|
+
**Unchanged on purpose:** a relationship field is still rejected only in the **first** item. In later items it is still skipped without being written. Rejecting it in every item would make calls that succeed today throw, so that is tracked as a separate change.
|
|
37
|
+
|
|
38
|
+
A new opt-in live suite, `tests/integration/create-many.spec.ts`, covers each case. Against Neo4j 5.26.32, the 4 bug cases fail without the fix.
|
|
39
|
+
|
|
3
40
|
## 2.4.5 (2026-10-18) — nested creates inside `update` store edge properties
|
|
4
41
|
|
|
5
42
|
### 🐛 `edge` was silently dropped on a nested `create` inside `update`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../../src/cli/introspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../../src/cli/introspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,gBAAgB,CAAC;AAuDjE;;;GAGG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,CAAC,CAgBrB"}
|
|
@@ -25,7 +25,32 @@ function toLiveItem(record) {
|
|
|
25
25
|
}
|
|
26
26
|
if (typeof name !== 'string' || name.length === 0)
|
|
27
27
|
return null;
|
|
28
|
-
|
|
28
|
+
const item = {
|
|
29
|
+
name,
|
|
30
|
+
type: typeof type === 'string' ? type : String(type ?? ''),
|
|
31
|
+
};
|
|
32
|
+
// The definition columns let the planner attribute a constraint by what
|
|
33
|
+
// it constrains, not just its name. Absent on a server → left undefined,
|
|
34
|
+
// and the planner then never treats the row as droppable.
|
|
35
|
+
const labels = stringList(record, 'labelsOrTypes');
|
|
36
|
+
const props = stringList(record, 'properties');
|
|
37
|
+
if (labels)
|
|
38
|
+
item.labelsOrTypes = labels;
|
|
39
|
+
if (props)
|
|
40
|
+
item.properties = props;
|
|
41
|
+
return item;
|
|
42
|
+
}
|
|
43
|
+
function stringList(record, key) {
|
|
44
|
+
let value;
|
|
45
|
+
try {
|
|
46
|
+
value = record.get(key);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return Array.isArray(value) && value.every((v) => typeof v === 'string')
|
|
52
|
+
? value
|
|
53
|
+
: undefined;
|
|
29
54
|
}
|
|
30
55
|
/**
|
|
31
56
|
* Fetch the live constraint/index state for the push planner. Read-only —
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../../src/cli/introspect.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../../src/cli/introspect.ts"],"names":[],"mappings":";;AA4DA,0CAmBC;AA5ED;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,MAEnB;IACC,IAAI,IAAa,CAAC;IAClB,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,IAAI,GAAmB;QAC3B,IAAI;QACJ,IAAI,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;KAC3D,CAAC;IACF,wEAAwE;IACxE,yEAAyE;IACzE,0DAA0D;IAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC/C,IAAI,MAAM;QAAE,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;IACxC,IAAI,KAAK;QAAE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IACnC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,UAAU,CACjB,MAAqC,EACrC,GAAW;IAEX,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QACtE,CAAC,CAAE,KAAkB;QACrB,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,QAAiB;IAEjB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpE,IAAI,CAAC;QACH,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChE,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACxD,OAAO;YACL,WAAW,EAAE,iBAAiB,CAAC,OAAO;iBACnC,GAAG,CAAC,UAAU,CAAC;iBACf,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;YACjD,OAAO,EAAE,aAAa,CAAC,OAAO;iBAC3B,GAAG,CAAC,UAAU,CAAC;iBACf,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;SAClD,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
|
|
@@ -8,6 +8,10 @@ export interface LiveSchemaItem {
|
|
|
8
8
|
* VECTOR / TEXT / POINT / LOOKUP for indexes.
|
|
9
9
|
*/
|
|
10
10
|
type: string;
|
|
11
|
+
/** SHOW `labelsOrTypes` column, when the server exposes it. */
|
|
12
|
+
labelsOrTypes?: string[];
|
|
13
|
+
/** SHOW `properties` column, when the server exposes it. */
|
|
14
|
+
properties?: string[];
|
|
11
15
|
}
|
|
12
16
|
export interface LiveSchema {
|
|
13
17
|
constraints: LiveSchemaItem[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push-planner.d.ts","sourceRoot":"","sources":["../../../src/cli/push-planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,eAAe,
|
|
1
|
+
{"version":3,"file":"push-planner.d.ts","sourceRoot":"","sources":["../../../src/cli/push-planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,eAAe,EAEf,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAmBtD,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,gDAAgD;IAChD,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,2CAA2C;IAC3C,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B;;;;OAIG;IACH,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,wEAAwE;IACxE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,0EAA0E;IAC1E,WAAW,EAAE,wBAAwB,EAAE,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,UAAU,EAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,GACvD,QAAQ,CAoEV"}
|
|
@@ -68,7 +68,7 @@ function planSchemaSync(schema, live, vectorConfig) {
|
|
|
68
68
|
// Grafeo-attributable AND a safe identifier → droppable orphan. A name
|
|
69
69
|
// that matches the convention shape but carries unsafe characters (a
|
|
70
70
|
// hostile live constraint) is demoted to `unmanaged`, never dropped.
|
|
71
|
-
if (
|
|
71
|
+
if (isGrafeoConstraint(constraint, knownLabels) &&
|
|
72
72
|
isSafeIdentifier(constraint.name))
|
|
73
73
|
orphans.push({
|
|
74
74
|
name: constraint.name,
|
|
@@ -94,21 +94,28 @@ function planSchemaSync(schema, live, vectorConfig) {
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
97
|
+
* Is this live constraint one grafeo itself would have created — i.e. a
|
|
98
|
+
* single-label, single-property UNIQUENESS constraint on a label the schema
|
|
99
|
+
* knows, named exactly `uniqueConstraintName(label, prop)`?
|
|
100
|
+
*
|
|
101
|
+
* Decided from the constraint's DEFINITION, not its name alone. Pre-2.4.7
|
|
102
|
+
* any name starting with a known label passed (`Book_Archive_code_unique`
|
|
103
|
+
* looked like `Book` + prop `Archive_code`), so `--force-drop` could drop a
|
|
104
|
+
* constraint on a label grafeo doesn't manage — or a NODE KEY / existence
|
|
105
|
+
* constraint that merely shared the naming shape. Without the definition
|
|
106
|
+
* columns it is never treated as droppable: a missed orphan is harmless, a
|
|
107
|
+
* wrong drop is not.
|
|
100
108
|
*/
|
|
101
|
-
function
|
|
102
|
-
if (
|
|
109
|
+
function isGrafeoConstraint(constraint, knownLabels) {
|
|
110
|
+
if (constraint.type && constraint.type !== 'UNIQUENESS')
|
|
103
111
|
return false;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return false;
|
|
112
|
+
const labels = constraint.labelsOrTypes;
|
|
113
|
+
const props = constraint.properties;
|
|
114
|
+
if (!labels || !props || labels.length !== 1 || props.length !== 1)
|
|
115
|
+
return false;
|
|
116
|
+
const [label] = labels;
|
|
117
|
+
const [prop] = props;
|
|
118
|
+
return (knownLabels.has(label) &&
|
|
119
|
+
constraint.name === (0, index_statements_1.uniqueConstraintName)(label, prop));
|
|
113
120
|
}
|
|
114
121
|
//# sourceMappingURL=push-planner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push-planner.js","sourceRoot":"","sources":["../../../src/cli/push-planner.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"push-planner.js","sourceRoot":"","sources":["../../../src/cli/push-planner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/mutation.compiler.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"mutation.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/mutation.compiler.ts"],"names":[],"mappings":"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"}
|
|
@@ -603,19 +603,41 @@ class MutationCompiler {
|
|
|
603
603
|
const labelStr = this.getCachedLabelString(nodeDef);
|
|
604
604
|
const lines = [];
|
|
605
605
|
const params = {};
|
|
606
|
-
// Validate and sanitize: only scalar properties allowed
|
|
606
|
+
// Validate and sanitize: only scalar properties allowed. The column set
|
|
607
|
+
// is the UNION of every item's keys — pre-2.4.6 it was `data[0]`'s
|
|
608
|
+
// keys only, so a field that only later items supplied was silently
|
|
609
|
+
// dropped (and a relationship field there was neither rejected nor
|
|
610
|
+
// written).
|
|
607
611
|
const scalarKeys = [];
|
|
608
|
-
for (const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
612
|
+
for (const [index, item] of data.entries())
|
|
613
|
+
for (const key of Object.keys(item)) {
|
|
614
|
+
if (item[key] === undefined || scalarKeys.includes(key))
|
|
615
|
+
continue;
|
|
616
|
+
if (nodeDef.relationships.has(key)) {
|
|
617
|
+
// Only the first item's relationship fields have ever been
|
|
618
|
+
// rejected; in later items they were (and still are) skipped
|
|
619
|
+
// unwritten. Rejecting them everywhere would make calls that
|
|
620
|
+
// succeed today throw — tracked as a separate, breaking change.
|
|
621
|
+
if (index > 0)
|
|
622
|
+
continue;
|
|
623
|
+
throw new errors_1.OGMError(`createMany does not support relationship fields. Found: "${key}". Use create() for nested operations.`);
|
|
624
|
+
}
|
|
625
|
+
(0, validation_1.assertSafePropertyName)(key, 'createMany property');
|
|
626
|
+
scalarKeys.push(key);
|
|
627
|
+
}
|
|
614
628
|
// Identify @id (generated) fields that are NOT provided in data
|
|
615
629
|
const generatedFields = [];
|
|
616
630
|
for (const [, propDef] of nodeDef.properties)
|
|
617
631
|
if (propDef.isGenerated && !scalarKeys.includes(propDef.name))
|
|
618
632
|
generatedFields.push(propDef.name);
|
|
633
|
+
// A @id column supplied by SOME items only: the others still get a
|
|
634
|
+
// generated id (as create() would), never null.
|
|
635
|
+
const isPartialGenerated = (key) => Boolean(nodeDef.properties.get(key)?.isGenerated) &&
|
|
636
|
+
data.some((d) => d[key] === undefined || d[key] === null);
|
|
637
|
+
const columnExpr = (key) => {
|
|
638
|
+
const expr = (0, write_coercion_1.wrapListItemExpr)(`item.${(0, validation_1.escapeIdentifier)(key)}`, data.map((d) => d[key]), nodeDef.properties.get(key));
|
|
639
|
+
return isPartialGenerated(key) ? `coalesce(${expr}, randomUUID())` : expr;
|
|
640
|
+
};
|
|
619
641
|
// Whole-column `@default`s: applied only when NO item supplies the
|
|
620
642
|
// field. Per-item gaps inside a provided column stay null — one
|
|
621
643
|
// createMany batch shares a single Cypher text, and a per-item
|
|
@@ -628,22 +650,34 @@ class MutationCompiler {
|
|
|
628
650
|
!propDef.isCypher &&
|
|
629
651
|
!scalarKeys.includes(propDef.name))
|
|
630
652
|
defaultedProps.push(propDef);
|
|
631
|
-
// Build sanitized items (strip undefined values)
|
|
653
|
+
// Build sanitized items (strip undefined values). A `@default` field
|
|
654
|
+
// whose column is supplied by only some items is filled per item for
|
|
655
|
+
// the others — exactly what create() gives an item that omits it. An
|
|
656
|
+
// explicit `null` is kept as null.
|
|
632
657
|
const sanitizedItems = data.map((item) => {
|
|
633
658
|
const sanitized = {};
|
|
634
|
-
for (const key of scalarKeys)
|
|
659
|
+
for (const key of scalarKeys) {
|
|
660
|
+
const propDef = nodeDef.properties.get(key);
|
|
635
661
|
if (item[key] !== undefined)
|
|
636
|
-
sanitized[key] = (0, write_coercion_1.coerceWriteValue)(item[key],
|
|
662
|
+
sanitized[key] = (0, write_coercion_1.coerceWriteValue)(item[key], propDef);
|
|
663
|
+
else if (propDef?.defaultValue !== undefined &&
|
|
664
|
+
!propDef.isGenerated &&
|
|
665
|
+
!propDef.isCypher)
|
|
666
|
+
sanitized[key] = (0, write_coercion_1.resolveDefaultWriteValue)(propDef);
|
|
667
|
+
}
|
|
637
668
|
return sanitized;
|
|
638
669
|
});
|
|
639
670
|
params.items = sanitizedItems;
|
|
640
671
|
lines.push('UNWIND $items AS item');
|
|
641
672
|
if (skipDuplicates) {
|
|
642
|
-
//
|
|
673
|
+
// MERGE key: the unique/id fields EVERY item supplies — an item
|
|
674
|
+
// missing one would MERGE on null, which Neo4j rejects.
|
|
643
675
|
const mergeKeys = [];
|
|
644
676
|
for (const key of scalarKeys) {
|
|
645
677
|
const propDef = nodeDef.properties.get(key);
|
|
646
|
-
if (propDef &&
|
|
678
|
+
if (propDef &&
|
|
679
|
+
(propDef.isUnique || propDef.isGenerated) &&
|
|
680
|
+
data.every((d) => d[key] !== undefined && d[key] !== null))
|
|
647
681
|
mergeKeys.push(key);
|
|
648
682
|
}
|
|
649
683
|
if (mergeKeys.length === 0)
|
|
@@ -657,7 +691,7 @@ class MutationCompiler {
|
|
|
657
691
|
const onCreateSets = [];
|
|
658
692
|
for (const key of scalarKeys)
|
|
659
693
|
if (!mergeKeys.includes(key))
|
|
660
|
-
onCreateSets.push(`n.${(0, validation_1.escapeIdentifier)(key)} = ${(
|
|
694
|
+
onCreateSets.push(`n.${(0, validation_1.escapeIdentifier)(key)} = ${columnExpr(key)}`);
|
|
661
695
|
for (const field of generatedFields)
|
|
662
696
|
onCreateSets.push(`n.${(0, validation_1.escapeIdentifier)(field)} = randomUUID()`);
|
|
663
697
|
for (const propDef of defaultedProps) {
|
|
@@ -675,7 +709,7 @@ class MutationCompiler {
|
|
|
675
709
|
for (const field of generatedFields)
|
|
676
710
|
propParts.push(`${(0, validation_1.escapeIdentifier)(field)}: randomUUID()`);
|
|
677
711
|
for (const key of scalarKeys)
|
|
678
|
-
propParts.push(`${(0, validation_1.escapeIdentifier)(key)}: ${(
|
|
712
|
+
propParts.push(`${(0, validation_1.escapeIdentifier)(key)}: ${columnExpr(key)}`);
|
|
679
713
|
for (const propDef of defaultedProps) {
|
|
680
714
|
const paramName = `default_${propDef.name}`;
|
|
681
715
|
const bound = (0, write_coercion_1.resolveDefaultWriteValue)(propDef);
|