@platformatic/sql-mapper 3.4.1 → 3.5.1

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