UNPKG

8.23 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 MysqlBuilder extends Base {
9
10 static getConstants () {
11 return {
12 CONDITION_BUILDERS: {
13 'AND': 'buildLogicCondition',
14 'OR': 'buildLogicCondition',
15 'EQUAL': 'buildEqualCondition',
16 'NOT EQUAL': 'buildNotEqualCondition',
17 'BETWEEN': 'buildBetweenCondition',
18 'NOT BETWEEN': 'buildNotBetweenCondition',
19 'IN': 'buildInCondition',
20 'NOT IN': 'buildNotInCondition',
21 'LIKE': 'buildLikeCondition',
22 'NOT LIKE': 'buildNotLikeCondition',
23 'ID': 'buildIdCondition',
24 'NOT ID': 'buildNotIdCondition',
25 'FALSE': 'buildFalseCondition',
26 'EMPTY': 'buildEmptyCondition',
27 'NOT EMPTY': 'buildNotEmptyCondition',
28 'NULL': 'buildNullCondition',
29 'NOT NULL': 'buildNotNullCondition',
30 'EXISTS': 'buildExistsCondition',
31 'NOT EXISTS': 'buildNotExistsCondition'
32 },
33 SIMPLE_OPERATORS: {
34 '=': ' = ',
35 '!=': ' != ',
36 '>': ' > ',
37 '>=': ' >= ',
38 '<': ' < ',
39 '<=': ' <= '
40 }
41 };
42 }
43
44 escape (value) {
45 return this.db.escape(value);
46 }
47
48 normalizeField (field) {
49 if (typeof field !== 'string') {
50 throw new Error('Invalid field name');
51 }
52 return this.db.escapeId(field);
53 }
54
55 build (query) {
56 query.cmd = {
57 from: this.db.escapeId(query._from),
58 select: this.buildSelect(query._select),
59 where: this.buildWhere(query._where),
60 order: this.buildOrder(query._order),
61 offset: query._offset,
62 limit: query._limit,
63 };
64 query.afterBuild();
65 return query.cmd;
66 }
67
68 buildSelect (select) {
69 return select ? this.db.escapeId(select) : '*';
70 }
71
72 buildOrder (order) {
73 if (!order) {
74 return null;
75 }
76 const result = [];
77 for (const key of Object.keys(order)) {
78 result.push(`${this.db.escapeId(key)} ${order[key] === 1 ? 'ASC' : 'DESC'}`);
79 }
80 return result.length ? result.join(',') : null;
81 }
82
83 stringify (cmd) {
84 let sql = `SELECT ${cmd.select} FROM ${cmd.from}`;
85 if (cmd.where) {
86 sql += cmd.where;
87 }
88 if (cmd.order) {
89 sql +=` ORDER BY ${cmd.order}`;
90 }
91 if (cmd.offset) {
92 sql +=` LIMIT ${cmd.offset},${cmd.limit ? cmd.limit : 9999999999}`;
93 } else if (cmd.limit) {
94 sql +=` LIMIT ${cmd.limit}`;
95 }
96 return sql;
97 }
98
99 buildWhere (condition) {
100 if (!condition) {
101 return '';
102 }
103 if (typeof condition === 'object') {
104 condition = this.buildCondition(condition);
105 }
106 return ' WHERE '+ condition;
107 }
108
109 buildCondition (data) {
110 if (!Array.isArray(data)) {
111 return this.buildHashCondition(data);
112 }
113 return Object.prototype.hasOwnProperty.call(this.CONDITION_BUILDERS, data[0])
114 ? this[this.CONDITION_BUILDERS[data[0]]](...data)
115 : this.buildSimpleCondition(...data);
116 }
117
118 buildHashCondition (data) {
119 if (!data) {
120 return '';
121 }
122 const result = [];
123 for (const key of Object.keys(data)) {
124 const field = this.normalizeField(key);
125 if (Array.isArray(data[key])) {
126 data[key].length
127 ? result.push(`${field} IN (${this.escape(data[key])})`)
128 : result.push(`${field} IS NULL`);
129 } else if (data[key] === null) {
130 result.push(`${field} IS NULL`);
131 } else {
132 result.push(`${field}=${this.escape(data[key])}`);
133 }
134 }
135 return result.join(' AND ');
136 }
137
138 buildSimpleCondition (operator, field, value) {
139 if (!Object.prototype.hasOwnProperty.call(this.SIMPLE_OPERATORS, operator)) {
140 throw new Error('Invalid simple operator');
141 }
142 field = this.normalizeField(field);
143 return value === null
144 ? field + (operator === '=' ? ' IS NULL' : ' IS NOT NULL')
145 : field + this.SIMPLE_OPERATORS[operator] + this.escape(value);
146 }
147
148 buildLogicCondition (operator, ...operands) {
149 const items = [];
150 for (const operand of operands) {
151 items.push(this.buildCondition(operand));
152 }
153 return '('+ items.join(operator === 'AND' ? ') AND (' : ') OR (') +')';
154 }
155
156 buildEqualCondition (operator, field, value) {
157 return `${this.normalizeField(field)}=${this.escape(value)}`;
158 }
159
160 buildNotEqualCondition (operator, field, value) {
161 return Array.isArray(value)
162 ? this.buildNotInCondition()
163 : `${this.normalizeField(field)}!=${this.escape(value)}`;
164 }
165
166 // IN
167
168 buildInCondition (operator, field, value) {
169 return Array.isArray(value) && value.length === 0
170 ? `${this.normalizeField(field)} IS NULL`
171 : `${this.normalizeField(field)} IN (${this.escape(value)})`;
172 }
173
174 buildNotInCondition (operator, field, value) {
175 return Array.isArray(value) && value.length === 0
176 ? `${this.normalizeField(field)} IS NOT NULL`
177 : `${this.normalizeField(field)} NOT IN (${this.escape(value)})`;
178 }
179
180 // LIKE
181
182 buildLikeCondition (operator, field, value) {
183 return `${this.normalizeField(field)} LIKE ${this.escape(value)}`;
184 }
185
186 buildNotLikeCondition (operator, field, value) {
187 return `${this.normalizeField(field)} NOT LIKE ${this.escape(value)}`;
188 }
189
190 // BETWEEN
191
192 buildBetweenCondition (operator, field, min, max) {
193 return `${this.normalizeField(field)} BETWEEN ${this.escape(min)} AND ${this.escape(max)}`;
194 }
195
196 buildNotBetweenCondition (operator, field, min, max) {
197 return `${this.normalizeField(field)} NOT BETWEEN ${this.escape(min)} AND ${this.escape(max)}`;
198 }
199
200 // ID
201
202 buildIdCondition (operator, field, value) {
203 if (value === null || value === undefined) {
204 return this.buildNullCondition(operator, field);
205 }
206 return Array.isArray(value)
207 ? `${this.normalizeField(field)} IN (${this.escape(value)})`
208 : `${this.normalizeField(field)}=${this.escape(value)}`;
209 }
210
211 buildNotIdCondition (operator, field, value) {
212 if (value === null || value === undefined) {
213 return this.buildNotNullCondition(operator, field);
214 }
215 return Array.isArray(value)
216 ? `${this.normalizeField(field)} NOT IN (${this.escape(value)})`
217 : `${this.normalizeField(field)}=${this.escape(value)}`;
218 }
219
220 // FALSE
221
222 buildFalseCondition () {
223 return ' FALSE ';
224 }
225
226 // EMPTY
227
228 buildEmptyCondition (operator, field) {
229 field = this.normalizeField(field);
230 return `${field} IS NULL OR ${field} = ''`;
231 }
232
233 buildNotEmptyCondition (operator, field) {
234 field = this.normalizeField(field);
235 return `${field} IS NOT NULL AND ${field} != ''`;
236 }
237
238 // NULL
239
240 buildNullCondition (operator, field) {
241 return `${this.normalizeField(field)} IS NULL`;
242 }
243
244 buildNotNullCondition (operator, field) {
245 return `${this.normalizeField(field)} IS NOT NULL`;
246 }
247
248 // EXISTS
249
250 buildExistsCondition (operator, field) {
251 return `${this.normalizeField(field)} IS NULL`;
252 }
253
254 buildNotExistsCondition (operator, field) {
255 return `${this.normalizeField(field)} IS NOT NULL`;
256 }
257};
258module.exports.init();
\No newline at end of file