UNPKG

forerunnerdb

Version:

A NoSQL document store database for browsers and Node.js.

161 lines (137 loc) 4.34 kB
"use strict"; /** * Allows a method to accept overloaded calls with different parameters controlling * which passed overload function is called. * @param {Object} def * @returns {Function} * @constructor */ var Overload = function (def) { if (def) { var self = this, index, count, tmpDef, defNewKey, sigIndex, signatures; if (!(def instanceof Array)) { tmpDef = {}; // Def is an object, make sure all prop names are devoid of spaces for (index in def) { if (def.hasOwnProperty(index)) { defNewKey = index.replace(/ /g, ''); // Check if the definition array has a * string in it if (defNewKey.indexOf('*') === -1) { // No * found tmpDef[defNewKey] = def[index]; } else { // A * was found, generate the different signatures that this // definition could represent signatures = this.generateSignaturePermutations(defNewKey); for (sigIndex = 0; sigIndex < signatures.length; sigIndex++) { if (!tmpDef[signatures[sigIndex]]) { tmpDef[signatures[sigIndex]] = def[index]; } } } } } def = tmpDef; } return function () { var arr = [], lookup, type, name; // Check if we are being passed a key/function object or an array of functions if (def instanceof Array) { // We were passed an array of functions count = def.length; for (index = 0; index < count; index++) { if (def[index].length === arguments.length) { return self.callExtend(this, '$main', def, def[index], arguments); } } } else { // Generate lookup key from arguments // Copy arguments to an array for (index = 0; index < arguments.length; index++) { type = typeof arguments[index]; // Handle detecting arrays if (type === 'object' && arguments[index] instanceof Array) { type = 'array'; } // Handle been presented with a single undefined argument if (arguments.length === 1 && type === 'undefined') { break; } // Add the type to the argument types array arr.push(type); } lookup = arr.join(','); // Check for an exact lookup match if (def[lookup]) { return self.callExtend(this, '$main', def, def[lookup], arguments); } else { for (index = arr.length; index >= 0; index--) { // Get the closest match lookup = arr.slice(0, index).join(','); if (def[lookup + ',...']) { // Matched against arguments + "any other" return self.callExtend(this, '$main', def, def[lookup + ',...'], arguments); } } } } name = typeof this.name === 'function' ? this.name() : 'Unknown'; throw('ForerunnerDB.Overload "' + name + '": Overloaded method does not have a matching signature for the passed arguments: ' + this.jStringify(arr)); }; } return function () {}; }; /** * Generates an array of all the different definition signatures that can be * created from the passed string with a catch-all wildcard *. E.g. it will * convert the signature: string,*,string to all potentials: * string,string,string * string,number,string * string,object,string, * string,function,string, * string,undefined,string * * @param {String} str Signature string with a wildcard in it. * @returns {Array} An array of signature strings that are generated. */ Overload.prototype.generateSignaturePermutations = function (str) { var signatures = [], newSignature, types = ['string', 'object', 'number', 'function', 'undefined'], index; if (str.indexOf('*') > -1) { // There is at least one "any" type, break out into multiple keys // We could do this at query time with regular expressions but // would be significantly slower for (index = 0; index < types.length; index++) { newSignature = str.replace('*', types[index]); signatures = signatures.concat(this.generateSignaturePermutations(newSignature)); } } else { signatures.push(str); } return signatures; }; Overload.prototype.callExtend = function (context, prop, propContext, func, args) { var tmp, ret; if (context && propContext[prop]) { tmp = context[prop]; context[prop] = propContext[prop]; ret = func.apply(context, args); context[prop] = tmp; return ret; } else { return func.apply(context, args); } }; module.exports = Overload;