mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Extracted Bookshelf method overrides to plugin
no issue - all these functions override those within Bookshelf so this commit extracts them into a separate plugin from the Base model
This commit is contained in:
parent
bab12ca3d1
commit
a622f44564
3 changed files with 90 additions and 82 deletions
|
@ -62,6 +62,8 @@ ghostBookshelf.plugin(require('./plugins/user-type'));
|
|||
|
||||
ghostBookshelf.plugin(require('./plugins/data-manipulation'));
|
||||
|
||||
ghostBookshelf.plugin(require('./plugins/overrides'));
|
||||
|
||||
// Manages nested updates (relationships)
|
||||
ghostBookshelf.plugin('bookshelf-relations', {
|
||||
allowedOptions: ['context', 'importing', 'migrating'],
|
||||
|
|
|
@ -6,18 +6,14 @@
|
|||
// accesses the models directly.
|
||||
|
||||
// All other parts of Ghost, including the frontend & admin UI are only allowed to access data via the API.
|
||||
const _ = require('lodash');
|
||||
|
||||
const moment = require('moment');
|
||||
const ObjectId = require('bson-objectid');
|
||||
const schema = require('../../data/schema');
|
||||
|
||||
const ghostBookshelf = require('./bookshelf');
|
||||
|
||||
let proto;
|
||||
|
||||
// Cache an instance of the base model prototype
|
||||
proto = ghostBookshelf.Model.prototype;
|
||||
const proto = ghostBookshelf.Model.prototype;
|
||||
|
||||
// ## ghostBookshelf.Model
|
||||
// The Base Model which other Ghost objects will inherit from,
|
||||
|
@ -51,88 +47,11 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
|
|||
proto.initialize.call(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Bookshelf's .format() is run when fetching as well as saving.
|
||||
* We need a way to transform attributes only on save so we override
|
||||
* .sync() which is run on every database operation where we can
|
||||
* run any transforms needed only on insert and update operations
|
||||
*/
|
||||
sync: function sync() {
|
||||
const parentSync = proto.sync.apply(this, arguments);
|
||||
const originalUpdateSync = parentSync.update;
|
||||
const originalInsertSync = parentSync.insert;
|
||||
const self = this;
|
||||
|
||||
// deep clone attrs to avoid modifying underlying model attributes by reference
|
||||
parentSync.update = function update(attrs) {
|
||||
attrs = self.formatOnWrite(_.cloneDeep(attrs));
|
||||
return originalUpdateSync.apply(this, [attrs]);
|
||||
};
|
||||
|
||||
parentSync.insert = function insert(attrs) {
|
||||
attrs = self.formatOnWrite(_.cloneDeep(attrs));
|
||||
return originalInsertSync.apply(this, [attrs]);
|
||||
};
|
||||
|
||||
return parentSync;
|
||||
},
|
||||
|
||||
// format date before writing to DB, bools work
|
||||
format: function format(attrs) {
|
||||
return this.fixDatesWhenSave(attrs);
|
||||
},
|
||||
|
||||
// overridable function for models to format attrs only when saving to db
|
||||
formatOnWrite: function formatOnWrite(attrs) {
|
||||
return attrs;
|
||||
},
|
||||
|
||||
// format data and bool when fetching from DB
|
||||
parse: function parse(attrs) {
|
||||
return this.fixBools(this.fixDatesWhenFetch(attrs));
|
||||
},
|
||||
|
||||
/**
|
||||
* `shallow` - won't return relations
|
||||
* `omitPivot` - won't return pivot fields
|
||||
*
|
||||
* `toJSON` calls `serialize`.
|
||||
*
|
||||
* @param unfilteredOptions
|
||||
* @returns {*}
|
||||
*/
|
||||
toJSON: function toJSON(unfilteredOptions) {
|
||||
const options = ghostBookshelf.Model.filterOptions(unfilteredOptions, 'toJSON');
|
||||
options.omitPivot = true;
|
||||
|
||||
/**
|
||||
* removes null relations coming from `hasOne` - https://bookshelfjs.org/api.html#Model-instance-hasOne
|
||||
* Based on https://github.com/bookshelf/bookshelf/issues/72#issuecomment-25164617
|
||||
*/
|
||||
_.each(this.relations, (value, key) => {
|
||||
if (_.isEmpty(value)) {
|
||||
delete this.relations[key];
|
||||
}
|
||||
});
|
||||
// CASE: get JSON of previous attrs
|
||||
if (options.previous) {
|
||||
const clonedModel = _.cloneDeep(this);
|
||||
clonedModel.attributes = this._previousAttributes;
|
||||
|
||||
if (this.relationships) {
|
||||
this.relationships.forEach((relation) => {
|
||||
if (this._previousRelations && Object.prototype.hasOwnProperty.call(this._previousRelations, relation)) {
|
||||
clonedModel.related(relation).models = this._previousRelations[relation].models;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return proto.toJSON.call(clonedModel, options);
|
||||
}
|
||||
|
||||
return proto.toJSON.call(this, options);
|
||||
},
|
||||
|
||||
hasDateChanged: function (attr) {
|
||||
return moment(this.get(attr)).diff(moment(this.previous(attr))) !== 0;
|
||||
},
|
||||
|
|
87
core/server/models/base/plugins/overrides.js
Normal file
87
core/server/models/base/plugins/overrides.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
const _ = require('lodash');
|
||||
|
||||
/**
|
||||
* @param {import('bookshelf')} Bookshelf
|
||||
*/
|
||||
module.exports = function (Bookshelf) {
|
||||
const ParentModel = Bookshelf.Model;
|
||||
|
||||
Bookshelf.Model = Bookshelf.Model.extend({
|
||||
/**
|
||||
* Bookshelf's .format() is run when fetching as well as saving.
|
||||
* We need a way to transform attributes only on save so we override
|
||||
* .sync() which is run on every database operation where we can
|
||||
* run any transforms needed only on insert and update operations
|
||||
*/
|
||||
sync: function sync() {
|
||||
const parentSync = ParentModel.prototype.sync.apply(this, arguments);
|
||||
const originalUpdateSync = parentSync.update;
|
||||
const originalInsertSync = parentSync.insert;
|
||||
const self = this;
|
||||
|
||||
// deep clone attrs to avoid modifying underlying model attributes by reference
|
||||
parentSync.update = function update(attrs) {
|
||||
attrs = self.formatOnWrite(_.cloneDeep(attrs));
|
||||
return originalUpdateSync.apply(this, [attrs]);
|
||||
};
|
||||
|
||||
parentSync.insert = function insert(attrs) {
|
||||
attrs = self.formatOnWrite(_.cloneDeep(attrs));
|
||||
return originalInsertSync.apply(this, [attrs]);
|
||||
};
|
||||
|
||||
return parentSync;
|
||||
},
|
||||
|
||||
// format date before writing to DB, bools work
|
||||
format: function format(attrs) {
|
||||
return this.fixDatesWhenSave(attrs);
|
||||
},
|
||||
|
||||
// format data and bool when fetching from DB
|
||||
parse: function parse(attrs) {
|
||||
return this.fixBools(this.fixDatesWhenFetch(attrs));
|
||||
},
|
||||
|
||||
/**
|
||||
* `shallow` - won't return relations
|
||||
* `omitPivot` - won't return pivot fields
|
||||
*
|
||||
* `toJSON` calls `serialize`.
|
||||
*
|
||||
* @param unfilteredOptions
|
||||
* @returns {*}
|
||||
*/
|
||||
toJSON: function toJSON(unfilteredOptions) {
|
||||
const options = Bookshelf.Model.filterOptions(unfilteredOptions, 'toJSON');
|
||||
options.omitPivot = true;
|
||||
|
||||
/**
|
||||
* removes null relations coming from `hasOne` - https://bookshelfjs.org/api.html#Model-instance-hasOne
|
||||
* Based on https://github.com/bookshelf/bookshelf/issues/72#issuecomment-25164617
|
||||
*/
|
||||
_.each(this.relations, (value, key) => {
|
||||
if (_.isEmpty(value)) {
|
||||
delete this.relations[key];
|
||||
}
|
||||
});
|
||||
// CASE: get JSON of previous attrs
|
||||
if (options.previous) {
|
||||
const clonedModel = _.cloneDeep(this);
|
||||
clonedModel.attributes = this._previousAttributes;
|
||||
|
||||
if (this.relationships) {
|
||||
this.relationships.forEach((relation) => {
|
||||
if (this._previousRelations && Object.prototype.hasOwnProperty.call(this._previousRelations, relation)) {
|
||||
clonedModel.related(relation).models = this._previousRelations[relation].models;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return ParentModel.prototype.toJSON.call(clonedModel, options);
|
||||
}
|
||||
|
||||
return ParentModel.prototype.toJSON.call(this, options);
|
||||
}
|
||||
});
|
||||
};
|
Loading…
Add table
Reference in a new issue