@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.
- package/CHANGELOG.md +91 -6
- package/dist/api/MSSQLRouteAPIAdapter.d.ts +2 -2
- package/dist/api/MSSQLRouteAPIAdapter.js +3 -3
- package/dist/api/MSSQLRouteAPIAdapter.js.map +1 -1
- package/dist/common/CaptureInstance.d.ts +14 -0
- package/dist/common/CaptureInstance.js +2 -0
- package/dist/common/CaptureInstance.js.map +1 -0
- package/dist/common/MSSQLSourceTable.d.ts +16 -14
- package/dist/common/MSSQLSourceTable.js +35 -16
- package/dist/common/MSSQLSourceTable.js.map +1 -1
- package/dist/common/MSSQLSourceTableCache.js.map +1 -1
- package/dist/common/mssqls-to-sqlite.d.ts +1 -1
- package/dist/common/mssqls-to-sqlite.js +1 -1
- package/dist/common/mssqls-to-sqlite.js.map +1 -1
- package/dist/module/MSSQLModule.js +4 -4
- package/dist/module/MSSQLModule.js.map +1 -1
- package/dist/replication/CDCPoller.d.ts +45 -23
- package/dist/replication/CDCPoller.js +201 -61
- package/dist/replication/CDCPoller.js.map +1 -1
- package/dist/replication/CDCReplicationJob.d.ts +2 -2
- package/dist/replication/CDCReplicationJob.js +12 -4
- package/dist/replication/CDCReplicationJob.js.map +1 -1
- package/dist/replication/CDCReplicator.d.ts +2 -3
- package/dist/replication/CDCReplicator.js +1 -24
- package/dist/replication/CDCReplicator.js.map +1 -1
- package/dist/replication/CDCStream.d.ts +39 -16
- package/dist/replication/CDCStream.js +195 -102
- package/dist/replication/CDCStream.js.map +1 -1
- package/dist/replication/MSSQLConnectionManager.d.ts +1 -1
- package/dist/replication/MSSQLConnectionManager.js +17 -6
- package/dist/replication/MSSQLConnectionManager.js.map +1 -1
- package/dist/replication/MSSQLConnectionManagerFactory.d.ts +1 -1
- package/dist/replication/MSSQLConnectionManagerFactory.js.map +1 -1
- package/dist/replication/MSSQLSnapshotQuery.d.ts +1 -1
- package/dist/replication/MSSQLSnapshotQuery.js +2 -2
- package/dist/replication/MSSQLSnapshotQuery.js.map +1 -1
- package/dist/types/types.d.ts +4 -56
- package/dist/types/types.js +5 -24
- package/dist/types/types.js.map +1 -1
- package/dist/utils/deadlock.d.ts +9 -0
- package/dist/utils/deadlock.js +40 -0
- package/dist/utils/deadlock.js.map +1 -0
- package/dist/utils/mssql.d.ts +36 -18
- package/dist/utils/mssql.js +102 -100
- package/dist/utils/mssql.js.map +1 -1
- package/dist/utils/schema.d.ts +9 -0
- package/dist/utils/schema.js +34 -0
- package/dist/utils/schema.js.map +1 -1
- package/package.json +14 -14
- package/src/api/MSSQLRouteAPIAdapter.ts +4 -4
- package/src/common/CaptureInstance.ts +15 -0
- package/src/common/MSSQLSourceTable.ts +33 -24
- package/src/common/MSSQLSourceTableCache.ts +1 -1
- package/src/common/mssqls-to-sqlite.ts +1 -1
- package/src/module/MSSQLModule.ts +4 -4
- package/src/replication/CDCPoller.ts +275 -75
- package/src/replication/CDCReplicationJob.ts +13 -6
- package/src/replication/CDCReplicator.ts +2 -28
- package/src/replication/CDCStream.ts +265 -124
- package/src/replication/MSSQLConnectionManager.ts +17 -7
- package/src/replication/MSSQLConnectionManagerFactory.ts +1 -1
- package/src/replication/MSSQLSnapshotQuery.ts +3 -3
- package/src/types/types.ts +5 -28
- package/src/utils/deadlock.ts +44 -0
- package/src/utils/mssql.ts +163 -128
- package/src/utils/schema.ts +44 -1
- package/test/src/CDCStream.test.ts +7 -7
- package/test/src/CDCStreamTestContext.ts +14 -8
- package/test/src/CDCStream_resumable_snapshot.test.ts +6 -6
- package/test/src/LSN.test.ts +1 -1
- package/test/src/mssql-to-sqlite.test.ts +25 -17
- package/test/src/schema-changes.test.ts +474 -0
- package/test/src/util.ts +79 -22
- package/test/tsconfig.json +0 -1
- 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 {
|
|
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,
|
|
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 {
|
|
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:
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
+
}
|