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
The limitPerParent graph option applies limit(), offset() and first() of relations loaded with withGraphFetched() per parent instead of to all parents together, e.g. withGraphFetched('pets(latest)', { limitPerParent: true }). With page() / range() the relation query is limited as before. On MySQL before 8, relations with a limit are fetched with one query per parent. withGraphJoined() ignores the option and warns about it. #127#429
Fixes
Behaviour change:update() validates field expression keys like 'meta:color' like patch() does since 3.3.0: the written parts are validated against the json column's schema, including $refs, without its required, while the rest of the object is validated normally. The json column counts as present and doesn't get its default. Before, the keys were validated as top-level properties: invalid values passed, additionalProperties: false rejected the keys, a required json column counted as missing, and its default replaced the whole stored value. #160
Behaviour change: keys containing : that the schema declares in properties, e.g. 'ns:name', are normal properties and columns: validated as properties and written to their column by patch(), update() and merge(). Before, patch() (since 3.3.0) and update() / fromJson() treated them as field expressions and wrote them as JSON paths. Properties that only $beforeValidate() declares are still treated as field expressions. #160
Behaviour change:insertGraph() throws a ValidationError of type InvalidGraph for #unrelate / #delete markers also with allowMarkers: true, where 3.7.0 skipped the marked models: an insert has nothing to unrelate or delete. allowMarkers stays in the InsertGraphOptions typings until 4.0, deprecated and without effect. #2410
Behaviour change: a root model marked with #unrelate or #delete gets the error that the markers can only be used for related models, in upsertGraph() and insertGraph(), also without allowMarkers. #164
Behaviour change:upsertGraph() with noUpdate, noDelete, noUnrelate and insertMissing runs as an upsert like any other upsertGraph() call. Models that already exist are left alone instead of failing with duplicate key errors, and markers allowed with allowMarkers take effect. Only insertGraph() runs as an insert.
Behaviour change: many-to-many patch() / update() with join table extras select the ids of the matching related rows first, patch the join rows, and then the related rows by these ids, in batches of 500 values. A filter on a column that the patch changes, e.g. .patch({ name: 'renamed', role: 'new' }).where('movies.name', 'old'), left the join rows unchanged. These patches run several statements, so use a transaction if they need to be atomic. #161
On MySQL, limit() / offset() of many-to-many patch() / update() with join table extras pick the related rows to update, and only their join rows are updated. Before, all matching join rows were updated. Other databases ignore a limit in updates, as before. #161
Behaviour change:asFindQuery() in static hooks always runs the find query and returns the affected rows. It returned the value the query was resolved with, e.g. 0 for a patch with nothing to set, or the value of resolve() / cancelQuery(), and threw TypeError: related.some is not a function for many-to-many patches that only change join table extras.
asFindQuery() in static hooks of many-to-many patchAndFetchById() / updateAndFetchById() keeps the query's filters
Behaviour change: the id condition of $query() and of patchAndFetchById(), updateAndFetchById() and the other *ById methods gets its own where group, so a user's orWhere() can't get around it: $query().patch(…).orWhere(b) runs id = 1 and (b) instead of id = 1 or b. The where groups are built when the SQL is generated, so asFindQuery() in static hooks no longer drops or repeats where clauses of relation queries, which regressed in 3.3.0. #2191
Behaviour change:withGraphJoined() selects the root table's columns instead of *, so the columns of joined tables no longer land on the root models under their plain names. distinct('*') keeps its distinct.
distinctOn() with withGraphJoined(), withGraphFetched() and joinRelated(): its columns were treated as selected, so the other columns were missing from the models, and joined relations could fail with "column does not exist".
Behaviour change:withGraphJoined() throws when the root query selects a different column under a name it selects itself, e.g. a joined table's column without an alias like select('Person.*', 'pets.id'), select('pets.*'), ref('Person.age').as('name') or 'Person.name as id', and raw SQL, subqueries or aggregates under the name of an id column it needs to build the graph. Before, SQL Server returned arrays of values and the other databases silently kept one of them, sometimes grouping the root models by the wrong id. Raw SQL, subqueries and aggregates under other names replace the column. Select such columns under a different name.
Selections are matched after wrapIdentifier mapping (knexSnakeCaseMappers()) for column names and aliases too, so withGraphFetched() no longer selects a relation column a second time and strips it from the result when it's selected under its snake_case name
Behaviour change:resultSize() with withGraphJoined() throws model … has no idColumn for models without a primary key if the joined relations include a to-many relation, as the root models can't be counted without ids. Since 3.3.0 it counted the joined rows instead, or failed on MySQL. With only to-one relations, the rows are counted. #164
On SQL Server, the order of a relation's modify or an onBuild hook is left out of the subqueries of many-to-many modify queries, withGraphJoined() and joinRelated(), including through.modify, and out of update() / patch() queries, unless they have a limit. SQL Server rejects these orders. Other databases are unchanged. #167
On SQL Server, update(), patch() and delete() of aliased tables go through a common table expression, as SQL Server can't alias the table of these statements
Behaviour change: on SQL Server, constraint, not-null and data errors are thrown as DBError and its subclasses (UniqueViolationError, ForeignKeyViolationError, NotNullViolationError, CheckViolationError, DataError), with the tedious error as nativeError, like on the other databases. Read err.nativeError.number instead of err.number. This also makes the fix for primary key violations from 3.7.0 work with knex. #2688
The warning about duplicate relations in relation expressions like '[a.b, a.c]' says that only the last one is used and that it will throw in objection 4.0, instead of announcing an error in objection 2.0 #164
Behaviour change: all warnings objection logs start with [objection] , and each is logged once #164
The errors for mixing withGraphJoined() and withGraphFetched() quote relation names with double quotes like other error messages
Docs
What relate().returning() returns on each database, and which relations accept an array of ids
onBuildKnex(): calls on the objection builder that map to knex methods are applied
The typings require TypeScript 5.1, and CI checks them with it. With TypeScript 5.0, methods of custom query builders like firstWithName() { return this.where(...).first(); } are implicitly any without a return type annotation.
Other
The knex peer dependency is >=2.3.0 <4, the versions objection is tested with #95