@creator.co/wapi 1.3.19-alpha1 → 1.4.0-alpha1

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.
Files changed (72) hide show
  1. package/dist/package.json +2 -1
  2. package/dist/src/API/Request.js.map +1 -1
  3. package/dist/src/API/Response.js.map +1 -1
  4. package/dist/src/API/Utils.js.map +1 -1
  5. package/dist/src/BaseEvent/EventProcessor.js.map +1 -1
  6. package/dist/src/BaseEvent/Transaction.d.ts +1 -1
  7. package/dist/src/Config/Configuration.js.map +1 -1
  8. package/dist/src/Config/EnvironmentVar.js.map +1 -1
  9. package/dist/src/Crypto/JWT.js.map +1 -1
  10. package/dist/src/Database/Database.d.ts +8 -5
  11. package/dist/src/Database/Database.js +5 -3
  12. package/dist/src/Database/Database.js.map +1 -1
  13. package/dist/src/Database/DatabaseManager.d.ts +30 -9
  14. package/dist/src/Database/DatabaseManager.js +25 -10
  15. package/dist/src/Database/DatabaseManager.js.map +1 -1
  16. package/dist/src/Database/DatabaseTransaction.d.ts +66 -31
  17. package/dist/src/Database/DatabaseTransaction.js +51 -30
  18. package/dist/src/Database/DatabaseTransaction.js.map +1 -1
  19. package/dist/src/Database/integrations/knex/KnexDatabase.d.ts +22 -8
  20. package/dist/src/Database/integrations/knex/KnexDatabase.js +18 -13
  21. package/dist/src/Database/integrations/knex/KnexDatabase.js.map +1 -1
  22. package/dist/src/Database/integrations/knex/KnexTransaction.d.ts +39 -16
  23. package/dist/src/Database/integrations/knex/KnexTransaction.js +83 -17
  24. package/dist/src/Database/integrations/knex/KnexTransaction.js.map +1 -1
  25. package/dist/src/Database/integrations/kysely/KyselyDatabase.d.ts +55 -0
  26. package/dist/src/Database/integrations/kysely/KyselyDatabase.js +126 -0
  27. package/dist/src/Database/integrations/kysely/KyselyDatabase.js.map +1 -0
  28. package/dist/src/Database/integrations/kysely/KyselyTransaction.d.ts +70 -0
  29. package/dist/src/Database/integrations/kysely/KyselyTransaction.js +186 -0
  30. package/dist/src/Database/integrations/kysely/KyselyTransaction.js.map +1 -0
  31. package/dist/src/Database/integrations/pgsql/PostgresDatabase.d.ts +16 -11
  32. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js +19 -18
  33. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js.map +1 -1
  34. package/dist/src/Database/integrations/pgsql/PostgresTransaction.d.ts +42 -16
  35. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js +84 -18
  36. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js.map +1 -1
  37. package/dist/src/Database/types.d.ts +47 -26
  38. package/dist/src/Logger/Logger.d.ts +6 -6
  39. package/dist/src/Logger/Logger.js +12 -15
  40. package/dist/src/Logger/Logger.js.map +1 -1
  41. package/dist/src/Publisher/Publisher.js.map +1 -1
  42. package/dist/src/Server/RouteResolver.js.map +1 -1
  43. package/dist/src/Server/lib/ContainerServer.js.map +1 -1
  44. package/dist/src/Server/lib/Server.js.map +1 -1
  45. package/dist/src/Server/lib/container/GenericHandler.js +2 -2
  46. package/dist/src/Server/lib/container/GenericHandler.js.map +1 -1
  47. package/dist/src/Server/lib/container/GenericHandlerEvent.js +1 -1
  48. package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -1
  49. package/dist/src/Server/lib/container/Utils.js.map +1 -1
  50. package/dist/src/Validation/Validator.js.map +1 -1
  51. package/package.json +2 -1
  52. package/src/BaseEvent/Transaction.ts +2 -2
  53. package/src/Database/Database.ts +8 -5
  54. package/src/Database/DatabaseManager.ts +34 -17
  55. package/src/Database/DatabaseTransaction.ts +79 -35
  56. package/src/Database/integrations/knex/KnexDatabase.ts +22 -11
  57. package/src/Database/integrations/knex/KnexTransaction.ts +52 -19
  58. package/src/Database/integrations/kysely/KyselyDatabase.ts +87 -0
  59. package/src/Database/integrations/kysely/KyselyTransaction.ts +172 -0
  60. package/src/Database/integrations/pgsql/PostgresDatabase.ts +26 -14
  61. package/src/Database/integrations/pgsql/PostgresTransaction.ts +55 -22
  62. package/src/Database/types.ts +53 -31
  63. package/src/Logger/Logger.ts +12 -15
  64. package/src/Server/lib/container/GenericHandler.ts +2 -2
  65. package/tests/Database/DatabaseManager.test.ts +16 -1
  66. package/tests/Database/integrations/knex/KnexDatabase.test.ts +2 -2
  67. package/tests/Database/integrations/knex/KnexTransaction.test.ts +52 -45
  68. package/tests/Database/integrations/kysely/KyselyDatabase.test.ts +109 -0
  69. package/tests/Database/integrations/kysely/KyselyTransaction.test.ts +118 -0
  70. package/tests/Database/integrations/pg/PostgresDatabase.test.ts +32 -6
  71. package/tests/Database/integrations/pg/PostgresTransaction.test.ts +75 -9
  72. package/tsconfig.json +1 -0
