mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-21 09:52:06 +03:00
c0baf5fdee
no issue - `formatOnWrite` doesn't override anything in Bookshelf but we use it within the `override` plugin and sub-models may override it, so it's easier to keep these things together
95 lines
3.6 KiB
JavaScript
95 lines
3.6 KiB
JavaScript
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;
|
|
},
|
|
|
|
// overridable function for models to format attrs only when saving to db
|
|
// this function doesn't override anything in Bookshelf but we use this in
|
|
// this plugin and sub-models may override it, so it's easier to keep it in here
|
|
formatOnWrite: function formatOnWrite(attrs) {
|
|
return attrs;
|
|
},
|
|
|
|
// 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);
|
|
}
|
|
});
|
|
};
|