sql-love 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -10
- package/dist/index.cjs +84 -538
- package/dist/index.mjs +60 -505
- package/package.json +15 -15
package/dist/index.mjs
CHANGED
|
@@ -1,31 +1,15 @@
|
|
|
1
1
|
// src/Parser/Parser.ts
|
|
2
|
-
|
|
2
|
+
class Parser {
|
|
3
3
|
query;
|
|
4
|
-
/**
|
|
5
|
-
* Create a new instance
|
|
6
|
-
* @param query A Select object on which to build parsed conditions
|
|
7
|
-
*/
|
|
8
4
|
constructor(query) {
|
|
9
5
|
this.query = query;
|
|
10
6
|
}
|
|
11
|
-
/**
|
|
12
|
-
* Strip single-line and multi-line comment blocks
|
|
13
|
-
* @param sql The SQL string
|
|
14
|
-
* @return The SQL string without comments
|
|
15
|
-
* @private
|
|
16
|
-
*/
|
|
17
7
|
_stripComments(sql) {
|
|
18
8
|
sql = sql.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
19
9
|
sql = sql.replace(/--([\r\n]|\s+[^\r\n]+[\r\n])/g, "");
|
|
20
10
|
sql = sql.replace(/#[^\r\n]+[\r\n]/g, "");
|
|
21
11
|
return sql;
|
|
22
12
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Before splitting into SQL clauses, extract some regex-able subQueries
|
|
25
|
-
* @param sql The unparsed sql string
|
|
26
|
-
* @return An array with new sql and subQueries
|
|
27
|
-
* @private
|
|
28
|
-
*/
|
|
29
13
|
_extractSubQueries(sql) {
|
|
30
14
|
const subQueries = {};
|
|
31
15
|
let i = 0;
|
|
@@ -39,11 +23,6 @@ var Parser = class {
|
|
|
39
23
|
sql = sql.replace(/\bIN\s*\(\s*SELECT\s.+?\)/, extractor);
|
|
40
24
|
return { sql, subQueries };
|
|
41
25
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Inject column subQueries back into this object
|
|
44
|
-
* @param subQueries The lookup of extracted subQueries
|
|
45
|
-
* @private
|
|
46
|
-
*/
|
|
47
26
|
_injectSubQueries(subQueries) {
|
|
48
27
|
const replacer = ($0) => {
|
|
49
28
|
return subQueries[$0] || $0;
|
|
@@ -56,21 +35,10 @@ var Parser = class {
|
|
|
56
35
|
this.query._wheres = this.query._wheres.map(mapper);
|
|
57
36
|
this.query._havings = this.query._havings.map(mapper);
|
|
58
37
|
}
|
|
59
|
-
/**
|
|
60
|
-
* Split SQL into clauses (used by parse())
|
|
61
|
-
* @param sql The SQL to split
|
|
62
|
-
* @return
|
|
63
|
-
* @private
|
|
64
|
-
*/
|
|
65
38
|
_split(sql) {
|
|
66
39
|
const splitter = /(?:^|\s)(SELECT|FROM|(?:INNER|LEFT\s+OUTER|RIGHT\s+OUTER|LEFT|RIGHT|CROSS|FULL|FULL\s+OUTER)\s+JOIN|WHERE|GROUP\s+BY|HAVING|ORDER\s+BY|LIMIT|OFFSET|FETCH\s+NEXT)\b/i;
|
|
67
40
|
return sql.split(splitter);
|
|
68
41
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Get a QuickSelect object representing the given SQL SELECT statement
|
|
71
|
-
* @param rawSql The raw SQL for the SELECT statement
|
|
72
|
-
* @return True if the SQL was parsed successfully
|
|
73
|
-
*/
|
|
74
42
|
parse(rawSql) {
|
|
75
43
|
const stripped = this._stripComments(rawSql);
|
|
76
44
|
const { sql, subQueries } = this._extractSubQueries(stripped);
|
|
@@ -86,11 +54,6 @@ var Parser = class {
|
|
|
86
54
|
this._injectSubQueries(subQueries);
|
|
87
55
|
return true;
|
|
88
56
|
}
|
|
89
|
-
/**
|
|
90
|
-
* Handle SQL_CALC_FOUND_ROWS and column names
|
|
91
|
-
* @param clause The clause after the SELECT
|
|
92
|
-
* @private
|
|
93
|
-
*/
|
|
94
57
|
_handleSELECT(clause) {
|
|
95
58
|
let columns = clause.split(/s*,s*/);
|
|
96
59
|
let buffer = "";
|
|
@@ -118,84 +81,34 @@ var Parser = class {
|
|
|
118
81
|
}
|
|
119
82
|
});
|
|
120
83
|
}
|
|
121
|
-
/**
|
|
122
|
-
* Handle table names
|
|
123
|
-
* @param clause The clause after the FROM
|
|
124
|
-
* @private
|
|
125
|
-
*/
|
|
126
84
|
_handleFROM(clause) {
|
|
127
85
|
const tables = clause.split(/\s*,\s*/);
|
|
128
86
|
tables.forEach((table) => this.query.table(table));
|
|
129
87
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Handle INNER JOIN statements
|
|
132
|
-
* @param clause The clause after the INNER JOIN
|
|
133
|
-
* @private
|
|
134
|
-
*/
|
|
135
88
|
_handleINNER_JOIN(clause) {
|
|
136
89
|
this.query.innerJoin(clause);
|
|
137
90
|
}
|
|
138
|
-
/**
|
|
139
|
-
* Handle LEFT JOIN statements
|
|
140
|
-
* @param clause The clause after the LEFT JOIN
|
|
141
|
-
* @private
|
|
142
|
-
*/
|
|
143
91
|
_handleLEFT_JOIN(clause) {
|
|
144
92
|
this.query.leftJoin(clause);
|
|
145
93
|
}
|
|
146
|
-
/**
|
|
147
|
-
* Handle LEFT OUTER JOIN statements
|
|
148
|
-
* @param clause The clause after the LEFT OUTER JOIN
|
|
149
|
-
* @private
|
|
150
|
-
*/
|
|
151
94
|
_handleLEFT_OUTER_JOIN(clause) {
|
|
152
95
|
this.query.leftOuterJoin(clause);
|
|
153
96
|
}
|
|
154
|
-
/**
|
|
155
|
-
* Handle RIGHT JOIN statements
|
|
156
|
-
* @param clause The clause after the RIGHT JOIN
|
|
157
|
-
* @private
|
|
158
|
-
*/
|
|
159
97
|
_handleRIGHT_JOIN(clause) {
|
|
160
98
|
this.query.rightJoin(clause);
|
|
161
99
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Handle RIGHT OUTER JOIN statements
|
|
164
|
-
* @param clause The clause after the RIGHT OUTER JOIN
|
|
165
|
-
* @private
|
|
166
|
-
*/
|
|
167
100
|
_handleRIGHT_OUTER_JOIN(clause) {
|
|
168
101
|
this.query.rightOuterJoin(clause);
|
|
169
102
|
}
|
|
170
|
-
/**
|
|
171
|
-
* Handle CROSS JOIN statements
|
|
172
|
-
* @param clause The clause after the CROSS JOIN
|
|
173
|
-
* @private
|
|
174
|
-
*/
|
|
175
103
|
_handleCROSS_JOIN(clause) {
|
|
176
104
|
this.query.crossJoin(clause);
|
|
177
105
|
}
|
|
178
|
-
/**
|
|
179
|
-
* Handle FULL JOIN statements
|
|
180
|
-
* @param clause The clause after the FULL JOIN
|
|
181
|
-
* @private
|
|
182
|
-
*/
|
|
183
106
|
_handleFULL_JOIN(clause) {
|
|
184
107
|
this.query.fullJoin(clause);
|
|
185
108
|
}
|
|
186
|
-
/**
|
|
187
|
-
* Handle FULL OUTER JOIN statements
|
|
188
|
-
* @param clause The clause after the FULL OUTER JOIN
|
|
189
|
-
* @private
|
|
190
|
-
*/
|
|
191
109
|
_handleFULL_OUTER_JOIN(clause) {
|
|
192
110
|
this.query.fullOuterJoin(clause);
|
|
193
111
|
}
|
|
194
|
-
/**
|
|
195
|
-
* Handle WHERE conditions
|
|
196
|
-
* @param clause All the conditions after WHERE
|
|
197
|
-
* @private
|
|
198
|
-
*/
|
|
199
112
|
_handleWHERE(clause) {
|
|
200
113
|
if (/^(1|'1'|true)$/i.test(clause)) {
|
|
201
114
|
this.query._wheres.push(clause);
|
|
@@ -203,20 +116,9 @@ var Parser = class {
|
|
|
203
116
|
this._handleConditions("where", clause);
|
|
204
117
|
}
|
|
205
118
|
}
|
|
206
|
-
/**
|
|
207
|
-
* Handle HAVING statements
|
|
208
|
-
* @param clause All the conditions after HAVING
|
|
209
|
-
* @private
|
|
210
|
-
*/
|
|
211
119
|
_handleHAVING(clause) {
|
|
212
120
|
this._handleConditions("having", clause);
|
|
213
121
|
}
|
|
214
|
-
/**
|
|
215
|
-
* Build a conditions list
|
|
216
|
-
* @param type Either where or having
|
|
217
|
-
* @param clause The expressions following the type keyword
|
|
218
|
-
* @private
|
|
219
|
-
*/
|
|
220
122
|
_handleConditions(type, clause) {
|
|
221
123
|
const andGroups = clause.split(/\bAND\b/i);
|
|
222
124
|
andGroups.forEach((andGroup) => {
|
|
@@ -230,29 +132,14 @@ var Parser = class {
|
|
|
230
132
|
}
|
|
231
133
|
});
|
|
232
134
|
}
|
|
233
|
-
/**
|
|
234
|
-
* Handle GROUP BY statements
|
|
235
|
-
* @param clause The clauses after the GROUP BY
|
|
236
|
-
* @private
|
|
237
|
-
*/
|
|
238
135
|
_handleGROUP_BY(clause) {
|
|
239
136
|
const columns = clause.split(/\s*,\s*/);
|
|
240
137
|
columns.forEach((column) => this.query.groupBy(column));
|
|
241
138
|
}
|
|
242
|
-
/**
|
|
243
|
-
* Handle ORDER BY statements
|
|
244
|
-
* @param clause The clause after the ORDER BY
|
|
245
|
-
* @private
|
|
246
|
-
*/
|
|
247
139
|
_handleORDER_BY(clause) {
|
|
248
140
|
const columns = clause.split(/\s*,\s*/);
|
|
249
141
|
columns.forEach((column) => this.query.orderBy(column));
|
|
250
142
|
}
|
|
251
|
-
/**
|
|
252
|
-
* Handle LIMIT statements including "LIMIT #" and "LIMIT #, #"
|
|
253
|
-
* @param clause The clause after the LIMIT
|
|
254
|
-
* @private
|
|
255
|
-
*/
|
|
256
143
|
_handleLIMIT(clause) {
|
|
257
144
|
const offsetLimit = clause.match(/^(\d+|\?|:\w+)\s*,\s*(\d+|\?|:\w+)$/);
|
|
258
145
|
if (offsetLimit) {
|
|
@@ -263,26 +150,15 @@ var Parser = class {
|
|
|
263
150
|
this.query.limit(clause);
|
|
264
151
|
}
|
|
265
152
|
}
|
|
266
|
-
/**
|
|
267
|
-
* Handle OFFSET statements
|
|
268
|
-
* @param clause The number after the OFFSET
|
|
269
|
-
* @private
|
|
270
|
-
*/
|
|
271
153
|
_handleOFFSET(clause) {
|
|
272
154
|
clause = clause.replace(/^(\d+) ROWS$/i, "$1");
|
|
273
155
|
this.query.offset(clause);
|
|
274
156
|
}
|
|
275
|
-
/**
|
|
276
|
-
* Handle OFFSET statements
|
|
277
|
-
* @param clause The number after the OFFSET
|
|
278
|
-
* @private
|
|
279
|
-
*/
|
|
280
157
|
_handleFETCH_NEXT(clause) {
|
|
281
158
|
clause = clause.replace(/^(\d+) ROWS ONLY$/i, "$1");
|
|
282
159
|
this.query.limit(clause);
|
|
283
160
|
}
|
|
284
|
-
}
|
|
285
|
-
|
|
161
|
+
}
|
|
286
162
|
// src/substrCount/substrCount.ts
|
|
287
163
|
function substrCount(haystack, needle) {
|
|
288
164
|
let count = 0;
|
|
@@ -295,75 +171,22 @@ function substrCount(haystack, needle) {
|
|
|
295
171
|
}
|
|
296
172
|
|
|
297
173
|
// src/SelectBuilder/SelectBuilder.ts
|
|
298
|
-
var isNullish = (v) => v ===
|
|
174
|
+
var isNullish = (v) => v === undefined || v === null || v === false || isNaN(v);
|
|
299
175
|
var defaultEngine = "mysql";
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
* The list of values to bind to the query
|
|
303
|
-
* @private
|
|
304
|
-
*/
|
|
176
|
+
|
|
177
|
+
class SelectBuilder {
|
|
305
178
|
_bindings = [];
|
|
306
|
-
/**
|
|
307
|
-
* The list of strings to come immediately after "SELECT"
|
|
308
|
-
* and before column names
|
|
309
|
-
* @private
|
|
310
|
-
*/
|
|
311
179
|
_options = [];
|
|
312
|
-
/**
|
|
313
|
-
* The list of column names to select
|
|
314
|
-
* @private
|
|
315
|
-
*/
|
|
316
180
|
_tables = [];
|
|
317
|
-
/**
|
|
318
|
-
* The list of tables in the FROM clause
|
|
319
|
-
* @private
|
|
320
|
-
*/
|
|
321
181
|
_columns = [];
|
|
322
|
-
/**
|
|
323
|
-
* The list of JOIN strings to add
|
|
324
|
-
* @private
|
|
325
|
-
*/
|
|
326
182
|
_joins = [];
|
|
327
|
-
/**
|
|
328
|
-
* The list of WHERE clauses to join with AND
|
|
329
|
-
* @private
|
|
330
|
-
*/
|
|
331
183
|
_wheres = [];
|
|
332
|
-
/**
|
|
333
|
-
* The list of GROUP BY clauses to join with commas
|
|
334
|
-
* @private
|
|
335
|
-
*/
|
|
336
184
|
_groupBys = [];
|
|
337
|
-
/**
|
|
338
|
-
* The list of HAVING clauses to join with AND
|
|
339
|
-
* @private
|
|
340
|
-
*/
|
|
341
185
|
_havings = [];
|
|
342
|
-
/**
|
|
343
|
-
* The list of ORDER BY clauses to join with commas
|
|
344
|
-
* @private
|
|
345
|
-
*/
|
|
346
186
|
_orderBys = [];
|
|
347
|
-
/**
|
|
348
|
-
* The LIMIT to use
|
|
349
|
-
* @private
|
|
350
|
-
*/
|
|
351
187
|
_limit;
|
|
352
|
-
/**
|
|
353
|
-
* The OFFSET to use
|
|
354
|
-
* @private
|
|
355
|
-
*/
|
|
356
188
|
_offset;
|
|
357
|
-
/**
|
|
358
|
-
* The page used to construct an OFFSET based on the LIMIT
|
|
359
|
-
* @private
|
|
360
|
-
*/
|
|
361
189
|
_page;
|
|
362
|
-
/**
|
|
363
|
-
* Select constructor
|
|
364
|
-
* @param [sql] A base SQL query to parse
|
|
365
|
-
* @param [bindings] Placeholders to bind to the query
|
|
366
|
-
*/
|
|
367
190
|
constructor(sql = null, bindings = null) {
|
|
368
191
|
if (sql) {
|
|
369
192
|
if (bindings) {
|
|
@@ -377,33 +200,32 @@ var SelectBuilder = class _SelectBuilder {
|
|
|
377
200
|
new Parser(this).parse(sql);
|
|
378
201
|
}
|
|
379
202
|
}
|
|
380
|
-
/**
|
|
381
|
-
* Set the default database engine style (mssql, mysql, oracle, pg)
|
|
382
|
-
* @param engine
|
|
383
|
-
*/
|
|
384
203
|
static setDefaultEngine(engine) {
|
|
385
204
|
defaultEngine = engine;
|
|
386
|
-
return
|
|
205
|
+
return SelectBuilder;
|
|
387
206
|
}
|
|
388
|
-
/**
|
|
389
|
-
* Get the SQL as a pretty-printed string alongside an array of bindings
|
|
390
|
-
* @param engine The database engine style (mssql, mysql, oracle, pg)
|
|
391
|
-
* @return The SQL query as a string
|
|
392
|
-
*/
|
|
393
207
|
compile({
|
|
394
208
|
engine = defaultEngine,
|
|
395
209
|
bindingIndex = 1
|
|
396
210
|
} = {}) {
|
|
397
211
|
const lines = [
|
|
398
212
|
"SELECT",
|
|
399
|
-
this._options.length ? ` ${this._options.join(
|
|
400
|
-
|
|
213
|
+
this._options.length ? ` ${this._options.join(`
|
|
214
|
+
`)}` : null,
|
|
215
|
+
this._columns.length ? ` ${this._columns.join(`,
|
|
216
|
+
`)}` : ` *
|
|
217
|
+
`,
|
|
401
218
|
`FROM ${this._tables.join(", ")}`,
|
|
402
|
-
this._joins.length ? this._joins.join(
|
|
403
|
-
|
|
404
|
-
this.
|
|
405
|
-
|
|
406
|
-
this.
|
|
219
|
+
this._joins.length ? this._joins.join(`
|
|
220
|
+
`) : null,
|
|
221
|
+
this._wheres.length ? `WHERE ${this._wheres.join(`
|
|
222
|
+
AND `)}` : null,
|
|
223
|
+
this._groupBys.length ? `GROUP BY ${this._groupBys.join(`,
|
|
224
|
+
`)}` : null,
|
|
225
|
+
this._havings.length ? `HAVING ${this._havings.join(`
|
|
226
|
+
AND `)}` : null,
|
|
227
|
+
this._orderBys.length ? `ORDER BY ${this._orderBys.join(`,
|
|
228
|
+
`)}` : null
|
|
407
229
|
];
|
|
408
230
|
if (this._page > 0) {
|
|
409
231
|
const offset = (this._page - 1) * this._limit;
|
|
@@ -417,7 +239,8 @@ var SelectBuilder = class _SelectBuilder {
|
|
|
417
239
|
lines.push(this._compileLIMIT(engine, this._limit));
|
|
418
240
|
}
|
|
419
241
|
}
|
|
420
|
-
const pretty = lines.filter(Boolean).join(
|
|
242
|
+
const pretty = lines.filter(Boolean).join(`
|
|
243
|
+
`).trim();
|
|
421
244
|
let replacer;
|
|
422
245
|
const bindings = [];
|
|
423
246
|
if (engine === "pg") {
|
|
@@ -449,11 +272,6 @@ var SelectBuilder = class _SelectBuilder {
|
|
|
449
272
|
return `OFFSET ${offset} ROWS`;
|
|
450
273
|
}
|
|
451
274
|
}
|
|
452
|
-
/**
|
|
453
|
-
* Get SQL needed to return the found rows of this query
|
|
454
|
-
* @param engineStyle The database engine style (mssql, mysql, oracle, pg)
|
|
455
|
-
* @param countExpr The expression to use inside the COUNT()
|
|
456
|
-
*/
|
|
457
275
|
compileCount({
|
|
458
276
|
countExpr = "*",
|
|
459
277
|
engine = defaultEngine,
|
|
@@ -464,7 +282,8 @@ var SelectBuilder = class _SelectBuilder {
|
|
|
464
282
|
if (this._havings.length === 0) {
|
|
465
283
|
return { sql, bindings };
|
|
466
284
|
} else {
|
|
467
|
-
const subquerySql = sql.replace(/\n/g,
|
|
285
|
+
const subquerySql = sql.replace(/\n/g, `
|
|
286
|
+
`);
|
|
468
287
|
return {
|
|
469
288
|
sql: `SELECT COUNT(*) AS found_rows
|
|
470
289
|
FROM (
|
|
@@ -474,11 +293,6 @@ ${subquerySql}
|
|
|
474
293
|
};
|
|
475
294
|
}
|
|
476
295
|
}
|
|
477
|
-
/**
|
|
478
|
-
* Get SQL needed to union this query with another
|
|
479
|
-
* @param query The query to union
|
|
480
|
-
* @param engine The database engine style (mssql, mysql, oracle, pg)
|
|
481
|
-
*/
|
|
482
296
|
compileUnion(query, {
|
|
483
297
|
engine = defaultEngine,
|
|
484
298
|
bindingIndex = 1
|
|
@@ -495,11 +309,6 @@ UNION
|
|
|
495
309
|
bindings: [...first.bindings, ...second.bindings]
|
|
496
310
|
};
|
|
497
311
|
}
|
|
498
|
-
/**
|
|
499
|
-
* @param [fieldOrFields] If given, reset the given component(s), otherwise reset all query components
|
|
500
|
-
* Valid components: option, column, table, where, orWhere, having, groupBy, orderBy, limit, offset, page
|
|
501
|
-
* @return This object
|
|
502
|
-
*/
|
|
503
312
|
reset(fieldOrFields = null) {
|
|
504
313
|
if (Array.isArray(fieldOrFields)) {
|
|
505
314
|
fieldOrFields.forEach((name) => this.reset(name));
|
|
@@ -537,11 +346,8 @@ UNION
|
|
|
537
346
|
}
|
|
538
347
|
return this;
|
|
539
348
|
}
|
|
540
|
-
/**
|
|
541
|
-
* Clone this builder object
|
|
542
|
-
*/
|
|
543
349
|
getClone() {
|
|
544
|
-
const copy = new
|
|
350
|
+
const copy = new SelectBuilder;
|
|
545
351
|
copy._options = [...this._options];
|
|
546
352
|
copy._columns = [...this._columns];
|
|
547
353
|
copy._tables = [...this._tables];
|
|
@@ -556,10 +362,6 @@ UNION
|
|
|
556
362
|
copy._bindings = [...this._bindings];
|
|
557
363
|
return copy;
|
|
558
364
|
}
|
|
559
|
-
/**
|
|
560
|
-
* Build a version of this query that simply returns COUNT(*)
|
|
561
|
-
* @param [countExpr="*"] Use to specify `DISTINCT colname` if needed
|
|
562
|
-
*/
|
|
563
365
|
getFoundRowsQuery(countExpr = "*") {
|
|
564
366
|
if (this._havings.length === 0) {
|
|
565
367
|
const clone = this.getClone();
|
|
@@ -579,74 +381,34 @@ UNION
|
|
|
579
381
|
return subquery;
|
|
580
382
|
}
|
|
581
383
|
}
|
|
582
|
-
/**
|
|
583
|
-
* Add an array of column names to fetch
|
|
584
|
-
* @param columnNames The names of columns
|
|
585
|
-
*/
|
|
586
384
|
select(columnNames) {
|
|
587
385
|
this._columns = this._columns.concat(columnNames);
|
|
588
386
|
return this;
|
|
589
387
|
}
|
|
590
|
-
/**
|
|
591
|
-
* Add an array of column names to fetch
|
|
592
|
-
* @param columnNames The names of columns
|
|
593
|
-
*/
|
|
594
388
|
columns(columnNames) {
|
|
595
389
|
this._columns = this._columns.concat(columnNames);
|
|
596
390
|
return this;
|
|
597
391
|
}
|
|
598
|
-
/**
|
|
599
|
-
* Add a column name to fetch
|
|
600
|
-
* @param columnName The name of the column
|
|
601
|
-
*/
|
|
602
392
|
column(columnName) {
|
|
603
393
|
this._columns.push(columnName);
|
|
604
394
|
return this;
|
|
605
395
|
}
|
|
606
|
-
/**
|
|
607
|
-
* Add an option expression such as "TOP 10" or "SQL_CALC_FOUND_ROWS"
|
|
608
|
-
* @param optionExpression Expression to go after "SELECT" and before column list
|
|
609
|
-
*/
|
|
610
396
|
option(optionExpression) {
|
|
611
397
|
this._options.push(optionExpression);
|
|
612
398
|
return this;
|
|
613
399
|
}
|
|
614
|
-
/**
|
|
615
|
-
* Add a table to the "FROM" clause (same as .from())
|
|
616
|
-
* @param {String} tableName The name of the table to query
|
|
617
|
-
* @return {Select}
|
|
618
|
-
*/
|
|
619
400
|
table(tableName) {
|
|
620
401
|
this._tables.push(tableName);
|
|
621
402
|
return this;
|
|
622
403
|
}
|
|
623
|
-
/**
|
|
624
|
-
* Add multiple table to the "FROM" clause
|
|
625
|
-
* @param {Array} tableNames The names of the tables to query
|
|
626
|
-
* @return {Select}
|
|
627
|
-
*/
|
|
628
404
|
tables(tableNames) {
|
|
629
405
|
this._tables.push(...tableNames);
|
|
630
406
|
return this;
|
|
631
407
|
}
|
|
632
|
-
/**
|
|
633
|
-
* Add a table to the "FROM" clause (same as .table())
|
|
634
|
-
* @param {String} tableName The name of the table to query
|
|
635
|
-
* @return {Select}
|
|
636
|
-
*/
|
|
637
408
|
from(tableName) {
|
|
638
409
|
this._tables.push(tableName);
|
|
639
410
|
return this;
|
|
640
411
|
}
|
|
641
|
-
/**
|
|
642
|
-
* Add the given join type expression
|
|
643
|
-
* @param joinType The type of join (e.g. "INNER JOIN", "LEFT JOIN", etc.)
|
|
644
|
-
* @param expression The expression following the INNER JOIN keyword
|
|
645
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
646
|
-
* @example
|
|
647
|
-
* query.join('posts p ON p.id = c.post_id');
|
|
648
|
-
* query.join('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
649
|
-
*/
|
|
650
412
|
_addJoin(joinType, expression, bindings = []) {
|
|
651
413
|
if (bindings.length > 0) {
|
|
652
414
|
expression = expression.replace(/\?/g, () => {
|
|
@@ -656,118 +418,42 @@ UNION
|
|
|
656
418
|
}
|
|
657
419
|
this._joins.push(`${joinType} ${expression}`);
|
|
658
420
|
}
|
|
659
|
-
/**
|
|
660
|
-
* Add a JOIN expression
|
|
661
|
-
* @param expression The expression following the INNER JOIN keyword
|
|
662
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
663
|
-
* @example
|
|
664
|
-
* query.join('posts p ON p.id = c.post_id');
|
|
665
|
-
* query.join('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
666
|
-
*/
|
|
667
421
|
join(expression, bindings = []) {
|
|
668
422
|
this._addJoin("JOIN", expression, bindings);
|
|
669
423
|
return this;
|
|
670
424
|
}
|
|
671
|
-
/**
|
|
672
|
-
* Add a LEFT JOIN expression
|
|
673
|
-
* @param expression The expression following the LEFT JOIN keyword
|
|
674
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
675
|
-
* @example
|
|
676
|
-
* query.leftJoin('posts p ON p.id = c.post_id');
|
|
677
|
-
* query.leftJoin('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
678
|
-
*/
|
|
679
425
|
leftJoin(expression, bindings = []) {
|
|
680
426
|
this._addJoin("LEFT JOIN", expression, bindings);
|
|
681
427
|
return this;
|
|
682
428
|
}
|
|
683
|
-
/**
|
|
684
|
-
* Add a FULL JOIN expression
|
|
685
|
-
* @param expression The expression following the FULL JOIN keyword
|
|
686
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
687
|
-
* @example
|
|
688
|
-
* query.fullJoin('posts p ON p.id = c.post_id');
|
|
689
|
-
* query.fullJoin('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
690
|
-
*/
|
|
691
429
|
fullJoin(expression, bindings = []) {
|
|
692
430
|
this._addJoin("FULL JOIN", expression, bindings);
|
|
693
431
|
return this;
|
|
694
432
|
}
|
|
695
|
-
/**
|
|
696
|
-
* Add a RIGHT JOIN expression
|
|
697
|
-
* @param expression The expression following the RIGHT JOIN keyword
|
|
698
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
699
|
-
* @example
|
|
700
|
-
* query.rightJoin('posts p ON p.id = c.post_id');
|
|
701
|
-
* query.rightJoin('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
702
|
-
*/
|
|
703
433
|
rightJoin(expression, bindings = []) {
|
|
704
434
|
this._addJoin("RIGHT JOIN", expression, bindings);
|
|
705
435
|
return this;
|
|
706
436
|
}
|
|
707
|
-
/**
|
|
708
|
-
* Add a CROSS JOIN expression
|
|
709
|
-
* @param expression The expression following the CROSS JOIN keyword
|
|
710
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
711
|
-
* @example
|
|
712
|
-
* query.crossJoin('posts p ON p.id = c.post_id');
|
|
713
|
-
* query.crossJoin('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
714
|
-
*/
|
|
715
437
|
crossJoin(expression, bindings = []) {
|
|
716
438
|
this._addJoin("CROSS JOIN", expression, bindings);
|
|
717
439
|
return this;
|
|
718
440
|
}
|
|
719
|
-
/**
|
|
720
|
-
* Add an INNER JOIN expression (same as ->join())
|
|
721
|
-
* @param expression The expression following the INNER JOIN keyword
|
|
722
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
723
|
-
* @example
|
|
724
|
-
* query.innerJoin('posts p ON p.id = c.post_id');
|
|
725
|
-
* query.innerJoin('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
726
|
-
*/
|
|
727
441
|
innerJoin(expression, bindings = []) {
|
|
728
442
|
this._addJoin("INNER JOIN", expression, bindings);
|
|
729
443
|
return this;
|
|
730
444
|
}
|
|
731
|
-
/**
|
|
732
|
-
* Add a LEFT OUTER JOIN expression
|
|
733
|
-
* @param expression The expression following the LEFT OUTER JOIN keyword
|
|
734
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
735
|
-
* @example
|
|
736
|
-
* query.leftOuterJoin('posts p ON p.id = c.post_id');
|
|
737
|
-
* query.leftOuterJoin('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
738
|
-
*/
|
|
739
445
|
leftOuterJoin(expression, bindings = []) {
|
|
740
446
|
this._addJoin("LEFT OUTER JOIN", expression, bindings);
|
|
741
447
|
return this;
|
|
742
448
|
}
|
|
743
|
-
/**
|
|
744
|
-
* Add a FULL OUTER JOIN expression
|
|
745
|
-
* @param expression The expression following the FULL OUTER JOIN keyword
|
|
746
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
747
|
-
* @example
|
|
748
|
-
* query.fullOuterJoin('posts p ON p.id = c.post_id');
|
|
749
|
-
* query.fullOuterJoin('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
750
|
-
*/
|
|
751
449
|
fullOuterJoin(expression, bindings = []) {
|
|
752
450
|
this._addJoin("FULL OUTER JOIN", expression, bindings);
|
|
753
451
|
return this;
|
|
754
452
|
}
|
|
755
|
-
/**
|
|
756
|
-
* Add a RIGHT OUTER JOIN expression
|
|
757
|
-
* @param expression The expression following the RIGHT OUTER JOIN keyword
|
|
758
|
-
* @param bindings A list of values to bind to ? placeholders in the expression
|
|
759
|
-
* @example
|
|
760
|
-
* query.rightOuterJoin('posts p ON p.id = c.post_id');
|
|
761
|
-
* query.rightOuterJoin('posts p ON p.id = c.post_id AND p.deleted_at < ?', [myDate]);
|
|
762
|
-
*/
|
|
763
453
|
rightOuterJoin(expression, bindings = []) {
|
|
764
454
|
this._addJoin("RIGHT OUTER JOIN", expression, bindings);
|
|
765
455
|
return this;
|
|
766
456
|
}
|
|
767
|
-
/**
|
|
768
|
-
* Remove a join condition with the specified table
|
|
769
|
-
* @param table The name of the table or tables in the first part of the join statement
|
|
770
|
-
*/
|
|
771
457
|
unjoin(table) {
|
|
772
458
|
if (Array.isArray(table)) {
|
|
773
459
|
table.forEach((t) => this.unjoin(t));
|
|
@@ -779,34 +465,6 @@ UNION
|
|
|
779
465
|
});
|
|
780
466
|
return this;
|
|
781
467
|
}
|
|
782
|
-
/**
|
|
783
|
-
* Utility function to add conditions for a clause (WHERE, HAVING)
|
|
784
|
-
* @param collection The collection to add the clauses to (e.g. this._wheres or this._havings)
|
|
785
|
-
* @param criteria Criteria adhering to WhereCriteria type
|
|
786
|
-
* @example The following are equivalent
|
|
787
|
-
* this._conditions(this._wheres, ['deleted_at IS NULL']);
|
|
788
|
-
* this._conditions(this._wheres, ['deleted_at', null]);
|
|
789
|
-
* this._conditions(this._wheres, ['deleted_at', '=', null]);
|
|
790
|
-
* @example More examples
|
|
791
|
-
* this._conditions(this._wheres, ['fname', 'LIKE', 'joe']); // `fname` LIKE 'joe'
|
|
792
|
-
* this._conditions(this._wheres, ['fname', 'LIKE ?', 'joe']); // `fname` LIKE 'joe'
|
|
793
|
-
* this._conditions(this._wheres, ['fname LIKE %?%', 'joe']); // `fname` LIKE '%joe%'
|
|
794
|
-
* this._conditions(this._wheres, ['fname LIKE ?%', 'joe']); // `fname` LIKE 'joe%'
|
|
795
|
-
* this._conditions(this._wheres, ['fname', 'LIKE ?%', 'joe']); // `fname` LIKE 'joe%'
|
|
796
|
-
* this._conditions(this._wheres, ['price >', 10]); // `price` > 10
|
|
797
|
-
* this._conditions(this._wheres, ['price', '>', 10]); // `price` > 10
|
|
798
|
-
* this._conditions(this._wheres, ['price =', 10]); // `price` = 10
|
|
799
|
-
* this._conditions(this._wheres, ['price !=', 10]); // `price` != 10
|
|
800
|
-
* this._conditions(this._wheres, ['price', 10]); // `price` = 10
|
|
801
|
-
* this._conditions(this._wheres, ['price', '=', 10]); // `price` = 10
|
|
802
|
-
* this._conditions(this._wheres, ['price', '!=', 10]); // `price` != 10
|
|
803
|
-
* this._conditions(this._wheres, ['price', 'BETWEEN', [10,20]]); // `price` BETWEEN 10 AND 20
|
|
804
|
-
* this._conditions(this._wheres, ['price', 'NOT BETWEEN', [10,20]]); // `price` NOT BETWEEN 10 AND 20
|
|
805
|
-
* this._conditions(this._wheres, ['price', [10,20]]); // `price` IN(10,20)
|
|
806
|
-
* this._conditions(this._wheres, ['price', '=', [10,20]]); // `price` IN(10,20)
|
|
807
|
-
* this._conditions(this._wheres, ['price', 'IN', [10,20]]); // `price` IN(10,20)
|
|
808
|
-
* this._conditions(this._wheres, ['price', 'NOT IN', [10,20]]); // `price` NOT IN(10,20)
|
|
809
|
-
*/
|
|
810
468
|
_conditions(collection, criteria) {
|
|
811
469
|
const numArgs = criteria.length;
|
|
812
470
|
let [column, operator, value] = criteria;
|
|
@@ -837,15 +495,11 @@ UNION
|
|
|
837
495
|
operator = "=";
|
|
838
496
|
}
|
|
839
497
|
operator = operator.toLocaleUpperCase();
|
|
840
|
-
const likeMatch = operator.match(
|
|
841
|
-
/^(LIKE|NOT LIKE|ILIKE|NOT ILIKE)(?: (\?|\?%|%\?|%\?%))?$/i
|
|
842
|
-
);
|
|
498
|
+
const likeMatch = operator.match(/^(LIKE|NOT LIKE|ILIKE|NOT ILIKE)(?: (\?|\?%|%\?|%\?%))?$/i);
|
|
843
499
|
if (operator === "NOT BETWEEN" || operator === "BETWEEN") {
|
|
844
500
|
const one = this._bindings.length;
|
|
845
501
|
const two = this._bindings.length + 1;
|
|
846
|
-
collection.push(
|
|
847
|
-
`${column} ${operator} __BOUND_${one}__ AND __BOUND_${two}__`
|
|
848
|
-
);
|
|
502
|
+
collection.push(`${column} ${operator} __BOUND_${one}__ AND __BOUND_${two}__`);
|
|
849
503
|
this._bindings.push(value[0], value[1]);
|
|
850
504
|
} else if (likeMatch) {
|
|
851
505
|
const like = likeMatch[1].toUpperCase();
|
|
@@ -863,52 +517,32 @@ UNION
|
|
|
863
517
|
this._bindings.push(infix.replace("?", value || ""));
|
|
864
518
|
}
|
|
865
519
|
} else if (value === null) {
|
|
866
|
-
collection.push(
|
|
867
|
-
operator === "=" ? `${column} IS NULL` : `${column} IS NOT NULL`
|
|
868
|
-
);
|
|
520
|
+
collection.push(operator === "=" ? `${column} IS NULL` : `${column} IS NOT NULL`);
|
|
869
521
|
} else if (Array.isArray(value)) {
|
|
870
522
|
const inVals = [];
|
|
871
|
-
for (let i = 0;
|
|
523
|
+
for (let i = 0;i < value.length; i++) {
|
|
872
524
|
inVals.push(`__BOUND_${this._bindings.length}__`);
|
|
873
525
|
this._bindings.push(value[i]);
|
|
874
526
|
}
|
|
875
527
|
const joined = inVals.join(", ");
|
|
876
|
-
collection.push(
|
|
877
|
-
operator === "=" || operator === "IN" ? `${column} IN(${joined})` : `${column} NOT IN(${joined})`
|
|
878
|
-
);
|
|
528
|
+
collection.push(operator === "=" || operator === "IN" ? `${column} IN(${joined})` : `${column} NOT IN(${joined})`);
|
|
879
529
|
} else if (operator === "IN" || operator === "NOT IN") {
|
|
880
|
-
collection.push(
|
|
881
|
-
`${column} ${operator}(__BOUND_${this._bindings.length}__)`
|
|
882
|
-
);
|
|
530
|
+
collection.push(`${column} ${operator}(__BOUND_${this._bindings.length}__)`);
|
|
883
531
|
this._bindings.push(value);
|
|
884
532
|
} else {
|
|
885
|
-
collection.push(
|
|
886
|
-
`${column} ${operator} __BOUND_${this._bindings.length}__`
|
|
887
|
-
);
|
|
533
|
+
collection.push(`${column} ${operator} __BOUND_${this._bindings.length}__`);
|
|
888
534
|
this._bindings.push(value);
|
|
889
535
|
}
|
|
890
536
|
return this;
|
|
891
537
|
}
|
|
892
|
-
/**
|
|
893
|
-
* Add a group by column or expression
|
|
894
|
-
* @param column The name of a column (or expression) to group by
|
|
895
|
-
*/
|
|
896
538
|
groupBy(column) {
|
|
897
539
|
this._groupBys.push(column);
|
|
898
540
|
return this;
|
|
899
541
|
}
|
|
900
|
-
/**
|
|
901
|
-
* Add WHERE clauses to conditions (See _conditions for usage)
|
|
902
|
-
*/
|
|
903
542
|
where(...args) {
|
|
904
543
|
this._conditions(this._wheres, args);
|
|
905
544
|
return this;
|
|
906
545
|
}
|
|
907
|
-
/**
|
|
908
|
-
* Add a WHERE clause with a BETWEEN condition
|
|
909
|
-
* @param column The column name
|
|
910
|
-
* @param twoValueArray The two values to be between
|
|
911
|
-
*/
|
|
912
546
|
whereBetween(column, twoValueArray) {
|
|
913
547
|
if (!isNullish(twoValueArray[0]) && !isNullish(twoValueArray[1])) {
|
|
914
548
|
this.where(column, "BETWEEN", twoValueArray);
|
|
@@ -916,14 +550,9 @@ UNION
|
|
|
916
550
|
this.where(column, ">=", twoValueArray[0]);
|
|
917
551
|
} else if (isNullish(twoValueArray[0]) && !isNullish(twoValueArray[1])) {
|
|
918
552
|
this.where(column, "<=", twoValueArray[1]);
|
|
919
|
-
} else {
|
|
920
|
-
}
|
|
553
|
+
} else {}
|
|
921
554
|
return this;
|
|
922
555
|
}
|
|
923
|
-
/**
|
|
924
|
-
* Add a series of WHERE clauses joined by OR (See _conditions for usage)
|
|
925
|
-
* @param conditions
|
|
926
|
-
*/
|
|
927
556
|
_orConditions(conditions) {
|
|
928
557
|
const items = [];
|
|
929
558
|
if (Array.isArray(conditions)) {
|
|
@@ -948,41 +577,20 @@ UNION
|
|
|
948
577
|
return joined;
|
|
949
578
|
}
|
|
950
579
|
}
|
|
951
|
-
/**
|
|
952
|
-
* Add WHERE conditions to place inside an OR block (See _conditions for usage)
|
|
953
|
-
* @param conditions A list or object where each item is an array with parameters that would be taken by where()
|
|
954
|
-
*/
|
|
955
580
|
orWhere(conditions) {
|
|
956
581
|
const joined = this._orConditions(conditions);
|
|
957
582
|
this.where(`(${joined})`);
|
|
958
583
|
return this;
|
|
959
584
|
}
|
|
960
|
-
/**
|
|
961
|
-
* Add an OR with conditions under the HAVING clause
|
|
962
|
-
* @param conditions A list or object where each item is an array with parameters that would be taken by having()
|
|
963
|
-
*/
|
|
964
585
|
orHaving(conditions) {
|
|
965
586
|
const joined = this._orConditions(conditions);
|
|
966
587
|
this.having(`(${joined})`);
|
|
967
588
|
return this;
|
|
968
589
|
}
|
|
969
|
-
/**
|
|
970
|
-
* Add a HAVING condition (See _conditions for usage)
|
|
971
|
-
*/
|
|
972
590
|
having(...args) {
|
|
973
591
|
this._conditions(this._havings, args);
|
|
974
592
|
return this;
|
|
975
593
|
}
|
|
976
|
-
/**
|
|
977
|
-
* Add a column or expression to order by
|
|
978
|
-
* @param column The column name or expression to sort by. Include DESC or prefix with - to sort descending
|
|
979
|
-
* @param [direction] The direction to sort by (ASC or DESC)
|
|
980
|
-
* @example
|
|
981
|
-
* query.sortField('modified_at'); // ORDER BY modified_at
|
|
982
|
-
* query.sortField('-modified_at'); // ORDER BY modified_at DESC
|
|
983
|
-
* query.sortField('COUNT(*)'); // ORDER BY COUNT(*)
|
|
984
|
-
* query.sortField('COUNT(*) DESC'); // ORDER BY COUNT(*) DESC
|
|
985
|
-
*/
|
|
986
594
|
orderBy(column, direction = null) {
|
|
987
595
|
if (direction) {
|
|
988
596
|
this._orderBys.push(`${column} ${direction}`);
|
|
@@ -992,14 +600,6 @@ UNION
|
|
|
992
600
|
}
|
|
993
601
|
return this;
|
|
994
602
|
}
|
|
995
|
-
/**
|
|
996
|
-
* Sort by the given column, with a map of columns to translate
|
|
997
|
-
* @param fieldName The file name such as "created_at" or "-created_at" for descending
|
|
998
|
-
* @param [mapNames] Column names to translate from field to column expression
|
|
999
|
-
* @example
|
|
1000
|
-
* query.sortField('-modified_at'); // ORDER BY modified_at DESC
|
|
1001
|
-
* query.sortField('-created', {'created': 'created_at'}); // ORDER BY created_at DESC
|
|
1002
|
-
*/
|
|
1003
603
|
sortField(fieldName, mapNames = {}) {
|
|
1004
604
|
let direction = "ASC";
|
|
1005
605
|
if (fieldName.startsWith("-")) {
|
|
@@ -1010,26 +610,12 @@ UNION
|
|
|
1010
610
|
this.orderBy(column, direction);
|
|
1011
611
|
return this;
|
|
1012
612
|
}
|
|
1013
|
-
/**
|
|
1014
|
-
* Check to see if the given string is 0 or all digits not starting with 0
|
|
1015
|
-
* @param string The input string
|
|
1016
|
-
* @private
|
|
1017
|
-
*/
|
|
1018
613
|
_isEntirelyDigits(string) {
|
|
1019
614
|
return /^(0|[1-9]\d*)$/.test(string);
|
|
1020
615
|
}
|
|
1021
|
-
/**
|
|
1022
|
-
* Check to see if the given string is all digits
|
|
1023
|
-
* @param string The input string
|
|
1024
|
-
* @private
|
|
1025
|
-
*/
|
|
1026
616
|
_isEntirelyDigitsNoZeros(string) {
|
|
1027
617
|
return /^[1-9]\d*$/.test(string);
|
|
1028
618
|
}
|
|
1029
|
-
/**
|
|
1030
|
-
* Limit results to the given number
|
|
1031
|
-
* @param max The number to limit by (placeholder string or integer greater than 0)
|
|
1032
|
-
*/
|
|
1033
619
|
limit(max) {
|
|
1034
620
|
if (typeof max === "string") {
|
|
1035
621
|
max = max.trim();
|
|
@@ -1039,55 +625,38 @@ UNION
|
|
|
1039
625
|
} else if (typeof max === "number" && Number.isInteger(max) && max >= 1) {
|
|
1040
626
|
this._limit = max;
|
|
1041
627
|
} else {
|
|
1042
|
-
throw new Error(
|
|
1043
|
-
`SelectBuilder: "limit(n)" must receive a positive integer (got "${max}")`
|
|
1044
|
-
);
|
|
628
|
+
throw new Error(`SelectBuilder: "limit(n)" must receive a positive integer (got "${max}")`);
|
|
1045
629
|
}
|
|
1046
630
|
return this;
|
|
1047
631
|
}
|
|
1048
|
-
/**
|
|
1049
|
-
* Fetch results from the given offset
|
|
1050
|
-
* @param number The offset (placeholder string or integer greater than or equal to 0)
|
|
1051
|
-
*/
|
|
1052
632
|
offset(number) {
|
|
1053
633
|
if (typeof number === "string" && this._isEntirelyDigits(number.trim())) {
|
|
1054
634
|
this._offset = parseInt(number, 10);
|
|
1055
635
|
} else if (typeof number === "number" && Number.isInteger(number) && number >= 0) {
|
|
1056
636
|
this._offset = number;
|
|
1057
637
|
} else {
|
|
1058
|
-
throw new Error(
|
|
1059
|
-
`SelectBuilder: "offset(n)" must receive a positive integer (got "${number}")`
|
|
1060
|
-
);
|
|
638
|
+
throw new Error(`SelectBuilder: "offset(n)" must receive a positive integer (got "${number}")`);
|
|
1061
639
|
}
|
|
1062
640
|
return this;
|
|
1063
641
|
}
|
|
1064
|
-
/**
|
|
1065
|
-
* Set the offset based on the limit with the given page number
|
|
1066
|
-
* @param number The page number (integer greater than 0)
|
|
1067
|
-
*/
|
|
1068
642
|
page(number) {
|
|
1069
643
|
if (typeof number === "string" && this._isEntirelyDigitsNoZeros(number.trim())) {
|
|
1070
644
|
this._page = parseInt(number, 10);
|
|
1071
645
|
} else if (typeof number === "number" && Number.isInteger(number) && number >= 1) {
|
|
1072
646
|
this._page = number;
|
|
1073
647
|
} else {
|
|
1074
|
-
throw new Error(
|
|
1075
|
-
'SelectBuilder: "page(n)" must receive a positive integer'
|
|
1076
|
-
);
|
|
648
|
+
throw new Error('SelectBuilder: "page(n)" must receive a positive integer');
|
|
1077
649
|
}
|
|
1078
650
|
return this;
|
|
1079
651
|
}
|
|
1080
|
-
}
|
|
1081
|
-
|
|
652
|
+
}
|
|
1082
653
|
// src/extractGrouped/extractGrouped.ts
|
|
1083
654
|
function extractGrouped(field, records) {
|
|
1084
655
|
let idx = 0;
|
|
1085
656
|
const grouped = {};
|
|
1086
657
|
for (const record of records) {
|
|
1087
658
|
if (!(field in record)) {
|
|
1088
|
-
throw new Error(
|
|
1089
|
-
`Column "${String(field)}" is not present in record ${idx}`
|
|
1090
|
-
);
|
|
659
|
+
throw new Error(`Column "${String(field)}" is not present in record ${idx}`);
|
|
1091
660
|
}
|
|
1092
661
|
if (!grouped[record[field]]) {
|
|
1093
662
|
grouped[record[field]] = [];
|
|
@@ -1097,44 +666,35 @@ function extractGrouped(field, records) {
|
|
|
1097
666
|
}
|
|
1098
667
|
return grouped;
|
|
1099
668
|
}
|
|
1100
|
-
|
|
1101
669
|
// src/extractIndexed/extractIndexed.ts
|
|
1102
670
|
function extractIndexed(field, records) {
|
|
1103
671
|
let idx = 0;
|
|
1104
672
|
const indexed = {};
|
|
1105
673
|
for (const record of records) {
|
|
1106
674
|
if (!(field in record)) {
|
|
1107
|
-
throw new Error(
|
|
1108
|
-
`Column "${String(field)}" is not present in record ${idx}`
|
|
1109
|
-
);
|
|
675
|
+
throw new Error(`Column "${String(field)}" is not present in record ${idx}`);
|
|
1110
676
|
}
|
|
1111
677
|
indexed[record[field]] = record;
|
|
1112
678
|
idx++;
|
|
1113
679
|
}
|
|
1114
680
|
return indexed;
|
|
1115
681
|
}
|
|
1116
|
-
|
|
1117
682
|
// src/extractLookup/extractLookup.ts
|
|
1118
683
|
function extractLookup(keyField, valueField, records) {
|
|
1119
684
|
const lookup = {};
|
|
1120
685
|
let idx = 0;
|
|
1121
686
|
for (const record of records) {
|
|
1122
687
|
if (!(keyField in record)) {
|
|
1123
|
-
throw new Error(
|
|
1124
|
-
`Column "${String(keyField)}" is not present in record ${idx}`
|
|
1125
|
-
);
|
|
688
|
+
throw new Error(`Column "${String(keyField)}" is not present in record ${idx}`);
|
|
1126
689
|
}
|
|
1127
690
|
if (!(valueField in record)) {
|
|
1128
|
-
throw new Error(
|
|
1129
|
-
`Column "${String(valueField)}" is not present in record ${idx}`
|
|
1130
|
-
);
|
|
691
|
+
throw new Error(`Column "${String(valueField)}" is not present in record ${idx}`);
|
|
1131
692
|
}
|
|
1132
693
|
idx++;
|
|
1133
694
|
lookup[String(record[keyField])] = record[valueField];
|
|
1134
695
|
}
|
|
1135
696
|
return lookup;
|
|
1136
697
|
}
|
|
1137
|
-
|
|
1138
698
|
// src/getPagination/getPagination.ts
|
|
1139
699
|
function getPagination(query, total) {
|
|
1140
700
|
total = Number(total) || 0;
|
|
@@ -1167,7 +727,6 @@ function getPagination(query, total) {
|
|
|
1167
727
|
isLast
|
|
1168
728
|
};
|
|
1169
729
|
}
|
|
1170
|
-
|
|
1171
730
|
// src/runMysql/runMysql.ts
|
|
1172
731
|
function _queryToPromise(mysqlClient, sql, bindings) {
|
|
1173
732
|
return new Promise((resolve, reject) => {
|
|
@@ -1218,7 +777,6 @@ async function runMysqlAsyncWithCount(mysqlClient, query, {
|
|
|
1218
777
|
return { records, total: 0, pagination: getPagination(query, 0), fields };
|
|
1219
778
|
}
|
|
1220
779
|
}
|
|
1221
|
-
|
|
1222
780
|
// src/toSafeJson/toSafeJson.ts
|
|
1223
781
|
function toSafeJsonValue(value) {
|
|
1224
782
|
if (typeof value === "bigint") {
|
|
@@ -1245,19 +803,16 @@ function toSafeJsonString(records) {
|
|
|
1245
803
|
}
|
|
1246
804
|
|
|
1247
805
|
// src/runPrisma/runPrisma.ts
|
|
1248
|
-
async function runPrisma(prisma, query, { engine =
|
|
806
|
+
async function runPrisma(prisma, query, { engine = undefined } = {}) {
|
|
1249
807
|
const { sql, bindings } = query.compile({ engine });
|
|
1250
808
|
return prisma.$queryRawUnsafe(sql, ...bindings);
|
|
1251
809
|
}
|
|
1252
810
|
async function runPrismaWithCount(prisma, query, {
|
|
1253
|
-
engine =
|
|
811
|
+
engine = undefined,
|
|
1254
812
|
countExpr = "*"
|
|
1255
813
|
} = {}) {
|
|
1256
814
|
const { sql, bindings } = query.compile({ engine });
|
|
1257
|
-
const records = await prisma.$queryRawUnsafe(
|
|
1258
|
-
sql,
|
|
1259
|
-
...bindings
|
|
1260
|
-
);
|
|
815
|
+
const records = await prisma.$queryRawUnsafe(sql, ...bindings);
|
|
1261
816
|
if (records.length > 0) {
|
|
1262
817
|
const { sql: sql2, bindings: bindings2 } = query.compileCount({ engine, countExpr });
|
|
1263
818
|
const result = await prisma.$queryRawUnsafe(sql2, ...bindings2);
|
|
@@ -1268,20 +823,20 @@ async function runPrismaWithCount(prisma, query, {
|
|
|
1268
823
|
}
|
|
1269
824
|
}
|
|
1270
825
|
export {
|
|
1271
|
-
|
|
1272
|
-
SelectBuilder,
|
|
1273
|
-
extractGrouped,
|
|
1274
|
-
extractIndexed,
|
|
1275
|
-
extractLookup,
|
|
1276
|
-
getPagination,
|
|
1277
|
-
runMysql,
|
|
1278
|
-
runMysqlAsync,
|
|
1279
|
-
runMysqlAsyncWithCount,
|
|
1280
|
-
runMysqlWithCount,
|
|
1281
|
-
runPrisma,
|
|
1282
|
-
runPrismaWithCount,
|
|
1283
|
-
toSafeJsonRecord,
|
|
1284
|
-
toSafeJsonRecords,
|
|
826
|
+
toSafeJsonValue,
|
|
1285
827
|
toSafeJsonString,
|
|
1286
|
-
|
|
828
|
+
toSafeJsonRecords,
|
|
829
|
+
toSafeJsonRecord,
|
|
830
|
+
runPrismaWithCount,
|
|
831
|
+
runPrisma,
|
|
832
|
+
runMysqlWithCount,
|
|
833
|
+
runMysqlAsyncWithCount,
|
|
834
|
+
runMysqlAsync,
|
|
835
|
+
runMysql,
|
|
836
|
+
getPagination,
|
|
837
|
+
extractLookup,
|
|
838
|
+
extractIndexed,
|
|
839
|
+
extractGrouped,
|
|
840
|
+
SelectBuilder,
|
|
841
|
+
Parser
|
|
1287
842
|
};
|