Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set model.id if attributes contain a parsed version of idAttribute #1760

Merged
merged 2 commits into from
Feb 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions src/base/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,20 @@ ModelBase.prototype.initialize = function() {};
*
* This tells the model which attribute to expect as the unique identifier
* for each database row (typically an auto-incrementing primary key named
* `"id"`). Note that if you are using {@link Model#parse parse} and {@link
* `'id'`). Note that if you are using {@link Model#parse parse} and {@link
* Model#format format} (to have your model's attributes in `camelCase`,
* but your database's columns in `snake_case`, for example) this refers to
* the name returned by parse (`myId`), not the database column (`my_id`).
* the name returned by parse (`myId`), not the actual database column
* (`my_id`).
*
* If the table you're working with does not have an Primary-Key in the form
* of a single column - you'll have to override it with a getter that returns
* null. (overriding with undefined does not cascade the default behavior of
* the value `'id'`.
* Such a getter in ES6 would look like `get idAttribute() { return null }`
* You can also get the parsed id attribute value by using the model's
* {@link Model#parsedIdAttribute parsedIdAttribute} method.
*
* If the table you're working with does not have a Primary-Key in the form
* of a single column you'll have to override it with a getter that returns
* `null`. Overriding with `undefined` does not cascade the default behavior of
* the value `'id'`. Such a getter in ES6 would look like
* `get idAttribute() { return null }`.
*/
ModelBase.prototype.idAttribute = 'id';

Expand Down Expand Up @@ -157,6 +161,34 @@ ModelBase.prototype.get = function(attr) {
return this.attributes[attr];
};

/**
* @method
* @description
*
* Returns the model's {@link Model#idAttribute idAttribute} after applying the
* model's {@link Model#parse parse} method to it. Doesn't mutate the original
* value of {@link Model#idAttribute idAttribute} in any way.
*
* @example
*
* var Customer = bookshelf.Model.extend({
* idAttribute: 'id',
* parse: function(attrs) {
* return _.mapKeys(attrs, function(value, key) {
* return 'parsed_' + key;
* });
* }
* });
*
* customer.parsedIdAttribute() // 'parsed_id'
*
* @returns {mixed} Whatever value the parse method returns.
*/
ModelBase.prototype.parsedIdAttribute = function() {
var parsedAttributes = this.parse({[this.idAttribute]: null})
return parsedAttributes && Object.keys(parsedAttributes)[0]
}

/**
* @method
* @description Set a hash of attributes (one or many) on the model.
Expand Down Expand Up @@ -190,7 +222,10 @@ ModelBase.prototype.set = function(key, val, options) {
const prev = this._previousAttributes;

// Check for changes of `id`.
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
if (this.idAttribute in attrs)
this.id = attrs[this.idAttribute];
else if (this.parsedIdAttribute() in attrs)
this.id = attrs[this.parsedIdAttribute()];

// For each `set` attribute, update or delete the current value.
for (const attr in attrs) {
Expand Down
16 changes: 15 additions & 1 deletion test/integration/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ module.exports = function(bookshelf) {
});
});

describe('id, idAttribute', function() {
describe('#id, #idAttribute', function() {
it('should attach the id as a property on the model', function() {
var test = new bookshelf.Model({id: 1});
equal(test.id, 1);
Expand All @@ -141,6 +141,20 @@ module.exports = function(bookshelf) {

equal(test.id, 2);
});

it('#id should be set when model has custom parse method', function() {
var TestModel = bookshelf.Model.extend({
idAttribute: 'test_id',
parse: function(attrs) {
return _.mapKeys(attrs, function(val, key) {
return _.camelCase(key);
});
}
});
var test = new TestModel({test_id: 2}, {parse: true});

equal(test.id, 2);
});
});

describe('query', function() {
Expand Down