@axinom/mosaic-db-common 0.55.0-rc.13 → 0.55.0-rc.16

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.
@@ -28,7 +28,7 @@ export declare const runCurrentSql: (settings: Settings, logger: DbLogger) => Pr
28
28
  ]
29
29
  ```
30
30
  */
31
- export declare const getBeforeMigrationScripts: () => Promise<string[]>;
31
+ export declare const getBeforeMigrationScripts: (migrationsFolder?: string) => Promise<string[]>;
32
32
  /**
33
33
  * Retrieve a relative path to watch-fixtures.sql of `graphile-build-pg` package. The path is relative to the 'migrations' folder of a specific project.
34
34
  * Should only be used in development mode. Useful when there is a need to explicitly install postgraphile watch fixtures, so that database owner user can be created without a superuser privilege.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/migrations/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAO,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,UAAU,QAAQ,EAClB,SAAS,MAAM,EACf,QAAQ,QAAQ,KACf,OAAO,CAAC,IAAI,CAYd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,UAAU,QAAQ,EAClB,QAAQ,QAAQ,KACf,OAAO,CAAC,IAAI,CAKd,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,QAAa,OAAO,CAAC,MAAM,EAAE,CAgBlE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mCAAmC,QAAO,MAyBtD,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/migrations/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAO,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,UAAU,QAAQ,EAClB,SAAS,MAAM,EACf,QAAQ,QAAQ,KACf,OAAO,CAAC,IAAI,CAYd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,UAAU,QAAQ,EAClB,QAAQ,QAAQ,KACf,OAAO,CAAC,IAAI,CAOd,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,GACpC,mBAAmB,MAAM,KACxB,OAAO,CAAC,MAAM,EAAE,CAgBlB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mCAAmC,QAAO,MAyBtD,CAAC"}
@@ -50,7 +50,9 @@ exports.runSqlScripts = runSqlScripts;
50
50
  * @param settings - graphile-migrate settings object
51
51
  */
52
52
  const runCurrentSql = async (settings, logger) => {
53
- const path = 'migrations/current.sql';
53
+ var _a;
54
+ const migrationsFolder = (_a = settings.migrationsFolder) !== null && _a !== void 0 ? _a : (0, path_1.join)(process.cwd(), 'migrations');
55
+ const path = (0, path_1.join)(migrationsFolder, 'current.sql');
54
56
  const content = await fs_1.promises.readFile(path, 'utf8');
55
57
  logger.debug(`Running Script: '${path}'`);
56
58
  await (0, graphile_migrate_1.run)(settings, content, path);
@@ -71,8 +73,8 @@ exports.runCurrentSql = runCurrentSql;
71
73
  ]
72
74
  ```
73
75
  */
