// # Base Model // This is the model from which all other Ghost models extend. The model is based on Bookshelf.Model, and provides // several basic behaviours such as UUIDs, as well as a set of Data methods for accessing information from the database. // // The models are internal to Ghost, only the API and some internal functions such as migration and import/export // accesses the models directly. // All other parts of Ghost, including the frontend & admin UI are only allowed to access data via the API. const moment = require('moment'); const ObjectId = require('bson-objectid'); const schema = require('../../data/schema'); const ghostBookshelf = require('./bookshelf'); // Cache an instance of the base model prototype const proto = ghostBookshelf.Model.prototype; // ## ghostBookshelf.Model // The Base Model which other Ghost objects will inherit from, // including some convenience functions as static properties on the model. ghostBookshelf.Model = ghostBookshelf.Model.extend({ // Bookshelf `hasTimestamps` - handles created_at and updated_at properties hasTimestamps: true, // https://github.com/bookshelf/bookshelf/commit/a55db61feb8ad5911adb4f8c3b3d2a97a45bd6db parsedIdAttribute: function () { return false; }, // Ghost ordering handling, allows to order by permitted attributes by default and can be overriden on specific model level orderAttributes: function orderAttributes() { return Object.keys(schema.tables[this.tableName]) .map(key => `${this.tableName}.${key}`) .filter(key => key.indexOf('@@') === -1); }, // When loading an instance, subclasses can specify default to fetch defaultColumnsToFetch: function defaultColumnsToFetch() { return []; }, // Bookshelf `initialize` - declare a constructor-like method for model creation initialize: function initialize() { this.initializeEvents(); // @NOTE: Please keep here. If we don't initialize the parent, bookshelf-relations won't work. proto.initialize.call(this); }, // overridable function for models to format attrs only when saving to db formatOnWrite: function formatOnWrite(attrs) { return attrs; }, hasDateChanged: function (attr) { return moment(this.get(attr)).diff(moment(this.previous(attr))) !== 0; }, /** * we auto generate a GUID for each resource * no auto increment */ setId: function setId() { this.set('id', ObjectId().toHexString()); }, wasChanged() { /** * @NOTE: * Not every model & interaction is currently set up to handle "._changed". * e.g. we trigger a manual event for "tag.attached", where as "._changed" is undefined. * * Keep "true" till we are sure that "._changed" is always a thing. */ if (!this._changed) { return true; } if (!Object.keys(this._changed).length) { return false; } return true; } }); // Export ghostBookshelf for use elsewhere module.exports = ghostBookshelf;