objection
Version:
An SQL-friendly ORM for Node.js
417 lines (320 loc) • 7.54 kB
JavaScript
;
const { clone, cloneDeep } = require('./clone');
const SMALL_ARRAY_SIZE = 10;
function isEmpty(item) {
if (Array.isArray(item) || Buffer.isBuffer(item)) {
return item.length === 0;
} else if (isObject(item)) {
return Object.keys(item).length === 0;
} else {
return true;
}
}
function isObject(value) {
return value !== null && typeof value === 'object';
}
// Quick and dirty check if an object is a plain object and not
// for example an instance of some class.
function isPlainObject(value) {
return (
isObject(value) &&
(!value.constructor || value.constructor === Object) &&
(!value.toString || value.toString === Object.prototype.toString)
);
}
function isFunction(value) {
return typeof value === 'function';
}
function isRegExp(value) {
return value instanceof RegExp;
}
function isString(value) {
return typeof value === 'string';
}
function isNumber(value) {
return typeof value === 'number';
}
function asArray(value) {
return Array.isArray(value) ? value : [value];
}
function asSingle(value) {
return Array.isArray(value) ? value[0] : value;
}
function uniqBy(items, keyGetter = null) {
const map = new Map();
for (let i = 0, l = items.length; i < l; ++i) {
const item = items[i];
const key = keyGetter !== null ? keyGetter(item) : item;
map.set(key, item);
}
return Array.from(map.values());
}
function groupBy(items, keyGetter = null) {
const groups = new Map();
for (const item of items) {
const key = keyGetter !== null ? keyGetter(item) : item;
let group = groups.get(key);
if (!group) {
group = [];
groups.set(key, group);
}
group.push(item);
}
return groups;
}
function omit(obj, keysToOmit) {
keysToOmit = asArray(keysToOmit);
const keys = Object.keys(obj);
const out = {};
for (let i = 0, l = keys.length; i < l; ++i) {
const key = keys[i];
if (!keysToOmit.includes(key)) {
out[key] = obj[key];
}
}
return out;
}
function difference(arr1, arr2) {
const arr2Set = new Set(arr2);
const diff = [];
for (let i = 0; i < arr1.length; ++i) {
const value = arr1[i];
if (!arr2Set.has(value)) {
diff.push(value);
}
}
return diff;
}
function union(arr1, arr2) {
if (arr1.length < SMALL_ARRAY_SIZE && arr2.length < SMALL_ARRAY_SIZE) {
return unionSmall(arr1, arr2);
} else {
return unionGeneric(arr1, arr2);
}
}
function unionSmall(arr1, arr2) {
const all = arr1.slice();
for (let i = 0, l = arr2.length; i < l; ++i) {
const item = arr2[i];
if (all.indexOf(item) === -1) {
all.push(item);
}
}
return all;
}
function unionGeneric(arr1, arr2) {
const all = new Set();
for (let i = 0; i < arr1.length; ++i) {
all.add(arr1[i]);
}
for (let i = 0; i < arr2.length; ++i) {
all.add(arr2[i]);
}
return Array.from(all);
}
function last(arr) {
return arr[arr.length - 1];
}
function upperFirst(str) {
return str[0].toUpperCase() + str.substring(1);
}
function values(obj) {
if (isObject(obj)) {
const keys = Object.keys(obj);
const values = new Array(keys.length);
for (let i = 0, l = keys.length; i < l; ++i) {
values[i] = obj[keys[i]];
}
return values;
} else {
return [];
}
}
function once(func) {
let called = false;
let value = undefined;
return function () {
if (called === false) {
called = true;
value = func.apply(this, arguments);
}
return value;
};
}
function flatten(arrays) {
const out = [];
for (let i = 0, l = arrays.length; i < l; ++i) {
const value = arrays[i];
if (Array.isArray(value)) {
for (let j = 0; j < value.length; ++j) {
out.push(value[j]);
}
} else {
out.push(value);
}
}
return out;
}
function get(obj, path) {
for (let i = 0, l = path.length; i < l; ++i) {
const key = path[i];
if (!isObject(obj)) {
return undefined;
}
obj = obj[key];
}
return obj;
}
function set(obj, path, value) {
const inputObj = obj;
for (let i = 0, l = path.length - 1; i < l; ++i) {
const key = path[i];
if (!isSafeKey(key)) {
return inputObj;
}
let child = obj[key];
if (!isObject(child)) {
const nextKey = path[i + 1];
if (isNaN(nextKey)) {
child = {};
} else {
child = [];
}
obj[key] = child;
}
obj = child;
}
if (path.length > 0 && isObject(obj)) {
const key = path[path.length - 1];
if (isSafeKey(key)) {
obj[key] = value;
}
}
return inputObj;
}
function zipObject(keys, values) {
const out = {};
for (let i = 0, l = keys.length; i < l; ++i) {
const key = keys[i];
if (isSafeKey(key)) {
out[key] = values[i];
}
}
return out;
}
function chunk(arr, chunkSize) {
const out = [];
for (let i = 0, l = arr.length; i < l; ++i) {
const item = arr[i];
if (out.length === 0 || out[out.length - 1].length === chunkSize) {
out.push([]);
}
out[out.length - 1].push(item);
}
return out;
}
function jsonEquals(val1, val2) {
return jsonEqualsBase(val1, val2, compareStrict);
}
function jsonEqualsBase(val1, val2, compare) {
if (val1 === val2) {
return true;
}
return jsonEqualsSlowPath(val1, val2, compare);
}
function jsonEqualsSlowPath(val1, val2, compare) {
const type1 = typeof val1;
const type2 = typeof val2;
const isNonNullObject1 = type1 === 'object' && !compare(val1, null);
const isNonNullObject2 = type2 === 'object' && !compare(val2, null);
if (isNonNullObject1 && isNonNullObject2) {
const isArray1 = Array.isArray(val1);
const isArray2 = Array.isArray(val2);
if (isArray1 && isArray2) {
return jsonEqualsArray(val1, val2, compare);
} else if (!isArray1 && !isArray2) {
return jsonEqualsObject(val1, val2, compare);
} else {
return false;
}
} else if (isNonNullObject1 !== isNonNullObject2) {
return false;
} else {
return compare(val1, val2);
}
}
function jsonEqualsArray(arr1, arr2, compare) {
if (arr1.length !== arr2.length) {
return false;
}
for (let i = 0, l = arr1.length; i < l; ++i) {
if (!jsonEqualsBase(arr1[i], arr2[i], compare)) {
return false;
}
}
return true;
}
function jsonEqualsObject(obj1, obj2, compare) {
if (obj1.constructor === Date && obj2.constructor === Date) {
return equalsDate(obj1, obj2);
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (let i = 0, l = keys1.length; i < l; ++i) {
const key = keys1[i];
if (!jsonEqualsBase(obj1[key], obj2[key], compare)) {
return false;
}
}
return true;
}
function equalsDate(date1, date2) {
return date1.getTime() === date2.getTime();
}
function compareStrict(val1, val2) {
return val1 === val2;
}
function isSafeKey(key) {
return isNumber(key) || (isString(key) && key !== '__proto__');
}
function mergeMaps(map1, map2) {
const map = new Map(map1);
if (map2) {
for (const key of map2.keys()) {
map.set(key, map2.get(key));
}
}
return map;
}
module.exports = {
isEmpty,
isString,
isRegExp,
isObject,
isNumber,
isFunction,
jsonEquals,
isPlainObject,
difference,
upperFirst,
zipObject,
mergeMaps,
cloneDeep,
asSingle,
asArray,
flatten,
groupBy,
uniqBy,
values,
union,
chunk,
clone,
omit,
once,
last,
get,
set,
};