bookshelf-scopes
Advanced tools
Comparing version 1.4.0 to 1.5.0
{ | ||
"name": "bookshelf-scopes", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"description": "Giving you Rails like scopes in Bookshelf.js.", | ||
"main": "src/scopes.js", | ||
"dependencies": { | ||
"lodash": "^3.9.3" | ||
"lodash": "^3.10.1" | ||
}, | ||
"devDependencies": { | ||
"bluebird": "^2.9.27", | ||
"bookshelf": "^0.8.1", | ||
"bluebird": "^2.11.0", | ||
"bookshelf": "^0.8.2", | ||
"chai": "^2.3.0", | ||
"knex": "^0.8.6", | ||
"mocha": "^2.2.5", | ||
"sqlite3": "^3.0.8" | ||
"mocha": "^2.5.3", | ||
"sqlite3": "^3.1.8" | ||
}, | ||
@@ -22,3 +22,3 @@ "scripts": { | ||
"type": "git", | ||
"url": "https://github.com/pk4media/bookshelf-scopes.git" | ||
"url": "https://github.com/jtwebman/bookshelf-scopes.git" | ||
}, | ||
@@ -36,5 +36,5 @@ "keywords": [ | ||
"bugs": { | ||
"url": "https://github.com/pk4media/bookshelf-scopes/issues" | ||
"url": "https://github.com/jtwebman/bookshelf-scopes/issues" | ||
}, | ||
"homepage": "https://github.com/pk4media/bookshelf-scopes" | ||
"homepage": "https://github.com/jtwebman/bookshelf-scopes" | ||
} |
# Bookshelf-Scopes | ||
[![Circle CI](https://circleci.com/gh/pk4media/bookshelf-scopes/tree/master.svg?style=svg&circle-token=4f67b03079c057b9ae20ef5485459f97215eebe7)](https://circleci.com/gh/pk4media/bookshelf-scopes/tree/master) | ||
[![CircleCI](https://circleci.com/gh/jtwebman/bookshelf-scopes.svg?style=svg)](https://circleci.com/gh/jtwebman/bookshelf-scopes) | ||
Giving you Rails like scopes in Bookshelf.js. | ||
Giving you Rails like scopes in Bookshelf.js. This was originally a [PK4Media](https://github.com/pk4media/bookshelf-scopes) project but I moved it over to my account as they do not use it anymore. | ||
@@ -32,3 +32,3 @@ If you add in the plugin like so: | ||
}, | ||
nameContains: function(gb, text) { | ||
nameContains: function(qb, name) { | ||
qb.where(knex.raw('name LIKE ?', '%' + name + '%')); | ||
@@ -35,0 +35,0 @@ } |
@@ -5,98 +5,63 @@ 'use strict'; | ||
var applyScope = function (_this, applier) { | ||
return function (qb) { | ||
var tempStatements = qb._statements.slice(); | ||
// Apply scope | ||
applier.call(_this, qb); | ||
// Find added statements | ||
_.difference(qb._statements, tempStatements) | ||
// Memorize scoped statements | ||
.forEach(function (statement) { | ||
_this.unscoped.scopeStatements.push(statement); | ||
}); | ||
}; | ||
} | ||
module.exports = function(bookshelf) { | ||
var base = bookshelf.Model; | ||
var baseExtend = bookshelf.Model.extend; | ||
var ModelCtor = bookshelf.Model; | ||
var CollectionCtor = bookshelf.Collection; | ||
// `bookshelf.knex()` was deprecated in knex v0.8.0, use `knex.queryBuilder()` instead if available | ||
var QueryBuilder = (bookshelf.knex.queryBuilder) ? bookshelf.knex.queryBuilder().constructor : bookshelf.knex().constructor; | ||
bookshelf.Model.extend = function(protoProps, constructorProps) { | ||
var model = baseExtend.apply(this, arguments); | ||
var extended = function(Target) { | ||
// Model/Collection abstraction | ||
var isModel = !this.prototype.model; | ||
model.prototype.scopes = model.prototype.scopes || {}; | ||
var Ctor = isModel ? ModelCtor: CollectionCtor; | ||
_.defaults(model.prototype.scopes, this.prototype.scopes || {}); | ||
if (_.isFunction(Ctor.extended) && this.extended != Ctor.extended) { | ||
Ctor.extended(Target); | ||
} | ||
Object.keys(model.prototype.scopes).forEach(function(property) { | ||
model.prototype[property] = function() { | ||
// Parent model | ||
var Model = isModel ? this : Target.prototype.model; | ||
// Inherit scopes from parent | ||
Target.prototype.scopes = _.defaults({}, Target.prototype.scopes || {}, Model.prototype.scopes || {}); | ||
// Scopes as prototype methods | ||
Object.keys(Target.prototype.scopes).forEach(function(property) { | ||
Target.prototype[property] = function() { | ||
var _this = this; | ||
var passedInArguments = _.toArray(arguments); | ||
if (passedInArguments.length > 0 && passedInArguments[0] instanceof QueryBuilder) { | ||
this.scopes[property].apply(this, passedInArguments); | ||
return this; | ||
} else { | ||
return this.query(function(qb) { | ||
return this.query(applyScope(this, function(qb) { | ||
if (passedInArguments.length == 0 || !(passedInArguments[0] instanceof QueryBuilder)) { | ||
passedInArguments.unshift(qb); | ||
_this.scopes[property].apply(_this, passedInArguments); | ||
}); | ||
} | ||
} | ||
_this.scopes[property].apply(_this, passedInArguments); | ||
})); | ||
}; | ||
model[property] = function() { | ||
var instance = model.forge(); | ||
Target[property] = function() { | ||
var instance = Target.forge(); | ||
return instance[property].apply(instance, arguments); | ||
}; | ||
}); | ||
_.each(['hasMany', 'hasOne', 'belongsToMany', 'morphOne', 'morphMany', | ||
'belongsTo', 'through'], function(method) { | ||
var original = model.prototype[method]; | ||
model.prototype[method] = function() { | ||
var relationship = original.apply(this, arguments); | ||
var target = relationship.model || relationship.relatedData.target; | ||
var originalSelectConstraints = relationship.relatedData.selectConstraints; | ||
if (target.prototype.scopes) { | ||
relationship.relatedData.selectConstraints = function(knex, options) { | ||
originalSelectConstraints.apply(this, arguments); | ||
if (target.prototype.scopes.default) { | ||
if (!knex.appliedDefault) { | ||
knex.appliedDefault = true; | ||
target.prototype.scopes.default.apply(this, [knex, options]); | ||
} | ||
} | ||
}; | ||
Object.keys(target.prototype.scopes).forEach(function(key) { | ||
relationship[key] = function() { | ||
var passedInArguments = _.toArray(arguments); | ||
var currentSelectConstraints = relationship.relatedData.selectConstraints; | ||
relationship.relatedData.selectConstraints = function(knex, options) { | ||
currentSelectConstraints.apply(this, arguments); | ||
passedInArguments.unshift(knex); | ||
target.prototype.scopes[key].apply(target.prototype, passedInArguments); | ||
}; | ||
return relationship; | ||
}; | ||
}); | ||
relationship.unscoped = function() { | ||
relationship.relatedData.selectConstraints = function(knex, options) { | ||
var originalDefaultScope; | ||
if(target.prototype.scopes && target.prototype.scopes.default) { | ||
originalDefaultScope = target.prototype.scopes.default; | ||
delete target.prototype.scopes.default; | ||
} | ||
originalSelectConstraints.apply(this, arguments); | ||
if (originalDefaultScope) { | ||
target.prototype.scopes.default = originalDefaultScope; | ||
} | ||
}; | ||
return relationship; | ||
}; | ||
} | ||
return relationship; | ||
}; | ||
}); | ||
return model; | ||
}; | ||
var Model = bookshelf.Model.extend({ | ||
var abstractProperties = [{ | ||
@@ -106,2 +71,7 @@ scopes: null, | ||
initialize: function() { | ||
var superInitialize = (this instanceof ModelCtor | ||
? ModelCtor | ||
: CollectionCtor).prototype.initialize; | ||
this.unscoped.scopeStatements = []; | ||
superInitialize.apply(this, arguments); | ||
this.addScope(); | ||
@@ -113,8 +83,7 @@ }, | ||
if (self.scopes && self.scopes.default) { | ||
self.query(function(qb) { | ||
self.query(applyScope(this, function(qb) { | ||
if (!qb.appliedDefault) { | ||
qb.appliedDefault = true; | ||
self.scopes.default.call(self, qb); | ||
} | ||
}); | ||
})); | ||
} | ||
@@ -124,11 +93,34 @@ }, | ||
unscoped: function() { | ||
return this.resetQuery(); | ||
var unscoped = this.unscoped; | ||
return this.query(function function_name(qb) { | ||
// Remove scoped statements | ||
_.remove(qb._statements, function (statement) { | ||
return unscoped.scopeStatements.some(_.matches(statement)); | ||
}); | ||
// Clear scoped statements registry | ||
unscoped.scopeStatements = []; | ||
// and default applied state | ||
qb.appliedDefault = false; | ||
}); | ||
} | ||
}, { | ||
extended: extended, | ||
collection: function () { | ||
var Collection = bookshelf.Collection.extend({model: this}); | ||
return new (Function.prototype.bind.apply(Collection, [null].concat(Array.prototype.slice.call(arguments))))(); | ||
}, | ||
unscoped: function() { | ||
return this.forge().unscoped(); | ||
} | ||
}); | ||
}]; | ||
var Model = ModelCtor.extend.apply(ModelCtor, abstractProperties); | ||
delete abstractProperties[1].collection; | ||
var Collection = CollectionCtor.extend.apply(CollectionCtor, abstractProperties); | ||
bookshelf.Model = Model; | ||
bookshelf.Collection = Collection; | ||
}; |
@@ -231,2 +231,20 @@ 'use strict'; | ||
it('plugin initialize calls super initialize (#10)', function() { | ||
var superInitializeCalled = 0; | ||
var bookshelf = require('bookshelf')(knex); | ||
bookshelf.Model = bookshelf.Model.extend({ | ||
initialize: function() { | ||
superInitializeCalled++; | ||
} | ||
}); | ||
bookshelf.plugin(require('../src/scopes')); | ||
var TestModel1 = bookshelf.Model.extend({ | ||
tableName: 'testmodel' | ||
}); | ||
TestModel1.forge(); | ||
expect(superInitializeCalled).to.equal(1); | ||
}); | ||
}); |
@@ -203,3 +203,3 @@ 'use strict'; | ||
active: function(qb) { | ||
if (this !== TestModel1.prototype) { | ||
if (!(this instanceof bookshelf.Collection) || this.model !== TestModel1) { | ||
throw new Error('this not set to target prototype'); | ||
@@ -206,0 +206,0 @@ } |
Sorry, the diff of this file is not supported yet
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
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
50718
13
1268
Updatedlodash@^3.10.1