@@ -1,45 +1,60 @@
1
1
  import { Database } from './Database'
2
2
  import { DATABASES } from './DatabaseManager'
3
+ import { KnexDatabase } from './integrations/knex/KnexDatabase'
4
+ import { KyselyDatabase } from './integrations/kysely/KyselyDatabase'
5
+ import { PostgresDatabase } from './integrations/pgsql/PostgresDatabase'
3
6
 
4
7
  /**
5
- * Represents the available types of databases.
8
+ * Represents the possible types of databases available in the system.
6
9
  * @typedef {keyof typeof DATABASES} DatabaseType
7
10
  */
8
11
  export type DatabaseType = keyof typeof DATABASES
9
12
 
10
13
  /**
11
- * Represents the instance type of the specified database implementation.
12
- * @param {Type} Type - The type of the database implementation.
14
+ * Defines a type for a database class that includes instances for Knex, Postgres, and Kysely databases.
15
+ * @template T - The type of data the KyselyDatabase instance will handle.
16
+ * @property {new (...args: any[]) => KnexDatabase} knex - Constructor for KnexDatabase instances.
17
+ * @property {new (...args: any[]) => PostgresDatabase} pg - Constructor for PostgresDatabase instances.
18
+ * @property {new (...args: any[]) => KyselyDatabase<T>} kysely - Constructor for KyselyDatabase instances with type T.
13
19
  */
14
- export type DatabaseImplType<Type extends DatabaseType> = InstanceType<(typeof DATABASES)[Type]>
20
+ export type DatabaseClass<T> = {
21
+ knex: new (...args: any[]) => KnexDatabase
22
+ pg: new (...args: any[]) => PostgresDatabase
23
+ kysely: new (...args: any[]) => KyselyDatabase<T>
24
+ }
15
25
 
16
26
  /**
17
- * Defines a type for a database transaction based on the specified database type.
18
- * @param {Type} - The database type.
19
- * @returns The transaction type associated with the specified database type.
27
+ * Represents a specific implementation type for a database based on the provided DatabaseType.
28
+ * @param {DatabaseType} Type - The type of database to implement.
29
+ * @param {T} T - The generic type for the database implementation.
30
+ * @returns An instance of the specified database class for the given type.
20
31
  */
21
- export type DatabaseTransactionType<Type extends DatabaseType> =
22
- DatabaseImplType<Type> extends Database<infer TransactionType> ? TransactionType : never
32
+ export type DatabaseImplType<Type extends DatabaseType, T> = InstanceType<DatabaseClass<T>[Type]>
23
33
 
24
34
  /**
25
- * Represents the configuration for a database connection.
26
- * @template S - The type of the database (e.g. "mysql", "postgres", etc.)
27
- * @interface DbConfig
28
- * @property {S} type - The type of the database.
29
- * @property {string} driver - The driver to use for the database connection.
30
- * @property {string} host - The host of the database server.
31
- * @property {number} port - The port number of the database server.
32
- * @property {string} username - The username for the database connection.
33
- * @property {string} password - The password for the database connection.
34
- * @property {string} database - The name of the database to connect to.
35
- * @property {boolean} autoCommit - Whether or not to automatically commit transactions.
36
- * @property {number} maxConnections - The maximum number of connections to the database.
37
- * @property {boolean} [convertCamelToSnake] - Whether or not to convert camel case to snake case for column names.
38
- * @returns The transaction type associated with the specified database type.
35
+ * Defines the type of transaction for a specific database type and schema.
36
+ * @param {DatabaseType} Type - The type of the database.
37
+ * @param {DBSchema} DBSchema - The schema of the database.
38
+ * @returns The transaction type associated with the database type and schema.
39
39
  */
