utilitas 1995.2.11 → 1995.2.13
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 +1 -1
- package/dist/utilitas.lite.mjs +1 -1
- package/dist/utilitas.lite.mjs.map +1 -1
- package/lib/dbio.mjs +130 -84
- package/lib/manifest.mjs +1 -1
- package/package.json +1 -1
package/lib/dbio.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
assertSet, ensureArray, ensureString, log as _log, need,
|
|
2
|
+
assertSet, ensureArray, ensureString, log as _log, need, throwError,
|
|
3
3
|
} from './utilitas.mjs';
|
|
4
4
|
|
|
5
5
|
import { isPrimary } from './callosum.mjs';
|
|
@@ -7,21 +7,27 @@ import { isPrimary } from './callosum.mjs';
|
|
|
7
7
|
const _NEED = ['mysql2', 'pg'];
|
|
8
8
|
const [mysqlDefaultPort, postgresqlDefaultPort] = [3306, 5432];
|
|
9
9
|
const [mysqlQuote, postgresqlQuote] = ['`', ''];
|
|
10
|
+
const IFSC = 'information_schema';
|
|
10
11
|
const orders = { '+': 'ASC', '-': 'DESC' };
|
|
12
|
+
const [INSERT, UPDATE, RETURNING] = ['INSERT', 'UPDATE', 'RETURNING'];
|
|
13
|
+
const RETURNING_ALL = ` RETURNING *`;
|
|
11
14
|
const [fieldId, fieldAny] = ['id', '*'];
|
|
12
15
|
const fieldCount = `COUNT(${fieldAny})`;
|
|
16
|
+
const direct = { direct: true };
|
|
13
17
|
const comparison = ['=', '>', '<', '<>', '!='];
|
|
14
18
|
const fieldNoQuote = [fieldAny, fieldCount];
|
|
15
|
-
const log =
|
|
16
|
-
const defaultKey =
|
|
19
|
+
const log = content => _log(content, import.meta.url);
|
|
20
|
+
const defaultKey = options => options && options.key ? options.key : fieldId;
|
|
17
21
|
const queryOne = async (...args) => (await query(...args))[0];
|
|
18
22
|
const assertForce = op => assert(op?.force, "Option 'force' is required.", 500);
|
|
19
23
|
const [MYSQL, POSTGRESQL] = ['MYSQL', 'POSTGRESQL'];
|
|
20
24
|
const quote = name => `${bracket}${name}${bracket}`;
|
|
21
25
|
const join = elements => elements.join(', ');
|
|
26
|
+
const assembleDelete = table => `DELETE FROM ${quote(assertTable(table))}`;
|
|
27
|
+
const execByQuery = async (...a) => await rawQuery(...distillArguments(...a));
|
|
22
28
|
|
|
23
|
-
let provider, pool, actExecute, bracket,
|
|
24
|
-
|
|
29
|
+
let provider, pool, actExecute, bracket, sqlShowTables, placeholder,
|
|
30
|
+
sqlShowIndexes, fieldCountResult, sqlDesc, doublePlaceholder;
|
|
25
31
|
|
|
26
32
|
const init = async (options) => {
|
|
27
33
|
if (options) {
|
|
@@ -34,14 +40,17 @@ const init = async (options) => {
|
|
|
34
40
|
const mysql = await need('mysql2/promise');
|
|
35
41
|
delete options.provider;
|
|
36
42
|
[
|
|
37
|
-
provider, pool, port, actExecute, bracket,
|
|
38
|
-
|
|
39
|
-
fieldCountResult,
|
|
43
|
+
provider, pool, port, actExecute, bracket, sqlShowTables,
|
|
44
|
+
placeholder, fieldCountResult,
|
|
40
45
|
] = [
|
|
41
46
|
MYSQL, mysql.createPool(options), mysqlDefaultPort,
|
|
42
|
-
'execute', mysqlQuote, '
|
|
43
|
-
'?', 'SHOW INDEXES FROM ??', fieldCount,
|
|
47
|
+
'execute', mysqlQuote, 'SHOW TABLES', '?', fieldCount,
|
|
44
48
|
];
|
|
49
|
+
doublePlaceholder = `${placeholder}${placeholder}`;
|
|
50
|
+
[sqlShowIndexes, sqlDesc] = [
|
|
51
|
+
`SHOW INDEXES FROM ${doublePlaceholder}`,
|
|
52
|
+
`DESC ${doublePlaceholder}`,
|
|
53
|
+
];
|
|
45
54
|
break;
|
|
46
55
|
case 'PG':
|
|
47
56
|
case 'POSTGRE':
|
|
@@ -50,16 +59,17 @@ const init = async (options) => {
|
|
|
50
59
|
// https://node-postgres.com/apis/pool
|
|
51
60
|
const { Pool } = await need('pg');
|
|
52
61
|
[
|
|
53
|
-
provider, pool, port, actExecute, bracket,
|
|
54
|
-
sqlShowTable, defaultPlaceholder, sqlShowIndex,
|
|
62
|
+
provider, pool, port, actExecute, bracket, placeholder,
|
|
55
63
|
fieldCountResult,
|
|
56
64
|
] = [
|
|
57
65
|
POSTGRESQL, new Pool(options), postgresqlDefaultPort,
|
|
58
|
-
'query', postgresqlQuote, '
|
|
59
|
-
"SELECT * FROM information_schema.tables WHERE table_schema = 'public'",
|
|
60
|
-
'$1', 'SELECT * FROM pg_indexes WHERE tablename = $1',
|
|
61
|
-
'count',
|
|
66
|
+
'query', postgresqlQuote, '$1', 'count',
|
|
62
67
|
];
|
|
68
|
+
[sqlShowTables, sqlShowIndexes, sqlDesc] = [
|
|
69
|
+
[`${IFSC}.tables`, 'table_schema', "'public'", direct],
|
|
70
|
+
['pg_indexes', 'tablename', ''],
|
|
71
|
+
[`${IFSC}.COLUMNS`, 'TABLE_NAME', ''],
|
|
72
|
+
].map(args => assembleQueryByKeyValue(...args));
|
|
63
73
|
break;
|
|
64
74
|
default:
|
|
65
75
|
assert(
|
|
@@ -134,25 +144,29 @@ const execute = async (...args) => {
|
|
|
134
144
|
}
|
|
135
145
|
};
|
|
136
146
|
|
|
137
|
-
const assertTable = (table, message, status) =>
|
|
147
|
+
const assertTable = (table, message, status) => {
|
|
138
148
|
assert(table, message || 'Table is required.', status || 500);
|
|
149
|
+
return table;
|
|
150
|
+
};
|
|
139
151
|
|
|
140
152
|
const assertKeyValue = (key, value) => {
|
|
141
153
|
assert(key, 'Key is required.', 500);
|
|
142
154
|
assertSet(value, 'Value is required.', 500);
|
|
143
155
|
};
|
|
144
156
|
|
|
157
|
+
const assembleQueryByKeyValue = (table, key, value, options) =>
|
|
158
|
+
assembleQuery(table) + assembleKeyValue(key, value, options);
|
|
159
|
+
|
|
145
160
|
// const assertTableKeyValue = (table, key, value) => {
|
|
146
161
|
// assertTable(table);
|
|
147
162
|
// assertKeyValue(key, value);
|
|
148
163
|
// };
|
|
149
164
|
|
|
150
165
|
const assembleQuery = (table, options) => {
|
|
151
|
-
options = options || {};
|
|
152
166
|
assertTable(table);
|
|
153
167
|
const fields = [];
|
|
154
|
-
ensureArray(options
|
|
155
|
-
fields.push(fieldNoQuote.includes(field) || options
|
|
168
|
+
ensureArray(options?.fields).map((field) => {
|
|
169
|
+
fields.push(fieldNoQuote.includes(field) || options?.noQuote
|
|
156
170
|
? field : quote(field));
|
|
157
171
|
});
|
|
158
172
|
if (!fields.length) { fields.push(fieldAny); }
|
|
@@ -160,73 +174,94 @@ const assembleQuery = (table, options) => {
|
|
|
160
174
|
};
|
|
161
175
|
|
|
162
176
|
const rawAssembleKeyValue = (key, value, options) => {
|
|
163
|
-
options = options || {};
|
|
164
177
|
assertKeyValue(key, value);
|
|
165
|
-
let
|
|
178
|
+
let _placeholder;
|
|
179
|
+
switch (provider) {
|
|
180
|
+
case MYSQL:
|
|
181
|
+
_placeholder = placeholder;
|
|
182
|
+
break;
|
|
183
|
+
case POSTGRESQL:
|
|
184
|
+
_placeholder = `$${options?.placeholderIndex || 1}`;
|
|
185
|
+
}
|
|
186
|
+
const val = options?.direct ? value : _placeholder;
|
|
187
|
+
let express = `${getComparison(value) || '='} ${val}`;
|
|
166
188
|
if (Array.isArray(value)) {
|
|
167
189
|
assert(value.length, 'Invalid array value.', 500);
|
|
168
|
-
express = `IN (${
|
|
169
|
-
} else if (value === null) { express = `IS ${
|
|
170
|
-
return `${options
|
|
190
|
+
express = `IN (${val})`;
|
|
191
|
+
} else if (value === null) { express = `IS ${val}`; }
|
|
192
|
+
return `${options?.prefix || ''}${quote(key)} ${express}`;
|
|
171
193
|
};
|
|
172
194
|
|
|
173
|
-
const assembleKeyValue = (key, value, options) =>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return rawAssembleKeyValue(key, value, options);
|
|
177
|
-
};
|
|
195
|
+
const assembleKeyValue = (key, value, options) => rawAssembleKeyValue(
|
|
196
|
+
key, value, { ...options || {}, prefix: ' WHERE ' }
|
|
197
|
+
);
|
|
178
198
|
|
|
179
199
|
const pushValue = (values, item) => values.push(
|
|
180
200
|
Object.isObject(item) || Array.isArray(item) ? JSON.stringify(item) : item
|
|
181
201
|
);
|
|
182
202
|
|
|
183
203
|
const assembleSet = (data, options) => {
|
|
184
|
-
|
|
185
|
-
const [isArray, result] = [options.asArray || Array.isArray(data), []];
|
|
204
|
+
const [isArray, result] = [options?.asArray || Array.isArray(data), []];
|
|
186
205
|
ensureArray(data).map((item) => {
|
|
187
206
|
assert(Object.keys(item).length, 'Fields are required.', 500);
|
|
188
|
-
let [keys, vals, values, dupSql
|
|
207
|
+
let [pairs, keys, vals, values, dupSql, i, sql]
|
|
208
|
+
= [[], [], [], [], [], 0, ''];
|
|
189
209
|
for (let k in item) {
|
|
190
210
|
keys.push(k);
|
|
191
211
|
switch (provider) {
|
|
192
|
-
case MYSQL:
|
|
193
|
-
|
|
212
|
+
case MYSQL:
|
|
213
|
+
vals.push('?');
|
|
214
|
+
pairs.push(`${quote(k)} = ?`);
|
|
215
|
+
break;
|
|
216
|
+
case POSTGRESQL:
|
|
217
|
+
vals.push(`$${++i}`);
|
|
218
|
+
pairs.push(`${quote(k)} = $${i}`);
|
|
194
219
|
}
|
|
195
220
|
pushValue(values, item[k]);
|
|
196
221
|
}
|
|
197
|
-
if (options
|
|
222
|
+
if (options?.upsert) {
|
|
198
223
|
for (let k in item) {
|
|
199
|
-
|
|
224
|
+
switch (provider) {
|
|
225
|
+
case MYSQL: dupSql.push(`${quote(k)} = ?`); break;
|
|
226
|
+
case POSTGRESQL: dupSql.push(`${quote(k)} = $${++i}`); break;
|
|
227
|
+
}
|
|
200
228
|
pushValue(values, item[k]);
|
|
201
229
|
}
|
|
202
|
-
|
|
230
|
+
switch (provider) {
|
|
231
|
+
case MYSQL:
|
|
232
|
+
dupSql = ` ON DUPLICATE KEY UPDATE ${join(dupSql)}`;
|
|
233
|
+
break;
|
|
234
|
+
case POSTGRESQL:
|
|
235
|
+
const target = options?.key ? ` (${options?.key})` : '';
|
|
236
|
+
dupSql = ` ON CONFLICT${target} DO UPDATE SET ${join(dupSql)}`;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
203
239
|
} else { dupSql = ''; }
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
240
|
+
switch (options?.action) {
|
|
241
|
+
case INSERT:
|
|
242
|
+
sql = `(${join(keys.map(quote))}) VALUES (${join(vals)})`;
|
|
243
|
+
break;
|
|
244
|
+
case UPDATE:
|
|
245
|
+
sql = `SET ${pairs.join(', ')}`;
|
|
246
|
+
break;
|
|
247
|
+
default:
|
|
248
|
+
throwError(`Invalid action: '${options?.action}'.`, 400);
|
|
249
|
+
}
|
|
250
|
+
sql = `${options?.prefix || ''}${sql}${dupSql}${options?.subfix || ''}`;
|
|
207
251
|
result.push({ sql, values, object: item });
|
|
208
252
|
});
|
|
209
253
|
return isArray ? result : result[0];
|
|
210
254
|
};
|
|
211
255
|
|
|
212
|
-
const assembleInsert = (table, data, options) => {
|
|
213
|
-
options
|
|
214
|
-
assertTable(table)
|
|
215
|
-
|
|
216
|
-
return assembleSet(data, options);
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const assembleUpdate = (table, data, options) => {
|
|
220
|
-
options = options || {};
|
|
221
|
-
assertTable(table);
|
|
222
|
-
options.prefix = `UPDATE ${quote(table)} `;
|
|
223
|
-
return assembleSet(data, options);
|
|
224
|
-
};
|
|
256
|
+
const assembleInsert = (table, data, options) => assembleSet(data, {
|
|
257
|
+
...options || {}, action: INSERT,
|
|
258
|
+
prefix: `INSERT INTO ${quote(assertTable(table))} `,
|
|
259
|
+
});
|
|
225
260
|
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
};
|
|
261
|
+
const assembleUpdate = (table, data, options) => assembleSet(data, {
|
|
262
|
+
...options || {}, action: UPDATE,
|
|
263
|
+
prefix: `UPDATE ${quote(assertTable(table))} `,
|
|
264
|
+
});
|
|
230
265
|
|
|
231
266
|
const assembleTail = (options) => {
|
|
232
267
|
let sort = [];
|
|
@@ -240,7 +275,7 @@ const assembleTail = (options) => {
|
|
|
240
275
|
};
|
|
241
276
|
|
|
242
277
|
const tables = async (options) => {
|
|
243
|
-
const resp = await query(
|
|
278
|
+
const resp = await query(sqlShowTables);
|
|
244
279
|
return options?.raw ? resp : resp.map(x => {
|
|
245
280
|
switch (provider) {
|
|
246
281
|
case MYSQL: return Object.values(x)[0];
|
|
@@ -251,15 +286,18 @@ const tables = async (options) => {
|
|
|
251
286
|
|
|
252
287
|
const desc = async (table, options) => {
|
|
253
288
|
assertTable(table);
|
|
254
|
-
const [resp, result] = [await query(
|
|
289
|
+
const [resp, result] = [await query(sqlDesc, [table]), {}];
|
|
255
290
|
if (options?.raw) { return resp; }
|
|
256
|
-
|
|
291
|
+
switch (provider) {
|
|
292
|
+
case MYSQL: resp.map(x => result[x.Field] = x); break;
|
|
293
|
+
case POSTGRESQL: resp.map(x => result[x.column_name] = x); break;
|
|
294
|
+
}
|
|
257
295
|
return result;
|
|
258
296
|
};
|
|
259
297
|
|
|
260
298
|
const indexes = async (table, options) => {
|
|
261
299
|
assertTable(table);
|
|
262
|
-
const [resp, result] = [await query(
|
|
300
|
+
const [resp, result] = [await query(sqlShowIndexes, [table]), {}];
|
|
263
301
|
if (options?.raw) { return resp; }
|
|
264
302
|
switch (provider) {
|
|
265
303
|
case MYSQL: resp.map(x => result[x.Key_name] = x); break;
|
|
@@ -271,36 +309,37 @@ const indexes = async (table, options) => {
|
|
|
271
309
|
const drop = async (table, options) => {
|
|
272
310
|
assertTable(table);
|
|
273
311
|
assertForce(options);
|
|
274
|
-
|
|
312
|
+
const act = {
|
|
313
|
+
[MYSQL]: [query, [`DROP TABLE IF EXISTS ${doublePlaceholder}`, [table]]],
|
|
314
|
+
[POSTGRESQL]: [execute, [`DROP TABLE IF EXISTS ${table}`]],
|
|
315
|
+
}[provider]
|
|
316
|
+
return await act[0](...act[1]);
|
|
275
317
|
};
|
|
276
318
|
|
|
277
319
|
const queryAll = (table, options) =>
|
|
278
320
|
query(`${assembleQuery(table, options)}${assembleTail(options)}`);
|
|
279
321
|
|
|
280
322
|
const queryByKeyValue = async (table, key, value, options) => {
|
|
281
|
-
options = options || {};
|
|
282
323
|
const sql = assembleQuery(table, options)
|
|
283
324
|
+ assembleKeyValue(key, value)
|
|
284
325
|
+ assembleTail(options);
|
|
285
326
|
const resp = await query(sql, [value]);
|
|
286
|
-
return options
|
|
327
|
+
return options?.unique ? (resp && resp.length ? resp[0] : null) : resp;
|
|
287
328
|
};
|
|
288
329
|
|
|
289
|
-
const queryById = async (table, id, options) =>
|
|
290
|
-
|
|
291
|
-
options
|
|
292
|
-
|
|
293
|
-
};
|
|
330
|
+
const queryById = async (table, id, options) => await queryByKeyValue(
|
|
331
|
+
table, defaultKey(options), id,
|
|
332
|
+
{ ...options || {}, unique: !Array.isArray(id) }
|
|
333
|
+
);
|
|
294
334
|
|
|
295
335
|
const insert = async (table, fields, options) => {
|
|
296
|
-
options = options || {};
|
|
297
336
|
let [isArray, key, ids, error, result]
|
|
298
337
|
= [Array.isArray(fields), defaultKey(options), [], [], []];
|
|
299
|
-
const subfix = provider === POSTGRESQL ? (options
|
|
300
|
-
options
|
|
301
|
-
) :
|
|
338
|
+
const subfix = provider === POSTGRESQL ? (options?.skipEcho ? (
|
|
339
|
+
options?.key ? ` ${RETURNING} ${key}` : ''
|
|
340
|
+
) : RETURNING_ALL) : '';
|
|
302
341
|
for (let item of assembleInsert(
|
|
303
|
-
table, fields, { ...options, asArray: true, subfix })
|
|
342
|
+
table, fields, { ...options || {}, asArray: true, subfix })
|
|
304
343
|
) {
|
|
305
344
|
try {
|
|
306
345
|
const resp = await execute(item.sql, item.values);
|
|
@@ -314,7 +353,7 @@ const insert = async (table, fields, options) => {
|
|
|
314
353
|
ids.push(resp.insertId);
|
|
315
354
|
} catch (err) { error.push(err); }
|
|
316
355
|
}
|
|
317
|
-
if (!options
|
|
356
|
+
if (!options?.skipEcho && ids.length) {
|
|
318
357
|
switch (provider) {
|
|
319
358
|
case MYSQL:
|
|
320
359
|
result = await queryById(table, ids, options);
|
|
@@ -345,13 +384,18 @@ const countByKeyValue = async (table, key, value) => {
|
|
|
345
384
|
};
|
|
346
385
|
|
|
347
386
|
const updateByKeyValue = async (table, key, value, fields, options) => {
|
|
348
|
-
options = options || {};
|
|
349
387
|
assertTable(table);
|
|
350
|
-
|
|
351
|
-
|
|
388
|
+
const dfKey = defaultKey(options);
|
|
389
|
+
const subfix = assembleKeyValue(key, value, {
|
|
390
|
+
placeholderIndex: Object.keys(fields).length + 1,
|
|
391
|
+
}) + (provider === POSTGRESQL ? (options?.skipEcho ? (
|
|
392
|
+
options?.key ? ` ${RETURNING} ${dfKey}` : ''
|
|
393
|
+
) : RETURNING_ALL) : '');
|
|
394
|
+
let { sql, values } = assembleUpdate(table, fields, { subfix });
|
|
395
|
+
sql += assembleTail(options);
|
|
352
396
|
const resp = await query(sql, [...values, value]);
|
|
353
|
-
return options
|
|
354
|
-
?
|
|
397
|
+
return !options?.skipEcho && provider === MYSQL
|
|
398
|
+
? await queryByKeyValue(table, key, value, options) : resp;
|
|
355
399
|
};
|
|
356
400
|
|
|
357
401
|
const updateById = async (table, id, fields, options) => {
|
|
@@ -365,11 +409,13 @@ const deleteByKeyValue = async (table, key, value, options) => {
|
|
|
365
409
|
const sql = assembleDelete(table)
|
|
366
410
|
+ assembleKeyValue(key, value)
|
|
367
411
|
+ assembleTail(options);
|
|
368
|
-
return await
|
|
412
|
+
return await {
|
|
413
|
+
[MYSQL]: query, [POSTGRESQL]: execByQuery,
|
|
414
|
+
}[provider](sql, [value]);
|
|
369
415
|
};
|
|
370
416
|
|
|
371
|
-
const deleteById = (table, id, options) =>
|
|
372
|
-
deleteByKeyValue(table, defaultKey(options), id);
|
|
417
|
+
const deleteById = async (table, id, options) =>
|
|
418
|
+
await deleteByKeyValue(table, defaultKey(options), id);
|
|
373
419
|
|
|
374
420
|
const deleteAll = async (table, options) => {
|
|
375
421
|
assertForce(options);
|
package/lib/manifest.mjs
CHANGED