sails-hook-orm
Version:
The ORM hook from Sails core.
120 lines (96 loc) • 6.01 kB
JavaScript
/**
* Module dependencies
*/
var _ = require('@sailshq/lodash');
var unrecognizedDatastoreError = require('../constants/unrecognized-datastore.error');
var invalidDatastoreError = require('../constants/invalid-datastore.error');
var constructError = require('./construct-error');
var validateAdapter = require('./validate-adapter');
/**
* validateDatastoreConfig()
*
* Normalize and validate the provided datastore (fka "connection") configuration.
*
* @required {String} datastoreIdentity [f.k.a. "connection" identity]
* @required {Dictionary} hook
* @required {SailsApp} sails
*
* @returns {Dictionary} [datastore/connection]
* @throws {Error} E_ADAPTER_NOT_COMPATIBLE
* @throws {Error} E_ADAPTER_NOT_INSTALLED
* @throws {Error} E_COULD_NOT_LOAD_ADAPTER
* @throws {Error} E_UNRECOGNIZED_DATASTORE
* @throws {Error} E_INVALID_DATASTORE
*/
module.exports = function validateDatastoreConfig(datastoreIdentity, hook, sails){
// ╔═╗╔═╗╦═╗╔═╗╔═╗╦═╗╔╦╗ ╔╗ ╔═╗╔═╗╦╔═╗ ╦ ╦╔═╗╦ ╦╔╦╗╔═╗╔╦╗╦╔═╗╔╗╔
// ╠═╝║╣ ╠╦╝╠╣ ║ ║╠╦╝║║║ ╠╩╗╠═╣╚═╗║║ ╚╗╔╝╠═╣║ ║ ║║╠═╣ ║ ║║ ║║║║
// ╩ ╚═╝╩╚═╚ ╚═╝╩╚═╩ ╩ ╚═╝╩ ╩╚═╝╩╚═╝ ╚╝ ╩ ╩╩═╝╩═╩╝╩ ╩ ╩ ╩╚═╝╝╚╝
// ┌─ ┌─┐┌─┐ ┌┬┐┌─┐┌┬┐┌─┐┌─┐┌┬┐┌─┐┬─┐┌─┐ ┌─┐┌─┐┌┐┌┌─┐┬┌─┐ ─┐
// │───│ │├┤ ││├─┤ │ ├─┤└─┐ │ │ │├┬┘├┤ │ │ ││││├┤ ││ ┬───│
// └─ └─┘└ ─┴┘┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘┴└─└─┘ └─┘└─┘┘└┘└ ┴└─┘ ─┘
// If the specified datastore configuration has not been specified, then throw a fatal error.
var datastoreConfig = sails.config.datastores[datastoreIdentity];
if (!datastoreConfig) {
throw constructError(unrecognizedDatastoreError, {
datastoreIdentity: datastoreIdentity
});
}
var adapterIdentity;
// If `adapter` property of the datastore is a dictionary, then assume
// that this is an inline adapter definition (e.g. `require('sails-mysql')`).
if (_.isObject(datastoreConfig.adapter)) {
// The adapter must have an identity (e.g. `sails-mongo`).
if (!datastoreConfig.adapter.identity) {
throw new Error('Consistency violation: the adapter for datastore `' + datastoreIdentity + '` does not have an `identity` property.');
}
// Adapter identities must be unique.
if (hook.adapters[datastoreConfig.adapter.identity] && hook.adapters[datastoreConfig.adapter.identity] !== datastoreConfig.adapter) {
throw new Error('Consistency violation: attempted to load two different data adapters with the identity `' + datastoreConfig.adapter.identity + '`.');
}
// Shortcut reference to the adapter's identity.
adapterIdentity = datastoreConfig.adapter.identity;
// Then we'll validate our inline adapter definition.
// (note that this is mutating it inline!)
datastoreConfig.adapter = validateAdapter(datastoreConfig.adapter, adapterIdentity, datastoreIdentity);
// Next, we'll register the adapter.
hook.adapters[adapterIdentity] = datastoreConfig.adapter;
// And finally, we'll change the datastore configuration dictionary so that its
// `adapter` property is actually a string again.
datastoreConfig.adapter = adapterIdentity;
}
// Else if it is a string, the `adapter` property of the datastore config is usually
// the package name of an adapter, but it also sometimes might be the adapter's
// "identity" (for custom, defined-in-app adapters).
else if (_.isString(datastoreConfig.adapter) && datastoreConfig.adapter !== '') {
adapterIdentity = datastoreConfig.adapter;
}
// The `adapter` property is required for a datastore config dictionary.
else {
// Invalid datastore found; throw fatal error.
throw constructError(invalidDatastoreError, {
datastoreIdentity: datastoreIdentity
});
}
// ╔╗╔╔═╗╦═╗╔╦╗╔═╗╦ ╦╔═╗╔═╗ ┌┬┐┌─┐┌┬┐┌─┐┌─┐┌┬┐┌─┐┬─┐┌─┐ ┌─┐┌─┐┌┐┌┌─┐┬┌─┐
// ║║║║ ║╠╦╝║║║╠═╣║ ║╔═╝║╣ ││├─┤ │ ├─┤└─┐ │ │ │├┬┘├┤ │ │ ││││├┤ ││ ┬
// ╝╚╝╚═╝╩╚═╩ ╩╩ ╩╩═╝╩╚═╝╚═╝ ─┴┘┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘┴└─└─┘ └─┘└─┘┘└┘└ ┴└─┘
// Now build our normalized datastore config to return.
var normalizedDatastoreConfig = {};
// Adapters can provide a `defaults` dictionary which serves as a set of default properties for datastore config.
// If an adapter exists for this datastore, we know it has already been validated; so we can safely use that as
// the basis for our normalized datastore configuration. (note: this step may eventually supported by Waterline core,
// in which case it could be removed here)
if (hook.adapters[adapterIdentity]) {
_.extend(normalizedDatastoreConfig, hook.adapters[adapterIdentity].defaults);
}
// Either way, then merge in the the app-level datastore configuration.
_.extend(normalizedDatastoreConfig, datastoreConfig);
// If the datastore config has a `url` property, trim any trailing slashes off of it.
if (_.isString(normalizedDatastoreConfig.url)) {
normalizedDatastoreConfig.url = normalizedDatastoreConfig.url.replace(/\/$/,'');
}
// Success- datastore has been normalized and validated.
// (any missing adapters were ignored)
return normalizedDatastoreConfig;
};