Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: bookshelf/bookshelf
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: zubeio/bookshelf
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 10 commits
  • 3 files changed
  • 2 contributors

Commits on Aug 30, 2015

  1. Return * on insert

    jendewalt committed Aug 30, 2015
    Copy the full SHA
    d1bd476 View commit details
  2. Copy the full SHA
    9672409 View commit details
  3. Use lodash

    jendewalt committed Aug 30, 2015
    Copy the full SHA
    54e2a83 View commit details
  4. Copy the full SHA
    418d0b0 View commit details
  5. Copy the full SHA
    fbff49b View commit details
  6. Sm fix

    jendewalt committed Aug 30, 2015
    Copy the full SHA
    40c18ad View commit details

Commits on Sep 4, 2015

  1. Copy the full SHA
    0c3dce3 View commit details
  2. Copy the full SHA
    9998e7f View commit details

Commits on Sep 6, 2015

  1. Copy the full SHA
    b02321c View commit details
  2. Copy the full SHA
    dee20cb View commit details
Showing with 83 additions and 67 deletions.
  1. +20 −13 lib/base/model.js
  2. +57 −51 lib/model.js
  3. +6 −3 lib/sync.js
33 changes: 20 additions & 13 deletions lib/base/model.js
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ ModelBase.prototype.initialize = function () {};

