UNPKG

waterline-criteria

Version:

Utility library for working with Waterline criterias. Especially useful when building Sails adapters for key/value databases.

157 lines (117 loc) 3.26 kB
/** * Module dependencies */ var _ = require('lodash'); var X_ISO_DATE = require('./X_ISO_DATE.constant'); /** * Sort the tuples in `data` using `comparator`. * * @param { Dictionary[] } data * @param { Dictionary } comparator * @param { Function } when * @return { Dictionary[] } */ module.exports = function(data, comparator, when) { if (!comparator || !data) { return data; } // Equivalent to a SQL "WHEN" when = when||function rankSpecialCase (record, attrName) { // `null` ranks lower than anything else if ( typeof record[attrName]==='undefined' || record[attrName] === null ) { return false; } else { return true; } }; return sortData(_.cloneDeep(data), comparator, when); }; ////////////////////////// /// /// private methods || /// \/ /// ////////////////////////// /** * Sort `data` (tuples) using `sortVector` (comparator obj) * * Based on method described here: * http://stackoverflow.com/a/4760279/909625 * * @param { Dictionary[] } data [tuples] * @param { Dictionary } sortVector [mongo-style comparator Dictionary] * @return { Dictionary[] } */ function sortData(data, sortVector, when) { // Constants var GREATER_THAN = 1; var LESS_THAN = -1; var EQUAL = 0; return data.sort(function _compare(a, b) { return _.reduce(sortVector, function (flagSoFar, sortDirection, attrName){ var outcome; // Handle special cases (defined by WHEN): var $a = when(a, attrName); var $b = when(b, attrName); if (!$a && !$b) outcome = EQUAL; else if (!$a && $b) outcome = LESS_THAN; else if ($a && !$b) outcome = GREATER_THAN; // General case: else { // Coerce types $a = a[attrName]; $b = b[attrName]; if ( $a < $b ) outcome = LESS_THAN; else if ( $a > $b ) outcome = GREATER_THAN; else outcome = EQUAL; } // Less-Than case (-1) // (leaves flagSoFar untouched if it has been set, otherwise sets it) if ( outcome === LESS_THAN ) { return flagSoFar || -sortDirection; } // Greater-Than case (1) // (leaves flagSoFar untouched if it has been set, otherwise sets it) else if ( outcome === GREATER_THAN ) { return flagSoFar || sortDirection; } // Equals case (0) // (always leaves flagSoFar untouched) else return flagSoFar; }, 0);//</_.reduce> });//</data.sort()> } /** * Coerce a value to its probable intended type for sorting. * * @param {???} x * @return {???} */ function coerceIntoBestGuessType (x) { switch ( guessType(x) ) { case 'booleanish': return (x==='true')?true:false; case 'numberish': return +x; case 'dateish': return new Date(x); default: return x; } } function guessType (x) { if (!_.isString(x)) { return typeof x; } // Probably meant to be a boolean else if (x === 'true' || x === 'false') { return 'booleanish'; } // Probably meant to be a number else if (+x === x) { return 'numberish'; } // Probably meant to be a date else if (x.match(X_ISO_DATE)) { return 'dateish'; } // Just another string else return typeof x; }