@powersync/service-module-mssql 0.0.1

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 (92) hide show
  1. package/LICENSE +67 -0
  2. package/README.md +3 -0
  3. package/ci/init-mssql.sql +50 -0
  4. package/dist/api/MSSQLRouteAPIAdapter.d.ts +21 -0
  5. package/dist/api/MSSQLRouteAPIAdapter.js +248 -0
  6. package/dist/api/MSSQLRouteAPIAdapter.js.map +1 -0
  7. package/dist/common/LSN.d.ts +37 -0
  8. package/dist/common/LSN.js +64 -0
  9. package/dist/common/LSN.js.map +1 -0
  10. package/dist/common/MSSQLSourceTable.d.ts +27 -0
  11. package/dist/common/MSSQLSourceTable.js +35 -0
  12. package/dist/common/MSSQLSourceTable.js.map +1 -0
  13. package/dist/common/MSSQLSourceTableCache.d.ts +14 -0
  14. package/dist/common/MSSQLSourceTableCache.js +28 -0
  15. package/dist/common/MSSQLSourceTableCache.js.map +1 -0
  16. package/dist/common/mssqls-to-sqlite.d.ts +18 -0
  17. package/dist/common/mssqls-to-sqlite.js +143 -0
  18. package/dist/common/mssqls-to-sqlite.js.map +1 -0
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.js +2 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/module/MSSQLModule.d.ts +15 -0
  23. package/dist/module/MSSQLModule.js +68 -0
  24. package/dist/module/MSSQLModule.js.map +1 -0
  25. package/dist/replication/CDCPoller.d.ts +67 -0
  26. package/dist/replication/CDCPoller.js +183 -0
  27. package/dist/replication/CDCPoller.js.map +1 -0
  28. package/dist/replication/CDCReplicationJob.d.ts +17 -0
  29. package/dist/replication/CDCReplicationJob.js +76 -0
  30. package/dist/replication/CDCReplicationJob.js.map +1 -0
  31. package/dist/replication/CDCReplicator.d.ts +18 -0
  32. package/dist/replication/CDCReplicator.js +55 -0
  33. package/dist/replication/CDCReplicator.js.map +1 -0
  34. package/dist/replication/CDCStream.d.ts +106 -0
  35. package/dist/replication/CDCStream.js +536 -0
  36. package/dist/replication/CDCStream.js.map +1 -0
  37. package/dist/replication/MSSQLConnectionManager.d.ts +23 -0
  38. package/dist/replication/MSSQLConnectionManager.js +97 -0
  39. package/dist/replication/MSSQLConnectionManager.js.map +1 -0
  40. package/dist/replication/MSSQLConnectionManagerFactory.d.ts +10 -0
  41. package/dist/replication/MSSQLConnectionManagerFactory.js +28 -0
  42. package/dist/replication/MSSQLConnectionManagerFactory.js.map +1 -0
  43. package/dist/replication/MSSQLErrorRateLimiter.d.ts +10 -0
  44. package/dist/replication/MSSQLErrorRateLimiter.js +34 -0
  45. package/dist/replication/MSSQLErrorRateLimiter.js.map +1 -0
  46. package/dist/replication/MSSQLSnapshotQuery.d.ts +71 -0
  47. package/dist/replication/MSSQLSnapshotQuery.js +190 -0
  48. package/dist/replication/MSSQLSnapshotQuery.js.map +1 -0
  49. package/dist/types/mssql-data-types.d.ts +66 -0
  50. package/dist/types/mssql-data-types.js +62 -0
  51. package/dist/types/mssql-data-types.js.map +1 -0
  52. package/dist/types/types.d.ts +177 -0
  53. package/dist/types/types.js +141 -0
  54. package/dist/types/types.js.map +1 -0
  55. package/dist/utils/mssql.d.ts +80 -0
  56. package/dist/utils/mssql.js +329 -0
  57. package/dist/utils/mssql.js.map +1 -0
  58. package/dist/utils/schema.d.ts +21 -0
  59. package/dist/utils/schema.js +131 -0
  60. package/dist/utils/schema.js.map +1 -0
  61. package/package.json +51 -0
  62. package/src/api/MSSQLRouteAPIAdapter.ts +283 -0
  63. package/src/common/LSN.ts +77 -0
  64. package/src/common/MSSQLSourceTable.ts +54 -0
  65. package/src/common/MSSQLSourceTableCache.ts +36 -0
  66. package/src/common/mssqls-to-sqlite.ts +151 -0
  67. package/src/index.ts +1 -0
  68. package/src/module/MSSQLModule.ts +82 -0
  69. package/src/replication/CDCPoller.ts +241 -0
  70. package/src/replication/CDCReplicationJob.ts +87 -0
  71. package/src/replication/CDCReplicator.ts +70 -0
  72. package/src/replication/CDCStream.ts +688 -0
  73. package/src/replication/MSSQLConnectionManager.ts +113 -0
  74. package/src/replication/MSSQLConnectionManagerFactory.ts +33 -0
  75. package/src/replication/MSSQLErrorRateLimiter.ts +36 -0
  76. package/src/replication/MSSQLSnapshotQuery.ts +230 -0
  77. package/src/types/mssql-data-types.ts +79 -0
  78. package/src/types/types.ts +224 -0
  79. package/src/utils/mssql.ts +420 -0
  80. package/src/utils/schema.ts +172 -0
  81. package/test/src/CDCStream.test.ts +206 -0
  82. package/test/src/CDCStreamTestContext.ts +212 -0
  83. package/test/src/CDCStream_resumable_snapshot.test.ts +152 -0
  84. package/test/src/env.ts +11 -0
  85. package/test/src/mssql-to-sqlite.test.ts +474 -0
  86. package/test/src/setup.ts +12 -0
  87. package/test/src/util.ts +189 -0
  88. package/test/tsconfig.json +28 -0
  89. package/test/tsconfig.tsbuildinfo +1 -0
  90. package/tsconfig.json +26 -0
  91. package/tsconfig.tsbuildinfo +1 -0
  92. package/vitest.config.ts +15 -0
