UNPKG

5.22 kBJavaScriptView Raw
1/*!
2 * A MongoDB inspired ES6 Map() query language. - Copyright (c) 2017 Louis T. (https://lou.ist/)
3 * Licensed under the MIT license https://raw.githubusercontent.com/LouisT/MapQL/master/LICENSE
4 */
5'use strict';
6// Create a null Symbol as 'null' is a valid Map() key/value.
7const _null = Symbol(null),
8 __GLOBAL = new Function("try { return this === global; } catch (e) { return false; }")() ? global : window,
9 { typeToInt, intToType } = require('./DataTypes');
10
11/*
12 * Get/set a value from an Object/Array based on dot notation.
13 * Search Object: dot(['a', 'b', 'c'], { a: { b: { c: 1 } } }) == 1
14 * Search Array: dot(['a', 'b', 1], { a: { b: [1, 2, 3] } }) == 2
15 * Set: dot(['a', 'b', 'c'], { a: { b: { c: 1 } } }, { value: 2 }) == { a: { b: { c: 2 } } }
16 * Unset: dot(['a', 'b', 'c'], { a: { b: { c: 1 } } }, { unset: true }) == { a: { b: {} } }
17 * Defined: dot(['a', 'b', 'c', 2], { a: { b: { c: 1 } } }, { defined: true }) == false
18 */
19function dot (keys = [], obj = {}, options = {}) {
20 let opts = Object.assign({
21 autoCreate: true, // Create an Object key/value if it doesn't exist.
22 value: false, // Function to set the value if not false.
23 unset: false, // Unset the Object key if it exists.
24 defined: false // Return undefined if key does not exist.
25 }, options),
26 _apply = function (keys, obj, value) {
27 if (keys.length == 1 && (value || opts.unset)) {
28 return opts.unset ? delete obj[keys[0]] : obj[keys[0]] = value.apply(this, [obj[keys[0]] || _null]);
29 } else if (!keys[0]) {
30 return obj;
31 } else if (!opts.autoCreate || opts.defined || opts.unset) {
32 return (obj.hasOwnProperty(keys[0]) ? _apply(keys.slice(1), obj[keys[0]], value) : undefined);
33 }
34 return _apply(keys.slice(1), (obj.hasOwnProperty(keys[0]) ? obj[keys[0]] : (obj[keys[0]] = (!isNaN(parseInt(keys[1], 10)) ? [] : {}))), value);
35 };
36
37 try {
38 return _apply(keys, obj, (opts.value ? (is(opts.value, '!Function') ? (current, next) => { return next } : opts.value) : opts.value));
39 } catch (e) {
40 return undefined; // Value must not exist; return undefined!
41 }
42}
43
44/*
45 * Get the variable type.
46 */
47function getType (val) {
48 try {
49 if (__GLOBAL['Buffer'] && Buffer.isBuffer && Buffer.isBuffer(val)) {
50 return 'Buffer';
51 }
52 } catch (error) { }
53 return Object.prototype.toString.call(val).match(/(?:\[object (.+)\])/i)[1]
54};
55
56/*
57 * Test if a variable is the provided type; if type arg is prefixed with `!` test if NOT type.
58 * If typeOf is true, use 'typeof value' instead of getType.
59 */
60function is (val, type, typeOf = false) {
61 try {
62 return (/^!/.test(type) !== ((typeOf ? typeof val : getType(val).toLowerCase()) === type.toLowerCase().replace(/^!/,'')));
63 } catch (error) {
64 return false;
65 }
66}
67
68/*
69 * Deep clone Map/MapQL objects.
70 */
71function deepClone (obj, _Map = Map) {
72 if (is(obj, 'Null') || is(obj, '!Object', true)) {
73 return obj;
74 }
75 switch (getType(obj)) {
76 case 'Date':
77 return new Date(obj.getTime());
78 case 'MapQL': case 'Map':
79 return new _Map(deepClone(Array.from(obj), _Map));
80 case 'Set':
81 return new Set(deepClone(Array.from(obj), _Map));
82 case 'RegExp':
83 return new RegExp(obj);
84 case 'Array':
85 return new Array(obj.length).fill(0).map((val, idx) => {
86 return deepClone(obj[idx], _Map)
87 });
88 case 'Object':
89 return ((cloned) => {
90 for (let prop in obj) {
91 if (obj.hasOwnProperty(prop)) {
92 cloned[prop] = deepClone(obj[prop], _Map);
93 }
94 }
95 return cloned;
96 })({});
97 default: return obj;
98 }
99}
100
101/*
102 * Export all of the helper functions.
103 */
104module.exports = {
105 __GLOBAL: __GLOBAL,
106 _null: _null,
107 dotNotation: (keys = _null, obj = {}, options = {}) => {
108 // If multiple objects are provided, get each value one via dot notation.
109 return Array.isArray(obj) ? obj.map((_obj, idx) => {
110 // If `keys` is an array, use the corresponding object index.
111 return dot(String(Array.isArray(keys) ? keys[idx] : keys).trim().split('.'), _obj, options);
112 }) : dot((keys !== _null ? String(keys).trim().split('.') : []), obj, options);
113 },
114 is: (val, type, typeOf = false, some = false) => {
115 return Array.isArray(type) ? type[some ? 'some' : 'every']((t) => is(val, t, typeOf)) : is(val, type, typeOf);
116 },
117 getType: getType,
118 deepClone: deepClone,
119 typeToInt: typeToInt,
120 intToType: intToType
121};