@powersync/service-module-mssql 0.0.0-dev-20260313100403 → 0.0.0-dev-20260515144844

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 (75) hide show
  1. package/CHANGELOG.md +91 -6
  2. package/dist/api/MSSQLRouteAPIAdapter.d.ts +2 -2
  3. package/dist/api/MSSQLRouteAPIAdapter.js +3 -3
  4. package/dist/api/MSSQLRouteAPIAdapter.js.map +1 -1
  5. package/dist/common/CaptureInstance.d.ts +14 -0
  6. package/dist/common/CaptureInstance.js +2 -0
  7. package/dist/common/CaptureInstance.js.map +1 -0
  8. package/dist/common/MSSQLSourceTable.d.ts +16 -14
  9. package/dist/common/MSSQLSourceTable.js +35 -16
  10. package/dist/common/MSSQLSourceTable.js.map +1 -1
  11. package/dist/common/MSSQLSourceTableCache.js.map +1 -1
  12. package/dist/common/mssqls-to-sqlite.d.ts +1 -1
  13. package/dist/common/mssqls-to-sqlite.js +1 -1
  14. package/dist/common/mssqls-to-sqlite.js.map +1 -1
  15. package/dist/module/MSSQLModule.js +4 -4
  16. package/dist/module/MSSQLModule.js.map +1 -1
  17. package/dist/replication/CDCPoller.d.ts +45 -23
  18. package/dist/replication/CDCPoller.js +201 -61
  19. package/dist/replication/CDCPoller.js.map +1 -1
  20. package/dist/replication/CDCReplicationJob.d.ts +2 -2
  21. package/dist/replication/CDCReplicationJob.js +12 -4
  22. package/dist/replication/CDCReplicationJob.js.map +1 -1
  23. package/dist/replication/CDCReplicator.d.ts +2 -3
  24. package/dist/replication/CDCReplicator.js +1 -24
  25. package/dist/replication/CDCReplicator.js.map +1 -1
  26. package/dist/replication/CDCStream.d.ts +39 -16
  27. package/dist/replication/CDCStream.js +195 -102
  28. package/dist/replication/CDCStream.js.map +1 -1
  29. package/dist/replication/MSSQLConnectionManager.d.ts +1 -1
  30. package/dist/replication/MSSQLConnectionManager.js +17 -6
  31. package/dist/replication/MSSQLConnectionManager.js.map +1 -1
  32. package/dist/replication/MSSQLConnectionManagerFactory.d.ts +1 -1
  33. package/dist/replication/MSSQLConnectionManagerFactory.js.map +1 -1
  34. package/dist/replication/MSSQLSnapshotQuery.d.ts +1 -1
  35. package/dist/replication/MSSQLSnapshotQuery.js +2 -2
  36. package/dist/replication/MSSQLSnapshotQuery.js.map +1 -1
  37. package/dist/types/types.d.ts +4 -56
  38. package/dist/types/types.js +5 -24
  39. package/dist/types/types.js.map +1 -1
  40. package/dist/utils/deadlock.d.ts +9 -0
  41. package/dist/utils/deadlock.js +40 -0
  42. package/dist/utils/deadlock.js.map +1 -0
  43. package/dist/utils/mssql.d.ts +36 -18
  44. package/dist/utils/mssql.js +102 -100
  45. package/dist/utils/mssql.js.map +1 -1
  46. package/dist/utils/schema.d.ts +9 -0
  47. package/dist/utils/schema.js +34 -0
  48. package/dist/utils/schema.js.map +1 -1
  49. package/package.json +14 -14
  50. package/src/api/MSSQLRouteAPIAdapter.ts +4 -4
  51. package/src/common/CaptureInstance.ts +15 -0
  52. package/src/common/MSSQLSourceTable.ts +33 -24
  53. package/src/common/MSSQLSourceTableCache.ts +1 -1
  54. package/src/common/mssqls-to-sqlite.ts +1 -1
  55. package/src/module/MSSQLModule.ts +4 -4
  56. package/src/replication/CDCPoller.ts +275 -75
  57. package/src/replication/CDCReplicationJob.ts +13 -6
  58. package/src/replication/CDCReplicator.ts +2 -28
  59. package/src/replication/CDCStream.ts +265 -124
  60. package/src/replication/MSSQLConnectionManager.ts +17 -7
  61. package/src/replication/MSSQLConnectionManagerFactory.ts +1 -1
  62. package/src/replication/MSSQLSnapshotQuery.ts +3 -3
  63. package/src/types/types.ts +5 -28
  64. package/src/utils/deadlock.ts +44 -0
  65. package/src/utils/mssql.ts +163 -128
  66. package/src/utils/schema.ts +44 -1
  67. package/test/src/CDCStream.test.ts +7 -7
  68. package/test/src/CDCStreamTestContext.ts +14 -8
  69. package/test/src/CDCStream_resumable_snapshot.test.ts +6 -6
  70. package/test/src/LSN.test.ts +1 -1
  71. package/test/src/mssql-to-sqlite.test.ts +25 -17
  72. package/test/src/schema-changes.test.ts +474 -0
  73. package/test/src/util.ts +79 -22
  74. package/test/tsconfig.json +0 -1
  75. package/tsconfig.tsbuildinfo +1 -1
