grafeo-ogm 1.14.0 → 2.1.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/CHANGELOG.md +256 -0
- package/README.md +70 -0
- package/dist/cjs/compilers/fulltext.compiler.d.ts.map +1 -1
- package/dist/cjs/compilers/fulltext.compiler.js +30 -14
- package/dist/cjs/compilers/fulltext.compiler.js.map +1 -1
- package/dist/cjs/compilers/mutation.compiler.d.ts +7 -0
- package/dist/cjs/compilers/mutation.compiler.d.ts.map +1 -1
- package/dist/cjs/compilers/mutation.compiler.js +130 -36
- package/dist/cjs/compilers/mutation.compiler.js.map +1 -1
- package/dist/cjs/compilers/where.compiler.d.ts.map +1 -1
- package/dist/cjs/compilers/where.compiler.js +13 -4
- package/dist/cjs/compilers/where.compiler.js.map +1 -1
- package/dist/cjs/generator/type-emitters/fulltext-emitter.js +24 -8
- package/dist/cjs/generator/type-emitters/fulltext-emitter.js.map +1 -1
- package/dist/cjs/generator/type-emitters/sort-options-emitter.d.ts +2 -1
- package/dist/cjs/generator/type-emitters/sort-options-emitter.d.ts.map +1 -1
- package/dist/cjs/generator/type-emitters/sort-options-emitter.js +12 -5
- package/dist/cjs/generator/type-emitters/sort-options-emitter.js.map +1 -1
- package/dist/cjs/generator/type-emitters/utility-types.d.ts.map +1 -1
- package/dist/cjs/generator/type-emitters/utility-types.js +21 -1
- package/dist/cjs/generator/type-emitters/utility-types.js.map +1 -1
- package/dist/cjs/utils/cypher-sort-projection.d.ts +3 -0
- package/dist/cjs/utils/cypher-sort-projection.d.ts.map +1 -1
- package/dist/cjs/utils/cypher-sort-projection.js +13 -1
- package/dist/cjs/utils/cypher-sort-projection.js.map +1 -1
- package/dist/cjs/utils/validation.d.ts +72 -0
- package/dist/cjs/utils/validation.d.ts.map +1 -1
- package/dist/cjs/utils/validation.js +133 -0
- package/dist/cjs/utils/validation.js.map +1 -1
- package/dist/cjs/utils/write-coercion.d.ts +61 -0
- package/dist/cjs/utils/write-coercion.d.ts.map +1 -0
- package/dist/cjs/utils/write-coercion.js +213 -0
- package/dist/cjs/utils/write-coercion.js.map +1 -0
- package/dist/esm/compilers/fulltext.compiler.d.ts.map +1 -1
- package/dist/esm/compilers/fulltext.compiler.js +31 -15
- package/dist/esm/compilers/fulltext.compiler.js.map +1 -1
- package/dist/esm/compilers/mutation.compiler.d.ts +7 -0
- package/dist/esm/compilers/mutation.compiler.d.ts.map +1 -1
- package/dist/esm/compilers/mutation.compiler.js +130 -36
- package/dist/esm/compilers/mutation.compiler.js.map +1 -1
- package/dist/esm/compilers/where.compiler.d.ts.map +1 -1
- package/dist/esm/compilers/where.compiler.js +13 -4
- package/dist/esm/compilers/where.compiler.js.map +1 -1
- package/dist/esm/generator/type-emitters/fulltext-emitter.js +24 -8
- package/dist/esm/generator/type-emitters/fulltext-emitter.js.map +1 -1
- package/dist/esm/generator/type-emitters/sort-options-emitter.d.ts +2 -1
- package/dist/esm/generator/type-emitters/sort-options-emitter.d.ts.map +1 -1
- package/dist/esm/generator/type-emitters/sort-options-emitter.js +12 -5
- package/dist/esm/generator/type-emitters/sort-options-emitter.js.map +1 -1
- package/dist/esm/generator/type-emitters/utility-types.d.ts.map +1 -1
- package/dist/esm/generator/type-emitters/utility-types.js +21 -1
- package/dist/esm/generator/type-emitters/utility-types.js.map +1 -1
- package/dist/esm/utils/cypher-sort-projection.d.ts +3 -0
- package/dist/esm/utils/cypher-sort-projection.d.ts.map +1 -1
- package/dist/esm/utils/cypher-sort-projection.js +14 -2
- package/dist/esm/utils/cypher-sort-projection.js.map +1 -1
- package/dist/esm/utils/validation.d.ts +72 -0
- package/dist/esm/utils/validation.d.ts.map +1 -1
- package/dist/esm/utils/validation.js +129 -0
- package/dist/esm/utils/validation.js.map +1 -1
- package/dist/esm/utils/write-coercion.d.ts +61 -0
- package/dist/esm/utils/write-coercion.d.ts.map +1 -0
- package/dist/esm/utils/write-coercion.js +206 -0
- package/dist/esm/utils/write-coercion.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,261 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.1.0 (2026-08-13) — 🧭 Writes now store what the schema declares
|
|
4
|
+
|
|
5
|
+
> **Every write path now binds values as the Neo4j type the schema promises.** Until now the compilers bound raw JS values and left the rest to the driver — and the driver packs every JS `number` as a Bolt FLOAT64 and every string as a String. So `Int`/`BigInt` fields landed as **Doubles** ([#5](https://github.com/neomodular/grafeo-ogm/issues/5)), the six temporal types landed as **Strings**, and `BigInt`'s documented string input landed as a **String** — while reads converted every native value back to a JS primitive, so the corruption was invisible until something type-sensitive touched the property. `@default` rode along: parsed, documented in the README, and applied nowhere.
|
|
6
|
+
>
|
|
7
|
+
> **This is a minor version because behavior changes on inputs that previously "worked":** `position: 1.5` and `plays: 'abc'` now throw instead of silently storing the wrong type, schemas that declare `@default` now actually receive defaults on create, and the generated `BigInt` scalar changes shape. If your inputs already match the documented contract you can upgrade and regenerate directly — but read the **migration note** below if you have data written through the OGM before 2.1.0.
|
|
8
|
+
|
|
9
|
+
### 🐛 `Int` / `BigInt` writes are bound as Neo4j Integer ([#5](https://github.com/neomodular/grafeo-ogm/issues/5))
|
|
10
|
+
|
|
11
|
+
The driver packs every JS `number` as FLOAT64 — `disableLosslessIntegers` only affects reads — so every OGM-written `Int` property landed as a Double. Once a field held a mixed Long/Double population (OGM writes vs seed/raw-Cypher writes), Long-typed consumers crashed:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Failed to invoke function `apoc.coll.sortMulti`:
|
|
15
|
+
java.lang.ClassCastException: class java.lang.Double cannot be cast to class java.lang.Long
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Every mutation binding site — create, update, upsert (MERGE key, `ON CREATE SET`, `ON MATCH SET`), `createMany` items, and all edge-property paths through connect and nested updates (**14 sites** in total; the report named 5) — now binds `Int`/`BigInt` values through `neo4j.int()`. Numbers, bigints, integer strings, and pre-built `Integer` instances are all accepted; `null` clears as before.
|
|
19
|
+
|
|
20
|
+
**Rejected, not truncated:** a non-integral number (`1.5`) or a non-integer string (`'abc'`) for an integer field now throws `OGMError`. Coercing would silently truncate; binding raw would silently store the wrong type — both are the defect class 2.0.0 exists to reject.
|
|
21
|
+
|
|
22
|
+
### 🐛 Temporal writes are stored as native temporal types
|
|
23
|
+
|
|
24
|
+
`DateTime`, `Date`, `Time`, `LocalTime`, `LocalDateTime`, and `Duration` fields were stored as **String** properties — the write path had no temporal conversion at all, while the README's scalar table promised native storage and reads converted native temporals to ISO strings. Against natively-typed rows (seed, APOC, raw Cypher), `WHERE n.createdAt > $param` with a string param is a cross-type comparison: Neo4j evaluates it to `NULL` and **silently drops the row**.
|
|
25
|
+
|
|
26
|
+
ISO-string writes are now wrapped in the field's Cypher constructor — the parameter stays a string and Neo4j does the parsing, which preserves nanosecond precision and bracket timezones (`2024-01-15T10:30:00[America/New_York]`) that a JS `Date` round-trip would destroy:
|
|
27
|
+
|
|
28
|
+
```cypher
|
|
29
|
+
CREATE (n:`Event` { `startsAt`: datetime($create0_startsAt) })
|
|
30
|
+
SET n.`day` = date($update_day)
|
|
31
|
+
// list fields wrap element-wise:
|
|
32
|
+
`slots`: [wc_t IN $create0_slots | datetime(wc_t)]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The same wrapping applies to WHERE params for comparison-shaped operators (`=`, `_NOT`, `_GT`/`_GTE`/`_LT`/`_LTE`, `_IN`/`_NOT_IN`) across the main where compiler and the connect/disconnect where paths, so filters keep matching the natively-stored values. String operators (`_CONTAINS`, `_MATCHES`, …) are untouched. Driver temporal objects still bind raw — only strings are wrapped. Batched paths (`createMany`, array connect) share one Cypher expression per field, so a column mixing ISO strings with driver objects throws instead of guessing.
|
|
36
|
+
|
|
37
|
+
### 🐛 `BigInt` honours its generated contract in both directions
|
|
38
|
+
|
|
39
|
+
The generated scalar declared `BigInt: { input: string; output: string }` — but a string input sailed through to a **String property**, and reads returned `number` (or `bigint` above 2⁵³), never `string`. Integer strings now coerce through `neo4j.int()` (for `Int` fields too), and the scalar tells the truth:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
BigInt: { input: string | number | bigint; output: number | bigint };
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Regenerate your types to pick this up. If you annotated variables with the old `string` output type, those annotations were already wrong at runtime — the regen turns them into compile errors you can fix.
|
|
46
|
+
|
|
47
|
+
### 🐛 `@default` is now applied on create
|
|
48
|
+
|
|
49
|
+
`@default` was parsed into schema metadata and consumed by **nothing** — a documented silent no-op. It now applies wherever a node is created:
|
|
50
|
+
|
|
51
|
+
- `create` (nested relationship creates included)
|
|
52
|
+
- `upsert` — `ON CREATE SET` branch only, never `ON MATCH`, and never for MERGE-key fields
|
|
53
|
+
- `createMany` — as a whole-column default when **no** item supplies the field (per-item gaps inside a provided column stay `null`: every batch shares one Cypher text, and `coalesce()` would also override explicit nulls)
|
|
54
|
+
|
|
55
|
+
Defaults convert by declared type — `@default(value: "5")` on an `Int` binds an Integer, `Boolean` binds `true`/`false`, temporal defaults get their constructor wrapper. **A provided value always wins, and an explicit `null` stays `null`** — the user asked for null; a default overriding it would betray intent.
|
|
56
|
+
|
|
57
|
+
### ⚠️ Migrating data written before 2.1.0
|
|
58
|
+
|
|
59
|
+
Properties written through the OGM before this release carry the old storage types. New writes and filters use native types, so mixed populations should be migrated once, per affected field:
|
|
60
|
+
|
|
61
|
+
```cypher
|
|
62
|
+
// String-stored temporals → native (repeat per temporal field/label)
|
|
63
|
+
MATCH (n:Event) WHERE valueType(n.startsAt) STARTS WITH 'STRING'
|
|
64
|
+
SET n.startsAt = datetime(n.startsAt);
|
|
65
|
+
|
|
66
|
+
// Double-stored Ints → Long (only needed for Long-sensitive consumers,
|
|
67
|
+
// e.g. apoc.coll.sortMulti — Cypher numeric comparisons already match)
|
|
68
|
+
MATCH (n:ShelfRow) WHERE valueType(n.position) = 'FLOAT'
|
|
69
|
+
SET n.position = toInteger(n.position);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Until the temporal migration runs, WHERE filters on temporal fields will not match old String-stored rows (they compare as cross-type → `NULL`).
|
|
73
|
+
|
|
74
|
+
### Tests
|
|
75
|
+
|
|
76
|
+
- `tests/int-write-coercion.spec.ts` — 14 tests pinning Integer coercion across every mutation path.
|
|
77
|
+
- `tests/type-faithful-writes.spec.ts` — 24 tests pinning temporal wrapping (writes + WHERE), integer-string coercion, and `@default` semantics.
|
|
78
|
+
- 12 existing assertions that pinned the old behavior (raw-number edge params, unwrapped temporal comparisons, `DateTime` strings passed verbatim) updated to the corrected contract.
|
|
79
|
+
|
|
80
|
+
## 2.0.0 (2026-08-04) — 💥 Inputs that were silently truncated are now rejected
|
|
81
|
+
|
|
82
|
+
> **A major release with one theme: grafeo used to read the first key of certain input objects and throw the rest away without a word.** `sort` entries, fulltext leaves, and fulltext logical operators all did it. Every one produced a *successful* query answering a different question than the caller asked — no exception, no log, nothing in the Cypher to suggest anything was missing.
|
|
83
|
+
>
|
|
84
|
+
> **This is a major version because the fix is a behavior change on inputs that previously "worked."** Code that relied on the truncated shapes now throws at runtime, and regenerating types turns most of those shapes into compile errors. If your `sort` arrays and `fulltext` inputs already carry one key per object — the documented form throughout — **you are unaffected and can upgrade directly**.
|
|
85
|
+
|
|
86
|
+
### 💥 Breaking changes at a glance
|
|
87
|
+
|
|
88
|
+
| Shape | Before | Now |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| `sort: [{ a: 'ASC', b: 'DESC' }]` | `ORDER BY n.a ASC` — `b` dropped | throws; compile error after regen |
|
|
91
|
+
| `fulltext: { IdxA: {…}, IdxB: {…} }` | searched `IdxA` only | throws; compile error after regen |
|
|
92
|
+
| `fulltext: { OR: […], AND: […] }` | `OR` only | throws; compile error after regen |
|
|
93
|
+
| `fulltext: { NOT: {…}, AND: […] }` | **`AND` only — exclusion lost** | throws; compile error after regen |
|
|
94
|
+
| `fulltext: { OR: […], IdxA: {…} }` | `OR` only | throws at runtime |
|
|
95
|
+
| `sort: [null]`, `fulltext: null` | bare `TypeError` | `OGMError` |
|
|
96
|
+
| `const s: XSort = {}; s.a = 'ASC'` | compiled | compile error — push array entries |
|
|
97
|
+
|
|
98
|
+
Migration for each is mechanical and shown in the sections below. The short version: **one key per object; use the array (`sort`) or the `AND`/`OR` operators (`fulltext`) to express more than one.**
|
|
99
|
+
|
|
100
|
+
> **Origin.** Reported by the community ([#4](https://github.com/neomodular/grafeo-ogm/issues/4)) against `sort`, found in production where an admin-curated `position` column had been silently ignored for every client. Auditing for the same defect class turned up three more sites in `FulltextCompiler`, and reviewing *that* fix turned up a fourth at the operator dispatch.
|
|
101
|
+
|
|
102
|
+
### 🐛 A sort entry must now carry exactly one ordering key
|
|
103
|
+
|
|
104
|
+
`ORDER BY` precedence comes from an entry's **position in the array**, never from key order inside an object. The documented form was always correct and is unchanged:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// ✅ ORDER BY n.isUrgent DESC, n.position ASC
|
|
108
|
+
sort: [{ isUrgent: 'DESC' }, { position: 'ASC' }];
|
|
109
|
+
|
|
110
|
+
// ❌ compile error, and throws at runtime
|
|
111
|
+
sort: [{ isUrgent: 'DESC', position: 'ASC' }];
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Why reject rather than honour every key?** Because object key order is not a reliable carrier for precedence at a transport boundary. `graphql-js` `coerceInputValue` rebuilds input objects by iterating the **schema's** field definitions, not the order the client wrote them — so a client sending `{ position: ASC, isUrgent: DESC }` hands the resolver `{ isUrgent, position }` in SDL declaration order. Honouring both keys would have traded one silent wrong-order bug for another that only reproduces behind a GraphQL layer, and would have looked correct in direct TypeScript use. Array position survives that trip; key order does not.
|
|
115
|
+
|
|
116
|
+
### 🐛 A fulltext leaf must now reference exactly one index
|
|
117
|
+
|
|
118
|
+
The same defect lived at three sites in `FulltextCompiler` — `compileLeaf`, `compileRelationshipIndex`, and `compileRelationship` — each guarding the empty case and then reading `Object.keys(input)[0]`:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// ❌ before: searched CategoryNameIndex only, dropped CategoryBlurbIndex
|
|
122
|
+
// → CALL db.index.fulltext.queryNodes('CategoryNameIndex', $ft_phrase)
|
|
123
|
+
// → params: { ft_phrase: 'graph' } // 'neo4j' gone entirely
|
|
124
|
+
fulltext: {
|
|
125
|
+
CategoryNameIndex: { phrase: 'graph' },
|
|
126
|
+
CategoryBlurbIndex: { phrase: 'neo4j' },
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ✅ AND / OR already existed for this, and compile correctly
|
|
130
|
+
fulltext: {
|
|
131
|
+
AND: [
|
|
132
|
+
{ CategoryNameIndex: { phrase: 'graph' } },
|
|
133
|
+
{ CategoryBlurbIndex: { phrase: 'neo4j' } },
|
|
134
|
+
],
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**This one is more serious than the sort defect.** A dropped sort key returns the right rows in the wrong order; a dropped *search term* returns the **wrong rows** — a strictly wider result set, because one index was searched instead of two. A filter that silently stops filtering.
|
|
139
|
+
|
|
140
|
+
Phrase values are never echoed into the error message: they are user data and may carry control characters or sensitive content. Only index names — already identifier-validated — appear.
|
|
141
|
+
|
|
142
|
+
> **Note:** a characterization test, `should only use the first index when multiple are provided`, previously pinned the dropping behaviour. It described the defect rather than defending it (no rationale, while the sibling `SelectNormalizer` throws for the identical situation), and has been replaced with specs asserting rejection.
|
|
143
|
+
|
|
144
|
+
### 🐛 `AND` / `OR` / `NOT` must each be the only key in their object
|
|
145
|
+
|
|
146
|
+
Reviewing the leaf fix surfaced the same defect one level up, in the operator dispatch. `compileNode` tests `OR`, then `AND`, then `NOT`, and returns at the first hit — so anything else in the object was discarded without a word:
|
|
147
|
+
|
|
148
|
+
| Input | Compiled | Effect |
|
|
149
|
+
| --- | --- | --- |
|
|
150
|
+
| `{ OR: […], AND: […] }` | `OR` only | a filter disappears |
|
|
151
|
+
| `{ OR: […], SomeIndex: {…} }` | `OR` only | a filter disappears |
|
|
152
|
+
| `{ NOT: {…}, AND: […] }` | **`AND` only** | **the exclusion disappears** |
|
|
153
|
+
|
|
154
|
+
The third row is the dangerous one. `AND` is tested before `NOT`, so a `NOT` written alongside it vanished completely — the caller asked to *exclude* something and got no exclusion at all. That inverts intent rather than merely widening the result set.
|
|
155
|
+
|
|
156
|
+
Operators nest; they do not stack:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// ✅ correct
|
|
160
|
+
fulltext: { AND: [{ OR: [ /* … */ ] }, { CategoryBlurbIndex: { phrase: 'x' } }] }
|
|
161
|
+
|
|
162
|
+
// ❌ rejected
|
|
163
|
+
fulltext: { OR: [ /* … */ ], AND: [ /* … */ ] }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Sibling keys are **counted, never echoed** — unlike leaf index names they have not been identifier-validated at dispatch time, so interpolating them could forge log lines.
|
|
167
|
+
|
|
168
|
+
### 💥 BREAKING — generated `<Type>Sort` and `<Type>FulltextLeaf` types are now single-key
|
|
169
|
+
|
|
170
|
+
Both are wrapped in a new `ExactlyOneKey<T>` utility type, so a two-key entry is a **compile error** rather than a silent truncation. Unknown fields and invalid directions are rejected as before.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
export type SafedoseCategorySort = ExactlyOneKey<{
|
|
174
|
+
isUrgent?: InputMaybe<SortDirection>;
|
|
175
|
+
position?: InputMaybe<SortDirection>;
|
|
176
|
+
}>;
|
|
177
|
+
|
|
178
|
+
export type SafedoseCategoryFulltextLeaf = ExactlyOneKey<{
|
|
179
|
+
CategoryNameIndex?: FulltextIndexEntry;
|
|
180
|
+
CategoryBlurbIndex?: FulltextIndexEntry;
|
|
181
|
+
}>;
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Nested relationship index objects are wrapped too, since `compileRelationshipIndex` reads a single key as well.
|
|
185
|
+
|
|
186
|
+
`<Node>FulltextInput` keeps its `leaf | OR | AND | NOT` shape, but each operator member now marks the other two `?: never`:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
export type SafedoseCategoryFulltextInput =
|
|
190
|
+
| SafedoseCategoryFulltextLeaf
|
|
191
|
+
| { OR: SafedoseCategoryFulltextInput[]; AND?: never; NOT?: never }
|
|
192
|
+
| { AND: SafedoseCategoryFulltextInput[]; OR?: never; NOT?: never }
|
|
193
|
+
| { NOT: SafedoseCategoryFulltextInput; OR?: never; AND?: never };
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
This closes operator-vs-operator stacking at compile time. It deliberately does **not** close an operator mixed with a bare index key (`{ OR: [...], SomeIndex: {...} }`) — TypeScript permits a literal property that exists on any member of a union, so that shape stays a runtime rejection.
|
|
197
|
+
|
|
198
|
+
This lands when you **regenerate types**, and it breaks conditional sort building from an empty object literal. Push entries instead:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// before — no longer compiles
|
|
202
|
+
const s: BookSort = {};
|
|
203
|
+
if (byTitle) s.title = 'ASC';
|
|
204
|
+
|
|
205
|
+
// after
|
|
206
|
+
const sort: BookSort[] = [];
|
|
207
|
+
if (byTitle) sort.push({ title: 'ASC' });
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Types with no sortable fields emit `Record<string, never>` rather than collapsing to `never`. `<Type>Options` is unchanged.
|
|
211
|
+
|
|
212
|
+
### 🛡️ Runtime guards for the paths types cannot reach
|
|
213
|
+
|
|
214
|
+
Types alone are not sufficient, so every surface validates arity at compile time too — `compileSortClause` via `assertSingleSortKey`, the three `FulltextCompiler` leaf sites via `assertSingleFulltextKey`, and the operator dispatch via `assertSingleFulltextOperator` — alongside the `assertSafeIdentifier` checks already in those loops. This matters because `FindOptions<TSort>` defaults to `Record<string, 'ASC' | 'DESC'>` — an index signature — so the untyped `ogm.model('X')` path admits multi-key entries regardless, and "exactly one arbitrary key" is not expressible over an open record. The GraphQL-resolver path erases the types too, and operator-plus-index-key is not expressible in the union at all. The errors name the offending keys and show the correct form:
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
Sort entry has 2 keys (isUrgent, position); each sort entry must carry exactly
|
|
218
|
+
one ordering key, because ORDER BY precedence comes from array position and not
|
|
219
|
+
object key order. Use one entry per key: [{ isUrgent: 'DESC' }, { position: 'ASC' }].
|
|
220
|
+
|
|
221
|
+
Fulltext leaf has 2 keys (CategoryNameIndex, CategoryBlurbIndex); a fulltext entry
|
|
222
|
+
must reference exactly one index. Combine indexes with the AND / OR operators
|
|
223
|
+
instead: { AND: [{ CategoryNameIndex: … }, { CategoryBlurbIndex: … }] }.
|
|
224
|
+
|
|
225
|
+
Fulltext input carries AND + NOT; AND / OR / NOT must each be the only key in
|
|
226
|
+
their object, because the compiler reads the first one and ignores the rest.
|
|
227
|
+
Nest them instead: { AND: [{ OR: [...] }, { ... }] }.
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Every key is identifier-validated (not just the first), so an unsafe identifier in a non-surviving key is now caught too. Only recognised sort directions are echoed into the error string, and fulltext phrases never are. **Zero-key sort entries (`{}`) keep their existing runtime skip** — they contribute no ordering rather than a wrong one, so there is no silent-wrong-answer to close, though the new types do reject the literal. Empty fulltext inputs still throw, unchanged.
|
|
231
|
+
|
|
232
|
+
### 🛡️ Malformed inputs now throw `OGMError` instead of a bare `TypeError`
|
|
233
|
+
|
|
234
|
+
`sort: [null]` surfaced as `TypeError: Cannot convert undefined or null to object` thrown from inside `Object.entries`, and fulltext inputs failed the same way on `Object.keys(input)` / `'OR' in input`. Both escaped `catch (e) { if (e instanceof OGMError) … }`, even though every other malformed input on those paths was already an `OGMError`.
|
|
235
|
+
|
|
236
|
+
A new `assertPlainObject` guards each enumeration point: sort entries, fulltext inputs (in `compileNode`, so operator recursion such as `{ OR: [null] }` is covered too), index entry values (`{ BookSearch: null }`), and the standalone relationship fulltext entry. Only the value's **kind** is reported — never the value:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
Sort entry must be an object, got null.
|
|
240
|
+
Fulltext entry "BookTitleSearch" must be an object, got null.
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Tests
|
|
244
|
+
|
|
245
|
+
Nine compiler specs covering multi-key rejection, the error's key list and suggested form, three-key arity, a multi-key entry in a non-first position, multi-key `@cypher` entries failing before any `CALL` is emitted, unsafe identifiers in non-surviving keys, refusal to echo unrecognised directions, the documented form still compiling to both `ORDER BY` terms, and zero-key entries still skipped.
|
|
246
|
+
|
|
247
|
+
Eight **integration** specs (`tests/sort-entry-arity.spec.ts`) drive the public API rather than the compiler, proving the guard is actually reached from `Model.find` / `Model.findFirst` / `InterfaceModel.find` — and that it fires **before any query reaches the driver**, so there is no round-trip returning wrongly-ordered rows. Verified as genuine regression coverage: with the guard disabled, exactly the 11 arity specs fail and every pre-existing sort spec still passes.
|
|
248
|
+
|
|
249
|
+
Eight non-object specs guard the `OGMError` contract — five sort-entry kinds (`null`, `undefined`, array, string, number), a bad entry in a non-first position, and refusal to echo the offending value; plus four on the fulltext side covering a non-object top level, one nested inside an `OR` branch, a non-object index entry value, and kind-without-value reporting.
|
|
250
|
+
|
|
251
|
+
Fourteen fulltext compiler specs: four on leaf arity (rejection, the AND/OR remedy appearing while phrases never do, both indexes compiling under `AND`, single-index leaves unchanged) and six on operator arity (two stacked operators, `NOT` alongside `AND`, an operator mixed with a bare index key, sibling keys counted rather than echoed, a single operator unchanged, and properly nested operators). Disabling either guard fails exactly its own specs and no others.
|
|
252
|
+
|
|
253
|
+
Seven emitter specs cover the `ExactlyOneKey` wrapper for node and interface `Sort` types, the no-sortable-fields fallback, `<Type>Options` referencing `<Type>Sort` unchanged, the fulltext leaf wrapper, the nested relationship index wrapper, and the mutually-exclusive operator members on `<Node>FulltextInput`.
|
|
254
|
+
|
|
255
|
+
Generated output was additionally verified end-to-end under `tsc --strict` against a schema carrying an interface, a `@cypher` sort field, two fulltext indexes, and a relationship-only type. Failing to compile: the reported sort shape, multi-key `@cypher` entries, three-key entries, multi-key interface entries, unknown sort fields, invalid directions, empty entries, sorting an unsortable type, two-index fulltext leaves, unknown index names, `OR` + `AND`, and `NOT` + `AND`. Compiling cleanly: the documented sort form, `@cypher` and interface sorts, incremental array building, single-index leaves, scores, `AND` / `OR` / `NOT` composition — and, as documented above, operator-plus-index-key, which the runtime rejects instead. Full suite green (1673); lint and format clean.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
3
259
|
## 1.14.0 (2026-07-24) — 🛡️ Security release: NLS enforcement on interface reads & relationship writes, and a `_MATCHES` ReDoS guard
|
|
4
260
|
|
|
5
261
|
> **Three security fixes.** Two are object-level authorization gaps: grafeo's node-level-security (NLS) policies were threaded correctly through the concrete-model read and write paths, but two paths silently skipped the **target type's** policy — nested relationship projections on **interface** reads, and **connect/disconnect** relationship writes — so a caller whose own access was correctly scoped could still read, or link/unlink, related nodes their policy forbids. The third hardens the `_MATCHES` filter operator against server-side ReDoS. If you use `policies` with interface models or nested `connect`/`disconnect`, or expose `_MATCHES` to untrusted input, upgrade.
|
package/README.md
CHANGED
|
@@ -732,6 +732,36 @@ const books = await Book.find({
|
|
|
732
732
|
offset: 40,
|
|
733
733
|
},
|
|
734
734
|
});
|
|
735
|
+
// ORDER BY n.title ASC, n.published DESC
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
**Each sort entry carries exactly one ordering key.** `ORDER BY` precedence
|
|
739
|
+
comes from an entry's position in the array, never from key order inside an
|
|
740
|
+
object:
|
|
741
|
+
|
|
742
|
+
```typescript
|
|
743
|
+
// ✅ correct — precedence is unambiguous
|
|
744
|
+
sort: [{ title: 'ASC' }, { published: 'DESC' }];
|
|
745
|
+
|
|
746
|
+
// ❌ rejected — compile error, and throws at runtime
|
|
747
|
+
sort: [{ title: 'ASC', published: 'DESC' }];
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
Why not just honour both keys? Because object key order is not a reliable
|
|
751
|
+
carrier for precedence. When sort input arrives through a GraphQL layer,
|
|
752
|
+
`graphql-js` rebuilds input objects by iterating the schema's field
|
|
753
|
+
definitions, so the order a client wrote is already gone before the OGM sees
|
|
754
|
+
it. Array position survives that trip; key order does not.
|
|
755
|
+
|
|
756
|
+
Building a sort list conditionally works the same way — push entries rather
|
|
757
|
+
than assembling one object:
|
|
758
|
+
|
|
759
|
+
```typescript
|
|
760
|
+
const sort: BookSort[] = [];
|
|
761
|
+
if (byTitle) sort.push({ title: 'ASC' });
|
|
762
|
+
if (byDate) sort.push({ published: 'DESC' });
|
|
763
|
+
|
|
764
|
+
await Book.find({ options: { sort } });
|
|
735
765
|
```
|
|
736
766
|
|
|
737
767
|
---
|
|
@@ -930,6 +960,46 @@ await Book.find({ fulltext: { BookSearch: { phrase: 'graph' } } });
|
|
|
930
960
|
|
|
931
961
|
The runtime compiler is unchanged; this is a purely ergonomic type-level improvement. The global `FulltextInput`, `FulltextLeaf`, and `FulltextIndexEntry` exports remain for writing generic helpers across models.
|
|
932
962
|
|
|
963
|
+
**One index per leaf (v2.0.0+).** A fulltext leaf references exactly one index. To search several, compose them with `AND` / `OR` — which is what those operators are for:
|
|
964
|
+
|
|
965
|
+
```typescript
|
|
966
|
+
// ✅ correct — both indexes are searched
|
|
967
|
+
fulltext: {
|
|
968
|
+
AND: [
|
|
969
|
+
{ BookSearch: { phrase: 'graph' } },
|
|
970
|
+
{ BlurbSearch: { phrase: 'neo4j' } },
|
|
971
|
+
],
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// ❌ rejected — compile error, and throws at runtime
|
|
975
|
+
fulltext: {
|
|
976
|
+
BookSearch: { phrase: 'graph' },
|
|
977
|
+
BlurbSearch: { phrase: 'neo4j' },
|
|
978
|
+
}
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
Before v2.0.0 the second form compiled to a search of `BookSearch` **only**; `BlurbSearch` and its phrase were dropped with no error, so the query returned a strictly *wider* result set than intended. `AND` compiles to correlated subqueries, `OR` to a `UNION` with `max(score)` deduplication.
|
|
982
|
+
|
|
983
|
+
**One operator per object (v2.0.0+).** The same rule applies to `AND` / `OR` / `NOT` — they nest, they don't stack:
|
|
984
|
+
|
|
985
|
+
```typescript
|
|
986
|
+
// ✅ correct — nest to combine
|
|
987
|
+
fulltext: {
|
|
988
|
+
AND: [
|
|
989
|
+
{ OR: [{ BookSearch: { phrase: 'graph' } }, { BookSearch: { phrase: 'db' } }] },
|
|
990
|
+
{ NOT: { BlurbSearch: { phrase: 'draft' } } },
|
|
991
|
+
],
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// ❌ rejected — two operators in one object
|
|
995
|
+
fulltext: {
|
|
996
|
+
OR: [{ BookSearch: { phrase: 'graph' } }],
|
|
997
|
+
AND: [{ BlurbSearch: { phrase: 'neo4j' } }],
|
|
998
|
+
}
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
The compiler reads `OR`, then `AND`, then `NOT`, and stops at the first one it finds. Before v2.0.0 the rest were dropped silently — and because `AND` is checked before `NOT`, writing `{ NOT: …, AND: … }` compiled the `AND` alone and **discarded the exclusion entirely**. Mixing an operator with a bare index key (`{ OR: [...], BookSearch: {...} }`) is rejected at runtime; TypeScript can't express that one.
|
|
1002
|
+
|
|
933
1003
|
### Subgraph Operations
|
|
934
1004
|
|
|
935
1005
|
Clone or delete entire subgraphs using APOC procedures. Requires the APOC plugin installed in Neo4j.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fulltext.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/fulltext.compiler.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,aAAa,EAEd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"fulltext.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/fulltext.compiler.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,aAAa,EAEd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAkChF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,gBAAgB;IACf,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,cAAc;IAE1C;;;OAGG;IACH,OAAO,CACL,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,cAAc,EACvB,OAAO,SAAM,GACZ,cAAc;IAqBjB;;;OAGG;IACH,mBAAmB,CACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAC5D,QAAQ,EAAE,aAAa,EACvB,MAAM,SAAM,GACX,cAAc;IAgDjB,OAAO,CAAC,WAAW;IAmDnB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAqCnB,+EAA+E;IAC/E,OAAO,CAAC,gBAAgB;IAoCxB;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IAgFhC;;OAEG;IACH,OAAO,CAAC,SAAS;IAiDjB;;;OAGG;IACH,OAAO,CAAC,UAAU;IA8DlB;;;OAGG;IACH,OAAO,CAAC,UAAU;CA2BnB"}
|
|
@@ -67,12 +67,16 @@ class FulltextCompiler {
|
|
|
67
67
|
*/
|
|
68
68
|
compileRelationship(fulltext, relIndex, relVar = 'r') {
|
|
69
69
|
(0, validation_1.assertSafeIdentifier)(relVar, 'relationship variable');
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
(0, validation_1.assertPlainObject)(fulltext, 'Relationship fulltext input');
|
|
71
|
+
const entries = Object.entries(fulltext);
|
|
72
|
+
if (entries.length === 0)
|
|
72
73
|
throw new errors_1.OGMError('Fulltext input must contain at least one index entry');
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
74
|
+
// Validate every key, not just the surviving one, so the arity error only
|
|
75
|
+
// ever interpolates identifier-shaped strings.
|
|
76
|
+
for (const [key] of entries)
|
|
77
|
+
(0, validation_1.assertSafeIdentifier)(key, 'fulltext index name');
|
|
78
|
+
(0, validation_1.assertSingleFulltextKey)(entries, 'Relationship fulltext input');
|
|
79
|
+
const [indexName, input] = entries[0];
|
|
76
80
|
assertValidFulltextPhrase(input.phrase);
|
|
77
81
|
if (relIndex.name !== indexName)
|
|
78
82
|
throw new errors_1.OGMError(`Unknown relationship fulltext index "${indexName}". Expected "${relIndex.name}".`);
|
|
@@ -97,6 +101,12 @@ class FulltextCompiler {
|
|
|
97
101
|
compileNode(input, nodeDef, nodeVar, paramCounter, depth = 0) {
|
|
98
102
|
if (depth > MAX_DEPTH)
|
|
99
103
|
throw new errors_1.OGMError(`Fulltext logical nesting exceeds maximum depth of ${MAX_DEPTH}`);
|
|
104
|
+
// Guarded here rather than in `compile()` so it also covers every branch
|
|
105
|
+
// reached through OR / AND / NOT recursion, e.g. `{ OR: [null] }`.
|
|
106
|
+
(0, validation_1.assertPlainObject)(input, 'Fulltext input');
|
|
107
|
+
// The operator dispatch below returns on its first hit, so anything
|
|
108
|
+
// alongside OR / AND / NOT would be dropped without a word.
|
|
109
|
+
(0, validation_1.assertSingleFulltextOperator)(Object.keys(input));
|
|
100
110
|
if ((0, model_1.isFulltextLeaf)(input))
|
|
101
111
|
return this.compileLeaf(input, nodeDef, nodeVar, paramCounter);
|
|
102
112
|
if ('OR' in input)
|
|
@@ -113,11 +123,16 @@ class FulltextCompiler {
|
|
|
113
123
|
* - Relationship index: `{ relField: { IndexName: { phrase, score? } } }` — value is nested
|
|
114
124
|
*/
|
|
115
125
|
compileLeaf(leaf, nodeDef, nodeVar, paramCounter) {
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
126
|
+
const entries = Object.entries(leaf);
|
|
127
|
+
if (entries.length === 0)
|
|
118
128
|
throw new errors_1.OGMError('Fulltext input must contain at least one index entry');
|
|
119
|
-
const
|
|
120
|
-
|
|
129
|
+
for (const [k] of entries)
|
|
130
|
+
(0, validation_1.assertSafeIdentifier)(k, 'fulltext index or relationship name');
|
|
131
|
+
(0, validation_1.assertSingleFulltextKey)(entries, 'Fulltext leaf');
|
|
132
|
+
const key = entries[0][0];
|
|
133
|
+
// `isFulltextIndexEntry` uses the `in` operator, which throws a bare
|
|
134
|
+
// TypeError on a non-object (e.g. `{ BookSearch: null }`).
|
|
135
|
+
(0, validation_1.assertPlainObject)(leaf[key], `Fulltext entry "${key}"`);
|
|
121
136
|
const value = leaf[key];
|
|
122
137
|
// If value has `phrase`, it's a direct node index entry
|
|
123
138
|
if ((0, model_1.isFulltextIndexEntry)(value))
|
|
@@ -163,12 +178,13 @@ class FulltextCompiler {
|
|
|
163
178
|
const relProps = this.schema.relationshipProperties.get(relDef.properties);
|
|
164
179
|
if (!relProps)
|
|
165
180
|
throw new errors_1.OGMError(`@relationshipProperties type "${relDef.properties}" not found`);
|
|
166
|
-
const
|
|
167
|
-
if (
|
|
181
|
+
const innerEntries = Object.entries(inner);
|
|
182
|
+
if (innerEntries.length === 0)
|
|
168
183
|
throw new errors_1.OGMError('Relationship fulltext entry must contain an index name');
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
184
|
+
for (const [key] of innerEntries)
|
|
185
|
+
(0, validation_1.assertSafeIdentifier)(key, 'fulltext index name');
|
|
186
|
+
(0, validation_1.assertSingleFulltextKey)(innerEntries, `Relationship fulltext entry for "${relFieldName}"`);
|
|
187
|
+
const [indexName, input] = innerEntries[0];
|
|
172
188
|
const ftIndex = (relProps.fulltextIndexes ?? []).find((idx) => idx.name === indexName);
|
|
173
189
|
if (!ftIndex)
|
|
174
190
|
throw new errors_1.OGMError(`Unknown fulltext index "${indexName}" on @relationshipProperties "${relDef.properties}"`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fulltext.compiler.js","sourceRoot":"","sources":["../../../src/compilers/fulltext.compiler.ts"],"names":[],"mappings":";;;AAAA,sCAAqC;AACrC,oCAKkB;AAElB,
|
|
1
|
+
{"version":3,"file":"fulltext.compiler.js","sourceRoot":"","sources":["../../../src/compilers/fulltext.compiler.ts"],"names":[],"mappings":"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"}
|
|
@@ -120,6 +120,13 @@ export declare class MutationCompiler {
|
|
|
120
120
|
* Returns count of created nodes.
|
|
121
121
|
*/
|
|
122
122
|
compileCreateMany(data: Record<string, unknown>[], nodeDef: NodeDefinition, skipDuplicates?: boolean, labels?: string[]): MutationResult;
|
|
123
|
+
/**
|
|
124
|
+
* Resolve the PropertyDefinition of an edge (relationship) property so
|
|
125
|
+
* Int/BigInt edge writes get the same Integer coercion as node writes.
|
|
126
|
+
* Returns undefined when the relationship declares no properties type
|
|
127
|
+
* (the coercion then passes the value through untouched).
|
|
128
|
+
*/
|
|
129
|
+
private getEdgePropDef;
|
|
123
130
|
private buildCreateProperties;
|
|
124
131
|
private buildCreateRelationships;
|
|
125
132
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/mutation.compiler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EACL,cAAc,
|
|
1
|
+
{"version":3,"file":"mutation.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/mutation.compiler.ts"],"names":[],"mappings":"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"}
|