water-orm
Version:
A monolith version of Standalone waterline ORM
181 lines (138 loc) • 5.09 kB
JavaScript
/**
* Module dependencies
*/
var _ = require('lodash');
var utils = require('../utils/helpers');
var hasOwnProperty = utils.object.hasOwnProperty;
/**
* Transformation
*
* Allows for a Waterline Collection to have different
* attributes than what actually exist in an adater's representation.
*
* @param {Object} attributes
* @param {Object} tables
*/
var Transformation = module.exports = function(attributes, tables) {
// Hold an internal mapping of keys to transform
this._transformations = {};
// Initialize
this.initialize(attributes, tables);
return this;
};
/**
* Initial mapping of transformations.
*
* @param {Object} attributes
* @param {Object} tables
*/
Transformation.prototype.initialize = function(attributes, tables) {
var self = this;
Object.keys(attributes).forEach(function(attr) {
// Ignore Functions and Strings
if (['function', 'string'].indexOf(typeof attributes[attr]) > -1) return;
// If not an object, ignore
if (attributes[attr] !== Object(attributes[attr])) return;
// Loop through an attribute and check for transformation keys
Object.keys(attributes[attr]).forEach(function(key) {
// Currently just works with `columnName`, `collection`, `groupKey`
if (key !== 'columnName') return;
// Error if value is not a string
if (typeof attributes[attr][key] !== 'string') {
throw new Error('columnName transformation must be a string');
}
// Set transformation attr to new key
if (key === 'columnName') {
if (attr === attributes[attr][key]) return;
self._transformations[attr] = attributes[attr][key];
}
});
});
};
/**
* Transforms a set of attributes into a representation used
* in an adapter.
*
* @param {Object} attributes to transform
* @return {Object}
*/
Transformation.prototype.serialize = function(attributes, behavior) {
var self = this;
var values = _.clone(attributes);
behavior = behavior || 'default';
function recursiveParse(obj) {
// Return if no object
if (!obj) return;
// Handle array of types for findOrCreateEach
if (typeof obj === 'string') {
if (hasOwnProperty(self._transformations, obj)) {
values = self._transformations[obj];
return;
}
return;
}
Object.keys(obj).forEach(function(property) {
// Just a double check to exit if hasOwnProperty fails
if (!hasOwnProperty(obj, property)) return;
// Schema must be serialized in first level only
if (behavior === 'schema') {
if (hasOwnProperty(self._transformations, property)) {
obj[self._transformations[property]] = _.clone(obj[property]);
delete obj[property];
}
return;
}
// Recursively parse `OR` criteria objects to transform keys
if (Array.isArray(obj[property]) && property === 'or') return recursiveParse(obj[property]);
// If Nested Object call function again passing the property as obj
if ((toString.call(obj[property]) !== '[object Date]') && (_.isPlainObject(obj[property]))) {
// check if object key is in the transformations
if (hasOwnProperty(self._transformations, property)) {
obj[self._transformations[property]] = _.clone(obj[property]);
delete obj[property];
return recursiveParse(obj[self._transformations[property]]);
}
return recursiveParse(obj[property]);
}
// If the property === SELECT check for any transformation keys
if (property === 'select' && _.isArray(obj[property])) {
var arr = _.clone(obj[property]);
_.each(arr, function(prop) {
if(_.has(self._transformations, prop)) {
var idx = _.indexOf(obj[property], prop);
if(idx > -1) {
obj[property][idx] = self._transformations[prop];
}
}
});
}
// Check if property is a transformation key
if (hasOwnProperty(self._transformations, property)) {
obj[self._transformations[property]] = obj[property];
delete obj[property];
}
});
}
// Recursivly parse attributes to handle nested criteria
recursiveParse(values);
return values;
};
/**
* Transforms a set of attributes received from an adapter
* into a representation used in a collection.
*
* @param {Object} attributes to transform
* @return {Object}
*/
Transformation.prototype.unserialize = function(attributes) {
var self = this;
var values = _.clone(attributes);
// Loop through the attributes and change them
Object.keys(this._transformations).forEach(function(key) {
var transformed = self._transformations[key];
if (!hasOwnProperty(attributes, transformed)) return;
values[key] = attributes[transformed];
if (transformed !== key) delete values[transformed];
});
return values;
};