@platformatic/sql-mapper 3.0.0-alpha.4 → 3.0.0-alpha.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/eslint.config.js +2 -2
- package/{mapper.js → index.js} +164 -75
- package/lib/cache.js +17 -16
- package/lib/clean-up.js +3 -7
- package/lib/connection-info.js +2 -4
- package/lib/cursor.js +21 -13
- package/lib/entity.js +160 -63
- package/lib/errors.js +66 -25
- package/lib/queries/index.js +4 -23
- package/lib/queries/mariadb.js +2 -11
- package/lib/queries/mysql-shared.js +9 -19
- package/lib/queries/mysql.js +12 -26
- package/lib/queries/pg.js +12 -29
- package/lib/queries/shared.js +26 -29
- package/lib/queries/sqlite.js +17 -33
- package/lib/telemetry.js +7 -14
- package/lib/utils.js +12 -23
- package/package.json +9 -9
- /package/{mapper.d.ts → index.d.ts} +0 -0
package/lib/entity.js
CHANGED
|
@@ -1,20 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
import { findNearestString } from '@platformatic/foundation'
|
|
2
|
+
import camelcase from 'camelcase'
|
|
3
|
+
import { singularize } from 'inflected'
|
|
4
|
+
import { buildCursorCondition } from './cursor.js'
|
|
5
|
+
import {
|
|
6
|
+
InputNotProvidedError,
|
|
7
|
+
InvalidPrimaryKeyTypeError,
|
|
8
|
+
MissingWhereClauseError,
|
|
9
|
+
ParamNotAllowedError,
|
|
10
|
+
UnknownFieldError,
|
|
11
|
+
UnsupportedOperatorForArrayFieldError,
|
|
12
|
+
UnsupportedOperatorForNonArrayFieldError,
|
|
13
|
+
UnsupportedWhereClauseError
|
|
14
|
+
} from './errors.js'
|
|
15
|
+
import { wrapDB } from './telemetry.js'
|
|
16
|
+
import { sanitizeLimit, tableName, toLowerFirst, toSingular, toUpperFirst } from './utils.js'
|
|
17
|
+
|
|
18
|
+
function createMapper (
|
|
19
|
+
defaultDb,
|
|
20
|
+
sql,
|
|
21
|
+
log,
|
|
22
|
+
table,
|
|
23
|
+
fields,
|
|
24
|
+
primaryKeys,
|
|
25
|
+
relations,
|
|
26
|
+
queries,
|
|
27
|
+
autoTimestamp,
|
|
28
|
+
schema,
|
|
29
|
+
useSchemaInName,
|
|
30
|
+
limitConfig,
|
|
31
|
+
columns,
|
|
32
|
+
constraintsList
|
|
33
|
+
) {
|
|
18
34
|
/* istanbul ignore next */ // Ignoring because this won't be fully covered by DB not supporting schemas (SQLite)
|
|
19
35
|
const entityName = useSchemaInName ? toUpperFirst(`${schema}${toSingular(table)}`) : toSingular(table)
|
|
20
36
|
/* istanbul ignore next */
|
|
@@ -23,7 +39,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
23
39
|
|
|
24
40
|
// If the db is in the opts, uses it, otherwise uses the defaultDb
|
|
25
41
|
// if telemetry is enabled, wraps the db with telemetry
|
|
26
|
-
const getDB =
|
|
42
|
+
const getDB = opts => {
|
|
27
43
|
let db = opts?.tx || defaultDb
|
|
28
44
|
if (opts?.ctx?.app?.openTelemetry && opts?.ctx?.reply?.request) {
|
|
29
45
|
const req = opts.ctx.reply.request
|
|
@@ -44,10 +60,10 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
44
60
|
return acc
|
|
45
61
|
}, {})
|
|
46
62
|
|
|
47
|
-
const primaryKeysTypes = Array.from(primaryKeys).map(
|
|
63
|
+
const primaryKeysTypes = Array.from(primaryKeys).map(key => {
|
|
48
64
|
return {
|
|
49
65
|
key,
|
|
50
|
-
sqlType: fields[key].sqlType
|
|
66
|
+
sqlType: fields[key].sqlType
|
|
51
67
|
}
|
|
52
68
|
})
|
|
53
69
|
|
|
@@ -60,7 +76,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
60
76
|
if (fields[key] !== undefined) {
|
|
61
77
|
newKey = key
|
|
62
78
|
} else {
|
|
63
|
-
throw new
|
|
79
|
+
throw new UnknownFieldError(key)
|
|
64
80
|
}
|
|
65
81
|
}
|
|
66
82
|
newInput[newKey] = value
|
|
@@ -87,10 +103,10 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
87
103
|
async function save (args) {
|
|
88
104
|
const db = getDB(args)
|
|
89
105
|
if (args.input === undefined) {
|
|
90
|
-
throw new
|
|
106
|
+
throw new InputNotProvidedError()
|
|
91
107
|
}
|
|
92
108
|
// args.input is not array
|
|
93
|
-
const fieldsToRetrieve = computeFields(args.fields).map(
|
|
109
|
+
const fieldsToRetrieve = computeFields(args.fields).map(f => sql.ident(f))
|
|
94
110
|
const input = fixInput(args.input)
|
|
95
111
|
|
|
96
112
|
let hasPrimaryKeys = true
|
|
@@ -106,7 +122,8 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
106
122
|
now = new Date()
|
|
107
123
|
input[autoTimestamp.updatedAt] = now
|
|
108
124
|
}
|
|
109
|
-
if (hasPrimaryKeys) {
|
|
125
|
+
if (hasPrimaryKeys) {
|
|
126
|
+
// update
|
|
110
127
|
const res = await queries.updateOne(db, sql, table, schema, input, primaryKeys, fieldsToRetrieve)
|
|
111
128
|
if (res) {
|
|
112
129
|
return fixOutput(res)
|
|
@@ -128,7 +145,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
128
145
|
|
|
129
146
|
async function insert (args) {
|
|
130
147
|
const db = getDB(args)
|
|
131
|
-
const fieldsToRetrieve = computeFields(args.fields).map(
|
|
148
|
+
const fieldsToRetrieve = computeFields(args.fields).map(f => sql.ident(f))
|
|
132
149
|
const inputs = args.inputs
|
|
133
150
|
// This else is skipped on MySQL because of https://github.com/ForbesLindesay/atdatabases/issues/221
|
|
134
151
|
/* istanbul ignore else */
|
|
@@ -146,7 +163,17 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
146
163
|
/* istanbul ignore next */
|
|
147
164
|
if (queries.insertMany) {
|
|
148
165
|
// We are not fixing the input here because it is done in the query.
|
|
149
|
-
const res = await queries.insertMany(
|
|
166
|
+
const res = await queries.insertMany(
|
|
167
|
+
db,
|
|
168
|
+
sql,
|
|
169
|
+
table,
|
|
170
|
+
schema,
|
|
171
|
+
inputs,
|
|
172
|
+
inputToFieldMap,
|
|
173
|
+
primaryKeysTypes,
|
|
174
|
+
fieldsToRetrieve,
|
|
175
|
+
fields
|
|
176
|
+
)
|
|
150
177
|
return res.map(fixOutput)
|
|
151
178
|
} else {
|
|
152
179
|
// TODO this can be optimized, we can still use a batch insert if we do not want any fields
|
|
@@ -163,13 +190,13 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
163
190
|
|
|
164
191
|
async function updateMany (args) {
|
|
165
192
|
if (args.input === undefined) {
|
|
166
|
-
throw new
|
|
193
|
+
throw new InputNotProvidedError()
|
|
167
194
|
}
|
|
168
195
|
if (args.where === undefined || Object.keys(args.where).length === 0) {
|
|
169
|
-
throw new
|
|
196
|
+
throw new MissingWhereClauseError()
|
|
170
197
|
}
|
|
171
198
|
const db = getDB(args)
|
|
172
|
-
const fieldsToRetrieve = computeFields(args.fields).map(
|
|
199
|
+
const fieldsToRetrieve = computeFields(args.fields).map(f => sql.ident(f))
|
|
173
200
|
const input = fixInput(args.input)
|
|
174
201
|
if (autoTimestamp && fields[autoTimestamp.updatedAt]) {
|
|
175
202
|
const now = new Date()
|
|
@@ -190,9 +217,9 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
190
217
|
* The 'field' can be a relational field which is undefined
|
|
191
218
|
* in the inputToFieldMap
|
|
192
219
|
* @see sql-graphql
|
|
193
|
-
|
|
194
|
-
const requestedFields = fields.map(
|
|
195
|
-
if (relations.some(
|
|
220
|
+
*/
|
|
221
|
+
const requestedFields = fields.map(field => {
|
|
222
|
+
if (relations.some(relation => field === relation.column_name)) {
|
|
196
223
|
return field
|
|
197
224
|
}
|
|
198
225
|
return inputToFieldMap[field]
|
|
@@ -219,7 +246,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
219
246
|
all: 'ALL',
|
|
220
247
|
contains: '@>',
|
|
221
248
|
contained: '<@',
|
|
222
|
-
overlaps: '&&'
|
|
249
|
+
overlaps: '&&'
|
|
223
250
|
}
|
|
224
251
|
|
|
225
252
|
function computeCriteria (opts) {
|
|
@@ -238,14 +265,14 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
238
265
|
const value = where[key]
|
|
239
266
|
const field = inputToFieldMap[key]
|
|
240
267
|
if (!field) {
|
|
241
|
-
throw new
|
|
268
|
+
throw new UnknownFieldError(key)
|
|
242
269
|
}
|
|
243
270
|
for (const key of Object.keys(value)) {
|
|
244
271
|
const operator = whereMap[key]
|
|
245
272
|
/* istanbul ignore next */
|
|
246
273
|
if (!operator) {
|
|
247
274
|
// This should never happen
|
|
248
|
-
throw new
|
|
275
|
+
throw new UnsupportedWhereClauseError(JSON.stringify(where[key]))
|
|
249
276
|
}
|
|
250
277
|
const fieldWrap = fields[field]
|
|
251
278
|
/* istanbul ignore next */
|
|
@@ -261,7 +288,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
261
288
|
} else if (operator === '&&') {
|
|
262
289
|
criteria.push(sql`${sql.ident(field)} && ${value[key]}`)
|
|
263
290
|
} else {
|
|
264
|
-
throw new
|
|
291
|
+
throw new UnsupportedOperatorForArrayFieldError()
|
|
265
292
|
}
|
|
266
293
|
} else if (operator === '=' && value[key] === null) {
|
|
267
294
|
criteria.push(sql`${sql.ident(field)} IS NULL`)
|
|
@@ -276,10 +303,18 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
276
303
|
}
|
|
277
304
|
const like = operator === 'LIKE' ? sql`LIKE` : queries.hasILIKE ? sql`ILIKE` : sql`LIKE`
|
|
278
305
|
criteria.push(sql`${leftHand} ${like} ${value[key]}`)
|
|
279
|
-
} else if (
|
|
280
|
-
|
|
306
|
+
} else if (
|
|
307
|
+
operator === 'ANY' ||
|
|
308
|
+
operator === 'ALL' ||
|
|
309
|
+
operator === '@>' ||
|
|
310
|
+
operator === '<@' ||
|
|
311
|
+
operator === '&&'
|
|
312
|
+
) {
|
|
313
|
+
throw new UnsupportedOperatorForNonArrayFieldError()
|
|
281
314
|
} else {
|
|
282
|
-
criteria.push(
|
|
315
|
+
criteria.push(
|
|
316
|
+
sql`${sql.ident(field)} ${sql.__dangerous__rawValue(operator)} ${computeCriteriaValue(fieldWrap, value[key])}`
|
|
317
|
+
)
|
|
283
318
|
}
|
|
284
319
|
}
|
|
285
320
|
}
|
|
@@ -289,13 +324,18 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
289
324
|
function computeCriteriaValue (fieldWrap, value) {
|
|
290
325
|
if (Array.isArray(value)) {
|
|
291
326
|
return sql`(${sql.join(
|
|
292
|
-
value.map(
|
|
327
|
+
value.map(v => computeCriteriaValue(fieldWrap, v)),
|
|
293
328
|
sql`, `
|
|
294
329
|
)})`
|
|
295
330
|
}
|
|
296
331
|
|
|
297
332
|
/* istanbul ignore next */
|
|
298
|
-
if (
|
|
333
|
+
if (
|
|
334
|
+
fieldWrap.sqlType === 'int4' ||
|
|
335
|
+
fieldWrap.sqlType === 'int2' ||
|
|
336
|
+
fieldWrap.sqlType === 'float8' ||
|
|
337
|
+
fieldWrap.sqlType === 'float4'
|
|
338
|
+
) {
|
|
299
339
|
// This cat is needed in PostgreSQL
|
|
300
340
|
return sql`${Number(value)}`
|
|
301
341
|
} else {
|
|
@@ -305,7 +345,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
305
345
|
|
|
306
346
|
async function find (opts = {}) {
|
|
307
347
|
const db = getDB(opts)
|
|
308
|
-
const fieldsToRetrieve = computeFields(opts.fields).map(
|
|
348
|
+
const fieldsToRetrieve = computeFields(opts.fields).map(f => sql.ident(f))
|
|
309
349
|
const criteria = computeCriteria(opts)
|
|
310
350
|
const criteriaExists = criteria.length > 0
|
|
311
351
|
const isBackwardPagination = opts.nextPage === false
|
|
@@ -320,7 +360,16 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
320
360
|
}
|
|
321
361
|
|
|
322
362
|
if (opts.cursor) {
|
|
323
|
-
const cursorCondition = buildCursorCondition(
|
|
363
|
+
const cursorCondition = buildCursorCondition(
|
|
364
|
+
sql,
|
|
365
|
+
opts.cursor,
|
|
366
|
+
opts.orderBy,
|
|
367
|
+
inputToFieldMap,
|
|
368
|
+
fields,
|
|
369
|
+
computeCriteriaValue,
|
|
370
|
+
primaryKeys,
|
|
371
|
+
isBackwardPagination
|
|
372
|
+
)
|
|
324
373
|
if (cursorCondition) {
|
|
325
374
|
if (criteriaExists) query = sql`${query} AND ${cursorCondition}`
|
|
326
375
|
else query = sql`${query} WHERE ${cursorCondition}`
|
|
@@ -328,7 +377,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
328
377
|
}
|
|
329
378
|
|
|
330
379
|
if (opts.orderBy && opts.orderBy.length > 0) {
|
|
331
|
-
const orderBy = opts.orderBy.map(
|
|
380
|
+
const orderBy = opts.orderBy.map(order => {
|
|
332
381
|
const field = inputToFieldMap[order.field]
|
|
333
382
|
let direction = order.direction.toLowerCase()
|
|
334
383
|
if (isBackwardPagination) {
|
|
@@ -343,7 +392,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
343
392
|
query = sql`${query} LIMIT ${sanitizeLimit(opts.limit, limitConfig)}`
|
|
344
393
|
if (opts.offset !== undefined) {
|
|
345
394
|
if (opts.offset < 0) {
|
|
346
|
-
throw new
|
|
395
|
+
throw new ParamNotAllowedError(opts.offset)
|
|
347
396
|
}
|
|
348
397
|
query = sql`${query} OFFSET ${opts.offset}`
|
|
349
398
|
}
|
|
@@ -371,7 +420,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
371
420
|
|
|
372
421
|
async function _delete (opts) {
|
|
373
422
|
const db = getDB(opts)
|
|
374
|
-
const fieldsToRetrieve = computeFields(opts.fields).map(
|
|
423
|
+
const fieldsToRetrieve = computeFields(opts.fields).map(f => sql.ident(f))
|
|
375
424
|
const criteria = computeCriteria(opts)
|
|
376
425
|
const res = await queries.deleteAll(db, sql, table, schema, criteria, fieldsToRetrieve)
|
|
377
426
|
return res.map(fixOutput)
|
|
@@ -393,11 +442,25 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
393
442
|
insert,
|
|
394
443
|
save,
|
|
395
444
|
delete: _delete,
|
|
396
|
-
updateMany
|
|
445
|
+
updateMany
|
|
397
446
|
}
|
|
398
447
|
}
|
|
399
448
|
|
|
400
|
-
function buildEntity (
|
|
449
|
+
export function buildEntity (
|
|
450
|
+
db,
|
|
451
|
+
sql,
|
|
452
|
+
log,
|
|
453
|
+
table,
|
|
454
|
+
queries,
|
|
455
|
+
autoTimestamp,
|
|
456
|
+
schema,
|
|
457
|
+
useSchemaInName,
|
|
458
|
+
ignore,
|
|
459
|
+
limitConfig,
|
|
460
|
+
schemaList,
|
|
461
|
+
columns,
|
|
462
|
+
constraintsList
|
|
463
|
+
) {
|
|
401
464
|
const columnsNames = columns.map(c => c.column_name)
|
|
402
465
|
for (const ignoredColumn of Object.keys(ignore)) {
|
|
403
466
|
if (!columnsNames.includes(ignoredColumn)) {
|
|
@@ -407,21 +470,26 @@ function buildEntity (db, sql, log, table, queries, autoTimestamp, schema, useSc
|
|
|
407
470
|
}
|
|
408
471
|
|
|
409
472
|
// Compute the columns
|
|
410
|
-
columns = columns.filter(
|
|
473
|
+
columns = columns.filter(c => !ignore[c.column_name])
|
|
411
474
|
const fields = columns.reduce((acc, column) => {
|
|
412
475
|
acc[column.column_name] = {
|
|
413
476
|
sqlType: column.udt_name,
|
|
414
477
|
isNullable: column.is_nullable === 'YES',
|
|
415
|
-
isArray: column.isArray
|
|
478
|
+
isArray: column.isArray
|
|
416
479
|
}
|
|
417
480
|
|
|
418
481
|
// To get enum values in mysql and mariadb
|
|
419
482
|
/* istanbul ignore next */
|
|
420
483
|
if (column.udt_name === 'enum') {
|
|
421
|
-
acc[column.column_name].enum = column.column_type
|
|
484
|
+
acc[column.column_name].enum = column.column_type
|
|
485
|
+
.match(/'(.+?)'/g)
|
|
486
|
+
.map(enumValue => enumValue.slice(1, enumValue.length - 1))
|
|
422
487
|
}
|
|
423
488
|
|
|
424
|
-
if (
|
|
489
|
+
if (
|
|
490
|
+
autoTimestamp &&
|
|
491
|
+
(column.column_name === autoTimestamp.createdAt || column.column_name === autoTimestamp.updatedAt)
|
|
492
|
+
) {
|
|
425
493
|
acc[column.column_name].autoTimestamp = true
|
|
426
494
|
}
|
|
427
495
|
|
|
@@ -454,7 +522,7 @@ function buildEntity (db, sql, log, table, queries, autoTimestamp, schema, useSc
|
|
|
454
522
|
const validTypes = ['varchar', 'integer', 'uuid', 'serial']
|
|
455
523
|
const pkType = fields[constraint.column_name].sqlType.toLowerCase()
|
|
456
524
|
if (!validTypes.includes(pkType)) {
|
|
457
|
-
throw new
|
|
525
|
+
throw new InvalidPrimaryKeyTypeError(pkType, validTypes.join(', '))
|
|
458
526
|
}
|
|
459
527
|
}
|
|
460
528
|
}
|
|
@@ -465,9 +533,12 @@ function buildEntity (db, sql, log, table, queries, autoTimestamp, schema, useSc
|
|
|
465
533
|
/* istanbul ignore next */
|
|
466
534
|
if (!field) {
|
|
467
535
|
// This should never happen
|
|
468
|
-
log.warn(
|
|
469
|
-
|
|
470
|
-
|
|
536
|
+
log.warn(
|
|
537
|
+
{
|
|
538
|
+
constraint
|
|
539
|
+
},
|
|
540
|
+
`No field for ${constraint.column_name}`
|
|
541
|
+
)
|
|
471
542
|
continue
|
|
472
543
|
}
|
|
473
544
|
|
|
@@ -480,13 +551,28 @@ function buildEntity (db, sql, log, table, queries, autoTimestamp, schema, useSc
|
|
|
480
551
|
|
|
481
552
|
// we need to ignore for coverage here because cannot be covered with sqlite (no schema support)
|
|
482
553
|
// istanbul ignore next
|
|
483
|
-
const isForeignKeySchemaInConfig =
|
|
554
|
+
const isForeignKeySchemaInConfig =
|
|
555
|
+
schemaList?.length > 0 ? schemaList.includes(constraint.foreign_table_schema) : true
|
|
484
556
|
/* istanbul ignore if */
|
|
485
557
|
if (constraint.constraint_type === 'FOREIGN KEY' && isForeignKeySchemaInConfig) {
|
|
486
558
|
field.foreignKey = true
|
|
487
|
-
const foreignEntityName = singularize(
|
|
488
|
-
|
|
489
|
-
|
|
559
|
+
const foreignEntityName = singularize(
|
|
560
|
+
camelcase(
|
|
561
|
+
useSchemaInName
|
|
562
|
+
? camelcase(`${constraint.foreign_table_schema} ${constraint.foreign_table_name}`)
|
|
563
|
+
: constraint.foreign_table_name
|
|
564
|
+
)
|
|
565
|
+
)
|
|
566
|
+
const entityName = singularize(
|
|
567
|
+
camelcase(
|
|
568
|
+
useSchemaInName ? camelcase(`${constraint.table_schema} ${constraint.table_name}`) : constraint.table_name
|
|
569
|
+
)
|
|
570
|
+
)
|
|
571
|
+
const loweredTableWithSchemaName = toLowerFirst(
|
|
572
|
+
useSchemaInName
|
|
573
|
+
? camelcase(`${constraint.table_schema} ${camelcase(constraint.table_name)}`)
|
|
574
|
+
: camelcase(constraint.table_name)
|
|
575
|
+
)
|
|
490
576
|
constraint.loweredTableWithSchemaName = loweredTableWithSchemaName
|
|
491
577
|
constraint.foreignEntityName = foreignEntityName
|
|
492
578
|
constraint.entityName = entityName
|
|
@@ -521,10 +607,21 @@ function buildEntity (db, sql, log, table, queries, autoTimestamp, schema, useSc
|
|
|
521
607
|
}
|
|
522
608
|
}
|
|
523
609
|
|
|
524
|
-
const entity = createMapper(
|
|
610
|
+
const entity = createMapper(
|
|
611
|
+
db,
|
|
612
|
+
sql,
|
|
613
|
+
log,
|
|
614
|
+
table,
|
|
615
|
+
fields,
|
|
616
|
+
primaryKeys,
|
|
617
|
+
currentRelations,
|
|
618
|
+
queries,
|
|
619
|
+
autoTimestamp,
|
|
620
|
+
schema,
|
|
621
|
+
useSchemaInName,
|
|
622
|
+
limitConfig
|
|
623
|
+
)
|
|
525
624
|
entity.relations = currentRelations
|
|
526
625
|
|
|
527
626
|
return entity
|
|
528
627
|
}
|
|
529
|
-
|
|
530
|
-
module.exports = buildEntity
|
package/lib/errors.js
CHANGED
|
@@ -1,27 +1,68 @@
|
|
|
1
|
-
|
|
1
|
+
import createError from '@fastify/error'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
export const ERROR_PREFIX = 'PLT_SQL_MAPPER'
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
5
|
+
export const CannotFindEntityError = createError(`${ERROR_PREFIX}_CANNOT_FIND_ENTITY`, 'Cannot find entity %s')
|
|
6
|
+
export const SpecifyProtocolError = createError(
|
|
7
|
+
`${ERROR_PREFIX}_SPECIFY_PROTOCOLS`,
|
|
8
|
+
'You must specify either postgres, mysql or sqlite as protocols'
|
|
9
|
+
)
|
|
10
|
+
export const ConnectionStringRequiredError = createError(
|
|
11
|
+
`${ERROR_PREFIX}_CONNECTION_STRING_REQUIRED`,
|
|
12
|
+
'connectionString is required'
|
|
13
|
+
)
|
|
14
|
+
export const TableMustBeAStringError = createError(
|
|
15
|
+
`${ERROR_PREFIX}_TABLE_MUST_BE_A_STRING`,
|
|
16
|
+
'Table must be a string, got %s'
|
|
17
|
+
)
|
|
18
|
+
export const UnknownFieldError = createError(`${ERROR_PREFIX}_UNKNOWN_FIELD`, 'Unknown field %s')
|
|
19
|
+
export const InputNotProvidedError = createError(`${ERROR_PREFIX}_INPUT_NOT_PROVIDED`, 'Input not provided.')
|
|
20
|
+
export const UnsupportedWhereClauseError = createError(
|
|
21
|
+
`${ERROR_PREFIX}_UNSUPPORTED_WHERE_CLAUSE`,
|
|
22
|
+
'Unsupported where clause %s'
|
|
23
|
+
)
|
|
24
|
+
export const UnsupportedOperatorForArrayFieldError = createError(
|
|
25
|
+
`${ERROR_PREFIX}_UNSUPPORTED_OPERATOR`,
|
|
26
|
+
'Unsupported operator for Array field'
|
|
27
|
+
)
|
|
28
|
+
export const UnsupportedOperatorForNonArrayFieldError = createError(
|
|
29
|
+
`${ERROR_PREFIX}_UNSUPPORTED_OPERATOR_FOR_NON_ARRAY`,
|
|
30
|
+
'Unsupported operator for non Array field'
|
|
31
|
+
)
|
|
32
|
+
export const ParamNotAllowedError = createError(
|
|
33
|
+
`${ERROR_PREFIX}_PARAM_NOT_ALLOWED`,
|
|
34
|
+
'Param offset=%s not allowed. It must be not negative value.'
|
|
35
|
+
)
|
|
36
|
+
export const InvalidPrimaryKeyTypeError = createError(
|
|
37
|
+
`${ERROR_PREFIX}_INVALID_PRIMARY_KEY_TYPE`,
|
|
38
|
+
'Invalid Primary Key type: "%s". We support the following: %s'
|
|
39
|
+
)
|
|
40
|
+
export const ParamLimitNotAllowedError = createError(
|
|
41
|
+
`${ERROR_PREFIX}_PARAM_LIMIT_NOT_ALLOWED`,
|
|
42
|
+
'Param limit=%s not allowed. Max accepted value %s.'
|
|
43
|
+
)
|
|
44
|
+
export const ParamLimitMustBeNotNegativeError = createError(
|
|
45
|
+
`${ERROR_PREFIX}_PARAM_LIMIT_MUST_BE_NOT_NEGATIVE`,
|
|
46
|
+
'Param limit=%s not allowed. It must be a not negative value.'
|
|
47
|
+
)
|
|
48
|
+
export const MissingValueForPrimaryKeyError = createError(
|
|
49
|
+
`${ERROR_PREFIX}_MISSING_VALUE_FOR_PRIMARY_KEY`,
|
|
50
|
+
'Missing value for primary key %s'
|
|
51
|
+
)
|
|
52
|
+
export const MissingWhereClauseError = createError(`${ERROR_PREFIX}_MISSING_WHERE_CLAUSE`, 'Missing where clause', 400)
|
|
53
|
+
export const SQLiteOnlySupportsAutoIncrementOnOneColumnError = createError(
|
|
54
|
+
`${ERROR_PREFIX}_SQLITE_ONLY_SUPPORTS_AUTO_INCREMENT_ON_ONE_COLUMN`,
|
|
55
|
+
'SQLite only supports autoIncrement on one column'
|
|
56
|
+
)
|
|
57
|
+
export const MissingOrderByClauseError = createError(
|
|
58
|
+
`${ERROR_PREFIX}_MISSING_ORDER_BY_CLAUSE`,
|
|
59
|
+
'Missing orderBy clause'
|
|
60
|
+
)
|
|
61
|
+
export const MissingOrderByFieldForCursorError = createError(
|
|
62
|
+
`${ERROR_PREFIX}_MISSING_ORDER_BY_FIELD_FOR_CURSOR`,
|
|
63
|
+
'Cursor field(s) %s must be included in orderBy'
|
|
64
|
+
)
|
|
65
|
+
export const MissingUniqueFieldInCursorError = createError(
|
|
66
|
+
`${ERROR_PREFIX}_MISSING_UNIQUE_FIELD_IN_CURSOR`,
|
|
67
|
+
'Cursor must contain at least one primary key field'
|
|
68
|
+
)
|
package/lib/queries/index.js
CHANGED
|
@@ -1,23 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const obj = {}
|
|
6
|
-
|
|
7
|
-
Object.defineProperty(obj, 'pg', {
|
|
8
|
-
get: () => require('./pg'),
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
Object.defineProperty(obj, 'mysql', {
|
|
12
|
-
get: () => require('./mysql'),
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
Object.defineProperty(obj, 'mariadb', {
|
|
16
|
-
get: () => require('./mariadb'),
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
Object.defineProperty(obj, 'sqlite', {
|
|
20
|
-
get: () => require('./sqlite'),
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
module.exports = obj
|
|
1
|
+
export * as mariadb from './mariadb.js'
|
|
2
|
+
export * as mysql from './mysql.js'
|
|
3
|
+
export * as pg from './pg.js'
|
|
4
|
+
export * as sqlite from './sqlite.js'
|
package/lib/queries/mariadb.js
CHANGED
|
@@ -1,11 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const shared = require('./shared')
|
|
4
|
-
const mysql = require('./mysql-shared')
|
|
5
|
-
|
|
6
|
-
module.exports = {
|
|
7
|
-
...mysql,
|
|
8
|
-
insertOne: shared.insertOne,
|
|
9
|
-
insertMany: shared.insertMany,
|
|
10
|
-
deleteAll: shared.deleteAll,
|
|
11
|
-
}
|
|
1
|
+
export { listColumns, listConstraints, listTables, updateMany, updateOne } from './mysql-shared.js'
|
|
2
|
+
export { deleteAll, insertMany, insertOne } from './shared.js'
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { tableName } from '../utils.js'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
async function listTables (db, sql, schemas) {
|
|
3
|
+
export async function listTables (db, sql, schemas) {
|
|
6
4
|
if (schemas) {
|
|
7
5
|
const schemaList = sql.__dangerous__rawValue(schemas.map(s => `'${s}'`))
|
|
8
6
|
const res = await db.query(sql`
|
|
@@ -21,7 +19,7 @@ async function listTables (db, sql, schemas) {
|
|
|
21
19
|
}
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
async function listColumns (db, sql, table, schema) {
|
|
22
|
+
export async function listColumns (db, sql, table, schema) {
|
|
25
23
|
const query = sql`
|
|
26
24
|
SELECT column_name as column_name, data_type as udt_name, is_nullable as is_nullable, column_type as column_type, extra as is_generated
|
|
27
25
|
FROM information_schema.columns
|
|
@@ -31,7 +29,7 @@ async function listColumns (db, sql, table, schema) {
|
|
|
31
29
|
return db.query(query)
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
async function listConstraints (db, sql, table, schema) {
|
|
32
|
+
export async function listConstraints (db, sql, table, schema) {
|
|
35
33
|
const query = sql`
|
|
36
34
|
SELECT TABLE_NAME as table_name, TABLE_SCHEMA as table_schema, COLUMN_NAME as column_name, CONSTRAINT_TYPE as constraint_type, referenced_table_name AS foreign_table_name, referenced_table_schema AS foreign_table_schema, referenced_column_name AS foreign_column_name
|
|
37
35
|
FROM information_schema.table_constraints t
|
|
@@ -43,8 +41,8 @@ async function listConstraints (db, sql, table, schema) {
|
|
|
43
41
|
return db.query(query)
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
async function updateOne (db, sql, table, schema, input, primaryKeys, fieldsToRetrieve) {
|
|
47
|
-
const pairs = Object.keys(input).map(
|
|
44
|
+
export async function updateOne (db, sql, table, schema, input, primaryKeys, fieldsToRetrieve) {
|
|
45
|
+
const pairs = Object.keys(input).map(key => {
|
|
48
46
|
let value = input[key]
|
|
49
47
|
/* istanbul ignore next */
|
|
50
48
|
if (value && typeof value === 'object' && !(value instanceof Date)) {
|
|
@@ -73,8 +71,8 @@ async function updateOne (db, sql, table, schema, input, primaryKeys, fieldsToRe
|
|
|
73
71
|
return res[0]
|
|
74
72
|
}
|
|
75
73
|
|
|
76
|
-
async function updateMany (db, sql, table, schema, criteria, input, fieldsToRetrieve) {
|
|
77
|
-
const pairs = Object.keys(input).map(
|
|
74
|
+
export async function updateMany (db, sql, table, schema, criteria, input, fieldsToRetrieve) {
|
|
75
|
+
const pairs = Object.keys(input).map(key => {
|
|
78
76
|
let value = input[key]
|
|
79
77
|
/* istanbul ignore next */
|
|
80
78
|
if (value && typeof value === 'object' && !(value instanceof Date)) {
|
|
@@ -108,12 +106,4 @@ async function updateMany (db, sql, table, schema, criteria, input, fieldsToRetr
|
|
|
108
106
|
return res
|
|
109
107
|
}
|
|
110
108
|
|
|
111
|
-
|
|
112
|
-
listTables,
|
|
113
|
-
listColumns,
|
|
114
|
-
listConstraints,
|
|
115
|
-
updateOne,
|
|
116
|
-
updateMany,
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
module.exports.hasILIKE = false
|
|
109
|
+
export const hasILIKE = false
|