package/test/src/util.ts CHANGED
@@ -1,23 +1,17 @@
1
1
  import * as types from '@module/types/types.js';
2
2
  import { logger } from '@powersync/lib-services-framework';
3
- import {
4
- BucketStorageFactory,
5
- InternalOpId,
6
- ReplicationCheckpoint,
7
- TestStorageConfig,
8
- TestStorageFactory
9
- } from '@powersync/service-core';
3
+ import { BucketStorageFactory, InternalOpId, ReplicationCheckpoint, TestStorageConfig } from '@powersync/service-core';
10
4
 
11
5
  import * as mongo_storage from '@powersync/service-module-mongodb-storage';
12
6
  import * as postgres_storage from '@powersync/service-module-postgres-storage';
13
7
 
14
- import { describe, TestOptions } from 'vitest';
15
- import { env } from './env.js';
8
+ import { LSN } from '@module/common/LSN.js';
16
9
  import { MSSQLConnectionManager } from '@module/replication/MSSQLConnectionManager.js';
17
- import { createCheckpoint, enableCDCForTable, escapeIdentifier, getLatestLSN } from '@module/utils/mssql.js';
10
+ import { createCheckpoint, escapeIdentifier, getLatestLSN, toQualifiedTableName } from '@module/utils/mssql.js';
18
11
  import sql from 'mssql';
19
12
  import { v4 as uuid } from 'uuid';
20
- import { LSN } from '@module/common/LSN.js';
13
+ import { describe, TestOptions } from 'vitest';
14
+ import { env } from './env.js';
21
15
 
22
16
  export const TEST_URI = env.MSSQL_TEST_URI;
23
17
 
@@ -45,7 +39,7 @@ export const TEST_CONNECTION_OPTIONS = types.normalizeConnectionConfig({
45
39
  uri: TEST_URI,
46
40
  additionalConfig: {
47
41
  pollingBatchSize: 10,
48
- pollingIntervalMs: 1000,
42
+ pollingIntervalMs: 100,
49
43
  trustServerCertificate: true
50
44
  }
51
45
  });
@@ -72,13 +66,12 @@ export async function clearTestDb(connectionManager: MSSQLConnectionManager) {
72
66
  }
73
67
  }
74
68
 
