UNPKG

@balderdash/sails-edge

Version:

API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)

229 lines (195 loc) 8.49 kB
var _ = require('lodash'); var async = require('async'); var prompt = require('prompt'); var howto_loadAppModelsAndAdapters = require('./load-user-modules'); var howto_normalizeModelDef = require('./normalize-model'); var howto_buildORM = require('./build-orm'); var howto_backwardsCompatibleConfig = require('./backwards-compatibility/upgrade-sails.config'); var howto_backwardsCompatibleDatastore = require('./backwards-compatibility/upgrade-datastore'); module.exports = function(sails) { // Hydrate freeze-dried (context-free) modules using the sails app instance var loadAppModelsAndAdapters = howto_loadAppModelsAndAdapters(sails); var backwardsCompatibleConfig = howto_backwardsCompatibleConfig(sails); var normalizeModelDef = howto_normalizeModelDef(sails); var buildORM = howto_buildORM(sails); /** * Hook definition */ var hook = { defaults: { globals: { adapters: true, models: true }, // Default model properties models: { // This default connection (i.e. datasource) for the app // will be used for each model unless otherwise specified. connection: 'localDiskDb' }, // Connections to data sources, web services, and external APIs. // Can be attached to models and/or accessed directly. connections: { // Built-in disk persistence // (by default, creates the file: `.tmp/localDiskDb.db`) localDiskDb: { adapter: 'sails-disk' } } }, configure: function() { sails.models || (sails.models = { }); // Backwards compatibilty sails.config = backwardsCompatibleConfig(sails.config); // Listen for reload events sails.on('hook:orm:reload', hook.reload); // Listen for lower event, and tear down all of the adapters sails.once('lower', hook.teardown); }, //////////////////////////////////////////////////////////////////////////// // NOTE: If a user hook needs to add or modify model definitions, // the hook should wait until `hook:orm:loaded`, then reload the original // model modules `orm/loadUserModules`. Finally, the ORM should be flushed using // `reload()` below. //////////////////////////////////////////////////////////////////////////// initialize: function(cb) { var backwardsCompatibleDatastore = howto_backwardsCompatibleDatastore(sails); async.auto({ // Load model and adapter definitions defined in the project _loadModules: function (next) { loadAppModelsAndAdapters(next); }, // Load any adapters for connections with "forceLoadAdapter" forceLoadAdapters: function(next) { _.each(sails.config.connections, function(connection, connectionId) { if (connection.forceLoadAdapter) { backwardsCompatibleDatastore(connectionId, '<FORCE>'); } }); return next(); }, // Normalize model definitions and merge in defaults from // `sails.config.models.*` normalizedModelDefs: ['_loadModules', function normalizeModelDefs(next) { _.each(sails.models, function (model, identity) { normalizeModelDef(model, identity); }); next(null, sails.models); }], // Before continuing any further to actually start up the ORM, // check the migrate settings for each model to (1) use migrate:safe // in production and (2) prompt the user to make a decision if no migrate // configuration is present. _doubleCheckMigration: ['normalizedModelDefs', function (next) { // If there are no models, we're good if (!_.keys(sails.models).length) { return next(); } // If a project-wide migrate setting (sails.config.models.migrate) is defined, we're good. if (typeof sails.config.models.migrate !== 'undefined') { return next(); } // Otherwise show a prompt console.log('-----------------------------------------------------------------'); console.log(); prompt.start(); console.log('', 'Excuse my interruption, but it looks like this app'+'\n', 'does not have a project-wide "migrate" setting configured yet.'+'\n', '(perhaps this is the first time you\'re lifting it with models?)'+'\n', '\n', 'In short, this setting controls whether/how Sails will attempt to automatically'+'\n', 'rebuild the tables/collections/sets/etc. in your database schema.\n', 'You can read more about the "migrate" setting here:'+'\n', 'http://sailsjs.org/#!/documentation/concepts/ORM/model-settings.html?q=migrate\n' // 'command(⌘)+click to open links in the terminal' ); console.log('', 'In a production environment (NODE_ENV==="production") Sails always uses'+'\n', 'migrate:"safe" to protect inadvertent deletion of your data.\n', 'However during development, you have a few other options for convenience:'+'\n\n', '1. safe - never auto-migrate my database(s). I will do it myself (by hand)','\n', '2. alter - auto-migrate, but attempt to keep my existing data (experimental)\n', '3. drop - wipe/drop ALL my data and rebuild models every time I lift Sails\n' ); console.log('What would you like Sails to do?'); console.log(); sails.log.info('To skip this prompt in the future, set `sails.config.models.migrate`.'); sails.log.info('(conventionally, this is done in `config/models.js`)'); console.log(); sails.log.warn('** DO NOT CHOOSE "2" or "3" IF YOU ARE WORKING WITH PRODUCTION DATA **'); console.log(); prompt.get(['?'], function(err, result) { if (err) return next(err); result = result['?']; switch (result) { case 'alter': case '2': sails.config.models.migrate = 'alter'; break; case 'drop': case '3': sails.config.models.migrate = 'drop'; break; default: sails.config.models.migrate = 'safe'; break; } console.log(); console.log(' Temporarily using `sails.config.models.migrate="%s"...', sails.config.models.migrate); console.log(' (press CTRL+C to cancel-- continuing lift automatically in 0.5 seconds...)'); console.log(); setTimeout(function (){ return next(); },600); }); }], // Once all user model and adapter definitions are loaded // and normalized, go ahead and initialize the ORM, which // creates instantiated model objects and stuffs them in // sails.models. instantiatedCollections: ['_doubleCheckMigration', function (next, async_data) { buildORM(async_data.normalizedModelDefs, next); }] }, cb); }, // Reload ORM hook // (which mostly just runs the hook's `initialize()` fn again) reload: function () { // Teardown all of the adapters, since initialize() will restart them hook.teardown(function() { hook.initialize(function(err) { if (err) { sails.log.error('Failed to reinitialize ORM.'); sails.log.error(err); // TODO: emit "error" on app instance instead of throwing throw new Error(err); } else { // If the re-initialization was a success, trigger an event // in case something needs to respond to the ORM reload (e.g. pubsub hook) sails.emit('hook:orm:reloaded'); } }); }); }, // Teardown ORM hook teardown: function (cb) { cb = cb || function(err) { if (err) { sails.log.error('Failed to teardown ORM hook.'); sails.log.error(err); } }; async.forEach(Object.keys(sails.adapters || {}), function(name, next) { var adapter = sails.adapters[name]; if (adapter.teardown) { adapter.teardown(null, next); } else { next(); } }, cb); } }; return hook; };