74
- const getBeforeMigrationScripts = async () => {
75
- const executionPath = (0, path_1.join)(process.cwd(), 'migrations');
76
+ const getBeforeMigrationScripts = async (migrationsFolder) => {
77
+ const executionPath = migrationsFolder !== null && migrationsFolder !== void 0 ? migrationsFolder : (0, path_1.join)(process.cwd(), 'migrations');
76
78
  const dirPath = (0, path_1.resolve)(__dirname, '..', '..', 'migrations', 'before-migration');
77
79
  return (await (0, readdirp_1.readdirpPromise)(dirPath, {
78
80
  fileFilter: (entry) => entry.basename.endsWith('.sql'),
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/migrations/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/migrations/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-db-common",
3
- "version": "0.55.0-rc.13",
3
+ "version": "0.55.0-rc.16",
4
4
  "description": "This library encapsulates database-related functionality to develop Mosaic based services.",
5
5
  "author": "Axinom",
6
6
  "license": "PROPRIETARY",
@@ -22,12 +22,13 @@
22
22
  "ts:validate": "tsc",
23
23
  "build:ci": "yarn workspaces focus && yarn build",
24
24
  "dev": "tsc -w --project tsconfig.build.json",
25
- "test": "jest --silent",
26
- "test:watch": "jest --watch --silent",
27
- "test:cov": "jest --coverage --silent && yarn posttest:cov",
25
+ "test": "vitest run --silent",
26
+ "test:watch": "vitest watch",
27
+ "test:cov": "vitest run --coverage --silent && yarn posttest:cov",
28
28
  "posttest:cov": "ts-node ../../scripts/open-test-coverage.ts -- libs/db-common",
29
- "test:debug": "node --inspect -r ts-node/register ../../node_modules/jest/bin/jest.js --runInBand --silent",
30
- "test:ci": "jest --reporters=default --reporters=jest-junit --coverage --coverageReporters=cobertura --coverageReporters=html",
29
+ "test:debug": "vitest run --inspect-brk --no-file-parallelism",
30
+ "test:ci": "vitest run --reporter=default --reporter=junit --coverage --coverage.reporter=cobertura --coverage.reporter=html",
31
+ "test:ui": "vitest --ui",
31
32
  "lint": "eslint . --ext .ts,.tsx,.js --color --cache"
32
33
  },
33
34
  "dependencies": {
@@ -41,19 +42,20 @@
41
42
  "zapatos": "3.6.0"
42
43
  },
43
44
  "devDependencies": {
44
- "@axinom/mosaic-dev-be-common": "^0.15.1-rc.5",
45
+ "@axinom/mosaic-dev-be-common": "^0.16.0-rc.1",
45
46
  "@types/express": "^4.17.17",
46
47
  "@types/node": "^22.0.0",
47
48
  "@types/pg": "^8.6.1",
48
49
  "@types/yargs": "^16",
50
+ "@vitest/ui": "^4.0.18",
49
51
  "eslint": "^8.35.0",
50
- "jest": "^29",
51
52
  "rimraf": "^3.0.2",
52
53
  "ts-node": "^10.9.1",
53
- "typescript": "^5.9.3"
54
+ "typescript": "^5.9.3",
55
+ "vitest": "^4.0.18"
54
56
  },
55
57
  "publishConfig": {
56
58
  "access": "public"
57
59
  },
58
- "gitHead": "40779318c9b091b23a3aa559734727df3e903741"
60
+ "gitHead": "61cc0e626bb816beee81d16b31c46f1d2a13844d"
59
61
  }
@@ -1,3 +1,4 @@
1
+ import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
1
2
  import {
2
3
  PgAuthenticatedEndUser,
3
4
  PgAuthenticatedManagementSubject,
@@ -1,54 +1,79 @@
1
- import { compareMigrationHashes } from './compare-migration-hashes';
2
- import * as compareHelpers from './compare-migration-hashes-helpers';
3
- import { CompareMigrationHashesErrorCallback, MigrationRecord } from './types';
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
2
 
5
- let migrationsTableExistsCall = () => {
6
- return { rows: [{ migrationsTableExists: true }] };
7
- };
3
+ interface MockPgClient {
4
+ query: (queryString: string) => unknown;
5
+ release: () => void;
6
+ }
8
7
 
9
- let migrationsTableCall: () => {
10
- rows: unknown[];
11
- } = () => {
12
- return { rows: [] };
13
- };
8
+ interface MockPgState {
9
+ migrationsTableExistsCall: () => {
10
+ rows: { migrationsTableExists: boolean }[];
11
+ };
12
+ migrationsTableCall: () => { rows: unknown[] };
13
+ connectCallback: (() => Promise<MockPgClient>) | undefined;
14
+ }
14
15
 
15
- const defaultConnectCallback = async () => {
16
- return {
17
- query: (queryString: string) => {
18
- if (queryString.startsWith('SELECT EXISTS')) {
19
- return migrationsTableExistsCall();
20
- } else {
21
- return migrationsTableCall();
22
- }
16
+ const mockState = vi.hoisted(() => {
17
+ const state: MockPgState = {
18
+ migrationsTableExistsCall: () => {
19
+ return { rows: [{ migrationsTableExists: true }] };
23
20
  },
24
- release: () => {
25
- return;
21
+ migrationsTableCall: () => {
22
+ return { rows: [] };
26
23
  },
24
+ connectCallback: undefined,
25
+ };
26
+
27
+ const defaultConnectCallback = async () => {
28
+ return {
29
+ query: (queryString: string) => {
30
+ if (queryString.startsWith('SELECT EXISTS')) {
31
+ return state.migrationsTableExistsCall();
32
+ } else {
33
+ return state.migrationsTableCall();
34
+ }
35
+ },
36
+ release: () => {
37
+ return;
38
+ },
39
+ };
27
40
  };
28
- };
29
- let connectCallback = defaultConnectCallback;
30
41
 
31
- jest.mock('pg', () => {
32
- const original = jest.requireActual('pg');
42
+ state.connectCallback = defaultConnectCallback;
43
+
44
+ return {
45
+ state,
46
+ defaultConnectCallback,
47
+ };
48
+ });
49
+
50
+ vi.mock('pg', async () => {
51
+ const original = await vi.importActual<typeof import('pg')>('pg');
52
+
53
+ class MockPool {
54
+ connect = async () => {
55
+ return mockState.state.connectCallback!();
56
+ };
57
+
58
+ end = () => {
59
+ return;
60
+ };
61
+ }
62
+
33
63
  return {
34
64
  ...original,
35
- Pool: jest.fn().mockImplementation(() => {
36
- return {
37
- connect: async () => {
38
- return connectCallback();
39
- },
40
- end: () => {
41
- return;
42
- },
43
- };
44
- }),
65
+ Pool: MockPool,
45
66
  };
46
67
  });
47
68
 
69
+ import { compareMigrationHashes } from './compare-migration-hashes';
70
+ import * as compareHelpers from './compare-migration-hashes-helpers';
71
+ import { CompareMigrationHashesErrorCallback, MigrationRecord } from './types';
72
+
48
73
  describe('compareMigrationHashes', () => {
49
74
  let errorMessage: string;
50
75
  let errorMigrationRecords: MigrationRecord[] | undefined;
51
- let mockGetFileMigrationRecords: jest.SpyInstance;
76
+ let mockGetFileMigrationRecords: ReturnType<typeof vi.spyOn>;
52
77
  const mockErrorCallback: CompareMigrationHashesErrorCallback = (
53
78
  message: string,
54
79
  mismatchedRecords?: MigrationRecord[],
@@ -58,23 +83,22 @@ describe('compareMigrationHashes', () => {
58
83
  };
59
84
 
60
85
  beforeEach(() => {
61
- mockGetFileMigrationRecords = jest.spyOn(
86
+ mockGetFileMigrationRecords = vi.spyOn(
62
87
  compareHelpers,
63
88
  'getFileMigrationRecords',
64
89
  );
65
90
  });
66
91
 
67
92
  afterEach(() => {
68
- jest.restoreAllMocks();
69
- connectCallback = defaultConnectCallback;
70
- migrationsTableExistsCall = () => {
93
+ vi.restoreAllMocks();
94
+ mockState.state.connectCallback = mockState.defaultConnectCallback;
95
+ mockState.state.migrationsTableExistsCall = () => {
71
96
  return { rows: [{ migrationsTableExists: true }] };
72
97
  };
73
98
 
74
- migrationsTableCall = () => {
99
+ mockState.state.migrationsTableCall = () => {
75
100
  return { rows: [] };
76
101
  };
77
- mockGetFileMigrationRecords.mockClear();
78
102
  });
79
103
 
80
104
  const migration000001: MigrationRecord = {
@@ -121,20 +145,20 @@ describe('compareMigrationHashes', () => {
121
145
  mockGetFileMigrationRecords.mockImplementation(() => Promise.resolve([]));
122
146
 
123
147
  // Act & Assert
124
- await expect(async () =>
148
+ await expect(
125
149
  compareMigrationHashes({}, mockErrorCallback),
126
150
  ).rejects.toThrow('Database connection string is not set up.');
127
151
  });
128
152
 
129
153
  it('Connection to database fails - original error is thrown as is', async () => {
130
154
  // Arrange
131
- connectCallback = async () => {
155
+ mockState.state.connectCallback = async () => {
132
156
  throw new Error('database "test_database" does not exist');
133
157
  };
134
158
  mockGetFileMigrationRecords.mockImplementation(() => Promise.resolve([]));
135
159
 
136
160
  // Act & Assert
137
- await expect(async () =>
161
+ await expect(
138
162
  compareMigrationHashes(
139
163
  { connectionString: 'some connection string' },
140
164
  mockErrorCallback,
@@ -144,13 +168,13 @@ describe('compareMigrationHashes', () => {
144
168
 
145
169
  it('Migrations table exists check fails - original error is thrown', async () => {
146
170
  // Arrange
147
- migrationsTableExistsCall = () => {
171
+ mockState.state.migrationsTableExistsCall = () => {
148
172
  throw new Error('Query failed for whatever reason.');
149
173
  };
150
174
  mockGetFileMigrationRecords.mockImplementation(() => Promise.resolve([]));
151
175
 
152
176
  // Act & Assert
153
- await expect(async () =>
177
+ await expect(
154
178
  compareMigrationHashes(
155
179
  { connectionString: 'valid connection string' },
156
180
  mockErrorCallback,
@@ -160,13 +184,13 @@ describe('compareMigrationHashes', () => {
160
184
 
161
185
  it('Migrations history request to database fails - original error is thrown', async () => {
162
186
  // Arrange
163
- migrationsTableCall = () => {
187
+ mockState.state.migrationsTableCall = () => {
164
188
  throw new Error('Query failed for whatever reason.');
165
189
  };
166
190
  mockGetFileMigrationRecords.mockImplementation(() => Promise.resolve([]));
167
191
 
168
192
  // Act & Assert
169
- await expect(async () =>
193
+ await expect(
170
194
  compareMigrationHashes(
171
195
  { connectionString: 'valid connection string' },
172
196
  mockErrorCallback,
@@ -178,7 +202,7 @@ describe('compareMigrationHashes', () => {
178
202
  describe('migration hashes match', () => {
179
203
  it('if migration history table does not exist', async () => {
180
204
  // Arrange
181
- migrationsTableExistsCall = () => {
205
+ mockState.state.migrationsTableExistsCall = () => {
182
206
  return { rows: [{ migrationsTableExists: false }] };
183
207
  };
184
208
  mockGetFileMigrationRecords.mockImplementation(() => Promise.resolve([]));
@@ -197,7 +221,7 @@ describe('compareMigrationHashes', () => {
197
221
  it('if migration history is empty and no committed migrations', async () => {
198
222
  // Arrange
199
223
  mockGetFileMigrationRecords.mockImplementation(() => Promise.resolve([]));
200
- migrationsTableCall = () => {
224
+ mockState.state.migrationsTableCall = () => {
201
225
  return { rows: [] };
202
226
  };
203
227
 
@@ -217,7 +241,7 @@ describe('compareMigrationHashes', () => {
217
241
  mockGetFileMigrationRecords.mockImplementation(() =>
218
242
  Promise.resolve([migration000001, migration000002]),
219
243
  );
220
- migrationsTableCall = () => {
244
+ mockState.state.migrationsTableCall = () => {
221
245
  return { rows: [] };
222
246
  };
223
247
 
@@ -237,7 +261,7 @@ describe('compareMigrationHashes', () => {
237
261
  mockGetFileMigrationRecords.mockImplementation(() =>
238
262
  Promise.resolve([migration000001, migration000002, migration000003]),
239
263
  );
240
- migrationsTableCall = () => {
264
+ mockState.state.migrationsTableCall = () => {
241
265
  return { rows: [dbMigration000001] };
242
266
  };
243
267
 
@@ -257,7 +281,7 @@ describe('compareMigrationHashes', () => {
257
281
  mockGetFileMigrationRecords.mockImplementation(() =>
258
282
  Promise.resolve([migration000001, migration000002, migration000003]),
259
283
  );
260
- migrationsTableCall = () => {
284
+ mockState.state.migrationsTableCall = () => {
261
285
  return {
262
286
  rows: [dbMigration000001, dbMigration000002, dbMigration000003],
263
287
  };
@@ -279,7 +303,7 @@ describe('compareMigrationHashes', () => {
279
303
  it('if migration history has records and there is no committed migrations', async () => {
280
304
  // Arrange
281
305
  mockGetFileMigrationRecords.mockImplementation(() => Promise.resolve([]));
282
- migrationsTableCall = () => {
306
+ mockState.state.migrationsTableCall = () => {
283
307
  return {
284
308
  rows: [dbMigration000001, dbMigration000002, dbMigration000003],
285
309
  };
@@ -310,7 +334,7 @@ describe('compareMigrationHashes', () => {
310
334
  mockGetFileMigrationRecords.mockImplementation(() =>
311
335
  Promise.resolve([migration000001]),
312
336
  );
313
- migrationsTableCall = () => {
337
+ mockState.state.migrationsTableCall = () => {
314
338
  return {
315
339
  rows: [dbMigration000001, dbMigration000002, dbMigration000003],
316
340
  };
@@ -345,7 +369,7 @@ describe('compareMigrationHashes', () => {
345
369
  ...dbMigration000003,
346
370
  hash: 'sha1:a929171757965e9dc0bdd9678b11f5bc76fdcdd9',
347
371
  };
348
- migrationsTableCall = () => {
372
+ mockState.state.migrationsTableCall = () => {
349
373
  return {
350
374
  rows: [
351
375
  dbMigration000001,
@@ -384,7 +408,7 @@ describe('compareMigrationHashes', () => {
384
408
  ...dbMigration000003,
385
409
  previousHash: 'sha1:a929171757965e9dc0bdd9678b11f5bc76fdcdd9',
386
410
  };
387
- migrationsTableCall = () => {
411
+ mockState.state.migrationsTableCall = () => {
388
412
  return {
389
413
  rows: [
390
414
  migration000001,
@@ -38,7 +38,9 @@ export const runCurrentSql = async (
38
38
  settings: Settings,
39
39
  logger: DbLogger,
40
40
  ): Promise<void> => {
41
- const path = 'migrations/current.sql';
41
+ const migrationsFolder =
42
+ settings.migrationsFolder ?? join(process.cwd(), 'migrations');
43
+ const path = join(migrationsFolder, 'current.sql');
42
44
  const content = await fsp.readFile(path, 'utf8');
43
45
  logger.debug(`Running Script: '${path}'`);
44
46
  await run(settings, content, path);
@@ -59,8 +61,10 @@ export const runCurrentSql = async (
59
61
  ]
60
62
  ```
61
63
  */
62
- export const getBeforeMigrationScripts = async (): Promise<string[]> => {
63
- const executionPath = join(process.cwd(), 'migrations');
64
+ export const getBeforeMigrationScripts = async (
65
+ migrationsFolder?: string,
66
+ ): Promise<string[]> => {
67
+ const executionPath = migrationsFolder ?? join(process.cwd(), 'migrations');
64
68
  const dirPath = resolve(
65
69
  __dirname,
66
70
  '..',
@@ -1,64 +1,71 @@
1
- import { Pgoutput } from 'pg-logical-replication';
2
- import {
3
- LogicalReplicationMessageHandler,
4
- createLogicalReplicationService,
5
- } from './create-logical-replication-service';
6
-
7
- const sleep = (ms: number): Promise<void> =>
8
- new Promise((res) => setTimeout(res, ms));
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
9
2
 
10
- const repService: {
3
+ const repService = vi.hoisted(() => ({
11
4
  // We expose the callback methods that are normally called from the "on"
12
5
  // "data/error/heartbeat" emitted events to be able to manually call them.
13
- handleData?: (lsn: string, log: any) => Promise<void> | void;
14
- handleError?: (err: Error) => void;
15
- handleHeartbeat?: (
16
- lsn: string,
17
- timestamp: number,
18
- shouldRespond: boolean,
19
- ) => Promise<void> | void;
20
- acknowledge?: jest.Mock<any, any>;
21
- stop?: jest.Mock<any, any>;
22
- } = {};
6
+ handleData: undefined as
7
+ | ((lsn: string, log: any) => Promise<void> | void)
8
+ | undefined,
9
+ handleError: undefined as ((err: Error) => void) | undefined,
10
+ handleHeartbeat: undefined as
11
+ | ((
12
+ lsn: string,
13
+ timestamp: number,
14
+ shouldRespond: boolean,
15
+ ) => Promise<void> | void)
16
+ | undefined,
17
+ acknowledge: undefined as ReturnType<typeof vi.fn> | undefined,
18
+ stop: undefined as ReturnType<typeof vi.fn> | undefined,
19
+ }));
20
+
21
+ vi.mock('pg-logical-replication', async () => {
22
+ const actual = await vi.importActual<typeof import('pg-logical-replication')>(
23
+ 'pg-logical-replication',
24
+ );
25
+
26
+ class MockLogicalReplicationService {
27
+ constructor(_config: unknown, _ackConfig: unknown) {
28
+ repService.acknowledge = this.acknowledge;
29
+ repService.stop = this.stop;
30
+ }
31
+
32
+ on = (event: 'data' | 'error' | 'heartbeat', listener: any) => {
33
+ switch (event) {
34
+ case 'data':
35
+ repService.handleData = listener;
36
+ break;
37
+ case 'error':
38
+ repService.handleError = listener;
39
+ break;
40
+ case 'heartbeat':
41
+ repService.handleHeartbeat = listener;
42
+ break;
43
+ }
44
+ };
45
+
46
+ acknowledge = vi.fn();
47
+ removeAllListeners = vi.fn();
48
+ emit = vi.fn();
49
+ stop = vi.fn(() => Promise.resolve());
50
+ subscribe = () =>
51
+ new Promise(() => {
52
+ /** never return */
53
+ });
54
+ isStop = () => false;
55
+ }
23
56
 
24
- jest.mock('pg-logical-replication', () => {
25
57
  return {
26
- ...jest.requireActual('pg-logical-replication'),
27
- LogicalReplicationService: jest.fn().mockImplementation(() => {
28
- const lrs = {
29
- handleData: undefined,
30
- handleError: undefined,
31
- handleHeartbeat: undefined,
32
- on: (event: 'data' | 'error' | 'heartbeat', listener: any) => {
33
- switch (event) {
34
- case 'data':
35
- repService.handleData = listener;
36
- break;
37
- case 'error':
38
- repService.handleError = listener;
39
- break;
40
- case 'heartbeat':
41
- repService.handleHeartbeat = listener;
42
- break;
43
- }
44
- },
45
- acknowledge: jest.fn(),
46
- removeAllListeners: jest.fn(),
47
- emit: jest.fn(),
48
- stop: jest.fn(() => Promise.resolve()),
49
- subscribe: () =>
50
- new Promise(() => {
51
- /** never return */
52
- }),
53
- isStop: () => false,
54
- };
55
- repService.acknowledge = lrs.acknowledge;
56
- repService.stop = lrs.stop;
57
- return lrs;
58
- }),
58
+ ...actual,
59
+ LogicalReplicationService: MockLogicalReplicationService,
59
60
  };
60
61
  });
61
62
 
63
+ import { Pgoutput } from 'pg-logical-replication';
64
+ import {
65
+ LogicalReplicationMessageHandler,
66
+ createLogicalReplicationService,
67
+ } from './create-logical-replication-service';
68
+
62
69
  const relation: Pgoutput.MessageRelation = {
63
70
  tag: 'relation',
64
71
  relationOid: 1,
@@ -89,6 +96,10 @@ const relation: Pgoutput.MessageRelation = {
89
96
  };
90
97
 
91
98
  describe('createLogicalReplicationService', () => {
99
+ afterEach(() => {
100
+ vi.useRealTimers();
101
+ });
102
+
92
103
  beforeEach(() => {
93
104
  repService.handleData = undefined;
94
105
  repService.handleError = undefined;
@@ -98,27 +109,23 @@ describe('createLogicalReplicationService', () => {
98
109
  });
99
110
 
100
111
  it('initialization throws an error if empty operations array is passed', async () => {
101
- // Act
102
- try {
103
- await createLogicalReplicationService({
112
+ // Act & Assert
113
+ await expect(
114
+ createLogicalReplicationService({
104
115
  connectionString: 'test-valid-connection-string',
105
116
  publicationNames: ['test_publication'],
106
117
  replicationSlotName: 'test_slot',
107
- messageHandler: jest.fn(),
118
+ messageHandler: vi.fn(),
108
119
  operationsToWatch: [],
109
- });
110
- } catch (error) {
111
- // Assert
112
- // eslint-disable-next-line jest/no-conditional-expect
113
- expect((error as Error).message).toBe(
114
- 'Unable to start the logical replication service when operationsToWatch is an empty array.',
115
- );
116
- }
120
+ }),
121
+ ).rejects.toThrow(
122
+ 'Unable to start the logical replication service when operationsToWatch is an empty array.',
123
+ );
117
124
  });
118
125
 
119
126
  it('should call messageHandler and acknowledge the message when no errors are thrown', async () => {
120
127
  // Arrange
121
- const messageHandler: LogicalReplicationMessageHandler = jest.fn();
128
+ const messageHandler: LogicalReplicationMessageHandler = vi.fn();
122
129
  const cleanup = await createLogicalReplicationService({
123
130
  connectionString: 'test-valid-connection-string',
124
131
  publicationNames: ['test_publication'],
@@ -171,7 +178,7 @@ describe('createLogicalReplicationService', () => {
171
178
 
172
179
  it('should call messageHandler with minimal scoped message and acknowledge the message when no errors are thrown', async () => {
173
180
  // Arrange
174
- const messageHandler: LogicalReplicationMessageHandler = jest.fn();
181
+ const messageHandler: LogicalReplicationMessageHandler = vi.fn();
175
182
  const cleanup = await createLogicalReplicationService({
176
183
  connectionString: 'test-valid-connection-string',
177
184
  publicationNames: ['test_publication'],
@@ -249,11 +256,12 @@ describe('createLogicalReplicationService', () => {
249
256
 
250
257
  it('A heartbeat should be acknowledged after 5 seconds', async () => {
251
258
  // Arrange
259
+ vi.useFakeTimers();
252
260
  const cleanup = await createLogicalReplicationService({
253
261
  connectionString: 'test-valid-connection-string',
254
262
  publicationNames: ['test_publication'],
255
263
  replicationSlotName: 'test_slot',
256
- messageHandler: jest.fn(),
264
+ messageHandler: vi.fn(),
257
265
  });
258
266
  expect(repService.handleHeartbeat).toBeDefined();
259
267
 
@@ -264,9 +272,9 @@ describe('createLogicalReplicationService', () => {
264
272
  expect(repService.handleData).toBeDefined();
265
273
  expect(repService.handleError).toBeDefined();
266
274
  expect(repService.acknowledge).not.toHaveBeenCalled();
267
- await sleep(4000);
275
+ await vi.advanceTimersByTimeAsync(4000);
268
276
  expect(repService.acknowledge).not.toHaveBeenCalled();
269
- await sleep(1010);
277
+ await vi.advanceTimersByTimeAsync(1010);
270
278
  expect(repService.acknowledge).toHaveBeenCalled();
271
279
  expect(repService.stop).not.toHaveBeenCalled();
272
280
  await cleanup();
@@ -275,18 +283,19 @@ describe('createLogicalReplicationService', () => {
275
283
 
276
284
  it('A heartbeat should not be acknowledged after 5 seconds when a message acknowledgement comes in between', async () => {
277
285
  // Arrange
286
+ vi.useFakeTimers();
278
287
  const cleanup = await createLogicalReplicationService({
279
288
  connectionString: 'test-valid-connection-string',
280
289
  publicationNames: ['test_publication'],
281
290
  replicationSlotName: 'test_slot',
282
- messageHandler: jest.fn(),
291
+ messageHandler: vi.fn(),
283
292
  });
284
293
  expect(repService.handleData).toBeDefined();
285
294
  expect(repService.handleHeartbeat).toBeDefined();
286
295
 
287
296
  // Act
288
297
  await repService.handleHeartbeat!('0/00000001', 123, true);
289
- await sleep(1000);
298
+ await vi.advanceTimersByTimeAsync(1000);
290
299
  await repService.handleData!('0/00000002', {
291
300
  tag: 'insert',
292
301
  relation,
@@ -303,7 +312,7 @@ describe('createLogicalReplicationService', () => {
303
312
  // Assert
304
313
  expect(repService.handleError).toBeDefined();
305
314
  expect(repService.acknowledge).toHaveBeenCalledWith('0/00000002');
306
- await sleep(4010);
315
+ await vi.advanceTimersByTimeAsync(4010);
307
316
  expect(repService.acknowledge).toHaveBeenCalledTimes(1);
308
317
  expect(repService.stop).not.toHaveBeenCalled();
309
318
  await cleanup();
@@ -1,46 +1,70 @@
1
- import { stub } from '@axinom/mosaic-dev-be-common';
2
- import { Pool } from 'pg';
3
- import { SQLFragment } from 'zapatos/db';
4
- import { ensureReplicationSlotAndPublicationExist } from './ensure-replication-slot-and-publication-exist';
5
-
6
- const slotName = 'test_slot_name';
7
- const pubName = 'test_pub_name';
8
- let existsResult: () => unknown = () => undefined;
9
- let tablesResult: () => unknown = () => undefined;
10
- jest.mock('zapatos/db', () => {
1
+ import {
2
+ afterEach,
3
+ beforeEach,
4
+ describe,
5
+ expect,
6
+ it,
7
+ vi,
8
+ type MockInstance,
9
+ } from 'vitest';
10
+
11
+ const mockState = vi.hoisted(() => ({
12
+ slotName: 'test_slot_name',
13
+ pubName: 'test_pub_name',
14
+ existsResult: (() => undefined) as () => unknown,
15
+ tablesResult: (() => undefined) as () => unknown,
16
+ }));
17
+
18
+ vi.mock('zapatos/db', async () => {
19
+ const actual = await vi.importActual<typeof import('zapatos/db')>(
20
+ 'zapatos/db',
21
+ );
11
22
  return {
12
- ...jest.requireActual('zapatos/db'),
13
- sql: jest.fn().mockImplementation((_query, firstParam) => {
23
+ ...actual,
24
+ sql: vi.fn().mockImplementation((_query, firstParam) => {
14
25
  return stub<SQLFragment>({
15
- run: jest.fn().mockImplementation(() => {
16
- if (firstParam.value === slotName) {
17
- return existsResult();
26
+ run: vi.fn().mockImplementation(() => {
27
+ if (firstParam.value === mockState.slotName) {
28
+ return mockState.existsResult();
18
29
  }
19
- if (firstParam.value === pubName) {
20
- return tablesResult();
30
+ if (firstParam.value === mockState.pubName) {
31
+ return mockState.tablesResult();
21
32
  }
22
33
  return undefined;
23
34
  }),
24
35
  });
25
36
  }),
26
- transaction: jest.fn().mockImplementation(() => {
37
+ transaction: vi.fn().mockImplementation(() => {
27
38
  return;
28
39
  }),
29
40
  };
30
41
  });
31
42
 
43
+ import { stub } from '@axinom/mosaic-dev-be-common/vitest';
44
+ import { Pool } from 'pg';
45
+ import { SQLFragment } from 'zapatos/db';
46
+ import { ensureReplicationSlotAndPublicationExist } from './ensure-replication-slot-and-publication-exist';
47
+
48
+ const slotName = mockState.slotName;
49
+ const pubName = mockState.pubName;
50
+
32
51
  describe('ensureReplicationSlotAndPublicationExist', () => {
33
- let consoleOverride: jest.SpyInstance;
52
+ let consoleLogSpy: MockInstance;
53
+ const expectSingleLog = (message: string): void => {
54
+ expect(consoleLogSpy).toHaveBeenCalledTimes(1);
55
+ expect(consoleLogSpy).toHaveBeenCalledWith(message);
56
+ };
57
+
34
58
  beforeEach(() => {
35
- consoleOverride = jest
36
- .spyOn(console, 'log')
37
- .mockImplementation((log) => log);
59
+ consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {
60
+ return;
61
+ });
38
62
  });
39
63
 
40
64
  afterEach(() => {
41
- existsResult = () => undefined;
42
- tablesResult = () => undefined;
43
- jest.restoreAllMocks();
65
+ mockState.existsResult = () => undefined;
66
+ mockState.tablesResult = () => undefined;
67
+ vi.restoreAllMocks();
44
68
  });
45
69
 
46
70
  it.each([
@@ -51,8 +75,8 @@ describe('ensureReplicationSlotAndPublicationExist', () => {
51
75
  'call when slot and/or publication does not exist -> pass, %p, %p',
52
76
  async (slotExists, pubExists) => {
53
77
  // Arrange
54
- existsResult = () => [{ slotExists, pubExists }];
55
- tablesResult = () =>
78
+ mockState.existsResult = () => [{ slotExists, pubExists }];
79
+ mockState.tablesResult = () =>
56
80
  pubExists
57
81
  ? [
58
82
  { schemaname: 'app_public', tablename: 'table_one' },
@@ -71,7 +95,7 @@ describe('ensureReplicationSlotAndPublicationExist', () => {
71
95
  });
72
96
 
73
97
  // Assert
74
- expect(consoleOverride.mock.results[0].value).toBe(
98
+ expectSingleLog(
75
99
  'The replication slot "test_slot_name" and publication "test_pub_name" successfully (re)created.',
76
100
  );
77
101
  },
@@ -79,8 +103,8 @@ describe('ensureReplicationSlotAndPublicationExist', () => {
79
103
 
80
104
  it('call when slot and publication exist and new table is added -> pass', async () => {
81
105
  // Arrange
82
- existsResult = () => [{ slotExists: true, pubExists: true }];
83
- tablesResult = () => [
106
+ mockState.existsResult = () => [{ slotExists: true, pubExists: true }];
107
+ mockState.tablesResult = () => [
84
108
  { schemaname: 'app_public', tablename: 'table_one' },
85
109
  { schemaname: 'app_public', tablename: 'table_two' },
86
110
  ];
@@ -95,15 +119,15 @@ describe('ensureReplicationSlotAndPublicationExist', () => {
95
119
  });
96
120
 
97
121
  // Assert
98
- expect(consoleOverride.mock.results[0].value).toBe(
122
+ expectSingleLog(
99
123
  'The replication slot "test_slot_name" and publication "test_pub_name" successfully (re)created.',
100
124
  );
101
125
  });
102
126
 
103
127
  it('call when slot and publication exist and old table is removed -> pass', async () => {
104
128
  // Arrange
105
- existsResult = () => [{ slotExists: true, pubExists: true }];
106
- tablesResult = () => [
129
+ mockState.existsResult = () => [{ slotExists: true, pubExists: true }];
130
+ mockState.tablesResult = () => [
107
131
  { schemaname: 'app_public', tablename: 'table_one' },
108
132
  { schemaname: 'app_public', tablename: 'table_two' },
109
133
  { schemaname: 'app_public', tablename: 'table_three' },
@@ -119,15 +143,15 @@ describe('ensureReplicationSlotAndPublicationExist', () => {
119
143
  });
120
144
 
121
145
  // Assert
122
- expect(consoleOverride.mock.results[0].value).toBe(
146
+ expectSingleLog(
123
147
  'The replication slot "test_slot_name" and publication "test_pub_name" successfully (re)created.',
124
148
  );
125
149
  });
126
150
 
127
151
  it('call when slot and publication exist and one table is replaced by another -> pass', async () => {
128
152
  // Arrange
129
- existsResult = () => [{ slotExists: true, pubExists: true }];
130
- tablesResult = () => [
153
+ mockState.existsResult = () => [{ slotExists: true, pubExists: true }];
154
+ mockState.tablesResult = () => [
131
155
  { schemaname: 'app_public', tablename: 'table_one' },
132
156
  { schemaname: 'app_public', tablename: 'table_two' },
133
157
  { schemaname: 'app_public', tablename: 'table_three' },
@@ -143,15 +167,15 @@ describe('ensureReplicationSlotAndPublicationExist', () => {
143
167
  });
144
168
 
145
169
  // Assert
146
- expect(consoleOverride.mock.results[0].value).toBe(
170
+ expectSingleLog(
147
171
  'The replication slot "test_slot_name" and publication "test_pub_name" successfully (re)created.',
148
172
  );
149
173
  });
150
174
 
151
175
  it('call when slot and publication exist and tables are in sync -> skip', async () => {
152
176
  // Arrange
153
- existsResult = () => [{ slotExists: true, pubExists: true }];
154
- tablesResult = () => [
177
+ mockState.existsResult = () => [{ slotExists: true, pubExists: true }];
178
+ mockState.tablesResult = () => [
155
179
  { schemaname: 'app_public', tablename: 'table_one' },
156
180
  { schemaname: 'app_public', tablename: 'table_two' },
157
181
  { schemaname: 'app_public', tablename: 'table_three' },
@@ -167,7 +191,7 @@ describe('ensureReplicationSlotAndPublicationExist', () => {
167
191
  });
168
192
 
169
193
  // Assert
170
- expect(consoleOverride.mock.results[0].value).toBe(
194
+ expectSingleLog(
171
195
  'The replication slot "test_slot_name" and publication "test_pub_name" already exist.',
172
196
  );
173
197
  });
@@ -1,3 +1,4 @@
1
+ import { describe, expect, it } from 'vitest';
1
2
  import { transformCustomType } from './transform-custom-type';
2
3
 
3
4
  describe('transformCustomType', () => {
@@ -1,3 +1,4 @@
1
+ import { describe, expect, it } from 'vitest';
1
2
  import { nullable, optional } from './update-helpers';
2
3
 
3
4
  describe('nullable', () => {