@platformatic/sql-mapper 0.43.1 → 0.44.0
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/entity.js +10 -9
- package/lib/errors.js +25 -0
- package/lib/queries/mysql.js +2 -1
- package/lib/queries/shared.js +2 -1
- package/lib/queries/sqlite.js +2 -1
- package/lib/utils.js +3 -2
- package/mapper.d.ts +27 -32
- package/mapper.js +6 -4
- package/package.json +3 -3
- package/test/types/mapper.test-d.ts +45 -13
- package/test/where.test.js +4 -2
package/lib/entity.js
CHANGED
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
sanitizeLimit
|
|
9
9
|
} = require('./utils')
|
|
10
10
|
const { singularize } = require('inflected')
|
|
11
|
+
const errors = require('./errors')
|
|
11
12
|
|
|
12
13
|
function lowerCaseFirst (str) {
|
|
13
14
|
str = str.toString()
|
|
@@ -49,7 +50,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
49
50
|
if (fields[key] !== undefined) {
|
|
50
51
|
newKey = key
|
|
51
52
|
} else {
|
|
52
|
-
throw new
|
|
53
|
+
throw new errors.UnknownFieldError(key)
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
newInput[newKey] = value
|
|
@@ -76,7 +77,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
76
77
|
async function save (args) {
|
|
77
78
|
const db = args.tx || defaultDb
|
|
78
79
|
if (args.input === undefined) {
|
|
79
|
-
throw new
|
|
80
|
+
throw new errors.InputNotProvidedError()
|
|
80
81
|
}
|
|
81
82
|
// args.input is not array
|
|
82
83
|
const fieldsToRetrieve = computeFields(args.fields).map((f) => sql.ident(f))
|
|
@@ -154,7 +155,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
154
155
|
const db = args.tx || defaultDb
|
|
155
156
|
const fieldsToRetrieve = computeFields(args.fields).map((f) => sql.ident(f))
|
|
156
157
|
if (args.input === undefined) {
|
|
157
|
-
throw new
|
|
158
|
+
throw new errors.InputNotProvidedError()
|
|
158
159
|
}
|
|
159
160
|
const input = fixInput(args.input)
|
|
160
161
|
if (autoTimestamp && fields[autoTimestamp.updatedAt]) {
|
|
@@ -224,14 +225,14 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
224
225
|
const value = where[key]
|
|
225
226
|
const field = inputToFieldMap[key]
|
|
226
227
|
if (!field) {
|
|
227
|
-
throw new
|
|
228
|
+
throw new errors.UnknownFieldError(key)
|
|
228
229
|
}
|
|
229
230
|
for (const key of Object.keys(value)) {
|
|
230
231
|
const operator = whereMap[key]
|
|
231
232
|
/* istanbul ignore next */
|
|
232
233
|
if (!operator) {
|
|
233
234
|
// This should never happen
|
|
234
|
-
throw new
|
|
235
|
+
throw new errors.UnsupportedWhereClauseError(JSON.stringify(where[key]))
|
|
235
236
|
}
|
|
236
237
|
const fieldWrap = fields[field]
|
|
237
238
|
/* istanbul ignore next */
|
|
@@ -247,7 +248,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
247
248
|
} else if (operator === '&&') {
|
|
248
249
|
criteria.push(sql`${sql.ident(field)} && ${value[key]}`)
|
|
249
250
|
} else {
|
|
250
|
-
throw new
|
|
251
|
+
throw new errors.UnsupportedOperatorForArrayFieldError()
|
|
251
252
|
}
|
|
252
253
|
} else if (operator === '=' && value[key] === null) {
|
|
253
254
|
criteria.push(sql`${sql.ident(field)} IS NULL`)
|
|
@@ -263,7 +264,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
263
264
|
const like = operator === 'LIKE' ? sql`LIKE` : queries.hasILIKE ? sql`ILIKE` : sql`LIKE`
|
|
264
265
|
criteria.push(sql`${leftHand} ${like} ${value[key]}`)
|
|
265
266
|
} else if (operator === 'ANY' || operator === 'ALL' || operator === '@>' || operator === '<@' || operator === '&&') {
|
|
266
|
-
throw new
|
|
267
|
+
throw new errors.UnsupportedOperatorForNonArrayFieldError()
|
|
267
268
|
} else {
|
|
268
269
|
criteria.push(sql`${sql.ident(field)} ${sql.__dangerous__rawValue(operator)} ${computeCriteriaValue(fieldWrap, value[key])}`)
|
|
269
270
|
}
|
|
@@ -314,7 +315,7 @@ function createMapper (defaultDb, sql, log, table, fields, primaryKeys, relation
|
|
|
314
315
|
query = sql`${query} LIMIT ${sanitizeLimit(opts.limit, limitConfig)}`
|
|
315
316
|
if (opts.offset !== undefined) {
|
|
316
317
|
if (opts.offset < 0) {
|
|
317
|
-
throw new
|
|
318
|
+
throw new errors.ParamNotAllowedError(opts.offset)
|
|
318
319
|
}
|
|
319
320
|
query = sql`${query} OFFSET ${opts.offset}`
|
|
320
321
|
}
|
|
@@ -416,7 +417,7 @@ function buildEntity (db, sql, log, table, queries, autoTimestamp, schema, useSc
|
|
|
416
417
|
const validTypes = ['varchar', 'integer', 'uuid', 'serial']
|
|
417
418
|
const pkType = fields[constraint.column_name].sqlType.toLowerCase()
|
|
418
419
|
if (!validTypes.includes(pkType)) {
|
|
419
|
-
throw new
|
|
420
|
+
throw new errors.InvalidPrimaryKeyTypeError(pkType, validTypes.join(', '))
|
|
420
421
|
}
|
|
421
422
|
}
|
|
422
423
|
}
|
package/lib/errors.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const createError = require('@fastify/error')
|
|
4
|
+
|
|
5
|
+
const ERROR_PREFIX = 'PLT_SQL_MAPPER'
|
|
6
|
+
|
|
7
|
+
// We need to ignore this because some of the errors are actually not thrown
|
|
8
|
+
// in tests (but coverage is still 100% because in "ignored" code).
|
|
9
|
+
module.exports = {
|
|
10
|
+
CannotFindEntityError: createError(`${ERROR_PREFIX}_CANNOT_FIND_ENTITY`, 'Cannot find entity %s'),
|
|
11
|
+
SpecifyProtocolError: createError(`${ERROR_PREFIX}_SPECIFY_PROTOCOLS`, 'You must specify either postgres, mysql or sqlite as protocols'),
|
|
12
|
+
ConnectionStringRequiredError: createError(`${ERROR_PREFIX}_CONNECTION_STRING_REQUIRED`, 'connectionString is required'),
|
|
13
|
+
TableMustBeAStringError: createError(`${ERROR_PREFIX}_TABLE_MUST_BE_A_STRING`, 'Table must be a string, got %s'),
|
|
14
|
+
UnknownFieldError: createError(`${ERROR_PREFIX}_UNKNOWN_FIELD`, 'Unknown field %s'),
|
|
15
|
+
InputNotProvidedError: createError(`${ERROR_PREFIX}_INPUT_NOT_PROVIDED`, 'Input not provided.'),
|
|
16
|
+
UnsupportedWhereClauseError: createError(`${ERROR_PREFIX}_UNSUPPORTED_WHERE_CLAUSE`, 'Unsupported where clause %s'),
|
|
17
|
+
UnsupportedOperatorForArrayFieldError: createError(`${ERROR_PREFIX}_UNSUPPORTED_OPERATOR`, 'Unsupported operator for Array field'),
|
|
18
|
+
UnsupportedOperatorForNonArrayFieldError: createError(`${ERROR_PREFIX}_UNSUPPORTED_OPERATOR_FOR_NON_ARRAY`, 'Unsupported operator for non Array field'),
|
|
19
|
+
ParamNotAllowedError: createError(`${ERROR_PREFIX}_PARAM_NOT_ALLOWED`, 'Param offset=%s not allowed. It must be not negative value.'),
|
|
20
|
+
InvalidPrimaryKeyTypeError: createError(`${ERROR_PREFIX}_INVALID_PRIMARY_KEY_TYPE`, 'Invalid Primary Key type: "%s". We support the following: %s'),
|
|
21
|
+
ParamLimitNotAllowedError: createError(`${ERROR_PREFIX}_PARAM_LIMIT_NOT_ALLOWED`, 'Param limit=%s not allowed. Max accepted value %s.'),
|
|
22
|
+
ParamLimitMustBeNotNegativeError: createError(`${ERROR_PREFIX}_PARAM_LIMIT_MUST_BE_NOT_NEGATIVE`, 'Param limit=%s not allowed. It must be a not negative value.'),
|
|
23
|
+
MissingValueForPrimaryKeyError: createError(`${ERROR_PREFIX}_MISSING_VALUE_FOR_PRIMARY_KEY`, 'Missing value for primary key %s'),
|
|
24
|
+
SQLiteOnlySupportsAutoIncrementOnOneColumnError: createError(`${ERROR_PREFIX}_SQLITE_ONLY_SUPPORTS_AUTO_INCREMENT_ON_ONE_COLUMN`, 'SQLite only supports autoIncrement on one column')
|
|
25
|
+
}
|
package/lib/queries/mysql.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { insertPrep } = require('./shared')
|
|
4
4
|
const shared = require('./mysql-shared')
|
|
5
5
|
const { tableName } = require('../utils')
|
|
6
|
+
const errors = require('../errors')
|
|
6
7
|
|
|
7
8
|
function insertOne (db, sql, table, schema, input, primaryKeys, fieldsToRetrieve) {
|
|
8
9
|
const keysToSql = Object.keys(input).map((key) => sql.ident(key))
|
|
@@ -48,7 +49,7 @@ function insertOne (db, sql, table, schema, input, primaryKeys, fieldsToRetrieve
|
|
|
48
49
|
// TODO write a test that cover this
|
|
49
50
|
/* istanbul ignore next */
|
|
50
51
|
if (!input[key]) {
|
|
51
|
-
throw new
|
|
52
|
+
throw new errors.MissingValueForPrimaryKeyError(key)
|
|
52
53
|
}
|
|
53
54
|
where.push(sql`${sql.ident(key)} = ${input[key]}`)
|
|
54
55
|
}
|
package/lib/queries/shared.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { tableName } = require('../utils')
|
|
4
|
+
const errors = require('../errors')
|
|
4
5
|
|
|
5
6
|
/* istanbul ignore file */
|
|
6
7
|
|
|
@@ -71,7 +72,7 @@ function insertPrep (inputs, inputToFieldMap, fields, sql) {
|
|
|
71
72
|
let newKey = key
|
|
72
73
|
if (inputToFieldMap[key] === undefined) {
|
|
73
74
|
if (fields[key] === undefined) {
|
|
74
|
-
throw new
|
|
75
|
+
throw new errors.UnknownFieldError(key)
|
|
75
76
|
}
|
|
76
77
|
} else {
|
|
77
78
|
newKey = inputToFieldMap[key]
|
package/lib/queries/sqlite.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { randomUUID } = require('crypto')
|
|
4
|
+
const errors = require('../errors')
|
|
4
5
|
|
|
5
6
|
function fixValue (value) {
|
|
6
7
|
if (value instanceof Date) {
|
|
@@ -108,7 +109,7 @@ async function insertOne (db, sql, table, schema, input, primaryKeys, fieldsToRe
|
|
|
108
109
|
primaryKeyValue = null
|
|
109
110
|
hasAutoIncrementPK = true
|
|
110
111
|
} else {
|
|
111
|
-
throw new
|
|
112
|
+
throw new errors.SQLiteOnlySupportsAutoIncrementOnOneColumnError()
|
|
112
113
|
}
|
|
113
114
|
input[key] = primaryKeyValue
|
|
114
115
|
}
|
package/lib/utils.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { singularize } = require('inflected')
|
|
4
4
|
const camelcase = require('camelcase')
|
|
5
|
+
const errors = require('./errors')
|
|
5
6
|
|
|
6
7
|
function toUpperFirst (str) {
|
|
7
8
|
return str[0].toUpperCase() + str.slice(1)
|
|
@@ -23,11 +24,11 @@ function sanitizeLimit (unsafeLimit, conf) {
|
|
|
23
24
|
const max = conf?.max ?? 100
|
|
24
25
|
|
|
25
26
|
if (limit > max) {
|
|
26
|
-
throw new
|
|
27
|
+
throw new errors.ParamLimitNotAllowedError(limit, max)
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
if (limit < 0) {
|
|
30
|
-
throw new
|
|
31
|
+
throw new errors.ParamLimitMustBeNotNegativeError(limit)
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
return limit
|
package/mapper.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FastifyPluginAsync, FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
|
|
2
|
-
import type { PlatformaticApp } from '@platformatic/types'
|
|
3
2
|
import { SQL, SQLQuery } from '@databases/sql'
|
|
3
|
+
import { FastifyError } from '@fastify/error'
|
|
4
4
|
|
|
5
5
|
interface ILogger {
|
|
6
6
|
trace(): any,
|
|
@@ -297,7 +297,7 @@ export interface CreateConnectionPoolOptions extends BasePoolOptions {
|
|
|
297
297
|
log: ILogger
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
export function createConnectionPool(options: CreateConnectionPoolOptions)
|
|
300
|
+
export function createConnectionPool(options: CreateConnectionPoolOptions): Promise<{ db: Database, sql: SQL }>
|
|
301
301
|
|
|
302
302
|
export interface SQLMapperPluginOptions extends BasePoolOptions {
|
|
303
303
|
/**
|
|
@@ -333,7 +333,7 @@ export interface Entities {
|
|
|
333
333
|
[entityName: string]: Entity
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
-
export interface SQLMapperPluginInterface {
|
|
336
|
+
export interface SQLMapperPluginInterface<T extends Entities> {
|
|
337
337
|
/**
|
|
338
338
|
* A Database abstraction layer from [@Databases](https://www.atdatabases.org/)
|
|
339
339
|
*/
|
|
@@ -345,7 +345,7 @@ export interface SQLMapperPluginInterface {
|
|
|
345
345
|
/**
|
|
346
346
|
* An object containing a key for each table found in the schema, with basic CRUD operations. See [entity.md](./entity.md) for details.
|
|
347
347
|
*/
|
|
348
|
-
entities:
|
|
348
|
+
entities: T,
|
|
349
349
|
/**
|
|
350
350
|
* Adds hooks to the entity.
|
|
351
351
|
*/
|
|
@@ -357,33 +357,6 @@ export interface SQLMapperPluginInterface {
|
|
|
357
357
|
cleanUpAllEntities(): Promise<void>
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
-
// Extend the PlatformaticApp interface,
|
|
361
|
-
// Unfortunately we neeed to copy over all the types from SQLMapperPluginInterface
|
|
362
|
-
declare module '@platformatic/types' {
|
|
363
|
-
interface PlatformaticApp {
|
|
364
|
-
/**
|
|
365
|
-
* A Database abstraction layer from [@Databases](https://www.atdatabases.org/)
|
|
366
|
-
*/
|
|
367
|
-
db: Database,
|
|
368
|
-
/**
|
|
369
|
-
* The SQL builder from [@Databases](https://www.atdatabases.org/)
|
|
370
|
-
*/
|
|
371
|
-
sql: SQL,
|
|
372
|
-
/**
|
|
373
|
-
* An object containing a key for each table found in the schema, with basic CRUD operations. See [entity.md](./entity.md) for details.
|
|
374
|
-
*/
|
|
375
|
-
entities: Entities,
|
|
376
|
-
/**
|
|
377
|
-
* Adds hooks to the entity.
|
|
378
|
-
*/
|
|
379
|
-
addEntityHooks<EntityFields>(entityName: string, hooks: EntityHooks<EntityFields>): any
|
|
380
|
-
/**
|
|
381
|
-
* Clean up all the data in all entities
|
|
382
|
-
*/
|
|
383
|
-
cleanUpAllEntities(): Promise<void>
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
360
|
export interface PlatformaticContext {
|
|
388
361
|
app: FastifyInstance,
|
|
389
362
|
reply: FastifyReply
|
|
@@ -398,7 +371,7 @@ declare module 'fastify' {
|
|
|
398
371
|
/**
|
|
399
372
|
* Connects to the database and maps the tables to entities.
|
|
400
373
|
*/
|
|
401
|
-
export function connect(options: SQLMapperPluginOptions): Promise<SQLMapperPluginInterface
|
|
374
|
+
export function connect<T extends Entities>(options: SQLMapperPluginOptions): Promise<SQLMapperPluginInterface<T>>
|
|
402
375
|
/**
|
|
403
376
|
* Fastify plugin that connects to the database and maps the tables to entities.
|
|
404
377
|
*/
|
|
@@ -412,3 +385,25 @@ export module utils {
|
|
|
412
385
|
export function toSingular(str: string): string
|
|
413
386
|
}
|
|
414
387
|
|
|
388
|
+
/**
|
|
389
|
+
* All the errors thrown by the plugin.
|
|
390
|
+
*/
|
|
391
|
+
export module errors {
|
|
392
|
+
export const CannotFindEntityError: (entityName: string) => FastifyError
|
|
393
|
+
export const SpecifyProtocolError: () => FastifyError
|
|
394
|
+
export const ConnectionStringRequiredError: () => FastifyError
|
|
395
|
+
export const TableMustBeAStringError: (table: any) => FastifyError
|
|
396
|
+
export const UnknownFieldError: (key: string) => FastifyError
|
|
397
|
+
export const InputNotProvidedError: () => FastifyError
|
|
398
|
+
export const UnsupportedWhereClauseError: (where: string) => FastifyError
|
|
399
|
+
export const UnsupportedOperatorForArrayFieldError: () => FastifyError
|
|
400
|
+
export const UnsupportedOperatorForNonArrayFieldError: () => FastifyError
|
|
401
|
+
export const ParamNotAllowedError: (offset: string) => FastifyError
|
|
402
|
+
export const InvalidPrimaryKeyTypeError: (pkType: string, validTypes: string) => FastifyError
|
|
403
|
+
export const ParamLimitNotAllowedError: (limit: string, max: string) => FastifyError
|
|
404
|
+
export const ParamLimitMustBeNotNegativeError: (limit: string) => FastifyError
|
|
405
|
+
export const MissingValueForPrimaryKeyError: (key: string) => FastifyError
|
|
406
|
+
export const SQLiteOnlySupportsAutoIncrementOnOneColumnError: () => FastifyError
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
|
package/mapper.js
CHANGED
|
@@ -5,6 +5,7 @@ const buildCleanUp = require('./lib/clean-up')
|
|
|
5
5
|
const queriesFactory = require('./lib/queries')
|
|
6
6
|
const fp = require('fastify-plugin')
|
|
7
7
|
const { areSchemasSupported } = require('./lib/utils')
|
|
8
|
+
const errors = require('./lib/errors')
|
|
8
9
|
|
|
9
10
|
// Ignore the function as it is only used only for MySQL and PostgreSQL
|
|
10
11
|
/* istanbul ignore next */
|
|
@@ -89,7 +90,7 @@ async function createConnectionPool ({ log, connectionString, poolSize }) {
|
|
|
89
90
|
sql = sqlite.sql
|
|
90
91
|
db.isSQLite = true
|
|
91
92
|
} else {
|
|
92
|
-
throw new
|
|
93
|
+
throw new errors.SpecifyProtocolError()
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
return { db, sql }
|
|
@@ -101,7 +102,7 @@ async function connect ({ connectionString, log, onDatabaseLoad, poolSize, ignor
|
|
|
101
102
|
}
|
|
102
103
|
// TODO validate config using the schema
|
|
103
104
|
if (!connectionString) {
|
|
104
|
-
throw new
|
|
105
|
+
throw new errors.ConnectionStringRequiredError()
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
let queries
|
|
@@ -162,7 +163,7 @@ async function connect ({ connectionString, log, onDatabaseLoad, poolSize, ignor
|
|
|
162
163
|
// it should never happen.
|
|
163
164
|
/* istanbul ignore next */
|
|
164
165
|
if (typeof table !== 'string') {
|
|
165
|
-
throw new
|
|
166
|
+
throw new errors.TableMustBeAStringError(table)
|
|
166
167
|
}
|
|
167
168
|
if (ignore[table] === true) {
|
|
168
169
|
continue
|
|
@@ -199,7 +200,7 @@ async function connect ({ connectionString, log, onDatabaseLoad, poolSize, ignor
|
|
|
199
200
|
function addEntityHooks (entityName, hooks) {
|
|
200
201
|
const entity = entities[entityName]
|
|
201
202
|
if (!entity) {
|
|
202
|
-
throw new
|
|
203
|
+
throw new errors.CannotFindEntityError(entityName)
|
|
203
204
|
}
|
|
204
205
|
for (const key of Object.keys(hooks)) {
|
|
205
206
|
if (hooks[key] && entity[key]) {
|
|
@@ -239,3 +240,4 @@ module.exports.connect = connect
|
|
|
239
240
|
module.exports.createConnectionPool = createConnectionPool
|
|
240
241
|
module.exports.plugin = module.exports
|
|
241
242
|
module.exports.utils = require('./lib/utils')
|
|
243
|
+
module.exports.errors = errors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/sql-mapper",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "A data mapper utility for SQL databases",
|
|
5
5
|
"main": "mapper.js",
|
|
6
6
|
"types": "mapper.d.ts",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
"@databases/mysql": "^6.0.0",
|
|
26
26
|
"@databases/pg": "^5.4.1",
|
|
27
27
|
"@databases/sql": "^3.3.0",
|
|
28
|
+
"@fastify/error": "^3.2.1",
|
|
28
29
|
"@hapi/topo": "^6.0.2",
|
|
29
30
|
"@matteo.collina/sqlite-pool": "^0.3.0",
|
|
30
31
|
"camelcase": "^6.3.0",
|
|
31
32
|
"fastify-plugin": "^4.5.0",
|
|
32
|
-
"inflected": "^2.1.0"
|
|
33
|
-
"@platformatic/types": "0.43.1"
|
|
33
|
+
"inflected": "^2.1.0"
|
|
34
34
|
},
|
|
35
35
|
"tsd": {
|
|
36
36
|
"directory": "test/types"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { expectType } from 'tsd'
|
|
2
2
|
import { SQL, SQLQuery } from '@databases/sql'
|
|
3
3
|
import { fastify, FastifyInstance, FastifyReply } from 'fastify'
|
|
4
|
+
import { FastifyError } from '@fastify/error'
|
|
4
5
|
import {
|
|
5
6
|
connect,
|
|
6
7
|
plugin,
|
|
@@ -10,16 +11,24 @@ import {
|
|
|
10
11
|
Database,
|
|
11
12
|
SQLMapperPluginInterface,
|
|
12
13
|
EntityHooks,
|
|
13
|
-
createConnectionPool
|
|
14
|
+
createConnectionPool,
|
|
15
|
+
Entities,
|
|
16
|
+
errors
|
|
14
17
|
} from '../../mapper'
|
|
15
18
|
|
|
16
19
|
const log = {
|
|
17
|
-
trace() {},
|
|
18
|
-
error() {},
|
|
19
|
-
warn() {}
|
|
20
|
+
trace() { },
|
|
21
|
+
error() { },
|
|
22
|
+
warn() { }
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
declare module 'fastify' {
|
|
26
|
+
interface FastifyInstance {
|
|
27
|
+
platformatic: SQLMapperPluginInterface<Entities>
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const pluginOptions: SQLMapperPluginInterface<Entities> = await connect<Entities>({ connectionString: '', log })
|
|
23
32
|
expectType<Database>(pluginOptions.db)
|
|
24
33
|
expectType<SQL>(pluginOptions.sql)
|
|
25
34
|
expectType<{ [entityName: string]: Entity }>(pluginOptions.entities)
|
|
@@ -56,17 +65,17 @@ const entityHooks: EntityHooks = {
|
|
|
56
65
|
async count(originalCount: typeof entity.count, ...options: Parameters<typeof entity.count>): ReturnType<typeof entity.count> { return 0 },
|
|
57
66
|
}
|
|
58
67
|
expectType<EntityHooks>(entityHooks)
|
|
59
|
-
expectType<SQLMapperPluginInterface
|
|
60
|
-
expectType<SQLMapperPluginInterface
|
|
61
|
-
expectType<SQLMapperPluginInterface
|
|
62
|
-
expectType<SQLMapperPluginInterface
|
|
68
|
+
expectType<SQLMapperPluginInterface<Entities>>(await connect<Entities>({ connectionString: '', log }))
|
|
69
|
+
expectType<SQLMapperPluginInterface<Entities>>(await connect<Entities>({ connectionString: '', autoTimestamp: true, log }))
|
|
70
|
+
expectType<SQLMapperPluginInterface<Entities>>(await connect<Entities>({ connectionString: '', hooks: {}, log }))
|
|
71
|
+
expectType<SQLMapperPluginInterface<Entities>>(await connect<Entities>({
|
|
63
72
|
connectionString: '', hooks: {
|
|
64
73
|
Page: entityHooks
|
|
65
74
|
},
|
|
66
75
|
log
|
|
67
76
|
}))
|
|
68
|
-
expectType<SQLMapperPluginInterface
|
|
69
|
-
expectType<SQLMapperPluginInterface
|
|
77
|
+
expectType<SQLMapperPluginInterface<Entities>>(await connect<Entities>({ connectionString: '', ignore: {}, log }))
|
|
78
|
+
expectType<SQLMapperPluginInterface<Entities>>(await connect<Entities>({
|
|
70
79
|
connectionString: '', log, onDatabaseLoad(db: Database, sql: SQL) {
|
|
71
80
|
expectType<(query: SQLQuery) => Promise<any[]>>(db.query)
|
|
72
81
|
expectType<() => Promise<void>>(db.dispose)
|
|
@@ -81,10 +90,10 @@ expectType<SQLMapperPluginInterface>(await connect({
|
|
|
81
90
|
const instance: FastifyInstance = fastify()
|
|
82
91
|
instance.register(plugin, { connectionString: '', autoTimestamp: true })
|
|
83
92
|
instance.register((instance) => {
|
|
84
|
-
expectType<SQLMapperPluginInterface
|
|
93
|
+
expectType<SQLMapperPluginInterface<Entities>>(instance.platformatic)
|
|
85
94
|
|
|
86
95
|
instance.platformatic.addEntityHooks<EntityFields>('something', {
|
|
87
|
-
async find
|
|
96
|
+
async find(originalFind, options) {
|
|
88
97
|
expectType<Partial<EntityFields>[]>(await originalFind())
|
|
89
98
|
expectType<Parameters<typeof entity.find>[0]>(options)
|
|
90
99
|
|
|
@@ -105,3 +114,26 @@ instance.register((instance) => {
|
|
|
105
114
|
expectType<(str: string) => string>(utils.toSingular)
|
|
106
115
|
|
|
107
116
|
expectType<Promise<{ db: Database, sql: SQL }>>(createConnectionPool({ connectionString: '', log }))
|
|
117
|
+
|
|
118
|
+
// Errors
|
|
119
|
+
type ErrorWithNoParams = () => FastifyError
|
|
120
|
+
type ErrorWithOneParam = (param: string) => FastifyError
|
|
121
|
+
type ErrorWithOneAnyParam = (param: any) => FastifyError
|
|
122
|
+
type ErrorWithTwoParams = (param1: string, param2: string) => FastifyError
|
|
123
|
+
|
|
124
|
+
expectType<ErrorWithOneParam>(errors.CannotFindEntityError)
|
|
125
|
+
expectType<ErrorWithNoParams>(errors.SpecifyProtocolError)
|
|
126
|
+
expectType<ErrorWithNoParams>(errors.ConnectionStringRequiredError)
|
|
127
|
+
expectType<ErrorWithOneAnyParam>(errors.TableMustBeAStringError)
|
|
128
|
+
expectType<ErrorWithOneParam>(errors.UnknownFieldError)
|
|
129
|
+
expectType<ErrorWithNoParams>(errors.InputNotProvidedError)
|
|
130
|
+
expectType<ErrorWithOneParam>(errors.UnsupportedWhereClauseError)
|
|
131
|
+
expectType<ErrorWithNoParams>(errors.UnsupportedOperatorForArrayFieldError)
|
|
132
|
+
expectType<ErrorWithNoParams>(errors.UnsupportedOperatorForNonArrayFieldError)
|
|
133
|
+
expectType<ErrorWithOneParam>(errors.ParamNotAllowedError)
|
|
134
|
+
expectType<ErrorWithTwoParams>(errors.InvalidPrimaryKeyTypeError)
|
|
135
|
+
expectType<ErrorWithTwoParams>(errors.ParamLimitNotAllowedError)
|
|
136
|
+
expectType<ErrorWithOneParam>(errors.ParamLimitMustBeNotNegativeError)
|
|
137
|
+
expectType<ErrorWithOneParam>(errors.MissingValueForPrimaryKeyError)
|
|
138
|
+
expectType<ErrorWithNoParams>(errors.SQLiteOnlySupportsAutoIncrementOnOneColumnError)
|
|
139
|
+
|
package/test/where.test.js
CHANGED
|
@@ -452,7 +452,8 @@ test('limit should be 10 by default 100 at max', async ({ pass, teardown, same,
|
|
|
452
452
|
await entity.find({ limit: -1 })
|
|
453
453
|
fail('Expected error for limit not allowed value')
|
|
454
454
|
} catch (e) {
|
|
455
|
-
match(e,
|
|
455
|
+
match(e.message, 'Param limit=-1 not allowed. It must be a not negative value.')
|
|
456
|
+
match(e.code, 'PLT_SQL_MAPPER_PARAM_LIMIT_MUST_BE_NOT_NEGATIVE')
|
|
456
457
|
}
|
|
457
458
|
|
|
458
459
|
same(await (await entity.find({ limit: 1, offset: 0 })).length, 1)
|
|
@@ -535,7 +536,8 @@ test('limit must accept custom configuration', async ({ pass, teardown, same, fa
|
|
|
535
536
|
await entity.find({ limit: -1 })
|
|
536
537
|
fail('Expected error for limit not allowed value')
|
|
537
538
|
} catch (e) {
|
|
538
|
-
match(e,
|
|
539
|
+
match(e.message, 'Param limit=-1 not allowed. It must be a not negative value.')
|
|
540
|
+
match(e.code, 'PLT_SQL_MAPPER_PARAM_LIMIT_MUST_BE_NOT_NEGATIVE')
|
|
539
541
|
}
|
|
540
542
|
|
|
541
543
|
same(await (await entity.find({ limit: 1, offset: 0 })).length, 1)
|