diff --git a/doc/release-notes/changelog.md b/doc/release-notes/changelog.md index 190a9090f..d80cb9830 100644 --- a/doc/release-notes/changelog.md +++ b/doc/release-notes/changelog.md @@ -59,7 +59,7 @@ - `upsertGraph()` treats a row that lists itself in a relation on its own key, e.g. in its own `siblings`, as giving that relation no key, so the listing no longer conflicts with the key that the row's other places give: where 3.x threw a `ValidationError` of type `InvalidGraph`, such a graph is written, or throws the `NotFoundError` that asks for the `relate` option when a row it moves isn't related. A row that such a relation leaves out of its own list, e.g. a pet whose `siblings` name only the other pets, is removed from it, as in 3.x, also where the graph relates or moves the row. [#427](https://github.com/ditojs/objection/pull/427) - `upsertGraph()` patches a key that the graph gives a row, where it changes the key or the row isn't loaded, before it writes the rows that it relates by that key, at the same place or another one, so a foreign key with `ON UPDATE CASCADE` on that column holds, where 3.x wrote these rows with the old key and relied on the cascade. For these graphs, the patch and its `$beforeUpdate` run before the inserts and `$beforeInsert` of these rows, and before the relates and patches of the rows that read the key. A patch that also waits for a key or `#ref{}` value of these rows throws a `ValidationError` of type `InvalidGraph` before anything is written. [#428](https://github.com/ditojs/objection/issues/428) - `upsertGraph()` writes the keys that it changes under `noUpdate` with `patch()` instead of `update()`, so `$beforeUpdate()` and `$afterUpdate()` get `patch: true` in their options for them, as for the patches of other models. They were already validated as patches. [#415](https://github.com/ditojs/objection/issues/415) -- `insertGraph()` and `upsertGraph()` write in fewer queries: rows are deleted with one query per relation instead of one per owner, with all owners as `items` in the static hooks. On SQLite, rows are inserted in batches too, where 3.x inserted one row per query there, so the static `beforeInsert` and `afterInsert` hooks run once per batch with several models. See [migration](/release-notes/migration.md#insertgraph-and-upsertgraph-write-in-fewer-queries) +- `insertGraph()` and `upsertGraph()` write in fewer queries: rows are deleted with one query per relation instead of one per owner, with all owners as `items` in the static hooks. On SQLite, rows are inserted in batches too, where 3.x inserted one row per query there, so the static `beforeInsert` and `afterInsert` hooks run once per batch with several models. These batches use the query builder's `insert()`, so a custom `insert()` that sends arrays to `insertGraph()`, a 3.x workaround on SQLite, now recurses until it runs out of memory and needs to go. See [migration](/release-notes/migration.md#insertgraph-and-upsertgraph-write-in-fewer-queries) - Custom relation classes that extend `Relation` directly declare where their keys are stored with a `keySide` getter (`'owner'`, `'related'` or `'join'`) to be used in `insertGraph()` and `upsertGraph()`. Relations that extend the built-in relation classes inherit it. See [migration](/release-notes/migration.md#custom-relations-that-extend-relation-declare-keyside) - The deprecated `allowMarkers` option is removed from the `InsertGraphOptions` typings. It has no effect since 3.8.0, where `insertGraph()` rejects `#unrelate` and `#delete` markers. See [migration](/release-notes/migration.md#typescript-insertgraph-has-no-allowmarkers-option) - The type parameter of `RelateQueryBuilder` is the number query builder, e.g. `RelateQueryBuilder>` in custom query builders that override `relate()`. See [migration](/release-notes/migration.md#typescript-relatequerybuilder-takes-the-number-query-builder) diff --git a/doc/release-notes/migration.md b/doc/release-notes/migration.md index e5b5e84af..d08bd8b5b 100644 --- a/doc/release-notes/migration.md +++ b/doc/release-notes/migration.md @@ -287,6 +287,22 @@ Rows that the graph deletes are deleted with one query per relation instead of o On SQLite, rows that the graph inserts are inserted in batches, where 3.x inserted one row per query, so the static `beforeInsert` and `afterInsert` hooks get several models at once. +These batches go through the query builder's `insert()` with an array of rows. A custom `QueryBuilder` that sends arrays from `insert()` to `insertGraph()`, the usual 3.x way to insert several rows on SQLite, now calls itself until the process runs out of memory, without an error: + +```js +class MyQueryBuilder extends QueryBuilder { + insert(data) { + // Remove this override: `insert()` inserts arrays on SQLite itself. + if (Array.isArray(data) && data.length > 1) { + return this.insertGraph(data); + } + return super.insert(data); + } +} +``` + +Remove such overrides, as `insert()` inserts several rows on SQLite itself now. + ## Custom relations that extend Relation declare keySide `insertGraph()` and `upsertGraph()` read where the keys of a relation are stored from its `keySide` getter: `'owner'` for keys in the owner rows, like `BelongsToOneRelation`, `'related'` for keys in the related rows, like `HasManyRelation`, and `'join'` for keys in the rows of a join table, like `ManyToManyRelation`. Relation classes that extend the built-in relations inherit it. Classes that extend `Relation` directly need to declare it, or graph writes through them throw `not implemented`: