UNPKG

sails-hook-orm

Version:

The ORM hook from Sails core.

140 lines (108 loc) 6.06 kB
/** * Module dependencies */ var util = require('util'); var _ = require('@sailshq/lodash'); var Waterline = require('waterline'); var WaterlineUtils = require('waterline-utils'); /** * buildOntologyAndRunAutoMigrations() * * Instantiate a "live" Waterline model instance for each Sails * model definition, then tell Waterline to initialize the ORM * and trigger the callback with that fresh new Waterline ontology. * Finally, run auto-migrations. * * @required {Dictionary} hook * @required {SailsApp} sails * @required {Function} done * @param {Error?} err * @param {===} freshOntology [a freshly initialized ontology from Waterline] */ module.exports = function buildOntologyAndRunAutoMigrations(hook, sails, done) { // This variable is used below to hold a fresh ORM instance. var orm; try { sails.log.silly('Starting ORM...'); // First, instantiate a fresh, empty Waterline ORM instance. orm = Waterline(); // Next, iterate through each normalized model definition and register it with Waterline // (using the `loadCollection()` method). _.each(hook.models, function _loadEachModelDefIntoWaterline(normalizedModelDef, identity) { // Create a Waterline "Collection" instance for each model, then register it w/ the ORM. sails.log.silly('Registering model `%s` in Waterline', identity); orm.registerModel(Waterline.Model.extend(normalizedModelDef)); }); } catch (e) { return done(e); } // Save a private reference to the Waterline `orm` instance. hook._orm = orm; // Now, tell Waterline to initialize the ORM by calling its `.initialize()` method. // This performs tasks like interpretating the physical-layer schema, validating associations, // hooking up models to their datastores (fka "connections"), and performing auto-migrations. orm.initialize({ // Pass in the app's known adapters. adapters: hook.adapters, // We build and pass in a dictionary of normalized datastore configurations (fka connections) // which _are actually in use_ (this is to avoid unnecessary work in Waterline). datastores: hook.normalizedDSConfigs, // e.g. // ``` // { default: { schema: false, filePath: '.tmp/', adapter: 'sails-disk' } } // ``` // `defaults` are a set of default properties for every model definition. // They are defined in `sails.config.models`. // Note that the ORM hook takes care of this to some degree, but we also pass them in here. // This may change in future versions of Sails. defaults: sails.config.models }, function _afterInitializingWaterline (err, freshOntology) { if (err) { return done(err); } if (!_.isObject(freshOntology.collections) || _.isArray(freshOntology.collections) || _.isFunction(freshOntology.collections)) { // Note that prior to March 2016, the second arg of the callback was used instead of relying on the existing `freshOntology` we already // have instantiated above (however we've always _sent back_ the existing `freshOntology`-- we just used to use the second arg of the callback // for the set of collections) return done(new Error('Consistency violation: Expected `collections` property of ontology instance returned from Waterline to be a dictionary.\nInstead, here is what the ontology instance looks like:\n'+(util.inspect(freshOntology,{depth:null})))); } try { // Now that `waterline-schema` has validated that all of our associations are valid, // loop through each model again to set the correct `columnType` for each singular association. _.each(freshOntology.collections, function eachModel(WLModel) { // Loop through the normalized model and set a column type for each attribute _.each(WLModel.attributes, function eachAttribute(attrDef, attrName) { // If this attribute is a plural association, or not an association at all, skip it. if (!attrDef.model) { return; } // Otherwise, this is a singular association. // // Find out the column type of the primary key attribute of the associated model // so that we can use it as the column type of this singular association. // (This is for the purpose of automigrations.) var otherModelIdentity = attrDef.model; var otherWLModel = hook.models[otherModelIdentity]; var associatedPKAttrName = otherWLModel.primaryKey; var associatedPKAttrDef = otherWLModel.attributes[associatedPKAttrName]; var derivedColumnType = associatedPKAttrDef.autoMigrations.columnType; // Set the column type, mutating our WLModel inline. // > Also set the column type within the `schema` attrDef.autoMigrations.columnType = derivedColumnType; WLModel.schema[attrName].autoMigrations.columnType = derivedColumnType; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // FUTURE: remove the necessity for this last step by doing away with // `schema` and having everything simply edit the WLModel inline. // (^this depends on changes in Waterline core) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - });//</each attribute> });//</each model> } catch (e) { return done(e); } // If we don't have a global `migrate` setting at this point, it's because we don't // have any models (so the end user wasn't forced to choose a setting on lift). // So we can just skip migrations and return. if (!sails.config.models.migrate) { return done(undefined, freshOntology); } // Now that all relevant attributes have `autoMigrations` properties set, go ahead // and perform any requested migrations. WaterlineUtils.autoMigrations(sails.config.models.migrate, freshOntology, function(err) { if (err) { return done(err); } return done(undefined, freshOntology); }); });//</waterline.initialize()> };