bookshelf.js
Bookshelf is a JavaScript ORM for Node.js, built on the Knex SQL query builder. It features both Promise-based and traditional callback interfaces, transaction support, eager/nested-eager relation loading, polymorphic associations, and support for one-to-one, one-to-many, and many-to-many relations.
It is designed to work with PostgreSQL, MySQL, and SQLite3.
Website and documentation. The project is hosted on GitHub, and has a comprehensive test suite.
Introduction
Bookshelf aims to provide a simple library for common tasks when querying databases in JavaScript, and forming relations between these objects, taking a lot of ideas from the Data Mapper Pattern.
With a concise, literate codebase, Bookshelf is simple to read, understand, and extend. It doesn't force you to use any specific validation scheme, and provides flexible, efficient relation/nested-relation loading and first-class transaction support.
It's a lean object-relational mapper, allowing you to drop down to the raw Knex interface whenever you need a custom query that doesn't quite fit with the stock conventions.
Installation
You'll need to install a copy of Knex, and either mysql
, pg
, or sqlite3
from npm.
$ npm install knex
$ npm install bookshelf
# Then add one of the following:
$ npm install pg
$ npm install mysql
$ npm install sqlite3
The Bookshelf library is initialized by passing an initialized Knex client instance. The Knex documentation provides a number of examples for different databases.
// Setting up the database connection
const knex = require('knex')({
client: 'mysql',
connection: {
host : '127.0.0.1',
user : 'your_database_user',
password : 'your_database_password',
database : 'myapp_test',
charset : 'utf8'
}
})
const bookshelf = require('bookshelf')(knex)
// Defining models
const User = bookshelf.model('User', {
tableName: 'users'
})
This initialization should likely only ever happen once in your application. As it creates a connection pool for the current database, you should use the bookshelf
instance returned throughout your library. You'll need to store this instance created by the initialize somewhere in the application so you can reference it. A common pattern to follow is to initialize the client in a module so you can easily reference it later:
// In a file named, e.g. bookshelf.js
const knex = require('knex')(dbConfig)
module.exports = require('bookshelf')(knex)
// elsewhere, to use the bookshelf client:
const bookshelf = require('./bookshelf')
const Post = bookshelf.model('Post', {
// ...
})
Examples
Here is an example to get you started:
const knex = require('knex')({
client: 'mysql',
connection: process.env.MYSQL_DATABASE_CONNECTION
})
const bookshelf = require('bookshelf')(knex)
const User = bookshelf.model('User', {
tableName: 'users',
posts() {
return this.hasMany(Posts)
}
})
const Post = bookshelf.model('Post', {
tableName: 'posts',
tags() {
return this.belongsToMany(Tag)
}
})
const Tag = bookshelf.model('Tag', {
tableName: 'tags'
})
new User({id: 1}).fetch({withRelated: ['posts.tags']}).then((user) => {
console.log(user.related('posts').toJSON())
}).catch((error) => {
console.error(error)
})
Official Plugins
- Virtuals: Define virtual properties on your model to compute new values.
- Case Converter: Handles the conversion between the database's snake_cased and a model's camelCased properties automatically.
- Processor: Allows defining custom processor functions that handle transformation of values whenever they are
.set()
on a model.
Community plugins
- bookshelf-cascade-delete - Cascade delete related models on destroy.
- bookshelf-json-columns - Parse and stringify JSON columns on save and fetch instead of manually define hooks for each model (PostgreSQL and SQLite).
- bookshelf-mask - Similar to the functionality of the
Model#visible
attribute but supporting multiple scopes, masking models and collections using the json-mask API. - bookshelf-schema - A plugin for handling fields, relations, scopes and more.
- bookshelf-signals - A plugin that translates Bookshelf events to a central hub.
- bookshelf-paranoia - Protect your database from data loss by soft deleting your rows.
- bookshelf-uuid - Automatically generates UUIDs for your models.
- bookshelf-modelbase - An alternative to extend
Model
, adding timestamps, attribute validation and some native CRUD methods. - bookshelf-advanced-serialization - A more powerful visibility plugin, supporting serializing models and collections according to access permissions, application context, and after ensuring relations have been loaded.
- bookshelf-plugin-mode - Plugin inspired by the functionality of the
Model#visible
attribute, allowing to specify different modes with corresponding visible/hidden fields of model. - bookshelf-secure-password - A plugin for easily securing passwords using bcrypt.
- bookshelf-default-select - Enables default column selection for models. Inspired by the functionality of the
Model#visible
attribute, but operates on the database level. - bookshelf-ez-fetch - Convenient fetching methods which allow for compact filtering, relation selection and error handling.
- bookshelf-manager - Model & Collection manager to make it easy to create & save deep, nested JSON structures from API requests.
Support
Have questions about the library? Come join us in the #bookshelf freenode IRC channel for support on knex.js and bookshelf.js, or post an issue on Stack Overflow.
Contributing
If you want to contribute to Bookshelf you'll usually want to report an issue or submit a pull-request. For this purpose the online repository is available on GitHub.
For further help setting up your local development environment or learning how you can contribute to Bookshelf you should read the Contributing document available on GitHub.
F.A.Q.
Can I use standard node.js style callbacks?
Yes, you can call .asCallback(function(err, resp) {
on any database operation method and use the standard (err, result)
style callback interface if you prefer.
My relations don't seem to be loading, what's up?
Make sure to check that the type is correct for the initial parameters passed to the initial model being fetched. For example new Model({id: '1'}).load([relations...])
will not return the same as new Model({id: 1}).load([relations...])
- notice that the id is a string in one case and a number in the other. This can be a common mistake if retrieving the id from a url parameter.
This is only an issue if you're eager loading data with load without first fetching the original model. new Model({id: '1'}).fetch({withRelated: [relations...]})
should work just fine.
My process won't exit after my script is finished, why?
The issue here is that Knex, the database abstraction layer used by Bookshelf, uses connection pooling and thus keeps the database connection open. If you want your process to exit after your script has finished, you will have to call .destroy(cb)
on the knex
property of your Bookshelf
instance or on the Knex
instance passed during initialization. More information about connection pooling can be found over at the Knex docs.
How do I debug?
If you pass debug: true
in the options object to your knex
initialize call, you can see all of the query calls being made. You can also pass that same option to all methods that access the database, like model.fetch()
or model.destroy()
. Examples:
// Turning on debug mode for all queries
const knex = require('knex')({
debug: true,
client: 'mysql',
connection: process.env.MYSQL_DATABASE_CONNECTION
})
const bookshelf = require('bookshelf')(knex)
// Debugging a single query
new User({id: 1}).fetch({debug: true, withRelated: ['posts.tags']}).then(user => {
// ...
})
Sometimes you need to dive a bit further into the various calls and see what all is going on behind the scenes. You can use node-inspector, which allows you to debug code with debugger
statements like you would in the browser.
Bookshelf uses its own copy of the bluebird
Promise library. You can read up here for more on debugging Promises.
Adding the following block at the start of your application code will catch any errors not otherwise caught in the normal Promise chain handlers, which is very helpful in debugging:
process.stderr.on('data', (data) => {
console.log(data)
})
How do I run the test suite?
See the CONTRIBUTING document on GitHub.
Can I use Bookshelf outside of Node.js?
While it primarily targets Node.js, all dependencies are browser compatible, and it could be adapted to work with other javascript environments supporting a sqlite3 database, by providing a custom Knex adapter. No such adapter exists though.
Which open-source projects are using Bookshelf?
We found the following projects using Bookshelf, but there can be more:
- Ghost (A blogging platform) uses bookshelf. [Link]
- Soapee (Soap Making Community and Resources) uses bookshelf. [Link]
- NodeZA (Node.js social platform for developers in South Africa) uses bookshelf. [Link]
- Sunday Cook (A social cooking event platform) uses bookshelf. [Link]
- FlyptoX (Open-source Node.js cryptocurrency exchange) uses bookshelf. [Link]
- And of course, everything on here use bookshelf too.
Change Log
1.2.0 Jun 07, 2020 - Diff
Features
- Add option to control auto refresh after save: #2070
Tests
- Adds some more integration tests to
Collection#fetch
: #2079
Dependencies
- Support Knex version 0.21.0 and up: #2072
- Update some dependencies of dependencies to fix security warnings: #2078
1.1.1 Mar 28, 2020 - Diff
Bug fixes
- Fix attributes that are changed during event hook not being persisted: #2062
- Fix incorrect query object being sent to event handlers with
morphTo
: #2059 - Fix non-object attributes being passed to
model.parse()
in some cases: #2056
Documentation
- Fix typo in doclet: #2057
0.15.2 Mar 28, 2020 - Diff
Bug fixes
- Fix attributes that are changed during event hook not being persisted: #2063
1.1.0 Jan 31, 2020 - Diff
Features
- Add option to disable the count information in
fetchPage
: #2045
Tests
- Small refactor to some tests: #2050
Dependencies
1.0.1 Oct 06, 2019 - Diff
Bug fixes
- Fix JSON.stringify causing TypeError in some cases: #2029
Documentation
Dependencies
- Update js-yaml to version 3.13.1: #2023
- Update handlebars to version 4.2.1: #2022
- Update uuid to version 3.3.3: #2021
- Update sqlite3 to version 4.1.0: #2021
- Update sinon to 7.4.2: #2021
- Update prettier to 1.18.2: #2021
- Update mocha to version 6.2.0: #2021
- Update lint-staged to version 9.2.5: #2021
- Update jsdoc to version 3.6.3: #2021
- Update husky to version 3.0.5: #2021
- Update eslint-plugin-prettier to version 3.1.1: #2021
- Update eslint-config-prettier to version 6.3.0: #2021
- Update eslint to version 6.4.0: #2021
- Update chai to 4.2.0: #2021
- Update eslint-utils from 1.3.1 to 1.4.2: #2020
1.0.0 Sep 13, 2019 - Diff
Breaking changes
- This version requires Node.js 8+ if using a Knex version greater than 0.18.4, otherwise Node.js 6 is still supported: #1991
- Make
require: true
the default for Model#fetch: #2006 - Remove some Model and Collection lodash based methods: #2005
- Change Collection#where so it behaves like Model#where: #2001
- Move all plugins to their own repositories: #2000
- Promote some useful plugins to core: #1992, #1993, #1996
Enhancements
- Refresh model attributes after a save operation: #2012
Bug fixes
- Fix missing columns after save: #2012
- Fix Case Converter plugin overriding any previously defined parse methods: #2000, case-converter-plugin@1.0.0
- Fix registry saving models inadvertently across different bookshelf instances: #1996
Documentation
- Add example of how to use custom collections: #2015
- Improve documentation related to debug mode: #2014
- Add note that count methods return String with Postgres: #2013
- Fix typo in Readme: #1998
- Better Plugin Docs: #1992, #1993, #1996, #2000
Dependencies
- Update lint-staged to version 9.1.0: #1994
- Update bluebird to 3.5.5: #1991
- Update lodash to 4.17.14: #1991
- Update mocha to version 6.1.4: #1991
- Update mysql to version 2.17.1: #1991
- Update pg to version 7.11.0: #1991
- Update sinon to version 7.3.2: #1991
- Update sinon-chai to version 3.3.0: #1991
- Update sqlite3 to version 4.0.9: #1991
- Update uuid to version 3.3.2: #1991
- Update eslint-config-prettier to 6.0.0: #1957
- Update eslint to version 6.0.0: #1986
0.15.1 Jun 13, 2019 - Diff
0.15.0 Jun 13, 2019 - Diff
Breaking changes
- This version requires Node.js 6+
- Remove code that has been deprecated for a long time: #1956
Bug fixes
once
removes all events after it has been triggered: #1972- Pagination details are wrong when selecting distinct values of a column: #1950
- Fix missing attributes in some events: #1934
Test Suite
Documentation
Dependencies
- Update mocha to version 6.1.1: #1968
- Update eslint-config-prettier to 4.1.0: #1957
- Update sinon to version 7.2.4: #1947
- Update eslint to version 5.1.0: #1930
0.14.2 Dec 17, 2018 - Diff
Bug fixes
- Fix crash when using
groupBy
with table qualifier in pagination plugin: #1928 - Fix
undefined
transaction object with Knex 0.15+: #1926
Refactoring
- Refactor logic behind
.timestamp()
's decision for when to update theupdated_at
column: #1892
0.14.1 Dec 09, 2018 - Diff
Enhancements
- Allow passing custom options to the pagination plugin's internal count method. This is useful for better interoperability with other plugins: #1914
Bug fixes
- Fix
withRelated
fetch option not always grouping properly when using binary primary keys: #1918
Documentation
- Add a basic Events guide and fix some issues with the events doclets: #1917
0.14.0 Dec 09, 2018 - Diff
Breaking changes
- The
previous()
andpreviousAttributes()
methods were changed so that whenever a model is saved or destroyed the previous attributes are no longer reset to the current attributes. Since the old behavior wasn't very useful it's likely this won't cause issues for many people. There's a migration guide in case you are affected by this change. #1848 - Fix incorrect results in collection when models have duplicate ids. Checkout the migration guide in case you are affected by this. #1846
- Empty
hasOne
relation will now returnnull
instead of{}
when serialized: #1839. There's a migration guide in the rare event this causes you problems. - Add more helpful error messages on bad or insufficient
morphTo
data: #1824. There's a migration guide in case you are affected by this. - Changed the existing functionality so that saving a model that hasn't changed will not update its
updated_at
attribute: #1798. Checkout the migration guide in case you are affected by this.
Enhancements
Bug fixes
- Return clones of nested objects in
previousAttributes()
: #1876 - Fix incorrect
rowCount
value when usinggroupBy
withfetchPage()
: #1852 - Fix eager loading of relations when using
parse
/format
: #1838 - Fix inability to install bookshelf from git commit: #1835
- Fix
timestamp()
setting a key named"null"
in some cases: #1820 - Fix performance of including relationships: #1800
Test Suite
- Add test to check for adding
withRelated
inside events: #1853 - Add Node.js 10 to the Travis config: #1829
- Fix incorrect output ordering in tests in some cases: #1825
Documentation
- Change the JSDoc theme to add a Guides section (this was already released): #1909
- Fix
hasOne
's doc: #1890 - Fix many-to-many tutorial code: #1888
- Add code syntax highlighting for tutorials: #1850
- Fix a few issues with the collection documentation: #1836
- Fix
Model.load()
relations param: #1834 - Fix incorrect docs for collection:fetching event: #1831
- Add note on needing the Pagination plugin to use
fetchPage()
: #1803 - Fix incorrect data types and undocumented Model property: #1797
Dependencies
- Replace turbocolor with colorette: #1904
- Use prettier to format all
js
andjson
files: #1883 - Replace chalk with turbocolor: #1878
- Update some insecure dependencies: #1841
- Replace Babel with Node 4 compatible JavaScript: #1835
- Update sinon to the latest version: #1833
0.13.3 Mar 26, 2018 - Diff
Potentially breaking changes
- Saving a model that hasn't changed will not update its
updated_at
attribute. This was included in a patch release because the chances of any applications depending on this behavior are very small: #1798
Bug fixes
- Clean up automatic timestamps feature: #1798
Documentation
- Expand documentation of the automatic timestamps feature: #1798
0.13.2 Mar 23, 2018 - Diff
Bug fixes
- Fix timestamps set with Invalid Date in some cases: #1796
Documentation
- Fix incorrect data types and undocumented Model#defaults property: #1797
0.13.0 Mar 18, 2018 - Diff
Breaking changes
- Make
require: true
the default when deleting models: #1779 - Remove the second argument to the model's destroyed event handler: #1777
- Events are now triggered sequentially even when the handlers execute asynchronous code: #1768
- Drop support for Node versions older than 4: #1696
- Reorder
saving
andcreating
events to reflect the documentation: #1142
Enhancements
- Only request
returning
attribute if client supportsreturning
: #1770 - Throw error if user doesn't pass a valid Knex instance on initialize: #1756
- Add parameterized virtual properties to virtuals plugin: #1755
- Add individual attribute processor plugin to core: #1741
- Format
idAttribute
on save and delete: #1680 - Add
withSchema
option to all database operations: #1638 - Add a case converter plugin to core: #1093
Bug fixes
- Fix inconsistent timestamp values between save and fetch: #1784
- Set
model.id
if attributes being.set()
contain a parsed version ofidAttribute
: #1760 - Fix pagination plugin's
fetchPage()
ignoring or hanging with transactions: #1625 - Fix
fetchPage()
from pagination plugin not working for relation collections: #1561 - Don't try to update
idAttribute
if it hasn't changed: #1260
Test suite
- Increase timeout of the large arrays test: #1778
- Add test to verify that
parentId
is not undefined when usingfetchAll
with relations: #1769 - Fixes and general improvements to the test suite: #1753
- Remove OracleDB tests: #1744
- Fix invalid test related to dirty attributes: #1312
Documentation
- Improve docs about running tests: #1761
- Fix typo on parse-and-format tutorial: #1748
- Add Bookshelf Manager to list of community plugins: #1747
Dependencies
0.12.1 Jan 8, 2018 - Diff
Documentation
- Fix incorrect value of second argument to model event handlers: #1723
- Fix incorrect return value from
.detach()
: #1720 - Fix incorrect return value from
model.has()
: #1712 - Fix
fetching:collection
andfetched:collection
not being generated or visible on the navigation bar: #1114 - Update contributing document and issue templates: #1736
- Add more information and links to Parse and Format docs: #1727
- Add bookshelf-ez-fetch to Community Plugins: #1708
- Add bookshelf-default-select to Community Plugins: #1706
- Add information and examples about calling
super()
on model'sinitialize()
: #1529 - Add npm version badge to readme: f4dd792
Bug fixes
- Fix inability to attach belongsToMany relation to models fetched with
fetchAll()
: #1716 - Fix foreign key = 0 not fetching related object: #1639
- Fix unparsed
previousAttributes
for related models: #1457
Dependencies
0.12.0 Nov 27, 2017 - Diff
- Skip visibility-plugin
hidden
andvisible
attributes #1699.- Used w/
<model>.toJSON({ visibility: false })
- Used w/
- Updated knex peer dependency version to 0.14.x #1694.
- Documentation typo fixes #1693.
- Now caching
node_modules
to speed up travis-ci builds #1695. - Use Docker containers for test runs #1674.
- Make
postpublish
work regardless of git remote config #1697.
0.11.1 Nov 15, 2017 — Diff
- Fixed regression #1691: File missing on
postinstall
- npm
postinstall
script can be run as a part of npmprepublish
script.
- npm
0.11.0 Nov 15, 2017 — Diff
- Moved
.babelrc
->src/.babelrc
#1470 - Timestamp on save now utilizes a date option for timestamp updates on insert and update. #1592
- Used in options on save like so:
m.save({item: 'test'}, { date: dateInThePast })
- Used in options on save like so:
- Added
morphValues
formorphTo
relation. #1326 - Added ability to also set timestamps as model attributes in save.
- Removed non-production files from packaging / added them to .npmignore #1679
- Development Facing:
- Oracle tests only run when oracle is installed.
- Refactoring on the registry plugin.
- Updated a lot of documents related to repo organization.
0.10.4 - Jul 17, 2017 — Diff
- Allow knex 0.13.x.
- Use uuid instead of node-uuid.
- Test Bookshelf with Node v7.
- Updated Author info in
package.json
. - Remove lodash from build script.
- Add OracleDB integration tests.
- Add opportunity to override
visible
andhidden
behavior for toJSON function. - Do not load
belongsTo
ifforeignKey
isnull
. - Optimise
timestamp
function: respect updated_at/created_at being part of the query. - Fix
fetchPage
on Collection (pagination plugin). - Fixing virtuals when
omitNew=true
. - Lot's of typo fixes and documentation updates.
0.10.3 - Jan 21, 2017 — Diff
- Drop Node support for 0.10 and 0.12.
- Trigger creating event for attached models.
- Add support for uninstantiated models relations.
- Add
foreignKeyTarget
to relation methods.
0.10.2 - Sept 22, 2016 — Diff
- Fixes memory leak introduced in 0.10.0 caused by binding
this.listeners
intriggerThen
. - Fixes Bluebird warning when a Promise was internally rejected with a non-error.
0.10.1 - Sept 14, 2016 — Diff
- Allows using knex 0.12 as a peerDependency.
- knex instance used by bookshelf may be swapped out.
0.10.0 — Jun 29, 2016 — Diff
Breaking Changes
- Removal/renaming of certain lodash functions from Model and Collection that were removed in lodash 4:
- Collection Methods
- removed
CollectionBase#collect
=> useCollectionBase#map
instead - removed
CollectionBase#foldl
=> useCollectionBase#reduce
instead - removed
CollectionBase#inject
=> useCollectionBase#reduce
instead - removed
CollectionBase#foldr
=> useCollectionBase#reduceRight
instead - removed
CollectionBase#detect
=> useCollectionBase#find
instead - removed
CollectionBase#select
=> useCollectionBase#filter
instead - removed
CollectionBase#all
=> useCollectionBase#every
instead - removed
CollectionBase#any
=> useCollectionBase#some
instead - removed
CollectionBase#include
=> useCollectionBase#includes
instead - removed
CollectionBase#contains
=> useCollectionBase#includes
instead - removed
CollectionBase#rest
=> useCollectionBase#tail instead
- renamed
CollectionBase#invoke
=>CollectionBase#invokeMap
- split
CollectionBase#max
intoCollectionBase#maxBy
- see the lodash docs for more explanation - split
CollectionBase#min
intoCollectionBase#minBy
- see the lodash docs for more explanation
- removed
- Model Methods
- renamed
ModelBase#pairs
=>ModelBase#toPairs
- renamed
- Collection Methods
Other changes
- Update to Lodash 4. #1287
- Registry plugin: Better support for custom relations. #1294
0.9.5 — May 15, 2016 — Diff
- Add pagination plugin. #1183
- Fire
Model#event:fetched
on eagerly loaded relations. #1206 - Correct cloning of
Model#belongsToMany
decorated relations. #1222 - Update Knex to 0.11.x. #1227
- Update minimum lodash version. #1230
0.9.4 — April 3, 2016 — Diff
- Include
babel-runtime
as a dependency. #1188
0.9.3 — April 3, 2016 — Diff
- Bugfix: Restore support for
camelCase
andcolon:separated
event names. #1184
0.9.2 — February 17, 2016 — Diff
- Permit up to Knex 0.11.0 via
peerDependencies
. Model.forge
works for ES6 classes. #924- Fix
Collection#count
forhasMany
relations. #1115
0.9.1 — November 4, 2015 — Diff
Events#off
can now unregister multiple methods at once. #983- Permit Knex 0.10.0 via
peerDependencies
. #998
0.9.0 — November 1, 2015 — Diff
- Repo no longer includes built source or generated documentation. Release script updated to include these only in the tagged release commit. #950.
Model#previous
returnedundefined
instead ofnull
for non-existent attributes.- Update tests and documentation to confirm that
null
(rather thanundefined
) is returned fromModel#fetch
andCollection#fetchOne
. - Fix error in virtuals plugin - #936
- Correct error updating parsed/formatted
Model#idAttribute
after successfulinsert
operation. #955 - Many documentation fixes.
0.8.2 — August 20, 2015 — Diff
- ES6/7: Move code base to
/src
— code is now compiled into/lib
via Babel. - Add
collection.count
,model.count
andModel.count
. - Add
model.refresh
. #796 - Prevent
fetch
andrefresh
from trying to add JSON attributes to awhere
clause. #550 #778 - Virtuals plugin now supports
{patch: true}
argument tomodel.save
. #542 - Restored
model.clone
andcollection.clone
, which were not previously working. #744 - Allow
bookshelf.Collection
to be modified and extended by plugins (so that relations andfetchAll
operations will return the extended instance). #681 #688 - Fix
model.timestamps
behavior which deviated from documentation. Also ensure thatcreatedAt
is set when{method: "insert"}
is passed explicitly. #787 - Calling
create
on athrough
relationship no longer tries to make a pivot object. Previously this would attempt to create an object with invalid foreign keys. #768 - Parse foreign keys set during
create
in a relation. #770
0.8.1 — May 12, 2015 — Diff
- Fix for regression in
initialize
not being called in Collection constructor, #737. - Fix for regression, removing
omitPivot
in 0.8 #721 - Added
serialize
, a method which contains toJSON logic for easier customization.
0.8.0 — May 1, 2015 — Diff
- Dropped Backbone dependency.
- More specific errors throughout, #522
- Support
{require: true}
for model.destroy #617 - Add lifecycle events on pivot models for
belongsToMany
,.through
#578 - Allows for select/column calls in the query builder closure, #633.
- Added per-constructor error classes #694 (note: this will not work in CoffeeScript).
Breaking Changes
- Removed the
__super__
internal property on the constructor, this shouldn't have been something you were relying on anyway.
0.7.9 — Oct 28, 2014 — Diff
- Fix for regression in columns / eager fetch query constraints, (#510).
0.7.8 — Oct 28, 2014 — Diff
- Timestamp
created_at
is now saved with any insert. - Fix for regression created by #429.
- New events,
attaching
,attached
,detaching
,detached
#452. - Ability to specify custom column names in morphTo, #454
- Fix for stack overflow with model list as arguments, #482
- Modified location of eager fetch query constraints internally.
0.7.7 — July 23, 2014 — Diff
- Fix for formatting on polymorphic keys, (#429).
- Added a resolve method for specifying a custom resolver function for the registry plugin.
0.7.6 — June 29, 2014 — Diff
- Add
omitPivot
flag on toJSON options for omitting the_pivot_
keys inthrough
andbelongsToMany
relations (#404).
0.7.5 — June 23, 2014 — Diff
- Fix missing
NotFoundError
&EmptyError
on Model & Collection, respectively (#389, #399).
0.7.4 — June 18, 2014 — Diff
- Added
bookshelf.model(name, protoProps, [staticProps])
syntax for registry plugin.
0.7.3 — June 17, 2014 — Diff
- Fix for collection dropping models early in set, #376.
0.7.2 — June 12, 2014 — Diff
- Pass a cloned copy of the model's attributes to
format
rather than the original, related to #315.
0.7.1 — June 10, 2014 — Diff
- Ensure the knex version >= 0.6.10, where a major regression affecting column names was fixed.
0.7.0 — June 9, 2014
- Added
Model#fetchAll
, for fetching a collection of models from a model. - Added
Model#where
, as a shortcut for the most commonly used query method. - Initializing via a plain options object is deprecated, you must now pass in an initialized knex instance.
- Adding typed errors (#221).
- Upgrade to support knex 0.6.x
0.6.12 — June 5, 2014 — Diff
- Fix for eager loaded
belongsTo
relation bug with custom parse/format (#377).
0.6.11 — June 4, 2014 — Diff
- Temporarily add knex to
peerDependencies
until 0.7 is released to support knex 0.6 and there exists a better internal method of doing a semver check. - Fix for
belongsTo
relation bug (#353).
0.6.10 — April 3, 2014 — Diff
- Bumping dependencies, including upgrading to Bluebird 1.2, trigger-then 0.3, fixing an erroneous "unhandledRejection" (#310).
fetchOne
properly resets the query on the collection, (#300).
0.6.9 — April 3, 2014 — Diff
- Only prefix model fields with the "tableName" after format has been called, (#308).
0.6.8 — March 6, 2014 — Diff
- Virtuals plugin may now accept a hash of attributes to set.
- Properly fix issue addressed in 0.6.7.
0.6.7 — March 2, 2014 — Diff
- Bugfix for edge case for eager loaded relations and
relatedData
settings.
0.6.6 — March 1, 2014 — Diff
- Bugfix for registry plugin, resolving correct models for "through" relations. (#260)
0.6.5 — February 28, 2014 — Diff
- Added
Collection#reduceThen
as a passthrough to Bluebird's "reduce" method with models. - Options are now passed to "plugin" method. (#254)
- Bugfix for registry plugin. (#259)
0.6.4 — February 11, 2014 — Diff
- Adds static method
Model.collection()
as a shortcut for creating a collection with the current model.
0.6.3 — February 9, 2014 — Diff
- Added an
Relation#updatePivot
method for updating tables on a "belongsToMany" relation. (#134, #230) - Allow mutating the options for passing constraints to eager loaded relations. (#151)
- All keys of an object passed into sync are properly prefixed before sync. (#177)
- Clearer error messages for debugging. (#204, #197)
- Fixed error message for updates that don't affect rows. (#228)
- Group by the correct key on "belongsTo.through" relations. (#214)
- Ability to only use
created_at
orupdated_at
as timestamp properties. (#158) - Numerous documentation corrections, clarifications, enhancements.
- Bumped Bluebird dependency to ~1.0.0.
Plugins:
- Added the
registry
plugin for registering models as strings, helping with the circular dependency problem. - Added the
virtuals
plugin for getting/setting virtual (computed) properties on the model. - Added the
visibility
plugin for specifying a whitelist/blacklist of keys when a model is serialized with toJSON.
0.6.2 — December 18, 2013 — Diff
- Debug may now be passed as an option in any sync method, to log queries, including relations.
- Save now triggers an error in updates with no affected rows. (#119)
- The
model.id
attribute is only set on insert if it's empty. (#130) - Ensure eager loaded relations can use attach/detach. (#120)
0.6.1 — November 26, 2013 — Diff
- Fixes bug with promise code and saving event firing, where promises are not properly resolved with ".all" during saving events.
0.6.0 — November 25, 2013 — Diff
- Updating dependency to knex.js 0.5.x.
- Switched from when.js to bluebird for promise implementation, with shim for backward compatibility.
- Switched from underscore to lodash, for semver reliability.
0.5.8 — November 24, 2013 — Diff
- Parse models after all relations have been eager loaded, for appropriate column name matching (thanks @benesch) (#97)
- Specify table for
withRelated
fetches to prevent column naming conflicts (#96). - Fix for polymorphic relation loading (#95).
- Other documentation tweaks and other internal code cleanup.
0.5.7 — October 11, 2013 — Diff
- The "fetching" event is now fired on eager loaded relation fetches.
0.5.6 — October 10, 2013 — Diff
- The
options.query
now contains the appropriateknex
instance during the "fetching" event handler.
0.5.5 — October 1, 2013 — Diff
- An eager loaded morphTo relation may now have child relations nested beneath it that are properly eager loaded, depending on the parent.
0.5.4 — October 1, 2013 — Diff
- Fix issue where the
relatedData
context was not appropriately maintained for subsequentCollection#create
calls after an eager load (#77). - Documentation improvements, encouraging the use of
Model#related
rather than calling a relation method directly, to keep association with the parent model'srelations
hash.
0.5.3 — September 26, 2013 — Diff
- The
columns
explicitly specified in a fetch are no-longer passed along when eager loading relations, fixes (#70).
0.5.2 — September 22, 2013 — Diff
- Fixed incorrect eager loading in
belongsTo
relations (#65).
0.5.1 — September 21, 2013 — Diff
- Fixed incorrect eager loading in
hasOne
relations (#63).
0.5.0 — September 20, 2013 — Diff
Major Breaking Changes
- Global state is no longer stored in the library, an instance is returned from
Bookshelf.initialize
, so you will need to call this once and then reference thisBookshelf
client elsewhere in your application. - Lowercasing of
bookshelf.initialize
,bookshelf.knex
,bookshelf.transaction
. - During the lifecycle events, such as "fetching", "saving", or "destroying", the model no-longer contains the active query builder instance at the time it is saved. If you need to modify the query builder chain inside of an event handler, you may now use
options.query
inside the event handlers.
Other changes
- Added
tableName
for all queries, so joins use the correct id (#61). - The
attach
&detach
now remove models from the associated collection, as appropriate (#59). - A
withPivot
no longer accepts an object to specify the keys for the returned pivot items, if you wish to specify how these pivot objects are defined on the object, a custom toJSON is your best bet. - Added
Collection#invokeThen
andCollection#mapThen
as convenience helpers forPromise.all(collection.invoke(method, args*))
andPromise.all(collection.map(method, iterator, [context]))
, respectively. - Added a
Bookshelf.plugin
method, for a standard way to extend Bookshelf instances. - A re-written modular architecture, to move the library toward becoming a database agnostic "data mapper" foundation, with the ablitiy to form relations between different data stores and types, not just SQL (although SQL is the primary focus for now). Also, support for AMD, for eventual use outside of Node.js runtime (with webSQL and likewise).
0.3.1 — August 29, 2013 - Diff
- Docs
- Fixed regression in
belongsToMany
custom column name order.
0.3.0 — August 28, 2013
- Support for a
Model#through
clause on various model relations. - Creating a model from a related collection maintains the appropriate relation data (#35).
- Support for a
{patch: true}
flag on save, to only update specific saved attributes. - Added a
fetchOne
method, for pulling out a single model from a collection, mostly useful for related collection instances. - Updated to Knex "0.2.x" syntax for insert / returning.
- Ability to specify a
morphValue
onModel#morphOne
orModel#morphMany
relations. - Internal refactor of relations for more consistent behavior.
0.2.8 — August 26, 2013
- Some minor fixes to make the
Sync
methods more consistent in their behavior when called directly, (#53).
0.2.7 — August 21, 2013
- Timestamp for
created_at
is not set during an "update" query, and the update where clause does not include theidAttribute
if it isn't present (#51).
0.2.6 — August 21, 2013
- Fixes bug with query function feature added in
0.2.5
, mentioned in (#51).
0.2.5 — August 19, 2013
- The
Model#query
method may now accept a function, for even more dynamic query building (#45). - Fix for relations not allowing
0
as a valid foreign key value (#49).
0.2.4 — July 30, 2013
- More consistent query resetting, fixing query issues on post-query event handlers.
- The
toJSON
is only called on a related model if the method exists, allowing for objects or arrays to be manually specified on therelations
hash and serialized properly on the parent'stoJSON
.
0.2.3 — July 7, 2013
- Fixing bug where
triggerThen
wasn't actually being used for several of the events as noted in 0.2.1 release.
0.2.2 — July 2, 2013
-
The Model's
related
method is now a no-op if the model doesn't have the related method. -
Any
withPivot
columns on many-to-many relations are now prefixed with_pivot
rather thanpivot
unless named otherwise, for consistency. -
The
_reset
is not called until after all triggered events so thathasChanged
can be used on the current model state in the "created", "updated", "saved", and "destroyed" events. -
Eager queries may be specified as an object with a function, to constrain the eager queries:
user.fetch({withRelated: ['accounts', { 'accounts.settings': function(qb) { qb.where('status', 'enabled'); } }, 'other_data']}).then(...
0.2.1 — June 26, 2013
- Using
triggerThen
instead oftrigger
for "created", "updated", "saved", "destroyed", and "fetched" events - if any async operations are needed after the model is created but before resolving the original promise.
0.2.0 — June 24, 2013
- Resolve Model's
fetch
promise withnull
rather thanundefined
. - An object of
query
constraints (e.g.{where: {...}, orWhere: {...}}
may be passed to the query method (#30). - Fix for empty eager relation responses not providing an empty model or collection instance on the
model.relations
object.
0.1.9 — June 19, 2013
- Resolve Model's
fetch
promise withundefined
if no model was returned. - An array of "created at" and "updated at" values may be used for
hasTimestamps
. - Format is called on the
Model#fetch
method. - Added an
exec
plugin to provide a node callback style interface for any of the promise methods.
0.1.8 — June 18, 2013
- Added support for polymorphic associations, with
morphOne
,morphMany
, andmorphTo
model methods.
0.1.7 — June 15, 2013
- Bugfix where
detach
may be used with no parameters to detach all related items (#19).
0.1.6 — June 15, 2013
- Fixing bug allowing custom
idAttribute
values to be used in eager loaded many-to-many relations (#18).
0.1.5 — June 11, 2013
- Ensuring each of the
_previousAttribute
andchanged
values are properly reset on related models after sync actions.
0.1.4 — June 10, 2013
- Fixing issue with
idAttribute
not being assigned after database inserts. - Removing various aliases
Events
methods for clarity.
0.1.3 — June 10, 2013
- Added
Model#hasChanged
,Model#previous
, andModel#previousAttributes
methods, for getting the previous value of the model since the last sync. - Using
Object.create(null)
for various internal model objects dealing with user values. - Calling
Model#related
on a model will now create an empty related object if one is not present on therelations
object. - Removed the
{patch: true}
option on save, instead only applying defaults if the objectisNew
, or if{defaults: true}
is passed. - Fix for
model.clone
's relation responses.
0.1.2 — May 17, 2013
- Added
triggerThen
andemitThen
for promise based events, used internally in the "creating", "updating", "saving", and "destroying" events. - Docs updates, fixing
{patch: true}
onupdate
to have intended functionality. - A model's
toJSON
is now correctly called on any related properties.
0.1.1 — May 16, 2013
- Fixed bug with eager loaded
belongsTo
relations (#14).
0.1.0 — May 13, 2013
- Initial Bookshelf release.