40
- export type DbConfig<S extends DatabaseType> = {
41
- type: S
42
- driver: string
40
+ export type DatabaseTransactionType<Type extends DatabaseType, DBSchema> =
41
+ DatabaseImplType<Type, DBSchema> extends Database<infer TransactionType> ? TransactionType : never
42
+
43
+ /**
44
+ * Defines the configuration options for different types of databases.
45
+ * @typedef {Object} DbBaseConfig
46
+ * @property {string} host - The host of the database.
47
+ * @property {number} port - The port number of the database.
48
+ * @property {string} username - The username for accessing the database.
49
+ * @property {string} password - The password for accessing the database.
50
+ * @property {string} database - The name of the database.
51
+ * @property {boolean} autoCommit - Flag indicating whether auto-commit is enabled.
52
+ * @property {number} maxConnections - The maximum number of connections allowed.
53
+ *
54
+ * @typedef {Object} DbConfig
55
+ * @property {string} type - The type of
56
+ */
57
+ type DbBaseConfig = {
43
58
  host: string
44
59
  port: number
45
60
  username: string
@@ -47,8 +62,15 @@ export type DbConfig<S extends DatabaseType> = {
47
62
  database: string
48
63
  autoCommit: boolean
49
64
  maxConnections: number
50
- } & (S extends 'knex'
51
- ? {
52
- convertCamelToSnake?: boolean
53
- }
54
- : any)
65
+ }
66
+ export type DbConfig<S extends DatabaseType> = DbBaseConfig & { type: S } & (S extends 'knex'
67
+ ? {
68
+ driver?: string
69
+ convertCamelToSnake?: boolean
70
+ }
71
+ : unknown) &
72
+ (S extends 'pg' | 'kysely'
73
+ ? {
74
+ readReplica?: DbBaseConfig
75
+ }
76
+ : unknown)
@@ -33,8 +33,10 @@ const PURE_CONSOLE = console['notGlobalLogger'] ? console['origin'] : console
33
33
  const DEFAULT_LOG_FUNCTION = PURE_CONSOLE.log.bind(PURE_CONSOLE)
34
34
 
35
35
  /**
36
- * An array of sensitive strings that should be blacklisted or excluded from certain operations.
37
- * This array includes strings such as 'password', 'phonenumber', 'resetCode', etc.
36
+ * Creates a blacklist array by mapping each string in the given array to its lowercase form.
37
+ * The resulting blacklist array is used to filter out sensitive information.
38
+ * @type {string[]} blacklist - An array of strings to be converted to lowercase and used as a blacklist.
39
+ * @returns {string[]} - An array of lowercase strings representing the blacklist.
38
40
  */
39
41
  const blacklist = ['password', 'token', 'accounts'].map(s => s.toLowerCase())
40
42
 
@@ -214,29 +216,24 @@ export default class Logger {
214
216
  }
215
217
 
216
218
  /**
217
- * Returns the name of the caller at the specified index in the call stack.
218
- * @param {number} index - The index of the caller in the call stack.
219
- * @returns {string} The name of the caller, including the file name and line number.
219
+ * Retrieves the name of the caller function at the specified index in the stack trace.
220
+ * @param {number} index - The index of the caller function in the stack trace.
221
+ * @returns {string} The name of the caller function along with the file path and line number.
220
222
  */
221
223
  private callerName(index: number): string {
222
224
  const safeIndex = Math.min(index, stackTrace.get().length)
223
225
  if (stackTrace.get()[safeIndex]) {
224
- let callerName = stackTrace.get()[safeIndex]
225
- ? stackTrace.get()[safeIndex].getTypeName()
226
- : null
227
- if (!callerName) {
228
- callerName = stackTrace?.get()?.[safeIndex]?.getFileName()?.split('/')
229
- callerName = callerName?.slice(callerName?.indexOf('src'))?.join('/')
230
- }
226
+ let callerName = stackTrace?.get()?.[safeIndex]?.getFileName()?.split('/')
227
+ callerName = callerName?.slice(callerName?.indexOf('src'))?.join('/')
231
228
  return callerName + ':' + stackTrace?.get()?.[safeIndex]?.getLineNumber()
232
229
  }
233
230
  return ''
234
231
  }
235
232
 
236
233
  /**
237
- * Processes a log message based on the specified log level and arguments.
238
- * @param {LOG_LEVELS} level - The log level of the message.
239
- * @param {any[]} args - The arguments to be logged.
234
+ * Processes log messages based on the specified log level.
235
+ * @param {LOG_LEVELS} level - The level of the log message.
236
+ * @param {any} args - The arguments to be logged.
240
237
  * @returns None
241
238
  */
242
239
  private processLog(level: LOG_LEVELS, args: any): void {
@@ -67,9 +67,9 @@ const processServerlessResponse = (invokation: GenericHandlerEventResponse, res:
67
67
  let response = res.status(invokation.data.statusCode)
68
68
  // check for stream
69
69
  if (invokation.data?.body?.pipe) {
70
- invokation.data.body.pipe(res)
70
+ invokation.data.body.pipe(response)
71
71
  } else {
72
- response = res.json(Utils.parseObjectNullIfEmpty(invokation.data.body) || {})
72
+ response = response.json(Utils.parseObjectNullIfEmpty(invokation.data.body) || {})
73
73
  }
74
74
  return response
75
75
  }
@@ -3,7 +3,7 @@ import { expect } from 'chai'
3
3
  import { DatabaseManager } from '../../src/Database'
4
4
  import type { DatabaseType, DbConfig } from '../../src/Database/types'
5
5
 
6
- type FakeDatabase = { host: string; type: 'knex' | 'pg' }
6
+ type FakeDatabase = { host: string; type: 'knex' | 'pg' | 'kysely' }
7
7
 
8
8
  const fakeConfig = (host: string, type: DatabaseType) => {
9
9
  return {
@@ -23,6 +23,9 @@ describe('Database Manager', () => {
23
23
  pg: jest.fn(config => {
24
24
  return { host: config.host, type: 'pg' } as any
25
25
  }) as any,
26
+ kysely: jest.fn(config => {
27
+ return { host: config.host, type: 'kysely' } as any
28
+ }) as any,
26
29
  }
27
30
 
28
31
  const create = config => underTest.create({ ...config }) as unknown as FakeDatabase
@@ -31,6 +34,8 @@ describe('Database Manager', () => {
31
34
  const knexConfig2 = fakeConfig('other', 'knex')
32
35
  const pgConfig1 = fakeConfig('localhost', 'pg')
33
36
  const pgConfig2 = fakeConfig('other', 'pg')
37
+ const kyselyConfig1 = fakeConfig('localhost', 'pg')
38
+ const kyselyConfig2 = fakeConfig('other', 'pg')
34
39
 
35
40
  const knex1 = create(knexConfig1)
36
41
  const knex2 = create(knexConfig1)
@@ -40,6 +45,10 @@ describe('Database Manager', () => {
40
45
  const pg2 = create(pgConfig1)
41
46
  const pg3 = create(pgConfig2)
42
47
 
48
+ const kysely1 = create(kyselyConfig1)
49
+ const kysely2 = create(kyselyConfig1)
50
+ const kysely3 = create(kyselyConfig2)
51
+
43
52
  expect(knex1).to.equal(knex2).to.not.equal(knex3).to.not.equal(pg1)
44
53
 
45
54
  expect(knexConfig1).to.be.deep.equal(knex1).to.be.deep.equal(knex2)
@@ -51,5 +60,11 @@ describe('Database Manager', () => {
51
60
  expect(pgConfig1).to.be.deep.equal(pg1).to.be.deep.equal(pg2)
52
61
 
53
62
  expect(pg3).to.be.deep.equal(pgConfig2)
63
+
64
+ expect(kysely1).to.equal(kysely2).to.not.equal(kysely3)
65
+
66
+ expect(kyselyConfig1).to.be.deep.equal(kysely1).to.be.deep.equal(kysely2)
67
+
68
+ expect(kysely3).to.be.deep.equal(kyselyConfig2)
54
69
  })
55
70
  })
@@ -47,7 +47,7 @@ describe('KnexDatabase', () => {
47
47
  const trans = await underTest.transaction()
48
48
 
49
49
  expect(trans).toBeInstanceOf(Function)
50
- expect(trans['delegate']).toBe(mockTrans)
50
+ expect(trans.transaction).toBe(mockTrans)
51
51
  })
52
52
 
53
53
  test('KnexDatabase - convert camel to snake', async () => {
@@ -70,6 +70,6 @@ describe('KnexDatabase', () => {
70
70
  const trans = await underTest.transaction()
71
71
 
72
72
  expect(trans).toBeInstanceOf(Function)
73
- expect(trans['delegate']).toBe(mockTrans)
73
+ expect(trans.transaction).toBe(mockTrans)
74
74
  })
75
75
  })
@@ -4,7 +4,7 @@ import { DbConfig } from '../../../../src/Database'
4
4
  import { KnexDatabase } from '../../../../src/Database/integrations/knex/KnexDatabase'
5
5
  import { KnexTransactionImpl } from '../../../../src/Database/integrations/knex/KnexTransaction'
6
6
 
7
- const testResources = (config: Partial<DbConfig<'knex'>>) => {
7
+ const testResources = async (config: Partial<DbConfig<'knex'>>) => {
8
8
  const database = {
9
9
  config: {
10
10
  autoCommit: true,
@@ -12,25 +12,31 @@ const testResources = (config: Partial<DbConfig<'knex'>>) => {
12
12
  } as DbConfig<'knex'>,
13
13
  } as KnexDatabase
14
14
 
15
- const mock = jest.fn() as any
16
- mock.commit = jest.fn()
17
- mock.rollback = jest.fn()
18
- mock.select = jest.fn()
15
+ const txMock = jest.fn() as any
16
+ txMock.commit = jest.fn()
17
+ txMock.rollback = jest.fn()
18
+ txMock.select = jest.fn()
19
19
 
20
- const delegate = mock as Knex.Transaction
20
+ const wMock = jest.fn() as any
21
+ wMock.transaction = jest.fn(() => txMock)
22
+
23
+ const writer = wMock as Knex
24
+ const transaction = txMock as Knex.Transaction
21
25
 
22
26
  return {
23
- delegate,
24
- underTest: KnexTransactionImpl.wrapDelegate(delegate, database),
27
+ transaction,
28
+ writer,
29
+ underTest: await KnexTransactionImpl.newTransaction(writer, database),
25
30
  }
26
31
  }
27
32
 
28
33
  describe('KnexTransaction', () => {
29
34
  test('Can only commit once', async () => {
30
- const { delegate, underTest } = testResources({})
35
+ const { writer, transaction, underTest } = await testResources({})
31
36
  await underTest.commit()
32
37
  expect(underTest.isOpen()).toBe(false)
33
- expect(delegate.commit).toBeCalled()
38
+ expect(writer.transaction).toBeCalled()
39
+ expect(transaction.commit).toBeCalled()
34
40
 
35
41
  await expect(underTest.commit).rejects.toThrowError(
36
42
  'Cannot commit, transaction is already closed!'
@@ -38,28 +44,29 @@ describe('KnexTransaction', () => {
38
44
  })
39
45
 
40
46
  test("Can't commit after rollback", async () => {
41
- const { delegate, underTest } = testResources({})
47
+ const { writer, transaction, underTest } = await testResources({})
42
48
  await underTest.rollback()
43
49
  expect(underTest.isOpen()).toBe(false)
44
- expect(delegate.rollback).toBeCalled()
50
+ expect(writer.transaction).toBeCalled()
51
+ expect(transaction.rollback).toBeCalled()
45
52
 
46
53
  await expect(underTest.commit).rejects.toThrowError(
47
54
  'Cannot commit, transaction is already closed!'
48
55
  )
49
56
  })
50
57
 
51
- test('Forwards calls to delegate', async () => {
52
- const { delegate, underTest } = testResources({})
58
+ test('Forwards calls to transaction', async () => {
59
+ const { transaction, underTest } = await testResources({})
53
60
  await underTest.select('name')
54
- expect(delegate.select).toBeCalledWith('name')
61
+ expect(transaction.select).toBeCalledWith('name')
55
62
  })
56
63
 
57
- test('Blocks delegate calls after commit', async () => {
58
- const { delegate, underTest } = testResources({})
64
+ test('Blocks transaction calls after commit', async () => {
65
+ const { transaction, underTest } = await testResources({})
59
66
  expect(underTest.select).toBeDefined()
60
67
 
61
68
  await underTest.commit()
62
- expect(delegate.commit).toBeCalled()
69
+ expect(transaction.commit).toBeCalled()
63
70
  expect(underTest.isOpen()).toBe(false)
64
71
 
65
72
  expect(underTest.select).toBeUndefined()
@@ -68,74 +75,74 @@ describe('KnexTransaction', () => {
68
75
 
69
76
  describe('KnexTransaction - closeSuccess', () => {
70
77
  test('Close success commits', async () => {
71
- const { delegate, underTest } = testResources({})
78
+ const { transaction, underTest } = await testResources({})
72
79
  await underTest.closeSuccess()
73
- expect(delegate.commit).toBeCalled()
80
+ expect(transaction.commit).toBeCalled()
74
81
  })
75
82
 
76
83
  test("Close success, doesn't commit again if already committed", async () => {
77
- const { delegate, underTest } = testResources({})
84
+ const { transaction, underTest } = await testResources({})
78
85
  await underTest.commit()
79
- expect(delegate.commit).toBeCalledTimes(1)
86
+ expect(transaction.commit).toBeCalledTimes(1)
80
87
  await underTest.closeSuccess()
81
- expect(delegate.commit).toBeCalledTimes(1)
88
+ expect(transaction.commit).toBeCalledTimes(1)
82
89
  })
83
90
 
84
91
  test('Close success, rolls back if not autocommit', async () => {
85
- const { delegate, underTest } = testResources({ autoCommit: false })
92
+ const { transaction, underTest } = await testResources({ autoCommit: false })
86
93
  await underTest.closeSuccess()
87
- expect(delegate.rollback).toBeCalled()
94
+ expect(transaction.rollback).toBeCalled()
88
95
  })
89
96
 
90
97
  test("Close success, doesn't rollback if already committed", async () => {
91
- const { delegate, underTest } = testResources({ autoCommit: false })
98
+ const { transaction, underTest } = await testResources({ autoCommit: false })
92
99
  await underTest.commit()
93
- expect(delegate.commit).toBeCalledTimes(1)
100
+ expect(transaction.commit).toBeCalledTimes(1)
94
101
  await underTest.closeSuccess()
95
- expect(delegate.rollback).not.toBeCalled()
96
- expect(delegate.commit).toBeCalledTimes(1)
102
+ expect(transaction.rollback).not.toBeCalled()
103
+ expect(transaction.commit).toBeCalledTimes(1)
97
104
  })
98
105
 
99
106
  test("Close success, doesn't rollback if already rolled back", async () => {
100
- const { delegate, underTest } = testResources({ autoCommit: false })
107
+ const { transaction, underTest } = await testResources({ autoCommit: false })
101
108
  await underTest.rollback()
102
- expect(delegate.rollback).toBeCalledTimes(1)
109
+ expect(transaction.rollback).toBeCalledTimes(1)
103
110
  await underTest.closeSuccess()
104
- expect(delegate.rollback).toBeCalledTimes(1)
105
- expect(delegate.commit).not.toBeCalled()
111
+ expect(transaction.rollback).toBeCalledTimes(1)
112
+ expect(transaction.commit).not.toBeCalled()
106
113
  })
107
114
  })
108
115
 
109
116
  describe('KnexTransaction - closeFailure', () => {
110
117
  test('Close failure rolls back', async () => {
111
- const { delegate, underTest } = testResources({})
118
+ const { transaction, underTest } = await testResources({})
112
119
  await underTest.closeFailure()
113
- expect(delegate.rollback).toBeCalled()
120
+ expect(transaction.rollback).toBeCalled()
114
121
  })
115
122
 
116
123
  test("Close failure, doesn't rollback again if already rolled back", async () => {
117
- const { delegate, underTest } = testResources({})
124
+ const { transaction, underTest } = await testResources({})
118
125
  await underTest.rollback()
119
- expect(delegate.rollback).toBeCalledTimes(1)
126
+ expect(transaction.rollback).toBeCalledTimes(1)
120
127
  await underTest.closeFailure()
121
- expect(delegate.rollback).toBeCalledTimes(1)
128
+ expect(transaction.rollback).toBeCalledTimes(1)
122
129
  })
123
130
 
124
131
  test("Close failure, doesn't rollback if already committed", async () => {
125
- const { delegate, underTest } = testResources({ autoCommit: false })
132
+ const { transaction, underTest } = await testResources({ autoCommit: false })
126
133
  await underTest.commit()
127
- expect(delegate.commit).toBeCalledTimes(1)
134
+ expect(transaction.commit).toBeCalledTimes(1)
128
135
  await underTest.closeFailure()
129
- expect(delegate.rollback).not.toBeCalled()
130
- expect(delegate.commit).toBeCalledTimes(1)
136
+ expect(transaction.rollback).not.toBeCalled()
137
+ expect(transaction.commit).toBeCalledTimes(1)
131
138
  })
132
139
  })
133
140
 
134
141
  describe('KnexTransaction - call direct', () => {
135
- test('Calls delegate', async () => {
136
- const { delegate, underTest } = testResources({ autoCommit: false })
142
+ test('Calls transaction', async () => {
143
+ const { transaction, underTest } = await testResources({ autoCommit: false })
137
144
 
138
145
  underTest('test')
139
- expect(delegate).toBeCalledWith('test')
146
+ expect(transaction).toBeCalledWith('test')
140
147
  })
141
148
  })
@@ -0,0 +1,109 @@
1
+ import { expect as c_expect } from 'chai'
2
+ import { PostgresDialect } from 'kysely'
3
+ import { PoolClient } from 'pg'
4
+
5
+ import type { DbConfig } from '../../../../src/Database'
6
+ import { KyselyDatabase } from '../../../../src/Database/integrations/kysely/KyselyDatabase'
7
+
8
+ const config: DbConfig<'kysely'> = {
9
+ type: 'kysely',
10
+ username: 'username',
11
+ password: 'password',
12
+ host: 'host',
13
+ port: 1234,
14
+ database: 'database',
15
+ maxConnections: 1,
16
+ autoCommit: true,
17
+ }
18
+
19
+ const config2: DbConfig<'kysely'> = {
20
+ ...config,
21
+ readReplica: config,
22
+ }
23
+
24
+ const expectedImplConfig = {
25
+ host: config.host,
26
+ port: config.port,
27
+ user: config.username,
28
+ password: config.password,
29
+ database: config.database,
30
+ max: config.maxConnections,
31
+ }
32
+
33
+ describe('KyselyDatabase', () => {
34
+ let mockTrans
35
+ let mockClient
36
+ let mockDriver
37
+ let mockDialect
38
+ let mockPgTrans
39
+ let mockPgClient
40
+ beforeEach(() => {
41
+ mockTrans = {
42
+ execute: jest.fn(async cb => {
43
+ cb(mockTrans)
44
+ }),
45
+ } as any
46
+ mockClient = jest.fn(
47
+ () =>
48
+ ({
49
+ transaction: () => mockTrans,
50
+ }) as any as PostgresDialect
51
+ )
52
+ KyselyDatabase['kyselyProvider'] = mockClient as any
53
+
54
+ mockDriver = {
55
+ execute: jest.fn(async () => {}),
56
+ } as any
57
+ mockDialect = jest.fn(
58
+ () =>
59
+ ({
60
+ createDriver: () => mockDriver,
61
+ }) as any as PostgresDialect
62
+ )
63
+ KyselyDatabase['kyselyPgProvider'] = mockDialect as any
64
+
65
+ mockPgTrans = {
66
+ query: jest.fn(() => {}),
67
+ } as any
68
+ mockPgClient = jest.fn(
69
+ () =>
70
+ ({
71
+ connect: async () => mockPgTrans,
72
+ }) as PoolClient
73
+ )
74
+ KyselyDatabase['pgProvider'] = mockPgClient as any
75
+ })
76
+
77
+ test('KyselyDatabase', async () => {
78
+ const underTest = new KyselyDatabase(config)
79
+ expect(mockPgClient).toHaveBeenNthCalledWith(1, expectedImplConfig)
80
+ expect(mockDialect).toHaveBeenCalledTimes(1)
81
+ expect(mockClient).toHaveBeenNthCalledWith(1, { dialect: underTest.pgClient })
82
+
83
+ const trans = await underTest.transaction()
84
+
85
+ expect(mockTrans.execute).toHaveBeenCalledTimes(1)
86
+ expect(trans.reader).toBeUndefined()
87
+ expect(trans.writer).toBeInstanceOf(Object)
88
+ expect(trans.writer.transaction).toBeInstanceOf(Function)
89
+ expect(trans).toBeInstanceOf(Function)
90
+ expect(trans['transaction']).toBe(mockTrans)
91
+ })
92
+
93
+ test('KyselyDatabase - read replica', async () => {
94
+ const underTest = new KyselyDatabase(config2)
95
+ expect(mockPgClient).toHaveBeenNthCalledWith(2, expectedImplConfig)
96
+ expect(mockDialect).toHaveBeenCalledTimes(2)
97
+ expect(mockClient).toHaveBeenNthCalledWith(1, { dialect: underTest.pgClient })
98
+ expect(mockClient).toHaveBeenNthCalledWith(2, { dialect: underTest.pgReadClient })
99
+
100
+ const trans = await underTest.transaction()
101
+
102
+ expect(mockTrans.execute).toHaveBeenCalledTimes(1)
103
+ expect(trans.writer).toBeInstanceOf(Object)
104
+ expect(trans.writer.transaction).toBeInstanceOf(Function)
105
+ expect(trans.reader).toBeInstanceOf(Object)
106
+ expect(trans).toBeInstanceOf(Function)
107
+ expect(trans['transaction']).toBe(mockTrans)
108
+ })
109
+ })
@@ -0,0 +1,118 @@
1
+ import { Kysely, PostgresDialect, Transaction } from 'kysely'
2
+
3
+ import type { DbConfig } from '../../../../src/Database'
4
+ import { KyselyDatabase } from '../../../../src/Database/integrations/kysely/KyselyDatabase'
5
+ import { KyselyTransactionImpl } from '../../../../src/Database/integrations/kysely/KyselyTransaction'
6
+
7
+ const testResources = async (config: Partial<DbConfig<'kysely'>>) => {
8
+ type DB = {
9
+ view: {
10
+ id: number
11
+ }
12
+ secondView: {
13
+ title: string
14
+ }
15
+ }
16
+
17
+ const database = {
18
+ config: {
19
+ autoCommit: true,
20
+ ...config,
21
+ } as DbConfig<'kysely'>,
22
+ } as KyselyDatabase<DB>
23
+
24
+ const transaction = jest.fn().mockImplementation(() => {
25
+ return {
26
+ execute: jest.fn(async cb => {
27
+ try {
28
+ await cb(transaction)
29
+ } catch (e) {
30
+ /* empty */
31
+ }
32
+ }),
33
+ executeQuery: jest.fn(),
34
+ }
35
+ })() as any as Transaction<DB>
36
+
37
+ const writer = jest.fn().mockImplementation(() => {
38
+ return {
39
+ transaction: jest.fn(() => transaction),
40
+ }
41
+ })() as any as Kysely<DB>
42
+
43
+ return {
44
+ transaction,
45
+ writer,
46
+ underTest: await KyselyTransactionImpl.newTransaction(writer, database),
47
+ }
48
+ }
49
+
50
+ describe('KyselyTransaction', () => {
51
+ test('Transaction starts opened', async () => {
52
+ const { transaction, underTest } = await testResources({})
53
+ expect(underTest.isOpen()).toBe(true)
54
+ expect(transaction['execute']).toHaveBeenCalledTimes(1)
55
+
56
+ await expect(underTest.begin).rejects.toThrowError(
57
+ 'Cannot begin, transaction is already opened!'
58
+ )
59
+ })
60
+
61
+ test('Can only commit once', async () => {
62
+ const { underTest } = await testResources({})
63
+ await underTest.commit()
64
+ expect(underTest.isOpen()).toBe(false)
65
+
66
+ await expect(underTest.commit).rejects.toThrowError(
67
+ 'Cannot commit, transaction is already closed!'
68
+ )
69
+ })
70
+
71
+ test('Can only rollback once', async () => {
72
+ const { underTest } = await testResources({})
73
+ await underTest.rollback()
74
+ expect(underTest.isOpen()).toBe(false)
75
+ await expect(underTest.rollback).rejects.toThrowError(
76
+ 'Cannot rollback, transaction is already closed!'
77
+ )
78
+ })
79
+
80
+ test("Can't open transaction twice", async () => {
81
+ const { underTest } = await testResources({})
82
+ expect(underTest.isOpen()).toBe(true)
83
+
84
+ await expect(underTest.begin).rejects.toThrowError(
85
+ 'Cannot begin, transaction is already opened!'
86
+ )
87
+ })
88
+
89
+ test('Can commit, begin and commit again ', async () => {
90
+ const { underTest } = await testResources({})
91
+ await underTest.commit()
92
+ expect(underTest.isOpen()).toBe(false)
93
+ await underTest.begin()
94
+ expect(underTest.isOpen()).toBe(true)
95
+ await underTest.commit()
96
+ expect(underTest.isOpen()).toBe(false)
97
+ })
98
+
99
+ test('Can commit, begin and rollback ', async () => {
100
+ const { underTest } = await testResources({})
101
+ await underTest.commit()
102
+ expect(underTest.isOpen()).toBe(false)
103
+ await underTest.begin()
104
+ expect(underTest.isOpen()).toBe(true)
105
+ await underTest.rollback()
106
+ expect(underTest.isOpen()).toBe(false)
107
+ })
108
+
109
+ test('Can rollback, begin and commit ', async () => {
110
+ const { underTest } = await testResources({})
111
+ await underTest.rollback()
112
+ expect(underTest.isOpen()).toBe(false)
113
+ await underTest.begin()
114
+ expect(underTest.isOpen()).toBe(true)
115
+ await underTest.commit()
116
+ expect(underTest.isOpen()).toBe(false)
117
+ })
118
+ })