@@ -0,0 +1,329 @@
1
+ import sql from 'mssql';
2
+ import { coerce, gte } from 'semver';
3
+ import { logger } from '@powersync/lib-services-framework';
4
+ import { LSN } from '../common/LSN.js';
5
+ import { getReplicationIdentityColumns } from './schema.js';
6
+ export const POWERSYNC_CHECKPOINTS_TABLE = '_powersync_checkpoints';
7
+ export const SUPPORTED_ENGINE_EDITIONS = new Map([
8
+ [2, 'Standard'],
9
+ [3, 'Enterprise - Enterprise, Developer, Evaluation'],
10
+ [5, 'SqlDatabase - Azure SQL Database'],
11
+ [8, 'SqlManagedInstance - Azure SQL Managed Instance']
12
+ ]);
13
+ // SQL Server 2022 and newer
14
+ export const MINIMUM_SUPPORTED_VERSION = '16.0';
15
+ export async function checkSourceConfiguration(connectionManager) {
16
+ const errors = [];
17
+ // 1) Check MSSQL version and Editions
18
+ const { recordset: versionResult } = await connectionManager.query(`
19
+ SELECT
20
+ CAST(SERVERPROPERTY('EngineEdition') AS int) AS engine,
21
+ CAST(SERVERPROPERTY('Edition') AS nvarchar(128)) AS edition,
22
+ CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)) AS version
23
+ `);
24
+ // If the edition is unsupported, return immediately
25
+ if (!SUPPORTED_ENGINE_EDITIONS.has(versionResult[0]?.engine)) {
26
+ errors.push(`The SQL Server edition '${versionResult[0]?.edition}' is not supported. PowerSync requires a MSSQL edition that supports CDC: ${Array.from(SUPPORTED_ENGINE_EDITIONS.values()).join(', ')}.`);
27
+ return errors;
28
+ }
29
+ // Only applicable to SQL Server stand-alone editions
30
+ if (versionResult[0]?.engine == 2 || versionResult[0]?.engine == 3) {
31
+ if (!isVersionAtLeast(versionResult[0]?.version, MINIMUM_SUPPORTED_VERSION)) {
32
+ errors.push(`The SQL Server version '${versionResult[0]?.version}' is not supported. PowerSync requires MSSQL 2022 (v16) or newer.`);
33
+ }
34
+ }
35
+ // 2) Check DB-level CDC
36
+ const { recordset: cdcEnabledResult } = await connectionManager.query(`
37
+ SELECT name AS db_name, is_cdc_enabled FROM sys.databases WHERE name = DB_NAME();
38
+ `);
39
+ const cdcEnabled = cdcEnabledResult[0]?.is_cdc_enabled;
40
+ if (!cdcEnabled) {
41
+ errors.push(`CDC is not enabled for database. Please enable it.`);
42
+ }
43
+ // 3) Check CDC user permissions
44
+ const { recordset: cdcUserResult } = await connectionManager.query(`
45
+ SELECT
46
+ CASE
47
+ WHEN IS_SRVROLEMEMBER('sysadmin') = 1
48
+ OR IS_MEMBER('db_owner') = 1
49
+ OR IS_MEMBER('cdc_admin') = 1
50
+ OR IS_MEMBER('cdc_reader') = 1
51
+ THEN 1 ELSE 0
52
+ END AS has_cdc_access;
53
+ `);
54
+ if (!cdcUserResult[0]?.has_cdc_access) {
55
+ errors.push(`The current user does not have the 'cdc_reader' role. Please assign this role to the user.`);
56
+ }
57
+ // 4) Check if the _powersync_checkpoints table is correctly configured
58
+ const checkpointTableErrors = await ensurePowerSyncCheckpointsTable(connectionManager);
59
+ errors.push(...checkpointTableErrors);
60
+ return errors;
61
+ }
62
+ export async function ensurePowerSyncCheckpointsTable(connectionManager) {
63
+ const errors = [];
64
+ try {
65
+ // check if the dbo_powersync_checkpoints table exists
66
+ const { recordset: checkpointsResult } = await connectionManager.query(`
67
+ SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${connectionManager.schema}' AND TABLE_NAME = '${POWERSYNC_CHECKPOINTS_TABLE}';
68
+ `);
69
+ if (checkpointsResult.length > 0) {
70
+ // Table already exists, check if CDC is enabled
71
+ const isEnabled = await isTableEnabledForCDC({
72
+ connectionManager,
73
+ table: POWERSYNC_CHECKPOINTS_TABLE,
74
+ schema: connectionManager.schema
75
+ });
76
+ if (!isEnabled) {
77
+ // Enable CDC on the table
78
+ await enableCDCForTable({
79
+ connectionManager,
80
+ table: POWERSYNC_CHECKPOINTS_TABLE
81
+ });
82
+ }
83
+ return errors;
84
+ }
85
+ }
86
+ catch (error) {
87
+ errors.push(`Failed ensure ${POWERSYNC_CHECKPOINTS_TABLE} table is correctly configured: ${error}`);
88
+ }
89
+ // Try to create the table
90
+ try {
91
+ await connectionManager.query(`
92
+ CREATE TABLE ${connectionManager.schema}.${POWERSYNC_CHECKPOINTS_TABLE} (
93
+ id INT IDENTITY PRIMARY KEY,
94
+ last_updated DATETIME NOT NULL DEFAULT (GETDATE())
95
+ )`);
96
+ }
97
+ catch (error) {
98
+ errors.push(`Failed to create ${POWERSYNC_CHECKPOINTS_TABLE} table: ${error}`);
99
+ }
100
+ try {
101
+ // Enable CDC on the table if not already enabled
102
+ await enableCDCForTable({
103
+ connectionManager,
104
+ table: POWERSYNC_CHECKPOINTS_TABLE
105
+ });
106
+ }
107
+ catch (error) {
108
+ errors.push(`Failed to enable CDC on ${POWERSYNC_CHECKPOINTS_TABLE} table: ${error}`);
109
+ }
110
+ return errors;
111
+ }
112
+ export async function createCheckpoint(connectionManager) {
113
+ await connectionManager.query(`
114
+ MERGE ${connectionManager.schema}.${POWERSYNC_CHECKPOINTS_TABLE} AS target
115
+ USING (SELECT 1 AS id) AS source
116
+ ON target.id = source.id
117
+ WHEN MATCHED THEN
118
+ UPDATE SET last_updated = GETDATE()
119
+ WHEN NOT MATCHED THEN
120
+ INSERT (last_updated) VALUES (GETDATE());
121
+ `);
122
+ }
123
+ /**
124
+ * Check if the specified table is enabled for CDC.
125
+ * @param options
126
+ */
127
+ export async function isTableEnabledForCDC(options) {
128
+ const { connectionManager, table, schema } = options;
129
+ const { recordset: checkResult } = await connectionManager.query(`
130
+ SELECT 1 FROM cdc.change_tables ct
131
+ JOIN sys.tables AS tbl ON tbl.object_id = ct.source_object_id
132
+ JOIN sys.schemas AS sch ON sch.schema_id = tbl.schema_id
133
+ WHERE sch.name = '${schema}'
134
+ AND tbl.name = '${table}'
135
+ `);
136
+ return checkResult.length > 0;
137
+ }
138
+ export async function enableCDCForTable(options) {
139
+ const { connectionManager, table } = options;
140
+ await connectionManager.execute('sys.sp_cdc_enable_table', [
141
+ { name: 'source_schema', value: connectionManager.schema },
142
+ { name: 'source_name', value: table },
143
+ { name: 'role_name', value: 'NULL' },
144
+ { name: 'supports_net_changes', value: 1 }
145
+ ]);
146
+ }
147
+ /**
148
+ * Check if the supplied version is newer or equal to the target version.
149
+ * @param version
150
+ * @param minimumVersion
151
+ */
152
+ export function isVersionAtLeast(version, minimumVersion) {
153
+ const coercedVersion = coerce(version);
154
+ const coercedMinimumVersion = coerce(minimumVersion);
155
+ return gte(coercedVersion, coercedMinimumVersion, { loose: true });
156
+ }
157
+ /**
158
+ * Checks that CDC the specified checkpoint LSN is within the retention threshold for all specified tables.
159
+ * CDC periodically cleans up old data up to the retention threshold. If replication has been stopped for too long it is
160
+ * possible for the checkpoint LSN to be older than the minimum LSN in the CDC tables. In such a case we need to perform a new snapshot.
161
+ * @param options
162
+ */
163
+ export async function isWithinRetentionThreshold(options) {
164
+ const { checkpointLSN, tables, connectionManager } = options;
165
+ for (const table of tables) {
166
+ const minLSN = await getMinLSN(connectionManager, table.captureInstance);
167
+ if (minLSN > checkpointLSN) {
168
+ logger.warn(`The checkpoint LSN:[${checkpointLSN}] is older than the minimum LSN:[${minLSN}] for table ${table.sourceTable.qualifiedName}. This indicates that the checkpoint LSN is outside of the retention window.`);
169
+ return false;
170
+ }
171
+ }
172
+ return true;
173
+ }
174
+ export async function getMinLSN(connectionManager, captureInstance) {
175
+ const { recordset: result } = await connectionManager.query(`SELECT sys.fn_cdc_get_min_lsn('${captureInstance}') AS min_lsn`);
176
+ const rawMinLSN = result[0].min_lsn;
177
+ return LSN.fromBinary(rawMinLSN);
178
+ }
179
+ export async function incrementLSN(lsn, connectionManager) {
180
+ const { recordset: result } = await connectionManager.query(`SELECT sys.fn_cdc_increment_lsn(@lsn) AS incremented_lsn`, [{ name: 'lsn', type: sql.VarBinary, value: lsn.toBinary() }]);
181
+ return LSN.fromBinary(result[0].incremented_lsn);
182
+ }
183
+ export async function getCaptureInstance(options) {
184
+ const { connectionManager, tableName, schema } = options;
185
+ const { recordset: result } = await connectionManager.query(`
186
+ SELECT
187
+ ct.capture_instance,
188
+ OBJECT_SCHEMA_NAME(ct.[object_id]) AS cdc_schema
189
+ FROM
190
+ sys.tables tbl
191
+ INNER JOIN sys.schemas sch ON tbl.schema_id = sch.schema_id
192
+ INNER JOIN cdc.change_tables ct ON ct.source_object_id = tbl.object_id
193
+ WHERE sch.name = '${schema}'
194
+ AND tbl.name = '${tableName}'
195
+ AND ct.end_lsn IS NULL;
196
+ `);
197
+ if (result.length === 0) {
198
+ return null;
199
+ }
200
+ return {
201
+ name: result[0].capture_instance,
202
+ schema: result[0].cdc_schema
203
+ };
204
+ }
205
+ /**
206
+ * Return the LSN of the latest transaction recorded in the transaction log
207
+ * @param connectionManager
208
+ */
209
+ export async function getLatestLSN(connectionManager) {
210
+ const { recordset: result } = await connectionManager.query('SELECT log_end_lsn FROM sys.dm_db_log_stats(DB_ID()) AS log_end_lsn');
211
+ return LSN.fromString(result[0].log_end_lsn);
212
+ }
213
+ /**
214
+ * Return the LSN of the lastest transaction replicated to the CDC tables.
215
+ * @param connectionManager
216
+ */
217
+ export async function getLatestReplicatedLSN(connectionManager) {
218
+ const { recordset: result } = await connectionManager.query('SELECT sys.fn_cdc_get_max_lsn() AS max_lsn;');
219
+ // LSN is a binary(10) returned as a Buffer
220
+ const rawLSN = result[0].max_lsn;
221
+ return LSN.fromBinary(rawLSN);
222
+ }
223
+ /**
224
+ * Escapes an identifier for use in MSSQL queries.
225
+ * @param identifier
226
+ */
227
+ export function escapeIdentifier(identifier) {
228
+ return `[${identifier}]`;
229
+ }
230
+ export function toQualifiedTableName(schema, tableName) {
231
+ return `${escapeIdentifier(schema)}.${escapeIdentifier(tableName)}`;
232
+ }
233
+ export function isIColumnMetadata(obj) {
234
+ if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
235
+ return false;
236
+ }
237
+ let propertiesMatched = true;
238
+ for (const value of Object.values(obj)) {
239
+ const property = value;
240
+ propertiesMatched =
241
+ typeof property.index === 'number' &&
242
+ typeof property.name === 'string' &&
243
+ typeof property.length === 'number' &&
244
+ (typeof property.type === 'function' || typeof property.type === 'object') &&
245
+ typeof property.nullable === 'boolean' &&
246
+ typeof property.caseSensitive === 'boolean' &&
247
+ typeof property.identity === 'boolean' &&
248
+ typeof property.readOnly === 'boolean';
249
+ }
250
+ return propertiesMatched;
251
+ }
252
+ export function addParameters(request, parameters) {
253
+ for (const param of parameters) {
254
+ if (param.type) {
255
+ request.input(param.name, param.type, param.value);
256
+ }
257
+ else {
258
+ request.input(param.name, param.value);
259
+ }
260
+ }
261
+ return request;
262
+ }
263
+ export async function getDebugTableInfo(options) {
264
+ const { connectionManager, tablePattern, table, syncRules } = options;
265
+ const { schema } = tablePattern;
266
+ let idColumnsResult = null;
267
+ let idColumnsError = null;
268
+ try {
269
+ idColumnsResult = await getReplicationIdentityColumns({
270
+ connectionManager: connectionManager,
271
+ schema,
272
+ tableName: table.name
273
+ });
274
+ }
275
+ catch (ex) {
276
+ idColumnsError = { level: 'fatal', message: ex.message };
277
+ }
278
+ const idColumns = idColumnsResult?.columns ?? [];
279
+ const sourceTable = {
280
+ connectionTag: connectionManager.connectionTag,
281
+ schema: schema,
282
+ name: table.name
283
+ };
284
+ const syncData = syncRules.tableSyncsData(sourceTable);
285
+ const syncParameters = syncRules.tableSyncsParameters(sourceTable);
286
+ if (idColumns.length === 0 && idColumnsError == null) {
287
+ let message = `No replication id found for ${toQualifiedTableName(schema, table.name)}. Replica identity: ${idColumnsResult?.identity}.`;
288
+ if (idColumnsResult?.identity === 'default') {
289
+ message += ' Configure a primary key on the table.';
290
+ }
291
+ idColumnsError = { level: 'fatal', message };
292
+ }
293
+ let selectError = null;
294
+ try {
295
+ await connectionManager.query(`SELECT TOP 1 * FROM [${toQualifiedTableName(schema, table.name)}]`);
296
+ }
297
+ catch (e) {
298
+ selectError = { level: 'fatal', message: e.message };
299
+ }
300
+ // Check if CDC is enabled for the table
301
+ let cdcError = null;
302
+ try {
303
+ const isEnabled = await isTableEnabledForCDC({
304
+ connectionManager: connectionManager,
305
+ table: table.name,
306
+ schema: schema
307
+ });
308
+ if (!isEnabled) {
309
+ cdcError = {
310
+ level: 'fatal',
311
+ message: `CDC is not enabled for table ${toQualifiedTableName(schema, table.name)}. Enable CDC with: sys.sp_cdc_enable_table @source_schema = '${schema}', @source_name = '${table.name}', @role_name = NULL, @supports_net_changes = 1`
312
+ };
313
+ }
314
+ }
315
+ catch (e) {
316
+ cdcError = { level: 'warning', message: `Could not check CDC status: ${e.message}` };
317
+ }
318
+ // TODO check RLS settings for table
319
+ return {
320
+ schema: schema,
321
+ name: table.name,
322
+ pattern: tablePattern.isWildcard ? tablePattern.tablePattern : undefined,
323
+ replication_id: idColumns.map((c) => c.name),
324
+ data_queries: syncData,
325
+ parameter_queries: syncParameters,
326
+ errors: [idColumnsError, selectError, cdcError].filter((error) => error != null)
327
+ };
328
+ }
329
+ //# sourceMappingURL=mssql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mssql.js","sourceRoot":"","sources":["../../src/utils/mssql.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,OAAO,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAE3D,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAIvC,OAAO,EAAE,6BAA6B,EAAmD,MAAM,aAAa,CAAC;AAI7G,MAAM,CAAC,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AAEpE,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,GAAG,CAAC;IAC/C,CAAC,CAAC,EAAE,UAAU,CAAC;IACf,CAAC,CAAC,EAAE,gDAAgD,CAAC;IACrD,CAAC,CAAC,EAAE,kCAAkC,CAAC;IACvC,CAAC,CAAC,EAAE,iDAAiD,CAAC;CACvD,CAAC,CAAC;AAEH,4BAA4B;AAC5B,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,iBAAyC;IACtF,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,sCAAsC;IACtC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC;;;;;KAKhE,CAAC,CAAC;IAEL,oDAAoD;IACpD,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;QAC7D,MAAM,CAAC,IAAI,CACT,2BAA2B,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,6EAA6E,KAAK,CAAC,IAAI,CACzI,yBAAyB,CAAC,MAAM,EAAE,CACnC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAChB,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,qDAAqD;IACrD,IAAI,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,CAAC;QACnE,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,yBAAyB,CAAC,EAAE,CAAC;YAC5E,MAAM,CAAC,IAAI,CACT,2BAA2B,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,mEAAmE,CACxH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC;;KAEnE,CAAC,CAAC;IACL,MAAM,UAAU,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC;IAEvD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;IACpE,CAAC;IAED,gCAAgC;IAChC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC;;;;;;;;;KAShE,CAAC,CAAC;IAEL,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,4FAA4F,CAAC,CAAC;IAC5G,CAAC;IAED,uEAAuE;IACvE,MAAM,qBAAqB,GAAG,MAAM,+BAA+B,CAAC,iBAAiB,CAAC,CAAC;IACvF,MAAM,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC,CAAC;IAEtC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,iBAAyC;IAC7F,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,CAAC;QACH,sDAAsD;QACtD,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC;oEACP,iBAAiB,CAAC,MAAM,uBAAuB,2BAA2B;GAC3I,CAAC,CAAC;QACD,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,gDAAgD;YAChD,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC;gBAC3C,iBAAiB;gBACjB,KAAK,EAAE,2BAA2B;gBAClC,MAAM,EAAE,iBAAiB,CAAC,MAAM;aACjC,CAAC,CAAC;YACH,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,0BAA0B;gBAC1B,MAAM,iBAAiB,CAAC;oBACtB,iBAAiB;oBACjB,KAAK,EAAE,2BAA2B;iBACnC,CAAC,CAAC;YACL,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,iBAAiB,2BAA2B,mCAAmC,KAAK,EAAE,CAAC,CAAC;IACtG,CAAC;IAED,0BAA0B;IAC1B,IAAI,CAAC;QACH,MAAM,iBAAiB,CAAC,KAAK,CAAC;iBACjB,iBAAiB,CAAC,MAAM,IAAI,2BAA2B;;;IAGpE,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,oBAAoB,2BAA2B,WAAW,KAAK,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,CAAC;QACH,iDAAiD;QACjD,MAAM,iBAAiB,CAAC;YACtB,iBAAiB;YACjB,KAAK,EAAE,2BAA2B;SACnC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,2BAA2B,2BAA2B,WAAW,KAAK,EAAE,CAAC,CAAC;IACxF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,iBAAyC;IAC9E,MAAM,iBAAiB,CAAC,KAAK,CAAC;YACpB,iBAAiB,CAAC,MAAM,IAAI,2BAA2B;;;;;;;GAOhE,CAAC,CAAC;AACL,CAAC;AAOD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAoC;IAC7E,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAErD,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAC9D;;;;0BAIsB,MAAM;0BACN,KAAK;OACxB,CACJ,CAAC;IACF,OAAO,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;AAChC,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAiC;IACvE,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAE7C,MAAM,iBAAiB,CAAC,OAAO,CAAC,yBAAyB,EAAE;QACzD,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,iBAAiB,CAAC,MAAM,EAAE;QAC1D,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE;QACrC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE;QACpC,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE;KAC3C,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,cAAsB;IACtE,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,qBAAqB,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAErD,OAAO,GAAG,CAAC,cAAe,EAAE,qBAAsB,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACvE,CAAC;AAQD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,OAA0C;IACzF,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;IAC7D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,iBAAiB,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;QACzE,IAAI,MAAM,GAAG,aAAa,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CACT,uBAAuB,aAAa,oCAAoC,MAAM,eAAe,KAAK,CAAC,WAAW,CAAC,aAAa,8EAA8E,CAC3M,CAAC;YACF,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,iBAAyC,EAAE,eAAuB;IAChG,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CACzD,kCAAkC,eAAe,eAAe,CACjE,CAAC;IACF,MAAM,SAAS,GAAW,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC5C,OAAO,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAQ,EAAE,iBAAyC;IACpF,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CACzD,0DAA0D,EAC1D,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAC9D,CAAC;IACF,OAAO,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;AACnD,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAkC;IACzE,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACzD,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CACzD;;;;;;;;0BAQsB,MAAM;0BACN,SAAS;;OAE5B,CACJ,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,gBAAgB;QAChC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU;KAC7B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,iBAAyC;IAC1E,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CACzD,qEAAqE,CACtE,CAAC;IACF,OAAO,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,iBAAyC;IACpF,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC3G,2CAA2C;IAC3C,MAAM,MAAM,GAAW,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACzC,OAAO,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,OAAO,IAAI,UAAU,GAAG,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,SAAiB;IACpE,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAQ;IACxC,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,iBAAiB,GAAG,IAAI,CAAC;IAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,KAAY,CAAC;QAC9B,iBAAiB;YACf,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ;gBAClC,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;gBACjC,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ;gBACnC,CAAC,OAAO,QAAQ,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC;gBAC1E,OAAO,QAAQ,CAAC,QAAQ,KAAK,SAAS;gBACtC,OAAO,QAAQ,CAAC,aAAa,KAAK,SAAS;gBAC3C,OAAO,QAAQ,CAAC,QAAQ,KAAK,SAAS;gBACtC,OAAO,QAAQ,CAAC,QAAQ,KAAK,SAAS,CAAC;IAC3C,CAAC;IAED,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAoB,EAAE,UAA4B;IAC9E,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AASD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAiC;IACvE,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IACtE,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC;IAEhC,IAAI,eAAe,GAA4C,IAAI,CAAC;IACpE,IAAI,cAAc,GAA0C,IAAI,CAAC;IACjE,IAAI,CAAC;QACH,eAAe,GAAG,MAAM,6BAA6B,CAAC;YACpD,iBAAiB,EAAE,iBAAiB;YACpC,MAAM;YACN,SAAS,EAAE,KAAK,CAAC,IAAI;SACtB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACZ,cAAc,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC;IAC3D,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,EAAE,OAAO,IAAI,EAAE,CAAC;IACjD,MAAM,WAAW,GAAoC;QACnD,aAAa,EAAE,iBAAiB,CAAC,aAAa;QAC9C,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;IACF,MAAM,QAAQ,GAAG,SAAS,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,SAAS,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAEnE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,IAAI,IAAI,EAAE,CAAC;QACrD,IAAI,OAAO,GAAG,+BAA+B,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,uBAAuB,eAAe,EAAE,QAAQ,GAAG,CAAC;QACzI,IAAI,eAAe,EAAE,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC5C,OAAO,IAAI,wCAAwC,CAAC;QACtD,CAAC;QACD,cAAc,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC/C,CAAC;IAED,IAAI,WAAW,GAA0C,IAAI,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,iBAAiB,CAAC,KAAK,CAAC,wBAAwB,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrG,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,WAAW,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IACvD,CAAC;IAED,wCAAwC;IACxC,IAAI,QAAQ,GAA0C,IAAI,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC;YAC3C,iBAAiB,EAAE,iBAAiB;YACpC,KAAK,EAAE,KAAK,CAAC,IAAI;YACjB,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,QAAQ,GAAG;gBACT,KAAK,EAAE,OAAO;gBACd,OAAO,EAAE,gCAAgC,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,gEAAgE,MAAM,sBAAsB,KAAK,CAAC,IAAI,iDAAiD;aACzO,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,+BAA+B,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;IACvF,CAAC;IAED,oCAAoC;IAEpC,OAAO;QACL,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS;QACxE,cAAc,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5C,YAAY,EAAE,QAAQ;QACtB,iBAAiB,EAAE,cAAc;QACjC,MAAM,EAAE,CAAC,cAAc,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAqC;KACrH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { SourceEntityDescriptor } from '@powersync/service-core';
2
+ import { TablePattern } from '@powersync/service-sync-rules';
3
+ import { MSSQLConnectionManager } from '../replication/MSSQLConnectionManager.js';
4
+ import { MSSQLColumnDescriptor } from '../types/mssql-data-types.js';
5
+ export interface GetColumnsOptions {
6
+ connectionManager: MSSQLConnectionManager;
7
+ schema: string;
8
+ tableName: string;
9
+ }
10
+ export interface GetReplicationIdentityColumnsOptions {
11
+ connectionManager: MSSQLConnectionManager;
12
+ schema: string;
13
+ tableName: string;
14
+ }
15
+ export interface ReplicationIdentityColumnsResult {
16
+ columns: MSSQLColumnDescriptor[];
17
+ identity: 'default' | 'nothing' | 'full' | 'index';
18
+ }
19
+ export declare function getReplicationIdentityColumns(options: GetReplicationIdentityColumnsOptions): Promise<ReplicationIdentityColumnsResult>;
20
+ export type ResolvedTable = Omit<SourceEntityDescriptor, 'replicaIdColumns'>;
21
+ export declare function getTablesFromPattern(connectionManager: MSSQLConnectionManager, tablePattern: TablePattern): Promise<ResolvedTable[]>;
@@ -0,0 +1,131 @@
1
+ async function getColumns(options) {
2
+ const { connectionManager, schema, tableName } = options;
3
+ const { recordset: columnResults } = await connectionManager.query(`
4
+ SELECT
5
+ col.name AS [name],
6
+ typ.name AS [type],
7
+ typ.system_type_id AS type_id,
8
+ typ.user_type_id AS user_type_id
9
+ FROM sys.columns AS col
10
+ JOIN sys.tables AS tbl ON tbl.object_id = col.object_id
11
+ JOIN sys.schemas AS sch ON sch.schema_id = tbl.schema_id
12
+ JOIN sys.types AS typ ON typ.user_type_id = col.user_type_id
13
+ WHERE sch.name = '${schema}'
14
+ AND tbl.name = '${tableName}'
15
+ ORDER BY col.column_id;
16
+ `);
17
+ return columnResults.map((row) => {
18
+ return {
19
+ name: row.name,
20
+ type: row.type,
21
+ typeId: row.type_id,
22
+ userTypeId: row.user_type_id
23
+ };
24
+ });
25
+ }
26
+ export async function getReplicationIdentityColumns(options) {
27
+ const { connectionManager, schema, tableName } = options;
28
+ const { recordset: primaryKeyColumns } = await connectionManager.query(`
29
+ SELECT
30
+ col.name AS [name],
31
+ typ.name AS [type],
32
+ typ.system_type_id AS type_id,
33
+ typ.user_type_id AS user_type_id
34
+ FROM sys.tables AS tbl
35
+ JOIN sys.schemas AS sch ON sch.schema_id = tbl.schema_id
36
+ JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id AND idx.is_primary_key = 1
37
+ JOIN sys.index_columns AS idx_col ON idx_col.object_id = idx.object_id AND idx_col.index_id = idx.index_id
38
+ JOIN sys.columns AS col ON col.object_id = idx_col.object_id AND col.column_id = idx_col.column_id
39
+ JOIN sys.types AS typ ON typ.user_type_id = col.user_type_id
40
+ WHERE sch.name = '${schema}'
41
+ AND tbl.name = '${tableName}'
42
+ ORDER BY idx_col.key_ordinal;
43
+ `);
44
+ if (primaryKeyColumns.length > 0) {
45
+ return {
46
+ columns: primaryKeyColumns.map((row) => ({
47
+ name: row.name,
48
+ type: row.type,
49
+ typeId: row.type_id,
50
+ userTypeId: row.user_type_id
51
+ })),
52
+ identity: 'default'
53
+ };
54
+ }
55
+ // No primary key, check if any of the columns have a unique constraint we can use
56
+ const { recordset: uniqueKeyColumns } = await connectionManager.query(`
57
+ SELECT
58
+ col.name AS [name],
59
+ typ.name AS [type],
60
+ typ.system_type_id AS type_id,
61
+ typ.user_type_id AS user_type_id
62
+ FROM sys.tables AS tbl
63
+ JOIN sys.schemas AS sch ON sch.schema_id = tbl.schema_id
64
+ JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id AND idx.is_unique_constraint = 1
65
+ JOIN sys.index_columns AS idx_col ON idx_col.object_id = idx.object_id AND idx_col.index_id = idx.index_id
66
+ JOIN sys.columns AS col ON col.object_id = idx_col.object_id AND col.column_id = idx_col.column_id
67
+ JOIN sys.types AS typ ON typ.user_type_id = col.user_type_id
68
+ WHERE sch.name = '${schema}'
69
+ AND tbl.name = '${tableName}'
70
+ ORDER BY idx_col.key_ordinal;
71
+ `);
72
+ if (uniqueKeyColumns.length > 0) {
73
+ return {
74
+ columns: uniqueKeyColumns.map((row) => ({
75
+ name: row.name,
76
+ type: row.type,
77
+ typeId: row.type_id,
78
+ userTypeId: row.user_type_id
79
+ })),
80
+ identity: 'index'
81
+ };
82
+ }
83
+ const allColumns = await getColumns(options);
84
+ return {
85
+ columns: allColumns,
86
+ identity: 'full'
87
+ };
88
+ }
89
+ export async function getTablesFromPattern(connectionManager, tablePattern) {
90
+ if (tablePattern.isWildcard) {
91
+ const { recordset: tableResults } = await connectionManager.query(`
92
+ SELECT
93
+ tbl.name AS [table],
94
+ sch.name AS [schema],
95
+ tbl.object_id AS object_id
96
+ FROM sys.tables tbl
97
+ JOIN sys.schemas sch ON tbl.schema_id = sch.schema_id
98
+ WHERE sch.name = '${tablePattern.schema}'
99
+ AND tbl.name LIKE '${tablePattern.tablePattern}'
100
+ `);
101
+ return tableResults
102
+ .map((row) => {
103
+ return {
104
+ objectId: row.object_id,
105
+ schema: row.schema,
106
+ name: row.table
107
+ };
108
+ })
109
+ .filter((table) => table.name.startsWith(tablePattern.tablePrefix));
110
+ }
111
+ else {
112
+ const { recordset: tableResults } = await connectionManager.query(`
113
+ SELECT
114
+ tbl.name AS [table],
115
+ sch.name AS [schema],
116
+ tbl.object_id AS object_id
117
+ FROM sys.tables tbl
118
+ JOIN sys.schemas sch ON tbl.schema_id = sch.schema_id
119
+ WHERE sch.name = '${tablePattern.schema}'
120
+ AND tbl.name = '${tablePattern.name}'
121
+ `);
122
+ return tableResults.map((row) => {
123
+ return {
124
+ objectId: row.object_id,
125
+ schema: row.schema,
126
+ name: row.table
127
+ };
128
+ });
129
+ }
130
+ }
131
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/utils/schema.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@powersync/service-module-mssql",
3
+ "repository": "https://github.com/powersync-ja/powersync-service",
4
+ "types": "dist/index.d.ts",
5
+ "version": "0.0.1",
6
+ "license": "FSL-1.1-ALv2",
7
+ "main": "dist/index.js",
8
+ "type": "module",
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.js",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "./types": {
19
+ "import": "./dist/types/types.js",
20
+ "require": "./dist/types/types.js",
21
+ "default": "./dist/types/types.js"
22
+ }
23
+ },
24
+ "dependencies": {
25
+ "mssql": "^12.1.1",
26
+ "semver": "^7.7.2",
27
+ "ts-codec": "^1.3.0",
28
+ "uri-js": "^4.4.1",
29
+ "uuid": "^11.1.0",
30
+ "@powersync/service-sync-rules": "0.29.7",
31
+ "@powersync/service-jsonbig": "0.17.12",
32
+ "@powersync/lib-services-framework": "0.7.10",
33
+ "@powersync/service-errors": "0.3.5",
34
+ "@powersync/service-core": "1.16.3",
35
+ "@powersync/service-types": "0.13.1"
36
+ },
37
+ "devDependencies": {
38
+ "@types/mssql": "^9.1.8",
39
+ "@types/semver": "^7.7.1",
40
+ "@types/uuid": "^10.0.0",
41
+ "@powersync/service-module-postgres-storage": "0.10.12",
42
+ "@powersync/service-module-mongodb-storage": "0.12.12",
43
+ "@powersync/service-core-tests": "0.12.12"
44
+ },
45
+ "scripts": {
46
+ "build": "tsc -b",
47
+ "build:tests": "tsc -b test/tsconfig.json",
48
+ "clean": "rm -rf ./dist && tsc -b --clean",
49
+ "test": "vitest"
50
+ }
51
+ }