1 |
|
2 |
|
3 |
|
4 | 'use strict';
|
5 |
|
6 | const Base = require('../base/Base');
|
7 |
|
8 | module.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);
|
100 | }
|
101 | return this.CONDITION_BUILDERS.hasOwnProperty(data[0])
|
102 | ? this[this.CONDITION_BUILDERS[data[0]]](...data)
|
103 | : this.buildSimpleCondition(...data);
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
192 |
|
193 | buildFalseCondition () {
|
194 | return {_id: false};
|
195 | }
|
196 |
|
197 |
|
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 |
|
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 |
|
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 | };
|
227 | module.exports.init();
|
228 |
|
229 | const EscapeHelper = require('../helper/EscapeHelper'); |
\ | No newline at end of file |