Reduce toJSON implementation: use the power of bookshelf (#9423)

refs #6103

- simplify `toJSON`
- `baseKey` was not used - have not find a single use case
- all the functionality of our `toJSON` is offered in bookshelf
- `omitPivot` does remove pivot elements from the JSON obj (bookshelf feature)
- `shallow` allows you to not return relations
- make use of `serialize`, see http://bookshelfjs.org/docs/src_base_model.js.html#line260
- fetching nested relations e.g. `users.roles` still works (unrelated to this refactoring)

> pick('shallow', 'baseKey', 'include', 'context')

We will re-add options validation in https://github.com/TryGhost/Ghost/pull/9427, but then with the official way: use `filterOptions`.

---

We return all fetched relations (pre-defined with `withRelated`) by default.
You can disable it with `shallow:true`.
This commit is contained in:
Katharina Irrgang 2018-02-14 17:32:11 +01:00 committed by GitHub
parent 58157b1411
commit 9ede5905f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 21 additions and 40 deletions

View File

@ -90,13 +90,7 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
// Bookshelf `initialize` - declare a constructor-like method for model creation
initialize: function initialize() {
var self = this,
options = arguments[1] || {};
// make options include available for toJSON()
if (options.include) {
this.include = _.clone(options.include);
}
var self = this;
[
'fetching',
@ -322,32 +316,20 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
return this.fixBools(this.fixDatesWhenFetch(attrs));
},
/**
* `shallow` - won't return relations
* `omitPivot` - won't return pivot fields
*
* `toJSON` calls `serialize`.
*
* @param options
* @returns {*}
*/
toJSON: function toJSON(options) {
var attrs = _.extend({}, this.attributes),
self = this;
options = options || {};
options = _.pick(options, ['shallow', 'baseKey', 'include', 'context']);
var opts = _.cloneDeep(options || {});
opts.omitPivot = true;
if (options && options.shallow) {
return attrs;
}
if (options && options.include) {
this.include = _.union(this.include, options.include);
}
_.each(this.relations, function each(relation, key) {
if (key.substring(0, 7) !== '_pivot_') {
// if include is set, expand to full object
var fullKey = _.isEmpty(options.baseKey) ? key : options.baseKey + '.' + key;
if (_.includes(self.include, fullKey)) {
attrs[key] = relation.toJSON(_.extend({}, options, {baseKey: fullKey, include: self.include}));
}
}
});
// @TODO upgrade bookshelf & knex and use serialize & toJSON to do this in a neater way (see #6103)
return proto.finalize.call(this, attrs);
return proto.toJSON.call(this, opts);
},
// Get attributes that have been updated (values before a .save() call)
@ -605,8 +587,7 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
data = this.filterData(data);
options = this.filterOptions(options, 'findOne');
// We pass include to forge so that toJSON has access
return this.forge(data, {include: options.include}).fetch(options);
return this.forge(data).fetch(options);
},
/**

View File

@ -41,7 +41,7 @@ Invite = ghostBookshelf.Model.extend({
data = this.filterData(data, 'findOne');
options.withRelated = _.union(options.withRelated, options.include);
var invite = this.forge(data, {include: options.include});
var invite = this.forge(data);
return invite.fetch(options);
},

View File

@ -84,8 +84,10 @@ module.exports = function (Bookshelf) {
return modelProto.fetchAll.apply(this, arguments);
},
finalize: function (attrs) {
var countRegex = /^(count)(__)(.*)$/;
serialize: function serialize(options) {
var attrs = modelProto.serialize.call(this, options),
countRegex = /^(count)(__)(.*)$/;
_.forOwn(attrs, function (value, key) {
var match = key.match(countRegex);
if (match) {

View File

@ -384,14 +384,12 @@ User = ghostBookshelf.Model.extend({
options.withRelated = _.union(options.withRelated, ['roles']);
options.include = _.union(options.include, ['roles']);
query = this.forge(data, {include: options.include});
query = this.forge(data);
query.query('join', 'roles_users', 'users.id', '=', 'roles_users.user_id');
query.query('join', 'roles', 'roles_users.role_id', '=', 'roles.id');
query.query('where', 'roles.name', '=', lookupRole);
} else {
// We pass include to forge so that toJSON has access
query = this.forge(data, {include: options.include});
query = this.forge(data);
}
if (status === 'active') {