Changelog
Releases of @abedmurrar/objection, a fork of objection.js 3.1.5. The versions before 4.0 are the releases of objection.js.
Unreleased
4.2.1 (2026-11-03)
Bug fixes
- SQLite: the ids that a multi-row
insert()returns were merged into the models by position, but SQLite doesn't guarantee the order of the rows thatreturningreturns, and ids that the models already had were overwritten. The rows of models with an id are now matched by that id, and the rows the database gave an id, ordered by it, are merged into the other models in their order: SQLite inserts the rows in the order of the input and gives them increasing ids. An insert of models that all have an id doesn't ask for ids.
4.2.0 (2026-11-03)
What's new
static useAfterFindInGraphs: with it, eager loading respects the staticafterFind()hook of a related model class.withGraphJoined()calls the hook for the joined relations of the class, which it didn't at all, and the related models that the hook returns, e.g. filtered ones, are whatwithGraphJoined()andwithGraphFetched()put in the graph. Before,withGraphFetched()assigned the related models before the hook ran, so anafterFind()that filters out models the user may not see didn't filter them in eager loading. Off by default; it will be on in 5.0. See afterFind() with eager loading. The bug and the design are from Jürg Lehni's ditojs/objection (#1963).
4.1.4 (2026-11-03)
Bug fixes
- Many-to-many
unrelate()and patches with join table extras modified every join row between the owner and the matching related rows. Filters on join table columns, likeunrelate().where('persons_movies.role', 'extra'), were ignored, so join rows they didn't match were deleted or patched too (#1853, #2127). The join rows are now filtered by a correlated subquery, so only the join rows that match are modified, also on MySQL and MariaDB.- On MySQL, filters that read the join table themselves (joins,
joinRelated(), subqueries, raw SQL) can't be used in that subquery. The ids of the matching join rows are then fetched in a separate query first. - The same happens when a trigger on the join table changes a table that the subquery reads, which MySQL rejects (#2406). The statement is run again with the ids, and the join table is remembered for the next statements.
- On MySQL, filters that read the join table themselves (joins,
upsertGraph()patches many-to-many rows by their ids, without a subquery that joins the join table (#135).asFindQuery()of a many-to-many patch or delete keeps its filters (#2266).- A query resolved with
resolve()in a hook doesn't patch join rows, update the instance of$query().patch(), or clear the owner keys of a BelongsToOnedelete()(#2184).resolve(0)andresolve(false)count as resolved. whereInComposite()with an empty list of composite values built invalid SQL,(a, b) in (())(#1914).
The bugs were found by Jürg Lehni in ditojs/objection, whose tests are ported. The correlated subquery follows his design; the MySQL code is this fork's own: dito fetches the ids first on every MySQL statement, which takes an extra query and modifies join rows that differ only in their other columns. The MySQL trigger case was first handled in ditojs/objection by Marcin L. See Ported from ditojs/objection.
4.1.3 (2026-11-03)
Performance
- Queries create far fewer promises. The hooks of a query run one after another, and only wait when a hook returns a promise, instead of about 40 promises per query. A
findById()runs 27% fewer CPU instructions in objection, adelete()14%, a single-rowinsert()or find 11%. The hooks run in the same order and see the same results.
4.1.2 (2026-11-03)
Performance
- MySQL:
insertGraph()andupsertGraph()insert the new rows of each table in one query, as on PostgreSQL, instead of one query per row. A person with 2 pets with 2 toys each takes 3 inserts instead of 7, and the graph insert benchmark on MySQL 8.4 went from 29% slower than objection 3.1.5 to 16% faster. Rows with an id and rows without one are inserted separately, because the ids of a multi-row insert can only be computed when none of the rows has one.
4.1.1 (2026-11-03)
Bug fixes
Ported from ditojs/objection: fixes by Jürg Lehni, and the $defs support by Jérémy Lal. Ported from ditojs/objection links the original commits.
- MySQL:
patch()anddelete()with a subquery of the same table inside a where group (where(qb => qb.whereIn('id', subquery))) or a join clause failed withER_UPDATE_TABLE_USED.delete().orderBy().limit()warns: knex leaves the order out of MySQL deletes and keeps the limit, so the query deletes any of the matching rows. It will throw in 5.0. See Deletes with a limit.insert().onConflict().ignore()gave ignored models the id0. They now keep no id.
insert().onConflict().ignore()on PostgreSQL and SQLite merged the returned rows into the models by position, so models got the values of other rows when some were ignored. The rows are matched by the conflict columns now.insertAndFetch()only fetches the models that have an id.- Graph inserts and upserts:
- With
relate, HasMany and HasOne children whose composite id contains the foreign key were treated as relates and dropped. upsertGraph()with cyclic references rejected, but its deletes still ran afterwards, outside the transaction.- When a graph write failed, the query rejected before its other running queries finished, so in a transaction they could commit rows after the rollback.
- The models that
upsertGraph()returns kept leaving out their unchanged props, so a later$query().patch()on them skipped those props. upsertGraph()withrelateandnoUpdatedidn't write the foreign keys of related HasMany and HasOne models.noInsertstill inserted the models below the skipped ones, as orphans. Models that a#reffrom outside points to are still inserted.upsertGraph()withnoUpdate,noDelete,noUnrelateandinsertMissingran as an insert and failed with aUniqueViolationErroron the existing rows.- BelongsToOne
$relatedQuery().insertGraph()inserted the model but didn't relate it to the owner.
- With
- Relations:
through.modifyof many-to-many relations was lost onbindKnex()classes, sounrelate()deleted join rows that the filter protects.- BelongsToOne
unrelate()ignored the relation'smodifywhen the query had no where clause, and cleared the keys of owner models it didn't unrelate. It now unrelates only the owners whose related row matches, like the other relations.
- Executing a
patchAndFetch()orupdateAndFetch()query a second time, e.g. by awaiting it twice, wrote the row that the first run fetched back over later changes. It now throws; create a new query for each run. - A
patch()ormerge()with a field expression like'meta:color'wrote nothing when the query was built before it ran, e.g. bytoKnexQuery()orclone(). - A
raw()set on a JSON attribute in$beforeInsert()or$beforeUpdate()was stored as the serialized raw builder instead of its value. withGraphJoined()with a model that has no primary key merged rows or gave children the wrong owner. It throws now, pointing towithGraphFetched().- Patch validation: boolean subschemas,
not(which rejected every patch),requiredin nullable or untyped objects, anyOf/oneOf options with onlyrequired, and$defs. TheJSONSchematype has$defs, anddefinitionsis deprecated.
Also fixed:
- MariaDB: same-table subqueries of updates and deletes were wrapped like on MySQL, which MariaDB doesn't need. The wrap broke correlated subqueries, e.g. a filtered BelongsToOne
unrelate()of a self-referencing relation failed withUnknown column.
4.1.0 (2026-11-03)
Bug fixes
- Types:
modify()on anAnyQueryBuilder<M>, as in modifiers that call other modifiers, returned a union of two query builders whose methods couldn't be called. It returns the query builder.$setRelated()and$appendRelated()check the relation name and the related models, likerelatedQuery(). A misspelled name, or models of another model class, is a compile error. Names the types can't check take the related model type explicitly:$setRelated<Pet>(name, pets). Unknown names already threw at runtime.
4.0.5 (2026-11-03)
Bug fixes
- Types:
Model.knex(knex)returns nothing andquery.knex(knex)returns the query builder. Both were typed as returningKnex.Model.ValidationErrorandModel.NotFoundErrorare declared.QueryBuilderOperation,QueryBuilderBase,RelationandRelationExpressioncan be imported in TypeScript, andclear()takes an operation class likeclear(QueryBuilderOperation).
- The check for an offset on delete queries, added in 4.0.4, no longer has a measurable cost.
- Docs:
- The raw value examples of
insert(),patch()andupdate()used'Jenni' || 'fer', which meansoron MySQL. They now useupper(?). outerJoin()andouterJoinRelated()build a bareouter join, which postgres, MySQL and SQLite reject. Their docs say so, and that MySQL has no full outer joins.
- The raw value examples of
4.0.4 (2026-11-03)
Bug fixes
- An offset on a delete query throws
offset() can't be used with a delete query. Deletes have no offset, and knex left it out:delete().page(2, 10)deleted the first 10 rows on MySQL, anddelete().offset(10)deleted every matching row on every database.page(0, n)andoffset(0)still work. See Deletes with a limit. - Types:
$transaction()returns the result of its callback, likeModel.transaction(). It was typed as returningKnex.knexIdentifierMappingis declared, so it can be imported in TypeScript.Model.concurrency,Model.cloneObjectAttributesandQueryBuilder.parseRelationExpression()are declared.
4.0.3 (2026-11-02)
What's new
- The documentation site has a sitemap, canonical URLs, a description and Open Graph and Twitter tags on every page, structured data on the home page, a social card image, a favicon and the date each page last changed. The pages are served without
.html. - The site and the guide link to this package's repository, examples and issues instead of objection.js's. The links to the v1 and v2 documentation of objection.js are gone.
- The npm package has a homepage (the documentation site), a longer description and more keywords.
4.0.2 (2026-11-02)
What's new
- Every link in the README goes to the documentation site, including the badges. The README no longer links to files on GitHub.
4.0.1 (2026-11-02)
What's new
- The README links to the documentation site of this package instead of to files in the repository, and no longer links to the objection.js repository. It still credits objection.js and its authors.
4.0.0 (2026-11-02)
What's new
4.0.0is the first stable release of the fork. It's published under npm'slatestdist-tag, sonpm install @abedmurrar/objectioninstalls it;@nextis no longer needed. See Breaking changes for what changed since objection.js 3.1.5.- The deprecation warning of
skipUndefined()says it will be removed in a future major version, instead of in 4.0.
4.0.0-beta.11 (2026-11-02)
What's new
- The performance page shows that the TypeScript build is as fast as the JavaScript one, and the contributing guide explains the rules that keep it that way.
4.0.0-beta.10 (2026-11-02)
Breaking changes
Model,QueryBuilder,ValidatorandAjvValidatorare exported as the classes themselves instead of ES5 constructor functions that inherited from them. ES5-style subclasses that callModel.call(this)orQueryBuilder.call(this)throw, as does code compiled to that form by TypeScript withtarget: "es5"or by Babel 6. Astatic init()override of aQueryBuilder,ValidatororAjvValidatorsubclass is now called when the class is constructed. See Breaking changes
4.0.0-beta.9 (2026-11-02)
Bug fixes
- 4.0.0-beta.6 to beta.8 were up to 20% slower than the JavaScript build: building queries up to 18%, batch inserts 20%,
toJSON()10% and validation 8%. Two utility modules exported getters, which made every call to them about three times slower. They export plain values again, and every benchmark is back within noise of the JavaScript build. A test keeps compiled modules from exporting getters.
4.0.0-beta.8 (2026-11-02)
What's new
- The README and the documentation say that the source is TypeScript, and the contributing guide explains the build.
4.0.0-beta.7 (2026-11-02)
What's new
- The model (
Model, the validators, the errors and the model graph),transaction()andinitialize()are TypeScript now. With that, the whole source is TypeScript, apart from the small package entry and the generated parsers. The compiled code and its behaviour are the same.
4.0.0-beta.6 (2026-11-02)
What's new
- The query builder core (
QueryBuilder, its operation support, the graph inserts and upserts and the transformations) is TypeScript now. The compiled code and its behaviour are the same.
4.0.0-beta.5 (2026-11-02)
What's new
- The relations guide no longer recommends
RelationsOffor models whose relations lead back to them, which fails with a circularity error. It recommendsModelInstanceinstead.
4.0.0-beta.4 (2026-11-02)
What's new
- The expression builders (
ref(),val(),raw(),fn(), relation expressions and the join code) are TypeScript now. The compiled code and its behaviour are the same.
4.0.0-beta.3 (2026-11-02)
What's new
- The fork documentation has many more examples, each with comments, the real SQL it produces and checked types, and fixes for seven mistakes in the existing pages.
4.0.0-beta.2 (2026-11-02)
What's new
- The query operations (
src/queryBuilder/operations) are TypeScript now. The compiled code and its behaviour are the same.
4.0.0-beta.1 (2026-11-02)
What's new
src/relationsis TypeScript now. The compiled code and its behaviour are the same.
4.0.0-beta.0 (2026-11-02)
Breaking changes
- package.json has an
exportsmap, so only the package entry can be imported. Imports of files inside the package, which were never documented, throwERR_PACKAGE_PATH_NOT_EXPORTED - Node.js 24 or newer is required, the two LTS lines that are still maintained (24 and 26). Node.js 20 reached its end of life in April 2026.
- knex 3.3 or newer is required. Older versions compile some queries differently:
delete().limit(n)on MySQL ignores the limit and deletes every matching row on knex 3.1, andupdateFrom()with a raw query gets its bindings in the wrong order before knex 3.3. knex 3.2 also rejects queries that combinedelete()with a limit on databases that don't support it, which includespage()andrange()on deletes on postgres and SQLite.
What's new
- An ES module entry:
import { Model } from '@abedmurrar/objection'works without CommonJS interop, with its own types. It re-exports the CommonJS build, soimportandrequire()give the same classes and objection is loaded once - Faster queries: objection's own work for a small query takes 13% to 19% less time,
toJSON()44% less, validating models 55% less, and a class bound to a transaction withbindKnex()no longer creates and compiles a validator of its own (91% less for a validated insert in a new transaction).withGraphJoined()parses the joined rows 20% faster and graph inserts and upserts take 12% to 15% less time. The generated SQL and the results are the same. Seebench/README.mdin the repository - On MySQL,
withGraphFetched()andfetchGraph()run their queries 4 at a time again, like on the other databases. 4.0.0-alpha.0 ran every query of graph operations one at a time to stop the deadlocks of concurrentupsertGraph()updates, which only writes need. A concurrency set on the model still applies to all queries - A documentation site at https://abedmurrar.github.io/objection.js/, with a Fork additions section that covers only what the fork adds to objection.js 3.1.5.
- The source is moving to TypeScript, one part at a time, starting with
src/utils. The compiled code and its behaviour are the same. - MariaDB support, tested on 10.6 and 11.4: objection recognizes knex 3.3's
mariadbclient, or aversionlike'11.4.0-MariaDB'in the knex config with mysql2, and generates SQL that MariaDB accepts for the MySQL features (JSON field expressions, thewhereJson*methods,val()and casts of JSON). Thefnhelpers of functions MariaDB doesn't have throw a clear error. See MariaDB - Add the knex methods objection didn't have:
andHaving()(which was typed but threw),andHavingIn(),andHavingNotIn(),andHavingNull(),andHavingNotNull(),andHavingExists(),andHavingNotExists(),andHavingBetween()andandHavingNotBetween(),comment(),hintComment(),using()for postgresdelete ... using,finally(), andorin join callbacks:join.on(a, b).or.on(c, d) - Types:
updateFrom(),clearGroup(),clearHaving()andoptions(), which worked but weren't typed clearGroup()andclearHaving()remove the operations, likeclearSelect()andclearWhere(), sohas()sees them as cleared- The tests no longer use bluebird. The native promises and
node:timers/promisescover what they used it for, and the test of unhandled rejections now sees the rejections of objection's own promises, which bluebird's handler never did - No more lodash: the package shipped a copy of lodash's
cloneDeep, which is replaced by a native clone with the same results, and the tests no longer use lodash. The package is 59 kB smaller, andtoJSON()of models whose JSON attributes hold class instances, Maps or Sets takes 87% less time
Bug fixes
orHavingIn(),orHavingBetween()andorHavingNotBetween()added their conditions withand, ashavingIn()and the othersonIn()and the otherinconditions of join callbacks with a raw column and a raw value, likejoin.onIn(fn.lower(ref('name')), raw('select ...')), lost the parentheses around the value.
4.0.0-alpha.0 (2026-10-20)
Security
- Require ajv 8.20 or newer, which fixes the advisories of ajv and its dependency fast-uri.
- Escape the keys of JSON field expressions. Keys containing
'allowed SQL injection throughref('col:key'),patch({ 'col:key': value }),onConflict().merge()and thewhereJson*methods, and keys containing?corrupted the bindings. Keys with,,{,},", whitespace orNULLnow refer to the actual key instead of being split #2077
Breaking changes
- knex 3.1 or newer is required. The fork is only tested with knex 3.
- On MySQL, graph operations (
insertGraph(),upsertGraph(),fetchGraph(), ...) run one query at a time by default. Concurrent updates ofupsertGraph()deadlocked without a transaction. Set concurrency on the model to run queries in parallel again. orWhere(and rawwhereclauses) can no longer escape the conditions objection adds itself.$relatedQuery('pets').where(a).orWhere(b).delete()used to produceowner and a or b(ora or b and ownerfor writes) and touch the rows of other owners. The same applied to relationfilter/modify,joinTableModify,relate(),unrelate(),$query(),deleteById(),patchAndFetchById(),updateAndFetchById()and staticrelatedQuery()subqueries. These clauses are now wrapped in parentheses. Queries without such clauses generate the same SQL as before. AfindById()you call yourself is not grouped, sofindById(1).orWhere(...)still means "id = 1 or ...". #2191, #1909for()can only be used with queries created using the staticrelatedQuery(). Before,Person.query().for(1).delete()ignoredfor()and deleted every row. Write methods ofrelatedQuery()reject iffor()is not called before them; before,delete().for(1)silently did nothing andinsert().for(1)inserted rows withnullforeign keys #2185- JSON field expressions (
'col:key') and thewhereJson*methods throw on databases other than postgres and MySQL instead of generating invalid SQL. On MySQL the generated#>started a comment, silently dropping the rest of thewhereclause. - Patching a field of a
NULLJSON column (patch({ 'col:key': value })) creates the object. Before, the column stayedNULLon postgres. - Types: Relation expressions are checked in
withGraphFetched(),withGraphJoined(),fetchGraph(),$fetchGraph(),modifyGraph(),allowGraph()andjoinRelated()and its variants, in string and in object notation. Unknown relations give errors likeUnknown relation "toyz" at "pets"and syntax errors likeMissing "]" in relation expression. Expressions that aren't known at compile time (like astringvariable) aren't checked, and neither are expressions aftercastTo(Model) - Types:
withGraphFetched(),withGraphJoined(),fetchGraph()and$fetchGraph()add the relations they load to the result type, including nested relations, aliases ('pets as animals',$relation) and repeated calls. To-many relations are arrays and to-one relations are| null(or| undefinedfor relations declared as optional without| null). Modifiers that return the query builder add the relations they load, inmodify()and in$modify.Loaded<Person, '[pets, mom]'>is the type of a model with relations loaded. See the relations guide - Types: Named modifiers are checked against the static
modifiersof the model when it's an object without a type annotation or a getter: inmodify('name', ...args)(including the arguments and lists of modifiers) and in relation expressions ('pets(onlyDogs)',$modify: 'onlyDogs'). Names added withmodifiers()aren't known, so they aren't checked after it. See the modifiers recipe - Types: The callback of
modifyGraph()gets the query builder of the related model, also for aliases. The model can still be given explicitly:modifyGraph<Pet>(expr, modifier) - Types:
withGraphFetched()and the methods that keep the result kind keep union result types likePerson[] | Person | numberinstead of turning them into one kind - Types: Query results only have the relations the query loaded.
await Person.query()isModelRow<Person>[], the model without its relation properties, so readingperson.petswithout loading it is a compile error. Rows can still be used where the model is expected. After modifiers that don't return the query builder, named modifiers,insertGraph(),upsertGraph()andcastTo(Model)the result has all relations of the model as optional properties again, as before. So do models withprivateorprotectedmembers and models that declare a relation as required (pets!: Pet[]). Query builders whose type is written explicitly (QueryBuilder<Person>) keep their meaning. See the relations guide
What's new
- JSON field expressions work on MySQL:
ref('col:a.b').castInt()in selects, wheres, joins and orderBys, andpatch({ 'col:a.b': value }),update()andonConflict().merge(), which useJSON_SET() - The
whereJson*methods (whereJsonSupersetOf(),whereJsonSubsetOf(),whereJsonIsArray(),whereJsonIsObject(),whereJsonHasAny(),whereJsonHasAll()and their variants) work on MySQL and find the same rows as on postgres fnhas a typed helper for every MySQL 8.4 built-in function, likefn.dateFormat(),fn.timestampDiff('day', a, b),fn.groupConcat(expr, { orderBy, separator })andfn.jsonObject({ ... }). Objects and arrays passed as JSON documents are cast to JSON, and keywords like interval units are checked. MySQL-only functions throw on other databases. See fn- Types:
FunctionBuilder<T>carries the type of the result of the function ref(),val(),fn()andraw()have expression methods, so comparisons, conditions and arithmetic don't need raw SQL:Pet.ref('age').gte(3),eq(),ne(),gt(),gte(),lt(),lte(),in(),notIn(),like(),between(),isNull(),isNotNull(),isBlank(),isNotBlank(),and(),or(),not(),plus(),minus(),times()anddiv(). They can be used in selects, wheres, havings, orderBys, join callbacks and patches. In TypeScript the values are checked against the type of the column. See Expressions- Add
fn.case(),fn.exists()andfn.excluded()(the value an upsert tried to insert) - Aggregate functions have
filter(condition):fn.count().filter(Pet.ref('species').eq('dog')).fn.count()without arguments isCOUNT(*) - Add window functions:
fn.rowNumber(),fn.rank(),fn.denseRank(),fn.percentRank(),fn.cumeDist(),fn.ntile(),fn.lag(),fn.lead(),fn.firstValue(),fn.lastValue()andfn.nthValue(), andover({ partitionBy, orderBy })for them and the aggregate functions - Add
none(), which makes a query match no rows - Fix subqueries in join callbacks on MySQL, like
join(Pet, (join) => join.on(Pet.ref('version'), Pet.query().max('version'))). They threwparentQuery.isUpdate is not a function - Types:
Model.ref()only accepts the columns of the model (with an optional table or alias),'*'and fields of JSON columns, whose first key is checked when the column type has known keys.ReferenceBuilder<T>carries the type of the column, and the casts change it - Types:
patch(),update(),*AndFetch()andmerge()accept field expression keys of JSON columns:patch({ 'payload:courseName': 'Physics' }) - Types: Relations typed as a union of a model and an array of models are recognized as relations by
ModelPropsandModelRelations - Add
whereJsonOverlaps()andwhereJsonNotOverlaps()for MySQL'sJSON_OVERLAPS() val()of an object or an array is cast toJSONon MySQL, so it can be compared with JSON columns- Casts (
castInt(),castText(),castBool()...) ofref()andval()use types MySQL supports.CAST(x AS integer)for example is a syntax error on MySQL - Fix the bindings of
whereIn(),whereNotIn()andonIn()with a raw column that has bindings, likewhereIn(fn.lower(ref('name')), names). knex compiled the values before the column, so the column got the bindings of the values - Batch inserts (
insert([...]),insertAndFetch([...])and relation inserts) work on MySQL and SQLite. On MySQL the ids of the inserted rows are computed from the id of the first row, using@@auto_increment_increment. A MySQL batch where only some rows have an id is rejected before inserting. SQLite batch inserts need SQLite 3.35 or newer - Model classes can be used in place of table names:
join(Pet, Pet.ref('ownerId'), Person.ref('id')),from(Person), and alias objects likeinnerJoin({ p: Pet }, ...) Model.ref()works inside join callbacks. Before, it produced the source code of the model class as the table name- Add
onJsonPathEquals()andorOnJsonPathEquals()to join callbacks - Types: Join callbacks get objection's
JoinBuilderinstead of knex'sJoinClause, soref()andModel.ref()can be used for every column - Types: Custom query builders only need to declare
'~rebind'and keep their type through every method, includingthrowIfNotFound(),castTo()andrunAfter(). See the migration guide - Types: The type of
query()comes from the staticQueryBuilderproperty - Types:
runAfter()andcastTo<T>()set the result type, which is used byfirst(),throwIfNotFound()and the other methods that change the result kind - Types:
modify()checks the arguments passed to modifier functions and accepts modifiers written for any result kind.AnyQueryBuilder<M>is a query builder for modelMof any result kind - Types: Model classes can be used as the base class of mixins
- Types: The types of relations are inferred from
relationMappings, so relation properties don't need to be declared in the model. To-one relations areModel | null, to-many relations arrays, and many-to-many relations include theirextracolumns.defineRelations()preserves the exact mapping types, andinterface Person extends RelationsOf<typeof Person> {}adds the relations to the instance type. See the relations guide - Types:
relatedQuery()and$relatedQuery()only accept known relation names. For names that can't be checked, pass the related model type:relatedQuery<Pet>(name) - Types:
$relatedQuery()of a to-one relation can resolve toundefined - Types: Relation properties typed
Model | nullare recognized as relations byModelRelationsandModelProps - Fix infinite recursion in
andWhereJsonNotSupersetOf()
3.1.5
What's new
- Types: Fix generic static
this#2533 - Types: Add
fromRawto `FromSelector regex #2628 - Types: Fix argument types of
onConflict()#2635 - Types: Make
trxoptional forModel.transaction(trx, cb)#2694
3.1.4
What's new
- Fix
upsertGraph()$beforeUpdate()calls on empty relates #2605 - Don't call
onError()with internal exceptions #2603 - Remove docs and typings for nonexistent
$pick() - Make
$omitFromJson()+$omitFromDatabaseJson()compatible with old$omit()syntax
3.1.3
What's new
What's new
- Patch Validator: Prevent recursion on inner properties #2520
3.1.2
What's new
- Patch Validator: Prevent recursion on inner properties #2520
3.1.1
What's new
- Only add Ajv formats if they weren't added in user-land already #2482
3.1.0
What's new
- Support
$beforeUpdate()mutations inupsertGraph()#2233 - Remove deprecated
$afterGet()hook #2477 - Drop support for Node v12 #2478
3.0.5
What's new
3.0.4
What's new
- Fixes #2447
3.0.3
What's new
- Fixes #1673
- Fixes #1957
- Fixes #2105
- Fixes #2132
- Fixes #2251
- Fixes #2262
- Fixes #2271
- Fixes #2277
- Fixes #2308
- Fixes #2311
- Fixes #2311
- Fixes #2311
- Fixes #2332
- Fixes #2337
- Fixes #2372
- Fixes #2379
- Fixes #2383
- Fixes #2399
- Fixes #2404
- Fixes #2405
- Fixes #2408
- Fixes #2409
- Fixes #2423
3.0.2
What's new
- Fixes #1356
- Fixes #1957
- Fixes #2192
- Fixes #2247
- Fixes #2307
- Fixes #2308
- Fixes #2311
- Fixes #2323
- Fixes #2337
- Fixes #2362
3.0.1
What's new
3.0.0
What's new
- Fixes #1986
- Fixes #1987
- Fixes #1954
- Fixes #1993
- Fixes #1688
- Fixes #1651
- Fixes #2135
- Fixes #1936
- Fixes #1905
- Fixes #1997
- Fixes #2024
Breaking changes
See the migration guide.
2.2.10
What's new
- Add
modelClassproperty forValidationErrorandNotFoundError.
2.2.9
What's new
- Add
noWaitquery builder method.
2.2.8
What's new
2.2.7
What's new
QueryBuilder.castTocan now be used to cast query results to any typescript type.
2.2.6
What's new
- Fixes #1964
2.2.5
What's new
- Fixes #1855
2.2.4
What's new
- Add support for onConflict, merge and ignore knex methods.
2.2.2
What's new
2.2.1
What's new
2.2.0
What's new
2.1.4
What's new
- Fixes #1750
2.1.3
What's new
- Add
underscoreBetweenUppercaseLettersoption for snake case mappers. #1676
2.1.2
What's new
- Fix
startTransactiontypings.
2.1.1
What's new
- Fixes #1489
2.1.0
What's new
Changelog
2.0.10
What's new
- Fixes #1630
2.0.9
What's new
- Fixes #1606
2.0.8
What's new
- Fixes #1627
2.0.7
What's new
- Fixes #1607
2.0.6
What's new
- Fixes #1603
2.0.5
What's new
- Fixes
upsertGraphbug where composite keys were not selected correctly. See the fix here.
2.0.4
What's new
- New
skipFetchedoption forfetchGraphand$fetchGraph
2.0.3
What's new
2.0.0
What's new
Cleaner and more consistent API. A lot of methods have been renamed, removed combined and cleaned up. Most of the old methods still exist, but print a deprecation warning when first used. Some examples:
eager->withGraphFetchedjoinEager->withGraphJoined- removed
eagerAlgorithm(you must explicitly use eitherwithGraphFetchedorwithGraphJoined) - merged
allowEager,allowInsertandallowUpsertinto one methodallowGraph $loadRelated->$fetchGraphjoinRelation->joinRelated$relatedQueryno longer mutates the receiving model instances
New static hook API. The old instance hooks are still around.
relatedQuerycan now be used for more than just subqueries. See the examples here.modifiers can now take arguments and are a lot more useful. See this recipe for more info.
Objection now uses the db-errors library by default to wrap the database errors.
insertMissingupsertGraphoption now works as expected withrelate: true: items that are not found in the database are inserted.Brand new typings written from scratch with many improvements and finally a support for custom query builders
A bunch of improvements and bug fixes for
upsertGraph, including a huge speedup in some cases due to less data fetching.A brand new fn helper for calling SQL functions.
Objection now uses native promises instead of bluebird.
Objection is now leaner as we dropped a bunch of dependencies like
bluebirdandlodash.In addition to all of this, a huge number of bugs has been squashed!
Breaking changes
See the migration guide.
1.6.10
- Fixes #1455
1.6.9
- Revert fix for #1089. It was causing more bugs than it fixed. #1089 will be addressed in 2.0.
- Typings updates
1.6.8
- Fix #1287
1.6.7
- A bunch of regression bug fixes.
1.6.3
- Fixes: #1227
1.6.2
- Add
asmethod forrawmaking it possible to userawexpressions injoinEagermodifiers (as long as you give names to your raw expressions usingas).
1.6.1
- Fix some very rare upsertGraph edge cases.
1.6.0
Add
Model.traverseAsyncandmodelInstance.$traverseAsyncmethods.Fixes: #842 and #1205. This bug is about subqueries "inheriting" parent query table name and alias. This bug has been around a long time and there is a small chance that people have started accidentally or on purpose use it as a feature. If you get weird reference errors from subqueries (relation not found, table not found etc.) you may need to explicitly give an alias or use
fromin your subqueries after this update. This is a borderline breaking change, but since 2.0 is still pretty far away, I wanted to get this out faster. If I'm wrong and people are heavily depending on this bug, I'll revert the change.Fixes: #1215
Fixes: #1206
1.5.3
What's new
- Fixes #1204
1.5.1
What's new
- Relations are now loaded lazily #1202
relationMappings.modelClasscan now be a function that returns a model class.
1.5.0
What's new
- fix #1131
- fix #1114
- fix #1185
- fix #1109
- fix #1110
- add eagerObject and eagerModifiers accessors to QueryBuilder.
- complete rewrite of
insertGraphandupsertGraphcode. The rewrite brought a bunch of small performance optimizations and makes future development easier. No breaking changes. - Chaining
returning('*')toinsertGraphorupsertGraphnow propagates the call to all insert, update and delete operations. - Code using objectio can now be transpilsed to ES5. No need to add babel workarounds anymore.
1.4.0
What's new
1.3.0
What's new
- Use
objection.rawinstead ofknex.rawinModel.raw. #1077 - Allow modifiers (namedFilters) to be used in
modifyEagertoo. - Add
underscoreBeforeDigitsoption for snake case converters. #1025 - fix #1074
- Typing fixes
1.2.3
What's new
1.2.2
What's new
- Improve reference cycle detection in
upsertGraph
1.2.1
What's new
- fix #1009
1.2.0
What's new
- fix #919
- fix #964
- Add
aliasFormethod to public API - Prevent bluebird warnings
- UPPER_SNAKE_CASE support for
snakeCaseMappersandknexSnakeCaseMappers
1.1.10
What's new
- Nothing! the npm release was somehow borked. This was just a rerelease of 1.1.9.
1.1.9
What's new
- fix #782
1.1.8
What's new
- fix #909
1.1.7
What's new
- fix #884
1.1.6
What's new
- Add typings for fetchTableMetadata, tableMetadata and onbuildknex
1.1.5
What's new
- Make Model.fetchTableMetadata and Model.tableMetadata methods public. #871
- Add onBuildKnex query builder hook. #807
1.1.4
What's new
- fix subquery bug causing incompatibility with knex 0.14.5 and sqlite3
1.1.3
What's new
- fix regression in 1.1.2 (sorry about this) #869
1.1.2
What's new
1.1.1
What's new
- fix #865
- fix bug where the static
Model.relatedQuerydidn't use the relation name as an alias for the table. This may break code if you have explicitly referenced the subquery table. #859
1.1.0
What's new
- Optional object notation for relation expressions.
- fix #855
- fix #858
1.0.1
What's new
- Added public Relation.joinModelClass accessor
- Don't call
returningon sqlite (prevents a warning message added in knex 0.14.4) - fix #844
- Small documentation updates
- Small typing fixes end updates
1.0.0 🎉
What's new
- The static
relatedQuerymethod. - New reflection methods:
isFind,isInsert,isUpdate,isDelete,isRelate,isUnrelate,hasWheres,hasSelects,hasEager,has.clear.columnNameToPropertyName,propertyNameToColumnName. ManyToManyextras now work consistently in queries and filters. #760
Breaking changes
modelInstance.$query().delete().returning(something)now returns a single instance instead of an array. #659Node 6.0.0 is now the minimum. Objection will not work on node < 6.0.0.
ValidationErroroverhaul. This is a big one, so read this carefully! There are three things to check when you migrate to 1.0:- The
createValidationErrorandValidationErrorinterfaces have changed. If you have overridden thecreateValidationErrormethod in your project, or you create customValidationErrorinstances you need migrate to the interfaces. - The model validation errors (jsonSchema violations) have remained pretty much the same but there are couple of differences. Before, the keys of
error.datawere property names even when a nested object in a graph failed a validation. Now the keys for nested validation errors are key paths likefoo.bar[2].spam. Another tiny difference is the order of validation errors for each key inerror.data. Let's say a propertyspamfailed for your model anderror.data.spamcontains an array of objects that describe the failures. Before, the first failed validation was the last item in the array, now it is the first item. - All
ValidationErrorsnow have atypefield. Before allValidationErrorsbut the model validation errors (errors like "invalid relation expression", or "cyclic model graph") had no type, and could only be identified based on the existence of some weird key inerror.data. Theerror.datais now removed from those errors and thetypeshould be used instead. The message from the data is now stored inerror.message.
- The
Removed deprecated methods
whereRef,whereJsonFieldandwhereJsonEquals. Therefhelper can be used to replace thewhereRefcalls.refandlitcan be used to replace the removed json methods.ManyToManyextras now work consistently in queries and filters. #760. This is not a breaking change per se, but can cause some queries to fail with a "ambiguous identifier" error because the join table is now joined in places where it previously wasn't. You need to explicitly specify the table for those failing columns usingTable.theColumnsyntax.
Changes
isFindQueryis renamed toisFindand deprecated.
0.9.4
What's new
0.9.3
What's new
- Add beforeInsert hook for relations. #649 #19
- Add
relatedFindQueryMutatesandrelatedInsertQueryMutatesconfigs as well as$setRelatedand$appendRelatedhelpers. #599 - Fixed #648
0.9.2
What's new
- Fix regression:
fromfails with a subquery.
0.9.1
What's new
castTomethod for setting the model class of query result rows.onErrorQueryBuildermethod.knexSnakeCaseMappersandsnakeCaseMappersfor snake_case to camelCase conversions.
0.9.0
What's new
- Relations can now be defined using keys inside JSON columns. See the examples here.
lithelper function #275- Fixes for
upsertGraphwhen using composite keys. #517 - Added
noDelete,noUpdate,noInsert,noRelateandnoUnrelateoptions forupsertGraph. See UpsertGraphOptions docs for more info. insertGraphnow accepts an options object just likeupsertGraph.relateoption can be used instead of#dbRef. #586
Breaking changes
Instance update/patch with
returningnow return a single object instead of an array. #423Because of the support for JSON relations the
Relationclass has changed a bit.
0.8.8
What's new
- Typing updates: #489 #487
- Improve
resultSizemethod. #213 - Avoid unnecessary updates in upsertGraph #480
0.8.7
What's new
throwIfNotFoundnow also throws when update or delete doesn't change any rows.mixinandcomposehelpers for applying multiple plugins. #475 #473- Typing updates #474 #479
upsertGraphnow validates patched models correctly. #477
0.8.6
What's new
- Finally: the first version of
upsertGraphmethod! Please open issues about bugs, WTFs and missing features. - Strip readonly virtual properties in fromJson & friends #432
- Fixed #439
0.8.5
What's new
- Add
Model.useLimitInFirstconfiguration flag.
0.8.4
What's new
- New shorthand methods
joinEager,naiveEager,mergeJoinEagerandmergeNaiveEager. - New shorthand method
findOne - New reflection method
isFindQuery - ManyToMany extra properties can now be updated #413
0.8.3
What's new
NaiveEagerAlogrithm- Aliases in relation expressions #402
- New lazily evaluated
rawfunction. #275
0.8.2
What's new
Model.namedFiltersobject for defining shared filters that can be used by name in eager expressions.- Full support for views and table aliases in eager, join, joinRelation etc. #181
- Fix
bindTransactionbug withManyToManyRelationjunction tables #395
0.8.1
What's new
throwIfNotFoundmethod for making empty query results throw an exception.- fix error when passing model instance to a
wheremethod. #387
0.8.0
What's new
- All query methods now call
Model.queryto create aQueryBuilderinstance #346 - Objection is no longer transpiled. One of the implications is that you can use a github link in package.json to test experimental versions.
countcan now be called without arguments #364- A new
getRelationsmethod for plugin development and other reflection greatness.
Breaking changes
Old model definition
function Person() {
Model.apply(this, arguments);
}
Model.extend(Person);
Person.tableName = 'Person';
Person.prototype.fullName = function () {
return this.firstName + ' ' + this.lastName;
};
// More static and prototype methods.Easiest way to migrate to
classandextendskeywords
class Person extends Model {}
Person.tableName = 'Person';
Person.prototype.fullName = function () {
return this.firstName + ' ' + this.lastName;
};
// More static and prototype methods.Support for node versions below 4.0.0 has been removed. With it the support for legacy class inheritance using
Model.extendmethod has also been removed. This means that you need to change your model definitions to use theclassandextendskeywords. To achieve this with the minimum amount of changes you can simply swap the constructor function andModel.extendto a class definition. You can still define all static and prototype methods and properties the old way. See the example on the right -->Note that this also affects Babel transpilation. You cannot (or need to) use
babel-plugin-transform-es2015-classesanymore. See the ESNext example project as an example of how to setup babel.The default value of
pickJsonSchemaPropertieswas changed tofalse. Before, all properties that were not listed injsonSchemawere removed beforeinsert,patchorupdate(ifjsonSchmawas defined). Starting from this version you need to explicitly set the value totrue. You may have been used this feature by accident. If you have weird problems after the update, try settingobjection.Model.pickJsonSchemaProperties = true;to see if it helps.relateandunrelatemethods now return the result of the underlying query (patchin case ofHasManyRelation,HasOneRelation, andBelongsToOneRelation.insertotherwise). Before the method input was always returned.Model.RelatedQueryBuilderis removed.Model.QueryBuilderis now used to create all query builders for the model. This only affects you if you have defined custom query builders.
0.7.12
What's new
- fix #345
0.7.11
What's new
0.7.10
What's new
- fix bugs that prevented using
$relatedQueryandeagertogether withJoinEagerAlgorithm - typing updates
0.7.9
What's new
joinRelationnow acceptsRelationExpressionsand can join multiple and nested relations.
0.7.6
What's new
rangeandpagemethods now use a window function and only generate one query on postgresql #62- fix MSSQL 2100 parameter limit in eager queries #311
0.7.5
What's new
0.7.4
What's new
- automatically select columns needed for relations #309
- fix an issue where
$formatJsonwas called insideinsertGraph#326
0.7.3
What's new
- fix #325
- fix an issue where
selecthad to be used in addition todistinctin some cases
0.7.2
What's new
HasOneThroughRelationrelation type.
0.7.1
What's new
- fix
JoinEagerAlgorithmNPE bug
0.7.0
What's new
jsonSchemawithoutpropertiesnow works. #205relationMappingscan now be a function. #227- many to many extras can now be aliased. #223
- zero values are now allowed in relation columns. #228
- active transaction can now be accessed in
$before/$afterhooks throughqueryContext.transactionproperty. - Validation can now be easily modified through a new
Validatorinterface. #241 #199 - fix a
JoinEagerproblem where an empty result for a relation caused the following relations to be empty. #292 ref(fieldExpression)syntax to reduce need for knex.raw and updating single attribute inside JSON column. #270- mergeEager method.
Breaking changes
$relatedQuerynow returns a single model instead of an array for belongsToOne and hasOne relations. #155- identifier of a model can now be updated. Be careful with this one! Before if you forgot a wrong id in an
update/patchoperation, it would simply get ignored. Now the id is also updated just like any other column #100 Table.*is now selected by default in all queries instead of*. This will break some join queries that don't have an explicit select clause. #161ValidationError.datais now an object including, for each key, a list of errors with context info. #283
0.6.2
What's new
relationMappingscan now be a function #227
0.6.1
What's new
- fix bug #205
0.6.0
What's new
- Eager loading can now be done using joins and zero extra queries. See
eagerAlgorithm,defaultEagerAlgorithmandeagerfor more info. #refin graph inserts can now contain extra properties for many-to-many relations #156#dbRefcan now be used to refer to existing rows from ainsertWithRelatedgraph.modelPathsattribute for cleaner way to point to models in relationMappings.pickJsonSchemaPropertiesconfig parameter #110insertGraphAndFetchwithinsertWithRelatedAndFetchalias. #172- Added
$beforeDeleteand$afterDeletehooks #112 - Old values can now be accessed from
$beforeUpdate,$afterUpdate,$beforeValidateand$afterValidatehooks #185 - Support length property #168
- Make sure operations are executed in the order they are called #180
- Fetch nothing if the
whereclauses hit no rows inupdate/patchAndFetchByIdmethods #189 - Lots of performance tweaks.
$loadRelatedandloadRelatednow return aQueryBuilder.
Breaking changes
Undefined values as query method arguments now throw an exception. Before they were just silently ignored and for example
delete().where('id', undefined)caused the entire table to be deleted. skipUndefined method can be called for a query builder to handle the undefined values the old way.Deprecated method
dumpSqlis now removed.$loadRelatedandloadRelatednow return aQueryBuilder. This may break your code is some rare cases where you have called a non-standard promise method likereflectfor the return value of these functions.
0.5.5
What's new
0.5.4
What's new
- bugfix: insertWithRelated now works with
additionalProperties = falseinjsonSchema - Add updateAndFetch and patchAndFetch methods for
$query - bugfix: afterGet was not called for nested models in eager query
- Use ajv instad of tv4 for json schema validation
0.5.3
What's new
- ES6 promise compatibility fixes.
0.5.1
What's new
- $afterGet hook.
0.5.0
What's new
- joinRelation family of query builder methods.
HasOneRelationfor creating inverse one-to-one relations.- Relations have been renamed
OneToOneRelation-->BelongsToOneRelation,OneToManyRelation-->HasManyRelation. The old names work, but have been deprecated. - withSchema now works as expected and sets the schema of all queries executed by the query builder the method is called for.
- filterEager method for better eager query filtering.
- extra properties feature for selecting/inserting columns from/to the join table in many-to-many relations.
- Eager query recursion depth can be controlled like so:
parent.^5.
0.4.0
What's new
- Query context feature. See #51 and these docs for more info.
- Composite key support.
- findById, deleteById, whereComposite and whereInComposite query builder methods.
Breaking changes
There shouldn't be any major breaking changes. We moved from ES5 to ES7 + babel in this version so there are big changes in the codebase. If something comes up, please open an issue.
There are a few known corner cases that may break:
You can now define a model for the join table of
ManyToManyrelations inrelationMappings. This is optional, but may be needed if you already have a model for aManyToManyrelation and you usesnake_casetocamelCaseconversion for the column names. See the documentation on the through property of relationMappings.The repo no longer contains the actual built javascript. Only the ES7 code that is transpiled when the code is published to npm. Therefore you can no longer specify a git hash to package.json to use for example the HEAD version. We will start to publish alpha and RC versions to npm when something new and experimental is added to the library.
0.3.3
What's new
- fix regression: QueryBuilder.from is broken.
0.3.2
What's new
- Improved relation expression whitespace handling.
0.3.1
What's new
whereJson*methods can now be used inside functions given towheremethods.- Added multiple missing knex methods to
QueryBuilder.
0.3.0
What's new
- insertWithRelated method for inserting model trees
- insertAndFetch, updateAndFetchById and patchAndFetchById helper methods
- Filters for eager expressions
- New alternative way to use transactions
- Many performance updates related to cloning, serializing and deserializing model trees.
Breaking changes
- QueryBuilder methods
update,patchanddeletenow return the number of affected rows. The new methodsupdateAndFetchByIdandpatchAndFetchByIdmay help with the migration modelInstance.$query()instance method now returns a single model instead of an array- Removed
Model.generateId()method.$beforeInsertcan be used instead
0.2.8
What's new
- ES6 inheritance support
- generator function support for transactions
- traverse,pick and omit methods for Model and QueryBuilder
- bugfix: issue #38
0.2.7
What's new
- bugfix: fix #37 also for
$query(). - Significant
toJson/fromJsonperformance boost.
0.2.6
What's new
- bugfix: fix regression bug that broke dumpSql.
0.2.5
What's new
- bugfix: fix regression bug that prevented values assigned to
thisin$beforecallbacks from getting into the actual database query
0.2.4
What's new
- bugfix: many-to-many relations didn't work correctly with a snake_case to camelCase conversion in the related model class.
0.2.3
What's new
- Promise constructor is now exposed through
require('objection').Promise.
0.2.2
What's new
- $beforeUpdate, $afterUpdate, $beforeInsert etc. are now asynchronous and you can return promises from them.
- Added
Model.fn()shortcut toknex.fn. - Added missing
asCallbackandnodeifymethods forQueryBuilder.
0.2.1
What's new
- bugfix: Chaining
insertwithreturningnow returns all listed columns.
0.2.0
What's new
- New name
objection.js. $beforeInsert,$afterInsert,$beforeUpdateand$afterUpdatehooks forModel.- Postgres jsonb query methods:
whereJsonEquals,whereJsonSupersetOf,whereJsonSubsetOfand friends. whereRefquery method.- Expose
knex.raw()throughModel.raw(). - Expose
knex.client.formatter()throughModel.formatter(). QueryBuildercan be used to make sub queries just like knex'sQueryBuilder.- Possibility to use a custom
QueryBuildersubclass by overridingModel.QueryBuilder. - Filter queries/objects for relations.
- A pile of bug fixes.
Breaking changes
- Project was renamed to objection.js. Migrate simply by replacing
moronwithobjection.
0.1.0
First release.