75
- export async function resetTestTable(connectionManager: MSSQLConnectionManager, tableName: string) {
69
+ export async function dropTestTable(connectionManager: MSSQLConnectionManager, tableName: string) {
76
70
  await connectionManager.execute('sys.sp_cdc_disable_table', [
77
71
  { name: 'source_schema', value: connectionManager.schema },
78
72
  { name: 'source_name', value: tableName },
79
73
  { name: 'capture_instance', value: 'all' }
80
74
  ]);
81
-
82
75
  await connectionManager.query(`DROP TABLE [${tableName}]`);
83
76
  }
84
77
 
@@ -98,19 +91,26 @@ export async function createTestDb(connectionManager: MSSQLConnectionManager, db
98
91
  GO`);
99
92
  }
100
93
 
101
- export async function createTestTable(connectionManager: MSSQLConnectionManager, tableName: string): Promise<void> {
94
+ export async function createTestTable(
95
+ connectionManager: MSSQLConnectionManager,
96
+ tableName: string,
97
+ withCaptureInstance: boolean = true
98
+ ): Promise<void> {
102
99
  await connectionManager.query(`
103
100
  CREATE TABLE ${escapeIdentifier(connectionManager.schema)}.${escapeIdentifier(tableName)} (
104
101
  id UNIQUEIDENTIFIER PRIMARY KEY,
105
102
  description VARCHAR(MAX)
106
103
  )
107
104
  `);
108
- await enableCDCForTable({ connectionManager, table: tableName });
105
+ if (withCaptureInstance) {
106
+ await enableCDCForTable({ connectionManager, table: tableName });
107
+ }
109
108
  }
110
109
 
111
110
  export async function createTestTableWithBasicId(
112
111
  connectionManager: MSSQLConnectionManager,
113
- tableName: string
112
+ tableName: string,
113
+ withCaptureInstance: boolean = true
114
114
  ): Promise<void> {
115
115
  await connectionManager.query(`
116
116
  CREATE TABLE ${escapeIdentifier(connectionManager.schema)}.${escapeIdentifier(tableName)} (
@@ -118,7 +118,9 @@ export async function createTestTableWithBasicId(
118
118
  description VARCHAR(MAX)
119
119
  )
120
120
  `);
121
- await enableCDCForTable({ connectionManager, table: tableName });
121
+ if (withCaptureInstance) {
122
+ await enableCDCForTable({ connectionManager, table: tableName });
123
+ }
122
124
  }
123
125
 
124
126
  export interface TestData {
@@ -141,6 +143,24 @@ export async function insertTestData(connectionManager: MSSQLConnectionManager,
141
143
  return { id, description };
142
144
  }
143
145
 
146
+ export async function insertBasicIdTestData(
147
+ connectionManager: MSSQLConnectionManager,
148
+ tableName: string
149
+ ): Promise<TestData> {
150
+ const description = `description_${Math.floor(Math.random() * 1000000)}`;
151
+ const { recordset: result } = await connectionManager.query(
152
+ `
153
+ INSERT INTO ${toQualifiedTableName(connectionManager.schema, tableName)} (description)
154
+ OUTPUT INSERTED.id
155
+ VALUES (@description)
156
+ `,
157
+ [{ name: 'description', type: sql.NVarChar(sql.MAX), value: description }]
158
+ );
159
+ const id = result[0].id;
160
+
161
+ return { id, description };
162
+ }
163
+
144
164
  export async function waitForPendingCDCChanges(
145
165
  beforeLSN: LSN,
146
166
  connectionManager: MSSQLConnectionManager
@@ -157,10 +177,14 @@ export async function waitForPendingCDCChanges(
157
177
  );
158
178
 
159
179
  if (result.length === 0) {
160
- logger.info(`CDC changes pending. Waiting for 200ms...`);
180
+ logger.info(
181
+ `Test Assertion: CDC changes pending. Waiting for a transaction newer than: ${beforeLSN.toString()} for 200ms...`
182
+ );
161
183
  await new Promise((resolve) => setTimeout(resolve, 200));
162
184
  } else {
163
- logger.info(`Found LSN: ${LSN.fromBinary(result[0].start_lsn).toString()}`);
185
+ logger.info(
186
+ `Test Assertion: Expected CDC change found with LSN: ${LSN.fromBinary(result[0].start_lsn).toString()}`
187
+ );
164
188
  return;
165
189
  }
166
190
  }
@@ -182,14 +206,14 @@ export async function getClientCheckpoint(
182
206
  const timeout = options?.timeout ?? 50_000;
183
207
  let lastCp: ReplicationCheckpoint | null = null;
184
208
 
185
- logger.info(`Waiting for LSN checkpoint: ${lsn}`);
209
+ logger.info(`Test Assertion: Waiting for LSN checkpoint: ${lsn}`);
186
210
  while (Date.now() - start < timeout) {
187
211
  const storage = await storageFactory.getActiveStorage();
188
212
  const cp = await storage?.getCheckpoint();
189
213
  if (cp != null) {
190
214
  lastCp = cp;
191
215
  if (cp.lsn != null && cp.lsn >= lsn.toString()) {
192
- logger.info(`Got write checkpoint: ${lsn} : ${cp.checkpoint}`);
216
+ logger.info(`Test Assertion: Got write checkpoint: ${lsn} : ${cp.checkpoint}`);
193
217
  return cp.checkpoint;
194
218
  }
195
219
  }
@@ -206,3 +230,36 @@ export async function getClientCheckpoint(
206
230
  export function createUpperCaseUUID(): string {
207
231
  return uuid().toUpperCase();
208
232
  }
233
+
234
+ export async function renameTable(connectionManager: MSSQLConnectionManager, fromTable: string, toTable: string) {
235
+ await connectionManager.execute('sp_rename', [
236
+ { name: 'objname', value: toQualifiedTableName(connectionManager.schema, fromTable) },
237
+ { name: 'newname', value: toTable }
238
+ ]);
239
+ }
240
+
241
+ export interface EnableCDCForTableOptions {
242
+ connectionManager: MSSQLConnectionManager;
243
+ table: string;
244
+ captureInstance?: string;
245
+ }
246
+
247
+ export async function enableCDCForTable(options: EnableCDCForTableOptions): Promise<void> {
248
+ const { connectionManager, table, captureInstance } = options;
249
+
250
+ await connectionManager.execute('sys.sp_cdc_enable_table', [
251
+ { name: 'source_schema', value: connectionManager.schema },
252
+ { name: 'source_name', value: table },
253
+ { name: 'role_name', value: 'cdc_reader' },
254
+ { name: 'supports_net_changes', value: 0 },
255
+ ...(captureInstance !== undefined ? [{ name: 'capture_instance', value: captureInstance }] : [])
256
+ ]);
257
+ }
258
+
259
+ export async function disableCDCForTable(connectionManager: MSSQLConnectionManager, tableName: string) {
260
+ await connectionManager.execute('sys.sp_cdc_disable_table', [
261
+ { name: 'source_schema', value: connectionManager.schema },
262
+ { name: 'source_name', value: tableName },
263
+ { name: 'capture_instance', value: 'all' }
264
+ ]);
265
+ }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "extends": "../../../tsconfig.tests.json",
3
3
  "compilerOptions": {
4
- "baseUrl": "./",
5
4
  "paths": {
6
5
  "@/*": ["../../../packages/service-core/src/*"],
7
6
  "@module/*": ["../src/*"],