@creator.co/wapi 1.7.1-alpha4 → 1.7.2-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 (151) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.cjs +62 -0
  3. package/.github/workflows/npmpublish.yml +11 -0
  4. package/.github/workflows/prs.yml +13 -0
  5. package/dist/index.d.ts +14 -14
  6. package/dist/index.js +14 -14
  7. package/dist/index.js.map +1 -1
  8. package/dist/package-lock.json +2676 -454
  9. package/dist/package.json +2 -1
  10. package/dist/src/API/Request.d.ts +1 -1
  11. package/dist/src/API/Request.js +1 -1
  12. package/dist/src/API/Request.js.map +1 -1
  13. package/dist/src/API/Response.d.ts +1 -1
  14. package/dist/src/API/Response.js +1 -1
  15. package/dist/src/API/Response.js.map +1 -1
  16. package/dist/src/BaseEvent/EventProcessor.d.ts +2 -2
  17. package/dist/src/BaseEvent/EventProcessor.js +3 -3
  18. package/dist/src/BaseEvent/EventProcessor.js.map +1 -1
  19. package/dist/src/BaseEvent/Process.d.ts +3 -3
  20. package/dist/src/BaseEvent/Process.js +2 -2
  21. package/dist/src/BaseEvent/Process.js.map +1 -1
  22. package/dist/src/BaseEvent/Transaction.d.ts +5 -5
  23. package/dist/src/BaseEvent/Transaction.js +6 -6
  24. package/dist/src/BaseEvent/Transaction.js.map +1 -1
  25. package/dist/src/Cache/Redis.d.ts +1 -1
  26. package/dist/src/Cache/Redis.js +1 -1
  27. package/dist/src/Cache/Redis.js.map +1 -1
  28. package/dist/src/Cache/types.d.ts +1 -1
  29. package/dist/src/Config/Configuration.js +1 -1
  30. package/dist/src/Config/Configuration.js.map +1 -1
  31. package/dist/src/Database/Database.d.ts +2 -2
  32. package/dist/src/Database/DatabaseManager.d.ts +4 -4
  33. package/dist/src/Database/DatabaseManager.js +3 -3
  34. package/dist/src/Database/DatabaseManager.js.map +1 -1
  35. package/dist/src/Database/DatabaseTransaction.d.ts +1 -1
  36. package/dist/src/Database/index.d.ts +10 -10
  37. package/dist/src/Database/index.js +6 -6
  38. package/dist/src/Database/index.js.map +1 -1
  39. package/dist/src/Database/integrations/knex/KnexDatabase.d.ts +3 -3
  40. package/dist/src/Database/integrations/knex/KnexDatabase.js +2 -2
  41. package/dist/src/Database/integrations/knex/KnexDatabase.js.map +1 -1
  42. package/dist/src/Database/integrations/knex/KnexTransaction.d.ts +3 -3
  43. package/dist/src/Database/integrations/knex/KnexTransaction.js +1 -1
  44. package/dist/src/Database/integrations/knex/KnexTransaction.js.map +1 -1
  45. package/dist/src/Database/integrations/kysely/KyselyDatabase.d.ts +3 -3
  46. package/dist/src/Database/integrations/kysely/KyselyDatabase.js +2 -2
  47. package/dist/src/Database/integrations/kysely/KyselyDatabase.js.map +1 -1
  48. package/dist/src/Database/integrations/kysely/KyselyTransaction.d.ts +3 -3
  49. package/dist/src/Database/integrations/kysely/KyselyTransaction.js +1 -1
  50. package/dist/src/Database/integrations/kysely/KyselyTransaction.js.map +1 -1
  51. package/dist/src/Database/integrations/pgsql/PostgresDatabase.d.ts +3 -3
  52. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js +2 -2
  53. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js.map +1 -1
  54. package/dist/src/Database/integrations/pgsql/PostgresTransaction.d.ts +3 -3
  55. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js +1 -1
  56. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js.map +1 -1
  57. package/dist/src/Database/types.d.ts +5 -5
  58. package/dist/src/Globals.js +1 -1
  59. package/dist/src/Globals.js.map +1 -1
  60. package/dist/src/Logger/Logger.js +1 -1
  61. package/dist/src/Logger/Logger.js.map +1 -1
  62. package/dist/src/Server/RouteResolver.d.ts +2 -2
  63. package/dist/src/Server/Router.d.ts +3 -3
  64. package/dist/src/Server/Router.js +3 -3
  65. package/dist/src/Server/Router.js.map +1 -1
  66. package/dist/src/Server/lib/ContainerServer.d.ts +3 -3
  67. package/dist/src/Server/lib/ContainerServer.js +2 -2
  68. package/dist/src/Server/lib/ContainerServer.js.map +1 -1
  69. package/dist/src/Server/lib/Server.d.ts +2 -2
  70. package/dist/src/Server/lib/Server.js +4 -4
  71. package/dist/src/Server/lib/Server.js.map +1 -1
  72. package/dist/src/Server/lib/container/GenericHandler.d.ts +1 -1
  73. package/dist/src/Server/lib/container/GenericHandler.js +3 -3
  74. package/dist/src/Server/lib/container/GenericHandler.js.map +1 -1
  75. package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +1 -1
  76. package/dist/src/Server/lib/container/GenericHandlerEvent.js +2 -2
  77. package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -1
  78. package/dist/src/Server/lib/container/Proxy.d.ts +2 -2
  79. package/dist/src/Server/lib/container/Proxy.js +4 -4
  80. package/dist/src/Server/lib/container/Proxy.js.map +1 -1
  81. package/dist/src/Validation/Validator.d.ts +1 -1
  82. package/dist/src/Validation/Validator.js +2 -2
  83. package/dist/src/Validation/Validator.js.map +1 -1
  84. package/index.ts +14 -14
  85. package/jest.config.ts +37 -0
  86. package/jest.smoke.config.ts +34 -0
  87. package/package.json +2 -1
  88. package/src/API/Request.ts +2 -2
  89. package/src/API/Response.ts +2 -2
  90. package/src/BaseEvent/EventProcessor.ts +3 -3
  91. package/src/BaseEvent/Process.ts +3 -3
  92. package/src/BaseEvent/Transaction.ts +8 -8
  93. package/src/Cache/Redis.ts +2 -2
  94. package/src/Cache/types.ts +1 -1
  95. package/src/Config/Configuration.ts +1 -1
  96. package/src/Database/Database.ts +2 -2
  97. package/src/Database/DatabaseManager.ts +4 -4
  98. package/src/Database/DatabaseTransaction.ts +1 -1
  99. package/src/Database/index.ts +10 -10
  100. package/src/Database/integrations/knex/KnexDatabase.ts +3 -3
  101. package/src/Database/integrations/knex/KnexTransaction.ts +3 -3
  102. package/src/Database/integrations/kysely/KyselyDatabase.ts +3 -3
  103. package/src/Database/integrations/kysely/KyselyTransaction.ts +3 -3
  104. package/src/Database/integrations/pgsql/PostgresDatabase.ts +3 -3
  105. package/src/Database/integrations/pgsql/PostgresTransaction.ts +3 -3
  106. package/src/Database/types.ts +5 -5
  107. package/src/Globals.ts +1 -1
  108. package/src/Logger/Logger.ts +1 -1
  109. package/src/Server/RouteResolver.ts +2 -2
  110. package/src/Server/Router.ts +6 -6
  111. package/src/Server/lib/ContainerServer.ts +3 -3
  112. package/src/Server/lib/Server.ts +6 -6
  113. package/src/Server/lib/container/GenericHandler.ts +4 -4
  114. package/src/Server/lib/container/GenericHandlerEvent.ts +3 -3
  115. package/src/Server/lib/container/Proxy.ts +6 -6
  116. package/src/Validation/Validator.ts +2 -2
  117. package/tests/API/Request.test.ts +273 -0
  118. package/tests/API/Response.test.ts +367 -0
  119. package/tests/API/Utils.test.ts +167 -0
  120. package/tests/BaseEvent/EventProcessor.test.ts +261 -0
  121. package/tests/BaseEvent/Process.test.ts +49 -0
  122. package/tests/BaseEvent/Transaction.test.ts +408 -0
  123. package/tests/Cache/Redis-client.test.ts +90 -0
  124. package/tests/Cache/Redis-cluster.test.ts +100 -0
  125. package/tests/Config/Config.test.ts +205 -0
  126. package/tests/Config/EnvironmentVar.test.ts +250 -0
  127. package/tests/Crypto/Crypto.test.ts +88 -0
  128. package/tests/Crypto/JWT.test.ts +92 -0
  129. package/tests/Database/DatabaseManager.test.ts +71 -0
  130. package/tests/Database/integrations/knex/KnexDatabase.test.ts +76 -0
  131. package/tests/Database/integrations/knex/KnexTransaction.test.ts +149 -0
  132. package/tests/Database/integrations/kysely/KyselyDatabase.test.ts +113 -0
  133. package/tests/Database/integrations/kysely/KyselyTransaction.test.ts +119 -0
  134. package/tests/Database/integrations/pg/PostgresDatabase.test.ts +76 -0
  135. package/tests/Database/integrations/pg/PostgresTransaction.test.ts +118 -0
  136. package/tests/Logger/Logger.test.ts +219 -0
  137. package/tests/Mailer/Mailer.test.ts +59 -0
  138. package/tests/Publisher/Publisher.test.ts +94 -0
  139. package/tests/Server/RouteResolver.test.ts +102 -0
  140. package/tests/Server/Router.test.ts +39 -0
  141. package/tests/Server/lib/ContainerServer.test.ts +531 -0
  142. package/tests/Server/lib/Server.test.ts +12 -0
  143. package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
  144. package/tests/Server/lib/container/GenericHandlerEvent.test.ts +103 -0
  145. package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
  146. package/tests/Server/lib/container/Proxy.test.ts +268 -0
  147. package/tests/Server/lib/container/Utils.test.ts +47 -0
  148. package/tests/Test.utils.ts +74 -0
  149. package/tests/Validation/Validator.test.ts +76 -0
  150. package/tsconfig.json +26 -0
  151. package/tsconfig.smoke.json +26 -0
