elastic-builder
Version:
A JavaScript implementation of the elasticsearch Query DSL
152 lines (133 loc) • 4.32 kB
JavaScript
;
const { inspect } = require('util');
const isEmpty = require('lodash.isempty'),
isNil = require('lodash.isnil'),
isString = require('lodash.isstring'),
isObject = require('lodash.isobject'),
hasIn = require('lodash.hasin');
const has = require('lodash.has');
/**
* Check if the object is instance of class type
*
* @private
* @param {Object} instance
* @param {Class} type
* @throws {TypeError} Object must be an instance of class type
*/
exports.checkType = function checkType(instance, type) {
if (!(instance instanceof type)) {
if (isNil(instance)) {
console.warn(
`Was expecting instance of ${type.name} but got ${instance}!`
);
} else
console.warn(
`${inspect(instance)} is of the type ${typeof instance}`
);
throw new TypeError(`Argument must be an instance of ${type.name}`);
}
};
/**
* Wrapper for calling constructor with given parameters
*
* @private
* @param {function(new:T, ...*)} Cls The class constructor.
* @returns {function(...*): T} Wrapper of the class constructor which creates an instance of given Class
* @template T
*/
exports.constructorWrapper = function constructorWrapper(Cls) {
return (...args) => new Cls(...args);
};
/**
* Check if the number is in the given range.
* Returns `true` is number is less than or equal to min, max.
*
* @private
* @param {number} num
* @param {number} min
* @param {number} max
* @returns {boolean} `true` if in range, `false` otherwise
*/
function between(num, min, max) {
return num >= min && num <= max;
}
/**
* Finds and returns the first position of first digit in string
*
* @private
* @param {string} str
* @returns {number} Index of first digit in string.
* `-1` if digit is not found in string
*/
exports.firstDigitPos = function firstDigitPos(str) {
if (isEmpty(str)) return -1;
const len = str.length;
for (let idx = 0; idx < len; idx++) {
// '0'.charCodeAt(0) => 48
// '9'.charCodeAt(0) => 57
if (between(str.charCodeAt(idx), 48, 57)) return idx;
}
return -1;
};
/**
* Convert class object to JSON by recursively calling `toJSON` on the class members.
*
* @private
* @param {*} obj
* @returns {Object} JSON representation of class.
*/
exports.recursiveToJSON = function recursiveToJSON(obj) {
// Strings, numbers, booleans
if (!isObject(obj)) return obj;
// Each element in array needs to be recursively JSONified
if (Array.isArray(obj)) return obj.map(x => recursiveToJSON(x));
// If it is a native object, we'll not get anything different by calling toJSON
// If it is a custom object, toJSON needs to be called
// Custom object toJSON might return any datatype
// So let us handle it recursively
if (hasIn(obj, 'toJSON') && obj.constructor !== Object) {
return recursiveToJSON(obj.toJSON());
}
// Custom object toJSON or native object might have values which need to be JSONified
const json = {};
for (const key of Object.keys(obj)) {
json[key] = recursiveToJSON(obj[key]);
}
return json;
};
/**
* Helper function for creating function which will log warning and throw error
* on receiving invalid parameter
*
* @private
* @param {string} refUrl
* @param {string} paramName
* @param {*} validValues
* @returns {function}
*/
exports.invalidParam = function invalidParam(refUrl, paramName, validValues) {
return (paramVal, referenceUrl = refUrl) => {
referenceUrl && console.log(`See ${referenceUrl}`);
console.warn(`Got '${paramName}' - '${paramVal}'`);
const validValuesStr = isString(validValues)
? validValues
: inspect(validValues);
throw new Error(
`The '${paramName}' parameter should be one of ${validValuesStr}`
);
};
};
/**
* Set given default value on object if key is not present.
*
* @private
* @param {Object} obj
* @param {string} key
* @param {*} value
* @returns {boolean} `true` if the given object did not have `key` and `false` otherwise.
*/
exports.setDefault = function setDefault(obj, key, value) {
const itHasNot = !has(obj, key);
if (itHasNot) obj[key] = value;
return itHasNot;
};