You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Behaviour change:upsertGraph() replacing the row of a BelongsToOneRelation, e.g. { id: 1, pet: { id: 2 } }, points the owner to the new row before it deletes the old one. The static delete hooks of these deletes get no relation or items in their context, as the rows are deleted by id. Before, the old row was deleted first: with a NOT NULL foreign key and ON DELETE CASCADE, the database deleted the owner and upsertGraph() still succeeded, and foreign keys without ON DELETE action failed. A new row that repeats a unique value of the row it replaces now fails, as both exist at the same time: pass the id of the old row to update it instead. When noInsert or noRelate skips the replacement, the current row and the owner's reference are kept.
Behaviour change:upsertGraph() removing the row of a BelongsToOneRelation with pet: null or #delete sets the owner's foreign key to null before it deletes the row if the owner's jsonSchema allows null for it (in type, anyOf, oneOf or with nullable: true). Before, the row was deleted first: with ON DELETE CASCADE the database deleted the owner, and foreign keys without ON DELETE action failed. The owner is now patched, also with ON DELETE SET NULL, so its update hooks run (e.g. writing updatedAt), and the static delete hooks of these deletes, like those of replaced rows, get no relation or items in their context. Without a nullable schema for the key, the row is still deleted first and the owner's reference is left to the database. #212
Behaviour change:upsertGraph() no longer deletes a row that is missing in one place of the graph if the same graph relates or updates it in another place. The row is unrelated from its old place instead, so rows can be moved between parents in one call, also below related models. #214
Behaviour change:upsertGraph() with a #unrelate or #delete marker on a BelongsToOneRelation model that isn't the currently related one keeps the current one, as the marked model is ignored. Before, the current row was deleted without clearing the owner's foreign key. #213
Behaviour change:insertGraph() and upsertGraph() no longer insert the related models of models that noInsert skips, unless a #ref points to them. These were inserted without foreign keys. #215
insertGraph() logs a warning when it ignores new models below related models. This will throw in objection 4.0. Use upsertGraph() or a separate query to insert them. #217
Behaviour change: the graph options reject * and ^ in brackets with other relations, like children.[pets, ^], instead of never matching them #221
The #ref and #dbRef markers are removed from the results of insertGraph() and upsertGraph(), also from models they skip #221
upsertGraph() no longer throws "model (id=…) is not a child of model (id=…)" for children with ids below nodes related through a relate path option #220
$relatedQuery().insertGraph() with several models on many-to-many relations inserts the join rows on SQLite and MySQL, where it failed #219
$relatedQuery().insertGraph() on a BelongsToOneRelation relates the inserted row to the owner #216
Behaviour change:deleteById(), patchById() and updateById() also keep their id condition in its own where group, which the 3.8.0 notes already claimed for "the other *ById methods": deleteById(1).where(a).orWhere(b) runs id = 1 and (a or b) instead of id = 1 and a or b, which deleted other rows. A findById() added by the user stays in the user's where group, also in findById(1).patch(…). #232
Behaviour change: a many-to-many patch() / update() that only changes join table extras returns the number of related rows whose join rows it updated, instead of 0. The static afterUpdate hooks receive this number as their result instead of 0. patchAndFetchById() with only extras returns the patched row instead of undefined. #235
Behaviour change: on SQL Server, a many-to-many patch() / update() with join table extras applies limit(), offset() and orderBy() to the related rows it picks, and only updates their join rows, as on MySQL. Before, the limit applied to each batch of related rows, all join rows were updated, and an orderBy() with the limit failed with a syntax error. With limit().offset() but no orderBy() it now throws, as SQL Server rejects OFFSET without ORDER BY, where the offset was ignored before. #233
Many-to-many patch() / update() with join table extras select the related ids straight from their filter query, unless limit() or offset() picks the related rows on MySQL or SQL Server. Postgres could plan the previous query as a nested loop that ran for minutes #161
On MySQL, delete() with both orderBy() and limit() warns that the order has no effect, as knex leaves it out of the statement. This will throw in objection 4.0. #235
Behaviour change: query properties like raw(), ref() and subqueries given to a model instance are no longer written again once their keys are given a value, by assignment, $set(), $setJson() or a write that fetched the value. $setJson() keeps the query properties of earlier calls, $setJson(modelInstance) drops them for the keys the instance has, values that objection sets itself (e.g. foreign keys set by insertGraph() and $relatedQuery().insert()) beat a query property for the same key, values that $beforeInsert() / $beforeUpdate() set for keys given as query properties are removed from the instance after the hooks, as the query properties are written instead, and schema defaults no longer appear on the model or in toJSON() for keys given as query properties. #202
raw() and other query properties assigned to json attributes in $beforeInsert() and $beforeUpdate() are written instead of their serialized objects #203
Behaviour change:pickJsonSchemaProperties keeps field expression keys like 'meta:a' whose json column is in the schema, so patch(), update() and upsertGraph() write them instead of silently dropping them. insert() no longer silently drops such keys either: they reach the database and fail as they do without pickJsonSchemaProperties. Keys only found on Object.prototype (like 'toString') are no longer picked. upsertGraph() no longer selects field expression keys as columns. #204
Behaviour change: a patch(), update() or merge() that sets both a json column and a field expression into it throws a ValidationError, also when a model instance holds both, instead of dropping the field expression or failing with an SQL error #206
Behaviour change: patches and the field expressions of update() are validated without the required properties of schemas referenced by $id, like the ones added in onCreateAjv(), which regressed in 3.8.0. Whole values for such properties in patches are validated without required too, like local definitions. #207
onConflict().merge() with a json field expression key no longer fails with an ambiguous column on Postgres. merge({ 'meta:b': ref('meta:a') }) is still ambiguous: qualify the reference with the table, e.g. ref('items.meta:a'). #260
Behaviour change:hasSelection() and findSelection() treat a table name without schema as the schema-qualified table, so withGraphJoined() no longer throws for selections like persons.id of a model with a tableName like public.persons, a regression in 3.8.0, and replaces its persons.* selections #226
Behaviour change:withGraphJoined() tells apart rows whose ids are Buffers, e.g. binary UUIDs, and withGraphJoined() / withGraphFetched() tell apart keys whose dates differ only in milliseconds, composite keys whose strings contain commas, and string ids that contain / or ., also in upsertGraph(). Dates are keyed by their time, so a Date and a number with the same epoch milliseconds match, e.g. Date ids passed to fetchGraph() and the numbers SQLite returns for them. #222#223
resultSize() and the total of page() and range() respect distinctOn() with withGraphJoined() on Postgres, also on joined columns #224
limitPerParent limits the related items when the relation key is a JSON field #225
withGraphFetched() with the limitPerParent option works for related models with a schema-qualified tableName, also when the order names the schema #265
Behaviour change: when SQL Server reports several errors for one statement, e.g. for offset() without orderBy(), objection throws a DBError with all their messages, instead of the driver's AggregateError with an empty message, which is kept as nativeError
update(), patch() and delete() warn about offset(), as knex leaves it out there, and on SQL Server the limit too. This will throw an error in objection 4.0. #286
Types
Custom query builders that override withGraph() compile again, also with TypeScript 7, which broke in 3.7.0 with the relate().returning() typings
Docs
withGraphFetched() doesn't assign related rows whose keys only match by collation: by case or accents on MySQL, by case or trailing spaces on SQL Server #227
upsertGraph() matches ids by their exact value, and how to normalize uuids given in a different case #221