Comparing version 0.6.2 to 0.6.3
@@ -1,2 +0,2 @@ | ||
// Bookshelf.js 0.6.2 | ||
// Bookshelf.js 0.6.3 | ||
// --------------- | ||
@@ -49,2 +49,6 @@ | ||
_relation: function(type, Target, options) { | ||
if (type !== 'morphTo' && !_.isFunction(Target)) { | ||
throw new Error('A valid target model must be defined for the ' + | ||
_.result(this, 'tableName') + ' ' + type + 'relation'); | ||
} | ||
return new Relation(type, Target, options); | ||
@@ -82,3 +86,3 @@ } | ||
// Keep in sync with `package.json`. | ||
VERSION: '0.6.2', | ||
VERSION: '0.6.3', | ||
@@ -93,3 +97,13 @@ // Helper method to wrap a series of Bookshelf actions in a `knex` transaction block; | ||
plugin: function(plugin) { | ||
plugin(this); | ||
if (_.isString(plugin)) { | ||
try { | ||
require('./plugins/' + plugin)(this); | ||
} catch (e) { | ||
require(plugin)(this); | ||
} | ||
} else if (_.isArray(plugin)) { | ||
_.each(plugin, this.plugin, this); | ||
} else { | ||
plugin(this); | ||
} | ||
return this; | ||
@@ -96,0 +110,0 @@ } |
@@ -21,2 +21,5 @@ // Base Collection | ||
this.initialize.apply(this, arguments); | ||
if (!_.isFunction(this.model)) { | ||
throw new Error('A valid `model` constructor must be defined for all collections.'); | ||
} | ||
if (models) this.reset(models, _.extend({silent: true}, options)); | ||
@@ -23,0 +26,0 @@ }; |
@@ -19,3 +19,3 @@ // Eager Base | ||
EagerBase.prototype = { | ||
_.extend(EagerBase.prototype, { | ||
@@ -103,3 +103,3 @@ // This helper function is used internally to determine which relations | ||
}; | ||
}); | ||
@@ -106,0 +106,0 @@ var noop = function() {}; |
@@ -134,4 +134,4 @@ // Base Model | ||
var vals = {}; | ||
vals[keys[1]] = d; | ||
if (this.isNew(options) && (!options || options.method !== 'update')) vals[keys[0]] = d; | ||
if (keys[1]) vals[keys[1]] = d; | ||
if (this.isNew(options) && keys[0] && (!options || options.method !== 'update')) vals[keys[0]] = d; | ||
return vals; | ||
@@ -138,0 +138,0 @@ }, |
@@ -20,3 +20,3 @@ // Base Relation | ||
RelationBase.prototype = { | ||
_.extend(RelationBase.prototype, { | ||
@@ -41,3 +41,3 @@ // Creates a new relation instance, used by the `Eager` relation in | ||
}; | ||
}); | ||
@@ -44,0 +44,0 @@ RelationBase.extend = Backbone.Model.extend; |
@@ -17,3 +17,3 @@ // Base Sync | ||
BaseSync.prototype = { | ||
_.extend(BaseSync.prototype, { | ||
@@ -47,3 +47,3 @@ // Return a single model object. | ||
}; | ||
}); | ||
@@ -50,0 +50,0 @@ BaseSync.extend = Backbone.Model.extend; |
@@ -95,3 +95,3 @@ // Collection | ||
if (relatedData && (relatedData.type === 'belongsToMany' || relatedData.isThrough())) { | ||
return this.attach(model, options); | ||
return this.attach(model, _.omit(options, 'query')); | ||
} | ||
@@ -98,0 +98,0 @@ }) |
@@ -20,2 +20,5 @@ // EagerRelation | ||
// skip eager loading for rows where the foreign key isn't set | ||
if (relatedData.parentFk === null) return; | ||
if (relatedData.type === 'morphTo') return this.morphToFetch(relationName, relatedData, options); | ||
@@ -25,7 +28,6 @@ | ||
options.beforeFn.call(handled, handled.query()); | ||
return handled | ||
.sync(_.extend({}, options, {parentResponse: this.parentResponse})) | ||
.sync(_.extend(options, {parentResponse: this.parentResponse})) | ||
.select() | ||
.tap(eagerLoadHelper(this, relationName, handled, options)); | ||
.tap(eagerLoadHelper(this, relationName, handled, _.omit(options, 'parentResponse'))); | ||
}), | ||
@@ -32,0 +34,0 @@ |
@@ -188,3 +188,3 @@ // Model | ||
} else if (method === 'update' && resp === 0) { | ||
throw new Error('No rows were affected in the update, did you mean to pass the {insert: true} option?'); | ||
throw new Error('No rows were affected in the update, did you mean to pass the {method: "insert"} option?'); | ||
} | ||
@@ -191,0 +191,0 @@ |
@@ -187,3 +187,4 @@ // Relation | ||
eagerKeys: function(resp) { | ||
return _.uniq(_.pluck(resp, this.isInverse() ? this.key('foreignKey') : this.parentIdAttribute)); | ||
var key = this.isInverse() && !this.isThrough() ? this.key('foreignKey') : this.parentIdAttribute; | ||
return _.uniq(_.pluck(resp, key)); | ||
}, | ||
@@ -244,4 +245,8 @@ | ||
var grouped = _.groupBy(related, function(model) { | ||
return model.pivot ? model.pivot.get(this.key('foreignKey')) : | ||
this.isInverse() ? model.id : model.get(this.key('foreignKey')); | ||
if (model.pivot) { | ||
return this.isInverse() && this.isThrough() ? model.pivot.id : | ||
model.pivot.get(this.key('foreignKey')); | ||
} else { | ||
return this.isInverse() ? model.id : model.get(this.key('foreignKey')); | ||
} | ||
}, this); | ||
@@ -253,3 +258,5 @@ | ||
model = parentModels[i]; | ||
var groupedKey = this.isInverse() ? model.get(this.key('foreignKey')) : model.id; | ||
var groupedKey = !this.isInverse() ? model.id : | ||
this.isThrough() ? model.get(this.key('throughForeignKey')) : | ||
model.get(this.key('foreignKey')); | ||
var relation = model.relations[relationName] = this.relatedInstance(grouped[groupedKey]); | ||
@@ -356,2 +363,7 @@ relation.relatedData = this; | ||
// Update an existing relation's pivot table entry. | ||
updatePivot: function(data, options) { | ||
return this._handler('update', data, options); | ||
}, | ||
// Selects any additional columns on the pivot table, | ||
@@ -387,2 +399,10 @@ // taking a hash of columns which specifies the pivot | ||
var relatedData = this.relatedData; | ||
// Grab the `knex` query builder for the current model, and | ||
// check if we have any additional constraints for the query. | ||
var builder = this._builder(relatedData.joinTable()); | ||
if (options && options.query) { | ||
Helpers.query.call(null, {_knex: builder}, [options.query]); | ||
} | ||
data[relatedData.key('foreignKey')] = relatedData.parentFk; | ||
@@ -396,3 +416,3 @@ | ||
data[relatedData.key('otherKey')] = item.id; | ||
} else { | ||
} else if (method !== 'update') { | ||
_.extend(data, item); | ||
@@ -403,3 +423,3 @@ } | ||
} | ||
var builder = this._builder(relatedData.joinTable()); | ||
if (options) { | ||
@@ -419,2 +439,11 @@ if (options.transacting) builder.transacting(options.transacting); | ||
} | ||
if (method === 'update') { | ||
return builder.where(data).update(item).then(function (numUpdated) { | ||
if (options && options.require === true && numUpdated === 0) { | ||
throw new Error('No rows were updated'); | ||
} | ||
return numUpdated; | ||
}); | ||
} | ||
return builder.insert(data).then(function() { | ||
@@ -421,0 +450,0 @@ collection.add(item); |
@@ -22,6 +22,18 @@ // Sync | ||
// Prefix all keys of the passed in object with the | ||
// current table name | ||
prefixFields: function (fields) { | ||
var tableName = this.syncing.tableName; | ||
var prefixed = {}; | ||
for (var key in fields) { | ||
prefixed[tableName + '.' + key] = fields[key]; | ||
} | ||
return prefixed; | ||
}, | ||
// Select the first item from the database - only used by models. | ||
first: Promise.method(function() { | ||
this.query.where(this.syncing.format( | ||
_.extend(Object.create(null), this.syncing.attributes)) | ||
_.extend(Object.create(null), this.prefixFields(this.syncing.attributes))) | ||
).limit(1); | ||
@@ -28,0 +40,0 @@ return this.select(); |
{ | ||
"name": "bookshelf", | ||
"version": "0.6.2", | ||
"version": "0.6.3", | ||
"description": "A lightweight ORM for PostgreSQL, MySQL, and SQLite3, influenced by Backbone.js", | ||
@@ -8,3 +8,5 @@ "main": "bookshelf.js", | ||
"test": "mocha -R spec test/index.js", | ||
"doc": "groc -o docs --verbose dialects/base/collection.js dialects/**/*.js plugins/*.js bookshelf.js" | ||
"doc": "groc -o docs --verbose dialects/base/collection.js dialects/**/*.js plugins/*.js bookshelf.js", | ||
"release:patch": "git checkout master && export BOOKSHELF_DEV=0 && npm run-script test && npm run-script doc && git add . && git commit -m 'docs prep for release' && grunt release:patch", | ||
"release:minor": "git checkout master && export BOOKSHELF_DEV=0 && npm run-script test && npm run-script doc && git add . && git commit -m 'docs prep for release' && grunt release:minor" | ||
}, | ||
@@ -29,3 +31,3 @@ "homepage": "http://bookshelfjs.org", | ||
"knex": "~0.5.0", | ||
"bluebird": ">=0.11.0", | ||
"bluebird": "~1.0.0", | ||
"lodash": ">=2.0.0" | ||
@@ -32,0 +34,0 @@ }, |
@@ -41,2 +41,4 @@ var Promise = require('../dialects/base/promise').Promise; | ||
base.Eager(); | ||
require('./unit/sql/sync')(); | ||
@@ -43,0 +45,0 @@ }); |
@@ -66,2 +66,5 @@ var _ = require('lodash'); | ||
require('./integration/relations')(bookshelf); | ||
require('./integration/plugins/virtuals')(bookshelf); | ||
require('./integration/plugins/visibility')(bookshelf); | ||
require('./integration/plugins/registry')(bookshelf); | ||
}); | ||
@@ -68,0 +71,0 @@ |
@@ -174,2 +174,5 @@ | ||
return this.belongsTo(Post); | ||
}, | ||
blog: function() { | ||
return this.belongsTo(Blog).through(Post); | ||
} | ||
@@ -277,2 +280,2 @@ }); | ||
}; | ||
}; |
@@ -276,3 +276,12 @@ var _ = require('lodash'); | ||
}); | ||
it('does not fail, when joining another table having some columns with the same names - #176', function () { | ||
var model = new Site({id: 1}); | ||
model.query(function (qb) { | ||
qb.join('authors', 'authors.site_id', '=', 'sites.id'); | ||
}); | ||
return expect(model.fetch()).to.be.fulfilled; | ||
}); | ||
}); | ||
@@ -326,3 +335,3 @@ | ||
}, function(err) { | ||
expect(err.message).to.equal('No rows were affected in the update, did you mean to pass the {insert: true} option?'); | ||
expect(err.message).to.equal('No rows were affected in the update, did you mean to pass the {method: "insert"} option?'); | ||
}); | ||
@@ -539,2 +548,24 @@ | ||
it('will accept a falsy value as an option for created and ignore it', function() { | ||
var m = new Bookshelf.Model(null, {hasTimestamps: ['createdAt', null]}); | ||
m.sync = function() { | ||
equal(this.get('item'), 'test'); | ||
equal(_.isDate(this.get('createdAt')), true); | ||
equal(_.isDate(this.get('updatedAt')), false); | ||
return stubSync; | ||
}; | ||
return m.save({item: 'test'}); | ||
}); | ||
it('will accept a falsy value as an option for updated and ignore it', function() { | ||
var m = new Bookshelf.Model(null, {hasTimestamps: [null, 'updatedAt']}); | ||
m.sync = function() { | ||
equal(this.get('item'), 'test'); | ||
equal(_.isDate(this.get('updatedAt')), true); | ||
equal(_.isDate(this.get('createdAt')), false); | ||
return stubSync; | ||
}; | ||
return m.save({item: 'test'}); | ||
}); | ||
}); | ||
@@ -659,2 +690,2 @@ | ||
}; | ||
}; |
@@ -35,3 +35,3 @@ var _ = require('lodash'); | ||
var Posts = Collections.Posts; | ||
var Comments = Collections.Comment; | ||
var Comments = Collections.Comments; | ||
var Photos = Collections.Photos; | ||
@@ -327,2 +327,65 @@ var Authors = Collections.Authors; | ||
describe('Updating pivot tables with `updatePivot`', function () { | ||
var admin1_id; | ||
var admin2_id; | ||
before(function () { | ||
var admin1 = new Admin({username: 'updatetest', password: 'test'}); | ||
var admin2 = new Admin({username: 'updatetest2', password: 'test'}); | ||
return Promise.all([admin1.save(),admin2.save()]) | ||
.then(function (admin) { | ||
admin1_id = admin1.id; | ||
admin2_id = admin2.id; | ||
return (new Site({id: 1})).related('admins').attach([admin1, admin2]); | ||
}); | ||
}); | ||
after(function () { | ||
return new Site({id: 1}).admins().detach(); | ||
}); | ||
it('updates all rows inside the pivot table belonging to the current model', function() { | ||
var site1 = new Site({id: 1}); | ||
return site1.admins() | ||
.updatePivot({item: 'allupdated'}) | ||
.then(function (relation) { | ||
return relation.withPivot(['item']).fetch().then(function (col) { | ||
equal(col.get(admin1_id).pivot.get('item'), 'allupdated'); | ||
equal(col.get(admin2_id).pivot.get('item'), 'allupdated'); | ||
}); | ||
}); | ||
}); | ||
it('updates all rows, which match the passed in query-criteria', function() { | ||
var site1 = new Site({id: 1}); | ||
return site1.admins() | ||
.updatePivot({item: 'anotherupdate'}, { | ||
query: { | ||
whereIn: ['admin_id', [admin1_id]] | ||
} | ||
}) | ||
.then(function (relation) { | ||
return relation.withPivot(['item']).fetch().then(function (col) { | ||
equal(col.get(admin1_id).pivot.get('item'), 'anotherupdate'); | ||
equal(col.get(admin2_id).pivot.get('item'), 'allupdated'); | ||
}); | ||
}); | ||
}); | ||
it('throws an error if no columns are updated and `require: true` is passed as option', function() { | ||
// non-existent site | ||
return (new Site({id: 99999})).admins() | ||
.updatePivot({'item': 'testvalue'}, {require: true}) | ||
.then(function (relation) { | ||
throw new Error('this should not happen'); | ||
}).catch(function (err) { | ||
expect(err).to.be.ok; | ||
expect(err).to.be.an.instanceof(Error); | ||
}); | ||
}); | ||
}); | ||
describe('Custom foreignKey & otherKey', function() { | ||
@@ -411,2 +474,6 @@ | ||
it('eager loads belongsTo `through`', function() { | ||
return new Comments().fetch({log: true, withRelated: 'blog'}); | ||
}); | ||
}); | ||
@@ -552,4 +619,95 @@ | ||
describe('Issue #212 - Skipping unnecessary queries', function () { | ||
var oldAuthorSync; | ||
var oldSiteSync; | ||
var siteSyncCount = 0; | ||
var author; | ||
beforeEach(function () { | ||
siteSyncCount = 0; | ||
}); | ||
before(function () { | ||
Photo.prototype.sync = function () { | ||
return { | ||
first: function () { | ||
return Promise.resolve([{ | ||
id:1, | ||
imageable_type: 'sites', | ||
imageable_id: null | ||
}]); | ||
} | ||
}; | ||
}; | ||
Author.prototype.sync = function () { | ||
return { | ||
select: function () { | ||
return Promise.resolve([{ | ||
id:1, | ||
dummy: 'author' | ||
}]); | ||
}, | ||
first: function () { | ||
return Promise.resolve([{ | ||
id:1, | ||
first_name: 'Johannes', | ||
last_name: 'Lumpe', | ||
site_id: null | ||
}]); | ||
} | ||
}; | ||
}; | ||
Site.prototype.sync = function () { | ||
siteSyncCount++; | ||
return { | ||
select: function () { | ||
return Promise.resolve([{ | ||
id:1, | ||
dummy: 'content' | ||
}]); | ||
}, | ||
first: function () { | ||
return Promise.resolve([{ | ||
id:1, | ||
dummy: 'content' | ||
}]); | ||
} | ||
}; | ||
}; | ||
}); | ||
after(function () { | ||
delete Photo.prototype.sync; | ||
delete Author.prototype.sync; | ||
delete Site.prototype.sync; | ||
}); | ||
it('should not run a query for eagerly loaded `belongsTo` relations if the foreign key is null', function () { | ||
var a = new Author({id: 1}); | ||
return a.fetch({withRelated:'site'}) | ||
.then(function (model) { | ||
equal(siteSyncCount, 0); | ||
}).catch(function (err){ | ||
console.log(err); | ||
}); | ||
}); | ||
it('should not run a query for eagerly loaded `morphTo` relations if the foreign key is null', function () { | ||
var p = new Photo({id: 1}); | ||
return p.fetch({withRelated:'imageable'}) | ||
.then(function () { | ||
equal(siteSyncCount, 0); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}; | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
279965
53
7696
11
+ Addedbluebird@1.0.8(transitive)
- Removedbluebird@3.7.2(transitive)
Updatedbluebird@~1.0.0