UNPKG

water-orm

Version:

A monolith version of Standalone waterline ORM

169 lines (130 loc) 6.14 kB
/** * Module dependencies */ var _ = require('lodash'); var async = require('async'); var normalize = require('../../../utils/normalize'); var hasOwnProperty = require('../../../utils/helpers').object.hasOwnProperty; //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /** * NOTICE: * * This module is not currently being used. * Instead, a development-only solution is implemented in `ddl.js.` * Auto-migrations for production, that carefully backup data, * would be a great addition in the future, but must be carefully * evaluated, and probably should not be part of this core Waterline * module. */ //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /** * alter * * Default definition of `alter` functionality in an adapter. * Compare physical (original) attributes with specified new schema, * and change the physical layer accordingly. */ module.exports = function(cb) { // The collection we're working with var collectionID = this.collection; // Normalize Arguments cb = normalize.callback(cb); // Remove hasMany association keys before sending down to adapter var schema = _.clone(this.query._schema.schema) || {}; Object.keys(schema).forEach(function(key) { if (schema[key].type) return; delete schema[key]; }); // Check if the adapter defines an alter method, if so // go ahead and use that, passing down the new schema. if (hasOwnProperty(this.dictionary, 'alter')) { var connName = this.dictionary.alter; var adapter = this.connections[connName]._adapter; if (hasOwnProperty(adapter, 'alter')) { return adapter.alter(connName, collectionID, schema, cb); } } // Check if an addAttribute and removeAttribute adapter method are defined if (!hasOwnProperty(this.dictionary, 'addAttribute') || !hasOwnProperty(this.dictionary, 'removeAttribute')) { return cb(); // return cb(new Error('Both addAttribute() and removeAttribute() methods are required to use alter()')); } // Find the relevant connections to run this on var AdderConnection = this.dictionary.addAttribute; var RemoverConnection = this.dictionary.removeAttribute; // Find the relevant adapters to run this with var AdderAdapter = this.connections[AdderConnection]._adapter; var RemoverAdapter = this.connections[RemoverConnection]._adapter; if (!hasOwnProperty(AdderAdapter, 'addAttribute')) return cb(new Error('Adapter is missing an addAttribute() method')); if (!hasOwnProperty(RemoverAdapter, 'removeAttribute')) return cb(new Error('Adapter is missing a removeAttribute() method')); this.describe(function afterDescribe(err, originalAttributes) { if (err) return cb(err); // Iterate through each attribute in the new definition // Used for keeping track of previously undefined attributes // when updating the data stored at the physical layer. var newAttributes = _.reduce(schema, function checkAttribute(newAttributes, attribute, attrName) { if (!originalAttributes[attrName]) { newAttributes[attrName] = attribute; } return newAttributes; }, {}); // Iterate through physical columns in the database // Used for keeping track of no-longer-existent attributes. // These must be removed from the physical (original) database. var deprecatedAttributes = _.reduce(originalAttributes, function(deprecatedAttributes, attribute, attrName) { if (!schema[attrName]) { deprecatedAttributes[attrName] = attribute; } return deprecatedAttributes; }, {}); // Iterate through physical columns in the database // Used for keeping track of attributes which are now different // than their physical layer equivalents. var diff = _.reduce(originalAttributes, function(diff, attribute, attrName) { // Bail out if the attribute is no longer in the app-level schema if (!schema[attrName]) { return diff; } // var hasChanged = _.diff(schema[attrName], originalAttributes[attrName]); var hasChanged = false; // // TODO: // implement this! (note: it's not particularly easy) // // Probably not something that should be done in core. // console.log('\n\n************* ' + collectionID + '.' + attrName + ' ****************'); console.log('new: ', schema[attrName]); console.log('orig: ', originalAttributes[attrName]); if (hasChanged) { diff[attrName] = schema[attrName]; } return diff; }, {}); async.auto({ newAttributes: function(done_newAttributes) { async.eachSeries(_.keys(newAttributes), function(attrName, nextAttr_) { var attrDef = newAttributes[attrName]; AdderAdapter.addAttribute(AdderConnection, collectionID, attrName, attrDef, nextAttr_); }, done_newAttributes); }, deprecatedAttributes: function(done_deprecatedAttributes) { async.eachSeries(_.keys(deprecatedAttributes), function(attrName, nextAttr_) { RemoverAdapter.removeAttribute(RemoverConnection, collectionID, attrName, nextAttr_); }, done_deprecatedAttributes); }, modifiedAttributes: function(done_modifiedAttributes) { done_modifiedAttributes(); } }, cb); // // Should we update the data belonging to this attribute to reflect the new properties? // Realistically, this will mainly be about constraints, and primarily uniquness. // It'd be good if waterline could enforce all constraints at this time, // but there's a trade-off with destroying people's data // TODO: Figure this out // }); };