@@ -0,0 +1,88 @@
1
+ import { DecryptCommand, EncryptCommand, KMSClient } from '@aws-sdk/client-kms'
2
+ import { mockClient } from 'aws-sdk-client-mock'
3
+ import { expect } from 'chai'
4
+
5
+ import Crypto from '../../src/Crypto/Crypto.js'
6
+
7
+ const KMSMock = mockClient(KMSClient)
8
+
9
+ function fakeEncryption(v) {
10
+ const f = new TextEncoder().encode(v)
11
+ return Buffer.from(f as any, 'utf8').toString('hex')
12
+ }
13
+ function fakeDecryption(v) {
14
+ return new TextEncoder().encode(v)
15
+ }
16
+
17
+ describe('Encryption', () => {
18
+ // reset mock
19
+ beforeEach(() => {
20
+ KMSMock.reset()
21
+ })
22
+
23
+ const provider = new Crypto('ca-central-1', 'abc123')
24
+ test('Encrypts json object', async () => {
25
+ const encryptionObj = { userID: 123 }
26
+ KMSMock.on(EncryptCommand).resolves({
27
+ CiphertextBlob: new TextEncoder().encode(JSON.stringify(encryptionObj)),
28
+ })
29
+ const token = await provider.encryptData(encryptionObj)
30
+ expect(token).is.not.null
31
+ expect(token).to.be.equals(fakeEncryption(JSON.stringify(encryptionObj)))
32
+ })
33
+
34
+ test('Encrypts string', async () => {
35
+ const encryptionText = 'Hello encryption!'
36
+ KMSMock.on(EncryptCommand).resolves({
37
+ CiphertextBlob: new TextEncoder().encode(encryptionText),
38
+ })
39
+ const token = await provider.encryptData(encryptionText)
40
+ expect(token).is.not.null
41
+ expect(token).to.be.equals(fakeEncryption(encryptionText))
42
+ })
43
+
44
+ test('Fails to encrypt a number', async () => {
45
+ const encryptionText = 123
46
+ KMSMock.on(EncryptCommand).rejects(new Error('failed'))
47
+ const token = await provider.encryptData(encryptionText)
48
+ expect(token).is.null
49
+ })
50
+ })
51
+
52
+ describe('Decryption', () => {
53
+ // reset mock
54
+ beforeEach(() => {
55
+ KMSMock.reset()
56
+ })
57
+
58
+ const provider = new Crypto('ca-central-1', 'abc123')
59
+ test('Decrypts json object', async () => {
60
+ const encryptionObj = { userID: 123 }
61
+ KMSMock.on(DecryptCommand).resolves({
62
+ Plaintext: fakeDecryption(JSON.stringify(encryptionObj)),
63
+ })
64
+ const token = await provider.decryptData(fakeEncryption(JSON.stringify(encryptionObj)))
65
+ expect(token).is.not.null
66
+ expect(token).to.be.equals(JSON.stringify(encryptionObj))
67
+ })
68
+
69
+ test('Decrypts string', async () => {
70
+ const encryptionText = 'abc123'
71
+ KMSMock.on(DecryptCommand).resolves({
72
+ Plaintext: fakeDecryption(encryptionText),
73
+ })
74
+ const token = await provider.decryptData(fakeEncryption(encryptionText))
75
+ expect(token).is.not.null
76
+ expect(token).to.be.equals(encryptionText)
77
+ })
78
+
79
+ test('Fails to decrypt a number', async () => {
80
+ const encryptionText = 123
81
+ KMSMock.on(DecryptCommand).rejects(new Error('failed'))
82
+ // @ts-ignore
83
+ const token = await provider.decryptData(encryptionText)
84
+ expect(token).is.null
85
+ })
86
+ })
87
+
88
+ export {}
@@ -0,0 +1,92 @@
1
+ import { expect } from 'chai'
2
+
3
+ import JWT from '../../src/Crypto/JWT.js'
4
+ import { foreignToken, privateKey } from '../Test.utils.js'
5
+
6
+ describe('Creates token', () => {
7
+ const provider = new JWT(privateKey, '7d')
8
+ test('Creates token without explicity expiration', () => {
9
+ const token = provider.createToken({ userID: 123 })
10
+ expect(token).to.be.a('string')
11
+ expect(token).is.not.null
12
+ })
13
+
14
+ test('Creates token with explicity expiration', () => {
15
+ const token = provider.createToken({ userID: 123 }, '7d')
16
+ expect(token).to.be.a('string')
17
+ expect(token).is.not.null
18
+ })
19
+
20
+ test('Creates token with explicity token override', () => {
21
+ const token = provider.createToken({ userID: 123 }, '7d', privateKey)
22
+ expect(token).to.be.a('string')
23
+ expect(token).is.not.null
24
+ })
25
+
26
+ test('Creates token with explicity token options', () => {
27
+ const token = provider.createToken({ userID: 123 }, undefined, undefined, {
28
+ expiresIn: '7d',
29
+ })
30
+ expect(token).to.be.a('string')
31
+ expect(token).is.not.null
32
+ })
33
+
34
+ test('Creates token with no expiration', () => {
35
+ const localProvider = new JWT(privateKey)
36
+ const token = localProvider.createToken({ userID: 123 })
37
+ expect(token).to.be.a('string')
38
+ expect(token).is.not.null
39
+ })
40
+ })
41
+
42
+ describe('Validates token', () => {
43
+ const provider = new JWT(privateKey, '7d')
44
+ test('Succeed to validate just created token', () => {
45
+ // Creates token
46
+ const token = provider.createToken({ userID: 123 }, '7d', privateKey)
47
+ expect(token).to.be.a('string')
48
+ expect(token).is.not.null
49
+ // Validates token
50
+ const validationResp = provider.validateToken(token)
51
+ expect(validationResp).is.not.null
52
+ expect(validationResp.isValid).is.true
53
+ expect(validationResp['isExpired']).is.undefined
54
+ expect(validationResp['decodedToken']).is.not.null
55
+ expect(validationResp['decodedToken'].userID).to.be.equals(123)
56
+ expect(validationResp['decodedToken'].exp).to.be.a('number')
57
+ expect(validationResp['decodedToken'].exp).to.be.above(Date.now() / 1000)
58
+ })
59
+
60
+ test('Fails to validate invalid token', () => {
61
+ // Creates token
62
+ const token = provider.createToken({ userID: 123 }, '7d', privateKey)
63
+ // Validates token
64
+ const validationResp = provider.validateToken(token + '123')
65
+ expect(validationResp).is.not.null
66
+ expect(validationResp.isValid).is.false
67
+ expect(validationResp['isExpired']).is.undefined
68
+ expect(validationResp['decodedToken']).to.undefined
69
+ })
70
+
71
+ test('Fails to validate expired token', () => {
72
+ // Creates token
73
+ const token = provider.createToken({ userID: 123 }, '-7d', privateKey)
74
+ // Validates token
75
+ const validationResp = provider.validateToken(token)
76
+ expect(validationResp).is.not.null
77
+ expect(validationResp.isValid).is.false
78
+ expect(validationResp['isExpired']).is.true
79
+ expect(validationResp['decodedToken']).to.undefined
80
+ })
81
+
82
+ test('Fails to validate foreign token', () => {
83
+ // Validates token
84
+ const validationResp = provider.validateToken(foreignToken)
85
+ expect(validationResp).is.not.null
86
+ expect(validationResp.isValid).is.false
87
+ expect(validationResp['isExpired']).is.undefined
88
+ expect(validationResp['decodedToken']).to.undefined
89
+ })
90
+ })
91
+
92
+ export {}
@@ -0,0 +1,71 @@
1
+ import { jest } from '@jest/globals'
2
+ import { expect } from 'chai'
3
+
4
+ import { DatabaseManager } from '../../src/Database/index.js'
5
+ import type { DatabaseType, DbConfig } from '../../src/Database/types.js'
6
+
7
+ type FakeDatabase = { host: string; type: 'knex' | 'pg' | 'kysely' }
8
+
9
+ const fakeConfig = (host: string, type: DatabaseType) => {
10
+ return {
11
+ type,
12
+ host,
13
+ } as DbConfig<typeof type>
14
+ }
15
+
16
+ describe('Database Manager', () => {
17
+ test('should correctly create and cache database instances', () => {
18
+ const underTest = new DatabaseManager()
19
+
20
+ underTest['databases'] = {
21
+ knex: jest.fn((config: any) => {
22
+ return { host: config.host, type: 'knex' } as any
23
+ }) as any,
24
+ pg: jest.fn((config: any) => {
25
+ return { host: config.host, type: 'pg' } as any
26
+ }) as any,
27
+ kysely: jest.fn((config: any) => {
28
+ return { host: config.host, type: 'kysely' } as any
29
+ }) as any,
30
+ }
31
+
32
+ const create = config => underTest.create({ ...config }) as unknown as FakeDatabase
33
+
34
+ const knexConfig1 = fakeConfig('localhost', 'knex')
35
+ const knexConfig2 = fakeConfig('other', 'knex')
36
+ const pgConfig1 = fakeConfig('localhost', 'pg')
37
+ const pgConfig2 = fakeConfig('other', 'pg')
38
+ const kyselyConfig1 = fakeConfig('localhost', 'pg')
39
+ const kyselyConfig2 = fakeConfig('other', 'pg')
40
+
41
+ const knex1 = create(knexConfig1)
42
+ const knex2 = create(knexConfig1)
43
+ const knex3 = create(knexConfig2)
44
+
45
+ const pg1 = create(pgConfig1)
46
+ const pg2 = create(pgConfig1)
47
+ const pg3 = create(pgConfig2)
48
+
49
+ const kysely1 = create(kyselyConfig1)
50
+ const kysely2 = create(kyselyConfig1)
51
+ const kysely3 = create(kyselyConfig2)
52
+
53
+ expect(knex1).to.equal(knex2).to.not.equal(knex3).to.not.equal(pg1)
54
+
55
+ expect(knexConfig1).to.be.deep.equal(knex1).to.be.deep.equal(knex2)
56
+
57
+ expect(knex3).to.be.deep.equal(knexConfig2)
58
+
59
+ expect(pg1).to.equal(pg2).to.not.equal(pg3)
60
+
61
+ expect(pgConfig1).to.be.deep.equal(pg1).to.be.deep.equal(pg2)
62
+
63
+ expect(pg3).to.be.deep.equal(pgConfig2)
64
+
65
+ expect(kysely1).to.equal(kysely2).to.not.equal(kysely3)
66
+
67
+ expect(kyselyConfig1).to.be.deep.equal(kysely1).to.be.deep.equal(kysely2)
68
+
69
+ expect(kysely3).to.be.deep.equal(kyselyConfig2)
70
+ })
71
+ })
@@ -0,0 +1,76 @@
1
+ import { jest } from '@jest/globals'
2
+ import { Knex } from 'knex'
3
+
4
+ import type { DbConfig } from '../../../../src/Database/index.js'
5
+ import { KnexDatabase } from '../../../../src/Database/integrations/knex/KnexDatabase.js'
6
+
7
+ const config: DbConfig<'knex'> = {
8
+ type: 'knex',
9
+ username: 'username',
10
+ password: 'password',
11
+ host: 'host',
12
+ port: 1234,
13
+ database: 'database',
14
+ driver: 'driver',
15
+ maxConnections: 1,
16
+ autoCommit: true,
17
+ }
18
+
19
+ const expectedImplConfig = {
20
+ client: config.driver,
21
+ connection: {
22
+ host: config.host,
23
+ port: config.port,
24
+ user: config.username,
25
+ password: config.password,
26
+ database: config.database,
27
+ },
28
+ pool: {
29
+ min: 1,
30
+ max: config.maxConnections,
31
+ },
32
+ }
33
+
34
+ describe('KnexDatabase', () => {
35
+ test('KnexDatabase', async () => {
36
+ const mockTrans = { a: 'b' } as any
37
+ const mockClient = jest.fn(
38
+ () =>
39
+ ({
40
+ transaction: async () => mockTrans,
41
+ }) as Knex
42
+ )
43
+ KnexDatabase['knexProvider'] = mockClient
44
+
45
+ const underTest = new KnexDatabase(config)
46
+ expect(mockClient).toBeCalledWith(expectedImplConfig)
47
+
48
+ const trans = await underTest.transaction()
49
+
50
+ expect(trans).toBeInstanceOf(Function)
51
+ expect(trans.transaction).toBe(mockTrans)
52
+ })
53
+
54
+ test('KnexDatabase - convert camel to snake', async () => {
55
+ const mockTrans = { a: 'b' } as any
56
+ const mockClient = jest.fn(
57
+ () =>
58
+ ({
59
+ transaction: async () => mockTrans,
60
+ }) as Knex
61
+ )
62
+ KnexDatabase['knexProvider'] = mockClient
63
+
64
+ const underTest = new KnexDatabase({ ...config, convertCamelToSnake: true })
65
+ expect(mockClient).toBeCalledWith({
66
+ ...expectedImplConfig,
67
+ postProcessResponse: expect.any(Function),
68
+ wrapIdentifier: expect.any(Function),
69
+ })
70
+
71
+ const trans = await underTest.transaction()
72
+
73
+ expect(trans).toBeInstanceOf(Function)
74
+ expect(trans.transaction).toBe(mockTrans)
75
+ })
76
+ })
@@ -0,0 +1,149 @@
1
+ import { jest } from '@jest/globals'
2
+ import { Knex } from 'knex'
3
+
4
+ import { DbConfig } from '../../../../src/Database/index.js'
5
+ import { KnexDatabase } from '../../../../src/Database/integrations/knex/KnexDatabase.js'
6
+ import { KnexTransactionImpl } from '../../../../src/Database/integrations/knex/KnexTransaction.js'
7
+
8
+ const testResources = async (config: Partial<DbConfig<'knex'>>) => {
9
+ const database = {
10
+ config: {
11
+ autoCommit: true,
12
+ ...config,
13
+ } as DbConfig<'knex'>,
14
+ } as KnexDatabase
15
+
16
+ const txMock = jest.fn() as any
17
+ txMock.commit = jest.fn()
18
+ txMock.rollback = jest.fn()
19
+ txMock.select = jest.fn()
20
+
21
+ const wMock = jest.fn() as any
22
+ wMock.transaction = jest.fn(() => txMock)
23
+
24
+ const writer = wMock as Knex
25
+ const transaction = txMock as Knex.Transaction
26
+
27
+ return {
28
+ transaction,
29
+ writer,
30
+ underTest: await KnexTransactionImpl.newTransaction(writer, database),
31
+ }
32
+ }
33
+
34
+ describe('KnexTransaction', () => {
35
+ test('Can only commit once', async () => {
36
+ const { writer, transaction, underTest } = await testResources({})
37
+ await underTest.commit()
38
+ expect(underTest.isOpen()).toBe(false)
39
+ expect(writer.transaction).toBeCalled()
40
+ expect(transaction.commit).toBeCalled()
41
+
42
+ await expect(underTest.commit).rejects.toThrowError(
43
+ 'Cannot commit, transaction is already closed!'
44
+ )
45
+ })
46
+
47
+ test("Can't commit after rollback", async () => {
48
+ const { writer, transaction, underTest } = await testResources({})
49
+ await underTest.rollback()
50
+ expect(underTest.isOpen()).toBe(false)
51
+ expect(writer.transaction).toBeCalled()
52
+ expect(transaction.rollback).toBeCalled()
53
+
54
+ await expect(underTest.commit).rejects.toThrowError(
55
+ 'Cannot commit, transaction is already closed!'
56
+ )
57
+ })
58
+
59
+ test('Forwards calls to transaction', async () => {
60
+ const { transaction, underTest } = await testResources({})
61
+ await underTest.select('name')
62
+ expect(transaction.select).toBeCalledWith('name')
63
+ })
64
+
65
+ test('Blocks transaction calls after commit', async () => {
66
+ const { transaction, underTest } = await testResources({})
67
+ expect(underTest.select).toBeDefined()
68
+
69
+ await underTest.commit()
70
+ expect(transaction.commit).toBeCalled()
71
+ expect(underTest.isOpen()).toBe(false)
72
+
73
+ expect(underTest.select).toBeUndefined()
74
+ })
75
+ })
76
+
77
+ describe('KnexTransaction - closeSuccess', () => {
78
+ test('Close success commits', async () => {
79
+ const { transaction, underTest } = await testResources({})
80
+ await underTest.closeSuccess()
81
+ expect(transaction.commit).toBeCalled()
82
+ })
83
+
84
+ test("Close success, doesn't commit again if already committed", async () => {
85
+ const { transaction, underTest } = await testResources({})
86
+ await underTest.commit()
87
+ expect(transaction.commit).toBeCalledTimes(1)
88
+ await underTest.closeSuccess()
89
+ expect(transaction.commit).toBeCalledTimes(1)
90
+ })
91
+
92
+ test('Close success, rolls back if not autocommit', async () => {
93
+ const { transaction, underTest } = await testResources({ autoCommit: false })
94
+ await underTest.closeSuccess()
95
+ expect(transaction.rollback).toBeCalled()
96
+ })
97
+
98
+ test("Close success, doesn't rollback if already committed", async () => {
99
+ const { transaction, underTest } = await testResources({ autoCommit: false })
100
+ await underTest.commit()
101
+ expect(transaction.commit).toBeCalledTimes(1)
102
+ await underTest.closeSuccess()
103
+ expect(transaction.rollback).not.toBeCalled()
104
+ expect(transaction.commit).toBeCalledTimes(1)
105
+ })
106
+
107
+ test("Close success, doesn't rollback if already rolled back", async () => {
108
+ const { transaction, underTest } = await testResources({ autoCommit: false })
109
+ await underTest.rollback()
110
+ expect(transaction.rollback).toBeCalledTimes(1)
111
+ await underTest.closeSuccess()
112
+ expect(transaction.rollback).toBeCalledTimes(1)
113
+ expect(transaction.commit).not.toBeCalled()
114
+ })
115
+ })
116
+
117
+ describe('KnexTransaction - closeFailure', () => {
118
+ test('Close failure rolls back', async () => {
119
+ const { transaction, underTest } = await testResources({})
120
+ await underTest.closeFailure()
121
+ expect(transaction.rollback).toBeCalled()
122
+ })
123
+
124
+ test("Close failure, doesn't rollback again if already rolled back", async () => {
125
+ const { transaction, underTest } = await testResources({})
126
+ await underTest.rollback()
127
+ expect(transaction.rollback).toBeCalledTimes(1)
128
+ await underTest.closeFailure()
129
+ expect(transaction.rollback).toBeCalledTimes(1)
130
+ })
131
+
132
+ test("Close failure, doesn't rollback if already committed", async () => {
133
+ const { transaction, underTest } = await testResources({ autoCommit: false })
134
+ await underTest.commit()
135
+ expect(transaction.commit).toBeCalledTimes(1)
136
+ await underTest.closeFailure()
137
+ expect(transaction.rollback).not.toBeCalled()
138
+ expect(transaction.commit).toBeCalledTimes(1)
139
+ })
140
+ })
141
+
142
+ describe('KnexTransaction - call direct', () => {
143
+ test('Calls transaction', async () => {
144
+ const { transaction, underTest } = await testResources({ autoCommit: false })
145
+
146
+ underTest('test')
147
+ expect(transaction).toBeCalledWith('test')
148
+ })
149
+ })
@@ -0,0 +1,113 @@
1
+ import { jest } from '@jest/globals'
2
+ import { PostgresDialect } from 'kysely'
3
+ import * as pg from 'pg'
4
+
5
+ import type { DbConfig } from '../../../../src/Database/index.js'
6
+ import { KyselyDatabase } from '../../../../src/Database/integrations/kysely/KyselyDatabase.js'
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: any) => {
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 pg.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).toHaveBeenCalledTimes(1)
82
+ expect(mockClient.mock.calls[0][0].dialect).toEqual(underTest['pgClient'])
83
+ expect(mockClient.mock.calls[0][0].plugins).toBeInstanceOf(Array)
84
+ const trans = await underTest.transaction()
85
+
86
+ expect(mockTrans.execute).toHaveBeenCalledTimes(1)
87
+ expect(trans.reader).toBeUndefined()
88
+ expect(trans.writer).toBeInstanceOf(Object)
89
+ expect(trans.writer.transaction).toBeInstanceOf(Function)
90
+ expect(trans).toBeInstanceOf(Function)
91
+ expect(trans['transaction']).toBe(mockTrans)
92
+ })
93
+
94
+ test('KyselyDatabase - read replica', async () => {
95
+ const underTest = new KyselyDatabase(config2)
96
+ expect(mockPgClient).toHaveBeenNthCalledWith(2, expectedImplConfig)
97
+ expect(mockDialect).toHaveBeenCalledTimes(2)
98
+ expect(mockClient).toHaveBeenCalledTimes(2)
99
+ expect(mockClient.mock.calls[0][0].dialect).toEqual(underTest['pgClient'])
100
+ expect(mockClient.mock.calls[0][0].plugins).toBeInstanceOf(Array)
101
+ expect(mockClient.mock.calls[1][0].dialect).toEqual(underTest['pgReadClient'])
102
+ expect(mockClient.mock.calls[1][0].plugins).toBeInstanceOf(Array)
103
+
104
+ const trans = await underTest.transaction()
105
+
106
+ expect(mockTrans.execute).toHaveBeenCalledTimes(1)
107
+ expect(trans.writer).toBeInstanceOf(Object)
108
+ expect(trans.writer.transaction).toBeInstanceOf(Function)
109
+ expect(trans.reader).toBeInstanceOf(Object)
110
+ expect(trans).toBeInstanceOf(Function)
111
+ expect(trans['transaction']).toBe(mockTrans)
112
+ })
113
+ })