/**
* @name ModelBase#tableName
* @member {string}
* @member {string}
* @description
*
* A required property for any database usage, The
@@ -142,7 +142,7 @@ ModelBase.prototype.set = function (key, val, options) {
*
* var modelA = new bookshelf.Model();
* modelA.isNew(); // true
*
*
* var modelB = new bookshelf.Model({id: 1});
* modelB.isNew(); // false
*/
@@ -185,7 +185,14 @@ ModelBase.prototype.serialize = function (options) {
var relations = this.relations;
for (var key in relations) {
var relation = relations[key];
attrs[key] = relation.toJSON ? relation.toJSON(options) : relation;
// Zube addition so relations that are not present are null instead of {}
if (relation.toJSON) {
var relationAttrs = relation.toJSON(options);
if (_.isEmpty(relationAttrs) && !_.isArray(relationAttrs)) relationAttrs = null;
attrs[key] = relationAttrs;
} else {
attrs[key] = relation;
}
}
if (options && options.omitPivot) return attrs;
if (this.pivot) {
@@ -430,7 +437,7 @@ ModelBase.prototype.timestamp = function (options) {
* Model#destroy destroy}. If an attribute is passed, returns true only if that
* specific attribute has changed.
*
* @param {string=} attribute
* @param {string=} attribute
* @returns {bool}
* `true` if any attribute has changed. Or, if `attribute` was specified, true
* if it has changed.
@@ -534,32 +541,32 @@ _.each(modelMethods, function (method) {
* var checkit = require('checkit');
* var Promise = require('bluebird');
* var bcrypt = Promise.promisifyAll(require('bcrypt'));
*
*
* var Customer = bookshelf.Model.extend({
*
*
* initialize: function() {
* this.on('saving', this.validateSave);
* },
*
*
* validateSave: function() {
* return checkit(rules).run(this.attributes);
* },
*
*
* account: function() {
* return this.belongsTo(Account);
* },
*
*
* }, {
*
*
* login: Promise.method(function(email, password) {
* if (!email || !password) throw new Error('Email and password are both required');
* return new this({email: email.toLowerCase().trim()}).fetch({require: true}).tap(function(customer) {
* return bcrypt.compareAsync(customer.get('password'), password);
* });
* })
*
*
* });
*
*
* Customer.login(email, password)
* .then(function(customer) {
* res.json(customer.omit('password'));
@@ -593,4 +600,4 @@ _.each(modelMethods, function (method) {
*/
ModelBase.extend = require('../extend');

module.exports = ModelBase;
module.exports = ModelBase;
108 changes: 57 additions & 51 deletions lib/model.js
Original file line number Diff line number Diff line change
@@ -83,14 +83,14 @@ var _basePromise2 = _interopRequireDefault(_basePromise);
*
* Convert attributes by {@link Model#parse parse} before being {@link
* Model#set set} on the model.
*
*
*/
var BookshelfModel = _baseModel2['default'].extend({

/**
* The `hasOne` relation specifies that this table has exactly one of another
* type of object, specified by a foreign key in the other table.
*
*
* let Record = bookshelf.Model.extend({
* tableName: 'health_records'
* });
@@ -105,7 +105,7 @@ var BookshelfModel = _baseModel2['default'].extend({
* // select * from `health_records` where `patient_id` = 1;
* new Patient({id: 1}).related('record').fetch().then(function(model) {
* ...
* });
* });
*
* // alternatively, if you don't need the relation loaded on the patient's relations hash:
* new Patient({id: 1}).record().fetch().then(function(model) {
@@ -170,13 +170,13 @@ var BookshelfModel = _baseModel2['default'].extend({
* return this.belongsTo(Author);
* }
* });
*
*
* // select * from `books` where id = 1
* // select * from `authors` where id = book.author_id
* Book.where({id: 1}).fetch({withRelated: ['author']}).then(function(book) {
* console.log(JSON.stringify(book.related('author')));
* });
*
*
* @method Model#belongsTo
*
* @param {Model} Target
@@ -205,24 +205,24 @@ var BookshelfModel = _baseModel2['default'].extend({
* let Account = bookshelf.Model.extend({
* tableName: 'accounts'
* });
*
*
* let User = bookshelf.Model.extend({
*
*
* tableName: 'users',
*
*
* allAccounts: function () {
* return this.belongsToMany(Account);
* },
*
*
* adminAccounts: function() {
* return this.belongsToMany(Account).query({where: {access: 'admin'}});
* },
*
*
* viewAccounts: function() {
* return this.belongsToMany(Account).query({where: {access: 'readonly'}});
* }
*
* });
*
* });
*
* The default key names in the joining table are the singular versions of the
* model table names, followed by `_id` /
@@ -241,31 +241,31 @@ var BookshelfModel = _baseModel2['default'].extend({
* {@link Relation#through through} relation:
*
* let Doctor = bookshelf.Model.extend({
*
*
* patients: function() {
* return this.belongsToMany(Patient).through(Appointment);
* }
*
*
* });
*
*
* let Appointment = bookshelf.Model.extend({
*
*
* patient: function() {
* return this.belongsTo(Patient);
* },
*
*
* doctor: function() {
* return this.belongsTo(Doctor);
* }
*
*
* });
*
*
* let Patient = bookshelf.Model.extend({
*
*
* doctors: function() {
* return this.belongsToMany(Doctor).through(Appointment);
* }
*
*
* });
*
* @belongsTo Model
@@ -356,7 +356,7 @@ var BookshelfModel = _baseModel2['default'].extend({
* Model#morphOne morphOne}, but creating a {@link Collection collection}
* rather than a {@link Model model} (similar to a {@link Model#hasOne
* hasOne} vs. {@link Model#hasMany hasMany} relation).
*
*
* {@link Model#morphMany morphMany} is used to signify a {@link oneToMany
* one-to-many} or {@link manyToMany many-to-many} {@link polymorphicRelation
* polymorphic relation} with another `Target` model, where the `name` of the
@@ -425,7 +425,7 @@ var BookshelfModel = _baseModel2['default'].extend({
* return this.morphTo('imageable', ["ImageableType", "ImageableId"], Site, Post);
* }
* });
*
*
* @method Model#morphTo
*
* @param {string} name Prefix for `_id` and `_type` columns.
@@ -455,51 +455,51 @@ var BookshelfModel = _baseModel2['default'].extend({
* Helps to create dynamic relations between {@link Model models} and {@link
* Collection collections}, where a {@link Model#hasOne hasOne}, {@link
* Model#hasMany hasMany}, {@link Model#belongsTo belongsTo}, or {@link
* Model#belongsToMany belongsToMany} relation may run through a `JoinModel`.
* Model#belongsToMany belongsToMany} relation may run through a `JoinModel`.
*
* A good example of where this would be useful is if a book {@link
* Model#hasMany hasMany} paragraphs through chapters. Consider the following examples:
*
*
* let Book = bookshelf.Model.extend({
*
*
* tableName: 'books',
*
*
* // Find all paragraphs associated with this book, by
* // passing through the "Chapter" model.
* paragraphs: function() {
* return this.hasMany(Paragraph).through(Chapter);
* },
*
*
* chapters: function() {
* return this.hasMany(Chapter);
* }
*
*
* });
*
*
* let Chapter = bookshelf.Model.extend({
*
*
* tableName: 'chapters',
*
*
* paragraphs: function() {
* return this.hasMany(Paragraph);
* }
*
*
* });
*
*
* let Paragraph = bookshelf.Model.extend({
*
*
* tableName: 'paragraphs',
*
*
* chapter: function() {
* return this.belongsTo(Chapter);
* },
*
*
* // A reverse relation, where we can get the book from the chapter.
* book: function() {
* return this.belongsTo(Book).through(Chapter);
* }
*
*
* });
*
* The "through" table creates a pivot model, which it assigns to {@link
@@ -542,7 +542,7 @@ var BookshelfModel = _baseModel2['default'].extend({
/**
* Fetches a {@link Model model} from the database, using any {@link
* Model#attributes attributes} currently set on the model to form a `select`
* query.
* query.
*
* A {@link Model#fetching "fetching"} event will be fired just before the
* record is fetched; a good place to hook into for validation. {@link
@@ -551,7 +551,7 @@ var BookshelfModel = _baseModel2['default'].extend({
*
* If you need to constrain the query
* performed by fetch, you can call {@link Model#query query} before calling
* {@link Model#fetch fetch}.
* {@link Model#fetch fetch}.
*
* // select * from `books` where `ISBN-13` = '9780440180296'
* new Book({'ISBN-13': '9780440180296'})
@@ -573,7 +573,7 @@ var BookshelfModel = _baseModel2['default'].extend({
* loaded into a {@link Model#relations relations} property on the model, may
* be retrieved with the {@link Model#related related} method, and will be
* serialized as properties on a {@link Model#toJSON toJSON} call unless
* `{shallow: true}` is passed.
* `{shallow: true}` is passed.
*
* let Book = bookshelf.Model.extend({
* tableName: 'books',
@@ -584,7 +584,7 @@ var BookshelfModel = _baseModel2['default'].extend({
* return this.belongsTo(Genre);
* }
* })
*
*
* new Book({'ISBN-13': '9780440180296'}).fetch({
* withRelated: ['genre', 'editions']
* }).then(function(book) {
@@ -753,7 +753,7 @@ var BookshelfModel = _baseModel2['default'].extend({
* JSON.stringify(model);
* });
* });
*
*
* {
* title: 'post title',
* author: {...},
@@ -762,7 +762,7 @@ var BookshelfModel = _baseModel2['default'].extend({
* {tags: [...]}, {tags: [...]}
* ]
* }
*
*
* @param {string|string[]} relations The relation, or relations, to be loaded.
* @param {Object=} options Hash of options.
* @param {Transaction=} options.transacting
@@ -946,12 +946,18 @@ var BookshelfModel = _baseModel2['default'].extend({
}).then(function (resp) {

// After a successful database save, the id is updated if the model was created
if (method === 'insert' && this.id == null) {
this.attributes[this.idAttribute] = this.id = resp[0];
} else if (method === 'update' && resp === 0) {

// zube modifications. This allows us to return the full model attrs on save and update since we're using postgres.

if (method === 'update' && resp === 0) {
if (options.require !== false) {
throw new this.constructor.NoRowsUpdatedError('No Rows Updated');
}
} else {
var returningAttrs = resp[0];
this.attributes[this.idAttribute] = this.id = returningAttrs.id;
delete returningAttrs.id;
_lodash.extend(this.attributes, resp[0]);
}

// In case we need to reference the `previousAttributes` for the this
@@ -1060,7 +1066,7 @@ var BookshelfModel = _baseModel2['default'].extend({
* Destroyed event.
*
* Fired before a `delete` query. A promise may be returned from the event
* handler for async behaviour.
* handler for async behaviour.
*
* @event Model#destroyed
* @param {Model} model The model firing the event.
@@ -1102,19 +1108,19 @@ var BookshelfModel = _baseModel2['default'].extend({
* .then(function(model) {
* // ...
* });
*
*
* model
* .query({where: {other_id: '5'}, orWhere: {key: 'value'}})
* .fetch()
* .then(function(model) {
* // ...
* });
*
*
* model.query(function(qb) {
* qb.where('other_person', 'LIKE', '%Demo').orWhere('other_id', '>', 10);
* }).fetch()
* .then(function(model) { // ...
*
*
* let qb = model.query();
* qb.where({id: 1}).select().then(function(resp) { // ...
*
@@ -1258,4 +1264,4 @@ BookshelfModel.NotFoundError = _errors2['default'].NotFoundError;
BookshelfModel.NoRowsUpdatedError = _errors2['default'].NoRowsUpdatedError;
BookshelfModel.NoRowsDeletedError = _errors2['default'].NoRowsDeletedError;

module.exports = BookshelfModel;
module.exports = BookshelfModel;
9 changes: 6 additions & 3 deletions lib/sync.js
Original file line number Diff line number Diff line change
@@ -166,7 +166,9 @@ _.extend(Sync.prototype, {
// Issues an `insert` command on the query - only used by models.
insert: Promise.method(function () {
var syncing = this.syncing;
return this.query.insert(syncing.format(_.extend(Object.create(null), syncing.attributes)), syncing.idAttribute);

// zube modifications. We added returning * so all attrs are returned instead of just the id
return this.query.insert(syncing.format(_.extend(Object.create(null), syncing.attributes)), '*');
}),

// Issues an `update` command on the query - only used by models.
@@ -177,7 +179,8 @@ _.extend(Sync.prototype, {
if (_.where(query._statements, { grouping: 'where' }).length === 0) {
throw new Error('A model cannot be updated without a "where" clause or an idAttribute.');
}
return query.update(syncing.format(_.extend(Object.create(null), attrs)));
// zube modifications. We added returning * so all attrs are returned instead of none
return query.update(syncing.format(_.extend(Object.create(null), attrs)), '*');
}),

// Issues a `delete` command on the query.
@@ -193,4 +196,4 @@ _.extend(Sync.prototype, {

});

module.exports = Sync;
module.exports = Sync;