@powersync/service-module-mssql 0.9.0 → 0.10.0

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 (53) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/dist/api/MSSQLRouteAPIAdapter.js +26 -34
  3. package/dist/api/MSSQLRouteAPIAdapter.js.map +1 -1
  4. package/dist/common/MSSQLSourceTable.d.ts +12 -2
  5. package/dist/common/MSSQLSourceTable.js +30 -4
  6. package/dist/common/MSSQLSourceTable.js.map +1 -1
  7. package/dist/replication/CDCPoller.d.ts +13 -36
  8. package/dist/replication/CDCPoller.js +173 -129
  9. package/dist/replication/CDCPoller.js.map +1 -1
  10. package/dist/replication/CDCStream.d.ts +11 -14
  11. package/dist/replication/CDCStream.js +109 -103
  12. package/dist/replication/CDCStream.js.map +1 -1
  13. package/dist/replication/CaptureReconciler.d.ts +47 -0
  14. package/dist/replication/CaptureReconciler.js +155 -0
  15. package/dist/replication/CaptureReconciler.js.map +1 -0
  16. package/dist/replication/MSSQLConnectionManager.d.ts +1 -0
  17. package/dist/replication/MSSQLConnectionManager.js +19 -14
  18. package/dist/replication/MSSQLConnectionManager.js.map +1 -1
  19. package/dist/replication/MSSQLTableReconciliationContext.d.ts +21 -0
  20. package/dist/replication/MSSQLTableReconciliationContext.js +7 -0
  21. package/dist/replication/MSSQLTableReconciliationContext.js.map +1 -0
  22. package/dist/replication/SchemaChange.d.ts +67 -0
  23. package/dist/replication/SchemaChange.js +31 -0
  24. package/dist/replication/SchemaChange.js.map +1 -0
  25. package/dist/types/types.d.ts +8 -0
  26. package/dist/types/types.js +9 -0
  27. package/dist/types/types.js.map +1 -1
  28. package/dist/utils/mssql.js +1 -1
  29. package/dist/utils/schema.d.ts +14 -1
  30. package/dist/utils/schema.js +40 -45
  31. package/dist/utils/schema.js.map +1 -1
  32. package/package.json +4 -4
  33. package/src/api/MSSQLRouteAPIAdapter.ts +27 -33
  34. package/src/common/MSSQLSourceTable.ts +32 -4
  35. package/src/replication/CDCPoller.ts +206 -162
  36. package/src/replication/CDCStream.ts +142 -151
  37. package/src/replication/CaptureReconciler.ts +186 -0
  38. package/src/replication/MSSQLConnectionManager.ts +23 -14
  39. package/src/replication/MSSQLTableReconciliationContext.ts +29 -0
  40. package/src/replication/SchemaChange.ts +79 -0
  41. package/src/types/types.ts +21 -0
  42. package/src/utils/mssql.ts +1 -1
  43. package/src/utils/schema.ts +57 -58
  44. package/test/src/CDCPoller.test.ts +382 -0
  45. package/test/src/CDCStream.test.ts +6 -2
  46. package/test/src/CDCStreamTestContext.ts +7 -0
  47. package/test/src/CaptureReconciler.test.ts +171 -0
  48. package/test/src/MSSQLSourceTable.test.ts +30 -0
  49. package/test/src/config.test.ts +37 -0
  50. package/test/src/schema-changes.test.ts +513 -249
  51. package/test/src/schema.test.ts +17 -0
  52. package/test/src/util.ts +70 -6
  53. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,17 @@
1
+ import { unsupportedTablePatternMessage } from '@module/utils/schema.js';
2
+ import { TablePattern } from '@powersync/service-sync-rules';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ describe('unsupportedTablePatternMessage', () => {
6
+ it('accepts an exact table pattern', () => {
7
+ expect(unsupportedTablePatternMessage(new TablePattern('dbo', 'users'))).toBeNull();
8
+ });
9
+
10
+ it('rejects a table wildcard', () => {
11
+ expect(unsupportedTablePatternMessage(new TablePattern('dbo', 'test_data%'))).toMatch(/Table wildcards/);
12
+ });
13
+
14
+ it('rejects a schema wildcard', () => {
15
+ expect(unsupportedTablePatternMessage(new TablePattern('dbo%', 'users'))).toMatch(/Schema wildcards/);
16
+ });
17
+ });
package/test/src/util.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import * as types from '@module/types/types.js';
2
2
  import { logger } from '@powersync/lib-services-framework';
3
- import { BucketStorageFactory, ReplicationCheckpoint, TestStorageConfig } from '@powersync/service-core';
4
-
3
+ import { BucketStorageFactory, ReplicationCheckpoint, storage, TestStorageConfig } from '@powersync/service-core';
5
4
  import * as mongo_storage from '@powersync/service-module-mongodb-storage';
