UNPKG

7.04 kBJavaScriptView Raw
1/**
2 * @copyright Copyright (c) 2019 Maxim Khorin <maksimovichu@gmail.com>
3 */
4'use strict';
5
6const Base = require('../base/Base');
7
8module.exports = class MongoBuilder extends Base {
9
10 static getConstants () {
11 return {
12 CONDITION_BUILDERS: {
13 'AND': 'buildLogicCondition',
14 'OR': 'buildLogicCondition',
15 'NOR': 'buildLogicCondition',
16 'EQUAL': 'buildEqualCondition',
17 'NOT EQUAL': 'buildNotEqualCondition',
18 'BETWEEN': 'buildBetweenCondition',
19 'NOT BETWEEN':'buildNotBetweenCondition',
20 'IN': 'buildInCondition',
21 'NOT IN': 'buildNotInCondition',
22 'LIKE': 'buildLikeCondition',
23 'NOT LIKE': 'buildNotLikeCondition',
24 'ID': 'buildIdCondition',
25 'NOT ID': 'buildNotIdCondition',
26 'FALSE': 'buildFalseCondition',
27 'EMPTY': 'buildEmptyCondition',
28 'NOT EMPTY': 'buildNotEmptyCondition',
29 'NULL': 'buildNullCondition',
30 'NOT NULL': 'buildNotNullCondition',
31 'EXISTS': 'buildExistsCondition',
32 'NOT EXISTS': 'buildNotExistsCondition'
33 },
34 SIMPLE_OPERATORS: {
35 '=': '$eq',
36 '!=': '$ne',
37 '>': '$gt',
38 '>=': '$gte',
39 '<': '$lt',
40 '<=': '$lte'
41 }
42 };
43 }
44
45 normalizeField (field) {
46 if (typeof field !== 'string') {
47 throw new Error(`Invalid field: ${field}`);
48 }
49 return field;
50 }
51
52 build (query) {
53 query.cmd = {
54 from: query._from
55 };
56 const select = this.buildSelect(query._select);
57 if (select) {
58 query.cmd.select = select;
59 }
60 const where = this.buildWhere(query._where);
61 if (where) {
62 query.cmd.where = where;
63 }
64 const order = this.buildOrder(query._order);
65 if (order) {
66 query.cmd.order = order;
67 }
68 if (query._offset) {
69 query.cmd.offset = query._offset;
70 }
71 if (query._limit) {
72 query.cmd.limit = query._limit;
73 }
74 query.afterBuild();
75 return query.cmd;
76 }
77
78 buildSelect (select) {
79 return select;
80 }
81
82 buildOrder (order) {
83 if (!order) {
84 return undefined;
85 }
86 const result = {};
87 for (const key of Object.keys(order)) {
88 result[key] = order[key] === 1 ? 1 : -1;
89 }
90 return result;
91 }
92
93 buildWhere (condition) {
94 return condition ? this.buildCondition(condition) : {};
95 }
96
97 buildCondition (data) {
98 if (!Array.isArray(data)) {
99 return this.buildHashCondition(data); // hash format: {column1: value1}
100 }
101 return this.CONDITION_BUILDERS.hasOwnProperty(data[0])
102 ? this[this.CONDITION_BUILDERS[data[0]]](...data)
103 : this.buildSimpleCondition(...data); // format: operator, operand 1, operand 2
104 }
105
106 buildHashCondition (data) {
107 if (data) {
108 for (const key of Object.keys(data)) {
109 if (Array.isArray(data[key]) && data[key].length) {
110 data[key] = {$in: data[key]};
111 }
112 }
113 }
114 return data;
115 }
116
117 buildSimpleCondition (operator, field, value) {
118 if (!(this.SIMPLE_OPERATORS.hasOwnProperty(operator))) {
119 throw new Error(`Invalid simple operator: ${operator}`);
120 }
121 return {[this.normalizeField(field)]: {[this.SIMPLE_OPERATORS[operator]]: value}};
122 }
123
124 buildLogicCondition (operator, ...operands) {
125 const items = [];
126 for (const operand of operands) {
127 items.push(this.buildCondition(operand));
128 }
129 operator = operator === 'AND' ? '$and' : operator === 'OR' ? '$or' : '$nor';
130 return {[operator]: items};
131 }
132
133 // EQUAL
134
135 buildEqualCondition (operator, field, value) {
136 return {[this.normalizeField(field)]: value};
137 }
138
139 buildNotEqualCondition (operator, field, value) {
140 return {[this.normalizeField(field)]: {$ne: value}};
141 }
142
143 // IN
144
145 buildInCondition (operator, field, value) {
146 return {[this.normalizeField(field)]: Array.isArray(value) ? {$in: value} : value};
147 }
148
149 buildNotInCondition (operator, field, value) {
150 value = Array.isArray(value) ? {$nin: value} : {$ne: value};
151 return {[this.normalizeField(field)]: value};
152 }
153
154 // LIKE
155
156 buildLikeCondition (operator, field, value) {
157 return {[this.normalizeField(field)]: EscapeHelper.toRegex(value)};
158 }
159
160 buildNotLikeCondition (operator, field, value) {
161 return {[this.normalizeField(field)]: {$not: EscapeHelper.toRegex(value)}};
162 }
163
164 // BETWEEN
165
166 buildBetweenCondition (operator, field, min, max) {
167 field = this.normalizeField(field);
168 return {$and: [{[field]: {$gte: min}}, {[field]: {$lte: max}}]};
169 }
170
171 buildNotBetweenCondition () {
172 return {$not: this.buildBetweenCondition(...arguments)};
173 }
174
175 // ID
176
177 buildIdCondition (operator, field, value) {
178 value = this.db.constructor.normalizeId(value);
179 return {[this.normalizeField(field)]: Array.isArray(value) ? {$in: value} : value};
180 }
181
182 buildNotIdCondition (operator, field, value) {
183 field = this.normalizeField(field);
184 if (value === null) {
185 return {$or: [{[field]: {$ne: null}}, {[field]: {$exists: false}}]};
186 }
187 value = this.db.constructor.normalizeId(value);
188 return {[field]: Array.isArray(value) ? {$nin: value} : {$ne: value}};
189 }
190
191 // FALSE
192
193 buildFalseCondition () {
194 return {_id: false};
195 }
196
197 // EMPTY (check - null, undefined, [], '')
198
199 buildEmptyCondition (operator, field) {
200 return {[this.normalizeField(field)]: {$in: [null, '', []]}};
201 }
202
203 buildNotEmptyCondition (operator, field) {
204 return {[this.normalizeField(field)]: {$nin: [null, '', []]}};
205 }
206
207 // NULL (check only null NOT undefined value)
208
209 buildNullCondition (operator, field) {
210 return {[this.normalizeField(field)]: {$type: 10}};
211 }
212
213 buildNotNullCondition (operator, field) {
214 return {[this.normalizeField(field)]: {$not: {$type: 10}}};
215 }
216
217 // EXISTS (check only undefined value)
218
219 buildExistsCondition (operator, field) {
220 return {[this.normalizeField(field)]: {$exists: true}};
221 }
222
223 buildNotExistsCondition (operator, field) {
224 return {[this.normalizeField(field)]: {$exists: false}};
225 }
226};
227module.exports.init();
228
229const EscapeHelper = require('../helper/EscapeHelper');
\No newline at end of file