6
5
  import * as postgres_storage from '@powersync/service-module-postgres-storage';
7
6
 
7
+ import { CaptureInstance } from '@module/common/CaptureInstance.js';
8
8
  import { LSN } from '@module/common/LSN.js';
9
+ import { MSSQLSourceMetadata } from '@module/replication/CaptureReconciler.js';
9
10
  import { MSSQLConnectionManager } from '@module/replication/MSSQLConnectionManager.js';
10
11
  import { createCheckpoint, escapeIdentifier, getLatestLSN, toQualifiedTableName } from '@module/utils/mssql.js';
11
12
  import sql from 'mssql';
@@ -242,24 +243,87 @@ export interface EnableCDCForTableOptions {
242
243
  connectionManager: MSSQLConnectionManager;
243
244
  table: string;
244
245
  captureInstance?: string;
246
+ /**
247
+ * Columns to capture. SQL Server captures all columns by default.
248
+ */
249
+ capturedColumns?: string[];
245
250
  }
246
251
 
247
252
  export async function enableCDCForTable(options: EnableCDCForTableOptions): Promise<void> {
248
- const { connectionManager, table, captureInstance } = options;
253
+ const { connectionManager, table, captureInstance, capturedColumns } = options;
249
254
 
250
255
  await connectionManager.execute('sys.sp_cdc_enable_table', [
251
256
  { name: 'source_schema', value: connectionManager.schema },
252
257
  { name: 'source_name', value: table },
253
258
  { name: 'role_name', value: 'cdc_reader' },
254
259
  { name: 'supports_net_changes', value: 0 },
255
- ...(captureInstance !== undefined ? [{ name: 'capture_instance', value: captureInstance }] : [])
260
+ ...(captureInstance !== undefined ? [{ name: 'capture_instance', value: captureInstance }] : []),
261
+ ...(capturedColumns !== undefined ? [{ name: 'captured_column_list', value: capturedColumns.join(',') }] : [])
256
262
  ]);
257
263
  }
258
264
 
259
- export async function disableCDCForTable(connectionManager: MSSQLConnectionManager, tableName: string) {
265
+ /**
266
+ * Disable one capture instance, or all instances by default.
267
+ */
268
+ export async function disableCDCForTable(
269
+ connectionManager: MSSQLConnectionManager,
270
+ tableName: string,
271
+ captureInstance: string = 'all'
272
+ ) {
260
273
  await connectionManager.execute('sys.sp_cdc_disable_table', [
261
274
  { name: 'source_schema', value: connectionManager.schema },
262
275
  { name: 'source_name', value: tableName },
263
- { name: 'capture_instance', value: 'all' }
276
+ { name: 'capture_instance', value: captureInstance }
264
277
  ]);
265
278
  }
279
+
280
+ /**
281
+ * Create a capture instance with the given capture-table object id.
282
+ */
283
+ export function createCaptureInstance(objectId: number): CaptureInstance {
284
+ return {
285
+ name: `dbo_users_${objectId}`,
286
+ objectId,
287
+ minLSN: LSN.fromString(LSN.ZERO),
288
+ createDate: new Date(),
289
+ pendingSchemaChanges: []
290
+ };
291
+ }
292
+ /**
293
+ * Build a persisted source-table candidate with optional capture metadata.
294
+ */
295
+ export function createSourceTableCandidate(
296
+ id: string,
297
+ metadata?: MSSQLSourceMetadata,
298
+ overrides: Partial<ConstructorParameters<typeof storage.SourceTable>[0]> = {}
299
+ ): storage.SourceTable {
300
+ const descriptor = createSourceDescriptor();
301
+
302
+ return new storage.SourceTable({
303
+ id,
304
+ ref: descriptor,
305
+ objectId: descriptor.objectId,
306
+ replicaIdColumns: descriptor.replicaIdColumns,
307
+ snapshotComplete: true,
308
+ bucketDataSources: [],
309
+ parameterLookupSources: [],
310
+ sourceMetadata: metadata,
311
+ ...overrides
312
+ });
313
+ }
314
+
315
+ /**
316
+ * Create a source descriptor with optional identity overrides.
317
+ */
318
+ export function createSourceDescriptor(
319
+ overrides: Partial<storage.SourceEntityDescriptor> = {}
320
+ ): storage.SourceEntityDescriptor {
321
+ return {
322
+ connectionTag: 'default',
323
+ schema: 'dbo',
324
+ name: 'users',
325
+ objectId: 100,
326
+ replicaIdColumns: [{ name: 'id', type: 'int', typeId: 56 }],
327
+ ...overrides
328
+ };
329
+ }