@powersync/service-module-mysql 0.0.0-dev-20241015210820

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 (96) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/LICENSE +67 -0
  3. package/README.md +3 -0
  4. package/dev/.env.template +2 -0
  5. package/dev/README.md +9 -0
  6. package/dev/config/sync_rules.yaml +12 -0
  7. package/dev/docker/mysql/docker-compose.yaml +17 -0
  8. package/dev/docker/mysql/init-scripts/my.cnf +9 -0
  9. package/dev/docker/mysql/init-scripts/mysql.sql +38 -0
  10. package/dist/api/MySQLRouteAPIAdapter.d.ts +24 -0
  11. package/dist/api/MySQLRouteAPIAdapter.js +311 -0
  12. package/dist/api/MySQLRouteAPIAdapter.js.map +1 -0
  13. package/dist/common/ReplicatedGTID.d.ts +59 -0
  14. package/dist/common/ReplicatedGTID.js +110 -0
  15. package/dist/common/ReplicatedGTID.js.map +1 -0
  16. package/dist/common/check-source-configuration.d.ts +3 -0
  17. package/dist/common/check-source-configuration.js +46 -0
  18. package/dist/common/check-source-configuration.js.map +1 -0
  19. package/dist/common/common-index.d.ts +6 -0
  20. package/dist/common/common-index.js +7 -0
  21. package/dist/common/common-index.js.map +1 -0
  22. package/dist/common/get-replication-columns.d.ts +12 -0
  23. package/dist/common/get-replication-columns.js +103 -0
  24. package/dist/common/get-replication-columns.js.map +1 -0
  25. package/dist/common/get-tables-from-pattern.d.ts +7 -0
  26. package/dist/common/get-tables-from-pattern.js +28 -0
  27. package/dist/common/get-tables-from-pattern.js.map +1 -0
  28. package/dist/common/mysql-to-sqlite.d.ts +4 -0
  29. package/dist/common/mysql-to-sqlite.js +56 -0
  30. package/dist/common/mysql-to-sqlite.js.map +1 -0
  31. package/dist/common/read-executed-gtid.d.ts +6 -0
  32. package/dist/common/read-executed-gtid.js +40 -0
  33. package/dist/common/read-executed-gtid.js.map +1 -0
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.js +4 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/module/MySQLModule.d.ts +13 -0
  38. package/dist/module/MySQLModule.js +46 -0
  39. package/dist/module/MySQLModule.js.map +1 -0
  40. package/dist/replication/BinLogReplicationJob.d.ts +14 -0
  41. package/dist/replication/BinLogReplicationJob.js +88 -0
  42. package/dist/replication/BinLogReplicationJob.js.map +1 -0
  43. package/dist/replication/BinLogReplicator.d.ts +13 -0
  44. package/dist/replication/BinLogReplicator.js +25 -0
  45. package/dist/replication/BinLogReplicator.js.map +1 -0
  46. package/dist/replication/BinLogStream.d.ts +43 -0
  47. package/dist/replication/BinLogStream.js +421 -0
  48. package/dist/replication/BinLogStream.js.map +1 -0
  49. package/dist/replication/MySQLConnectionManager.d.ts +43 -0
  50. package/dist/replication/MySQLConnectionManager.js +81 -0
  51. package/dist/replication/MySQLConnectionManager.js.map +1 -0
  52. package/dist/replication/MySQLConnectionManagerFactory.d.ts +10 -0
  53. package/dist/replication/MySQLConnectionManagerFactory.js +21 -0
  54. package/dist/replication/MySQLConnectionManagerFactory.js.map +1 -0
  55. package/dist/replication/MySQLErrorRateLimiter.d.ts +10 -0
  56. package/dist/replication/MySQLErrorRateLimiter.js +43 -0
  57. package/dist/replication/MySQLErrorRateLimiter.js.map +1 -0
  58. package/dist/replication/zongji/zongji-utils.d.ts +7 -0
  59. package/dist/replication/zongji/zongji-utils.js +19 -0
  60. package/dist/replication/zongji/zongji-utils.js.map +1 -0
  61. package/dist/types/types.d.ts +50 -0
  62. package/dist/types/types.js +61 -0
  63. package/dist/types/types.js.map +1 -0
  64. package/dist/utils/mysql_utils.d.ts +14 -0
  65. package/dist/utils/mysql_utils.js +38 -0
  66. package/dist/utils/mysql_utils.js.map +1 -0
  67. package/package.json +51 -0
  68. package/src/api/MySQLRouteAPIAdapter.ts +357 -0
  69. package/src/common/ReplicatedGTID.ts +158 -0
  70. package/src/common/check-source-configuration.ts +59 -0
  71. package/src/common/common-index.ts +6 -0
  72. package/src/common/get-replication-columns.ts +124 -0
  73. package/src/common/get-tables-from-pattern.ts +44 -0
  74. package/src/common/mysql-to-sqlite.ts +59 -0
  75. package/src/common/read-executed-gtid.ts +43 -0
  76. package/src/index.ts +5 -0
  77. package/src/module/MySQLModule.ts +53 -0
  78. package/src/replication/BinLogReplicationJob.ts +97 -0
  79. package/src/replication/BinLogReplicator.ts +35 -0
  80. package/src/replication/BinLogStream.ts +547 -0
  81. package/src/replication/MySQLConnectionManager.ts +104 -0
  82. package/src/replication/MySQLConnectionManagerFactory.ts +28 -0
  83. package/src/replication/MySQLErrorRateLimiter.ts +44 -0
  84. package/src/replication/zongji/zongji-utils.ts +32 -0
  85. package/src/replication/zongji/zongji.d.ts +98 -0
  86. package/src/types/types.ts +102 -0
  87. package/src/utils/mysql_utils.ts +47 -0
  88. package/test/src/binlog_stream.test.ts +288 -0
  89. package/test/src/binlog_stream_utils.ts +152 -0
  90. package/test/src/env.ts +7 -0
  91. package/test/src/setup.ts +7 -0
  92. package/test/src/util.ts +62 -0
  93. package/test/tsconfig.json +28 -0
  94. package/tsconfig.json +26 -0
  95. package/tsconfig.tsbuildinfo +1 -0
  96. package/vitest.config.ts +15 -0
@@ -0,0 +1,110 @@
1
+ import * as uuid from 'uuid';
2
+ import * as mysql_utils from '../utils/mysql_utils.js';
3
+ /**
4
+ * A wrapper around the MySQL GTID value.
5
+ * This adds and tracks additional metadata such as the BinLog filename
6
+ * and position where this GTID could be located.
7
+ */
8
+ export class ReplicatedGTID {
9
+ static fromSerialized(comparable) {
10
+ return new ReplicatedGTID(ReplicatedGTID.deserialize(comparable));
11
+ }
12
+ static deserialize(comparable) {
13
+ const components = comparable.split('|');
14
+ if (components.length < 3) {
15
+ throw new Error(`Invalid serialized GTID: ${comparable}`);
16
+ }
17
+ return {
18
+ raw_gtid: components[1],
19
+ position: {
20
+ filename: components[2],
21
+ offset: parseInt(components[3])
22
+ }
23
+ };
24
+ }
25
+ static fromBinLogEvent(event) {
26
+ const { raw_gtid, position } = event;
27
+ const stringGTID = `${uuid.stringify(raw_gtid.server_id)}:${raw_gtid.transaction_range}`;
28
+ return new ReplicatedGTID({
29
+ raw_gtid: stringGTID,
30
+ position
31
+ });
32
+ }
33
+ constructor(options) {
34
+ this.options = options;
35
+ }
36
+ /**
37
+ * Get the BinLog position of this replicated GTID event
38
+ */
39
+ get position() {
40
+ return this.options.position;
41
+ }
42
+ /**
43
+ * Get the raw Global Transaction ID. This of the format `server_id:transaction_ranges`
44
+ */
45
+ get raw() {
46
+ return this.options.raw_gtid;
47
+ }
48
+ get serverId() {
49
+ return this.options.raw_gtid.split(':')[0];
50
+ }
51
+ /**
52
+ * Transforms a GTID into a comparable string format, ensuring lexicographical
53
+ * order aligns with the GTID's relative age. This assumes that all GTIDs
54
+ * have the same server ID.
55
+ *
56
+ * @returns A comparable string in the format
57
+ * `padded_end_transaction|raw_gtid|binlog_filename|binlog_position`
58
+ */
59
+ get comparable() {
60
+ const { raw, position } = this;
61
+ const [, transactionRanges] = this.raw.split(':');
62
+ let maxTransactionId = 0;
63
+ for (const range of transactionRanges.split(',')) {
64
+ const [start, end] = range.split('-');
65
+ maxTransactionId = Math.max(maxTransactionId, parseInt(start, 10), parseInt(end || start, 10));
66
+ }
67
+ const paddedTransactionId = maxTransactionId.toString().padStart(16, '0');
68
+ return [paddedTransactionId, raw, position.filename, position.offset].join('|');
69
+ }
70
+ toString() {
71
+ return this.comparable;
72
+ }
73
+ /**
74
+ * Calculates the distance in bytes from this GTID to the provided argument.
75
+ */
76
+ async distanceTo(connection, to) {
77
+ const [logFiles] = await mysql_utils.retriedQuery({
78
+ connection,
79
+ query: `SHOW BINARY LOGS;`
80
+ });
81
+ // Default to the first file for the start to handle the zero GTID case.
82
+ const startFileIndex = Math.max(logFiles.findIndex((f) => f['Log_name'] == this.position.filename), 0);
83
+ const startFileEntry = logFiles[startFileIndex];
84
+ if (!startFileEntry) {
85
+ return null;
86
+ }
87
+ /**
88
+ * Fall back to the next position for comparison if the replicated position is not present
89
+ */
90
+ const endPosition = to.position;
91
+ // Default to the past the last file to cater for the HEAD case
92
+ const testEndFileIndex = logFiles.findIndex((f) => f['Log_name'] == endPosition?.filename);
93
+ // If the endPosition is not defined and found. Fallback to the last file as the end
94
+ const endFileIndex = testEndFileIndex < 0 && !endPosition ? logFiles.length : logFiles.length - 1;
95
+ const endFileEntry = logFiles[endFileIndex];
96
+ if (!endFileEntry) {
97
+ return null;
98
+ }
99
+ return (startFileEntry['File_size'] -
100
+ this.position.offset -
101
+ endFileEntry['File_size'] +
102
+ endPosition.offset +
103
+ logFiles.slice(startFileIndex + 1, endFileIndex).reduce((sum, file) => sum + file['File_size'], 0));
104
+ }
105
+ }
106
+ /**
107
+ * Special case for the zero GTID which means no transactions have been executed.
108
+ */
109
+ ReplicatedGTID.ZERO = new ReplicatedGTID({ raw_gtid: '0:0', position: { filename: '', offset: 0 } });
110
+ //# sourceMappingURL=ReplicatedGTID.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReplicatedGTID.js","sourceRoot":"","sources":["../../src/common/ReplicatedGTID.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import mysqlPromise from 'mysql2/promise';
2
+ export declare function checkSourceConfiguration(connection: mysqlPromise.Connection): Promise<string[]>;
3
+ export declare function getMySQLVersion(connection: mysqlPromise.Connection): Promise<string>;
@@ -0,0 +1,46 @@
1
+ import * as mysql_utils from '../utils/mysql_utils.js';
2
+ export async function checkSourceConfiguration(connection) {
3
+ const errors = [];
4
+ const [[result]] = await mysql_utils.retriedQuery({
5
+ connection,
6
+ query: `
7
+ SELECT
8
+ @@GLOBAL.gtid_mode AS gtid_mode,
9
+ @@GLOBAL.log_bin AS log_bin,
10
+ @@GLOBAL.server_id AS server_id,
11
+ @@GLOBAL.log_bin_basename AS binlog_file,
12
+ @@GLOBAL.log_bin_index AS binlog_index_file
13
+ `
14
+ });
15
+ if (result.gtid_mode != 'ON') {
16
+ errors.push(`GTID is not enabled, it is currently set to ${result.gtid_mode}. Please enable it.`);
17
+ }
18
+ if (result.log_bin != 1) {
19
+ errors.push('Binary logging is not enabled. Please enable it.');
20
+ }
21
+ if (result.server_id < 0) {
22
+ errors.push(`Your Server ID setting is too low, it must be greater than 0. It is currently ${result.server_id}. Please correct your configuration.`);
23
+ }
24
+ if (!result.binlog_file) {
25
+ errors.push('Binary log file is not set. Please check your settings.');
26
+ }
27
+ if (!result.binlog_index_file) {
28
+ errors.push('Binary log index file is not set. Please check your settings.');
29
+ }
30
+ const [[binLogFormatResult]] = await mysql_utils.retriedQuery({
31
+ connection,
32
+ query: `SHOW VARIABLES LIKE 'binlog_format';`
33
+ });
34
+ if (binLogFormatResult.Value !== 'ROW') {
35
+ errors.push('Binary log format must be set to "ROW". Please correct your configuration');
36
+ }
37
+ return errors;
38
+ }
39
+ export async function getMySQLVersion(connection) {
40
+ const [[versionResult]] = await mysql_utils.retriedQuery({
41
+ connection,
42
+ query: `SELECT VERSION() as version`
43
+ });
44
+ return versionResult.version;
45
+ }
46
+ //# sourceMappingURL=check-source-configuration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-source-configuration.js","sourceRoot":"","sources":["../../src/common/check-source-configuration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,UAAmC;IAChF,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;QAChD,UAAU;QACV,KAAK,EAAE;;;;;;;OAOJ;KACJ,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,+CAA+C,MAAM,CAAC,SAAS,qBAAqB,CAAC,CAAC;IACpG,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CACT,iFAAiF,MAAM,CAAC,SAAS,sCAAsC,CACxI,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;QAC5D,UAAU;QACV,KAAK,EAAE,sCAAsC;KAC9C,CAAC,CAAC;IAEH,IAAI,kBAAkB,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;IAC3F,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAmC;IACvE,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;QACvD,UAAU;QACV,KAAK,EAAE,6BAA6B;KACrC,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC,OAAiB,CAAC;AACzC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './check-source-configuration.js';
2
+ export * from './get-replication-columns.js';
3
+ export * from './get-tables-from-pattern.js';
4
+ export * from './mysql-to-sqlite.js';
5
+ export * from './read-executed-gtid.js';
6
+ export * from './ReplicatedGTID.js';
@@ -0,0 +1,7 @@
1
+ export * from './check-source-configuration.js';
2
+ export * from './get-replication-columns.js';
3
+ export * from './get-tables-from-pattern.js';
4
+ export * from './mysql-to-sqlite.js';
5
+ export * from './read-executed-gtid.js';
6
+ export * from './ReplicatedGTID.js';
7
+ //# sourceMappingURL=common-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common-index.js","sourceRoot":"","sources":["../../src/common/common-index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { storage } from '@powersync/service-core';
2
+ import mysqlPromise from 'mysql2/promise';
3
+ export type GetReplicationColumnsOptions = {
4
+ connection: mysqlPromise.Connection;
5
+ schema: string;
6
+ table_name: string;
7
+ };
8
+ export type ReplicationIdentityColumnsResult = {
9
+ columns: storage.ColumnDescriptor[];
10
+ identity: string;
11
+ };
12
+ export declare function getReplicationIdentityColumns(options: GetReplicationColumnsOptions): Promise<ReplicationIdentityColumnsResult>;
@@ -0,0 +1,103 @@
1
+ import * as mysql_utils from '../utils/mysql_utils.js';
2
+ export async function getReplicationIdentityColumns(options) {
3
+ const { connection, schema, table_name } = options;
4
+ const [primaryKeyColumns] = await mysql_utils.retriedQuery({
5
+ connection: connection,
6
+ query: `
7
+ SELECT
8
+ s.COLUMN_NAME AS name,
9
+ c.DATA_TYPE AS type
10
+ FROM
11
+ INFORMATION_SCHEMA.STATISTICS s
12
+ JOIN
13
+ INFORMATION_SCHEMA.COLUMNS c
14
+ ON
15
+ s.TABLE_SCHEMA = c.TABLE_SCHEMA
16
+ AND s.TABLE_NAME = c.TABLE_NAME
17
+ AND s.COLUMN_NAME = c.COLUMN_NAME
18
+ WHERE
19
+ s.TABLE_SCHEMA = ?
20
+ AND s.TABLE_NAME = ?
21
+ AND s.INDEX_NAME = 'PRIMARY'
22
+ ORDER BY
23
+ s.SEQ_IN_INDEX;
24
+ `,
25
+ params: [schema, table_name]
26
+ });
27
+ if (primaryKeyColumns.length) {
28
+ return {
29
+ columns: primaryKeyColumns.map((row) => ({
30
+ name: row.name,
31
+ type: row.type
32
+ })),
33
+ identity: 'default'
34
+ };
35
+ }
36
+ // TODO: test code with tables with unique keys, compound key etc.
37
+ // No primary key, find the first valid unique key
38
+ const [uniqueKeyColumns] = await mysql_utils.retriedQuery({
39
+ connection: connection,
40
+ query: `
41
+ SELECT
42
+ s.INDEX_NAME,
43
+ s.COLUMN_NAME,
44
+ c.DATA_TYPE,
45
+ s.NON_UNIQUE,
46
+ s.NULLABLE
47
+ FROM
48
+ INFORMATION_SCHEMA.STATISTICS s
49
+ JOIN
50
+ INFORMATION_SCHEMA.COLUMNS c
51
+ ON
52
+ s.TABLE_SCHEMA = c.TABLE_SCHEMA
53
+ AND s.TABLE_NAME = c.TABLE_NAME
54
+ AND s.COLUMN_NAME = c.COLUMN_NAME
55
+ WHERE
56
+ s.TABLE_SCHEMA = ?
57
+ AND s.TABLE_NAME = ?
58
+ AND s.INDEX_NAME != 'PRIMARY'
59
+ AND s.NON_UNIQUE = 0
60
+ ORDER BY s.SEQ_IN_INDEX;
61
+ `,
62
+ params: [schema, table_name]
63
+ });
64
+ if (uniqueKeyColumns.length > 0) {
65
+ return {
66
+ columns: uniqueKeyColumns.map((col) => ({
67
+ name: col.COLUMN_NAME,
68
+ type: col.DATA_TYPE
69
+ })),
70
+ identity: 'index'
71
+ };
72
+ }
73
+ const [allColumns] = await mysql_utils.retriedQuery({
74
+ connection: connection,
75
+ query: `
76
+ SELECT
77
+ s.COLUMN_NAME AS name,
78
+ c.DATA_TYPE as type
79
+ FROM
80
+ INFORMATION_SCHEMA.COLUMNS s
81
+ JOIN
82
+ INFORMATION_SCHEMA.COLUMNS c
83
+ ON
84
+ s.TABLE_SCHEMA = c.TABLE_SCHEMA
85
+ AND s.TABLE_NAME = c.TABLE_NAME
86
+ AND s.COLUMN_NAME = c.COLUMN_NAME
87
+ WHERE
88
+ s.TABLE_SCHEMA = ?
89
+ AND s.TABLE_NAME = ?
90
+ ORDER BY
91
+ s.ORDINAL_POSITION;
92
+ `,
93
+ params: [schema, table_name]
94
+ });
95
+ return {
96
+ columns: allColumns.map((row) => ({
97
+ name: row.name,
98
+ type: row.type
99
+ })),
100
+ identity: 'full'
101
+ };
102
+ }
103
+ //# sourceMappingURL=get-replication-columns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-replication-columns.js","sourceRoot":"","sources":["../../src/common/get-replication-columns.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAcvD,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,OAAqC;IAErC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IACnD,MAAM,CAAC,iBAAiB,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;QACzD,UAAU,EAAE,UAAU;QACtB,KAAK,EAAE;;;;;;;;;;;;;;;;;;OAkBJ;QACH,MAAM,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;KAC7B,CAAC,CAAC;IAEH,IAAI,iBAAiB,CAAC,MAAM,EAAE,CAAC;QAC7B,OAAO;YACL,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBACvC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,IAAI,EAAE,GAAG,CAAC,IAAI;aACf,CAAC,CAAC;YACH,QAAQ,EAAE,SAAS;SACpB,CAAC;IACJ,CAAC;IAED,kEAAkE;IAClE,kDAAkD;IAClD,MAAM,CAAC,gBAAgB,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;QACxD,UAAU,EAAE,UAAU;QACtB,KAAK,EAAE;;;;;;;;;;;;;;;;;;;;;OAqBJ;QACH,MAAM,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;KAC7B,CAAC,CAAC;IAEH,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBACtC,IAAI,EAAE,GAAG,CAAC,WAAW;gBACrB,IAAI,EAAE,GAAG,CAAC,SAAS;aACpB,CAAC,CAAC;YACH,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;QAClD,UAAU,EAAE,UAAU;QACtB,KAAK,EAAE;;;;;;;;;;;;;;;;;OAiBJ;QACH,MAAM,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;KAC7B,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAChC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,CAAC,CAAC;QACH,QAAQ,EAAE,MAAM;KACjB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import * as sync_rules from '@powersync/service-sync-rules';
2
+ import mysql from 'mysql2/promise';
3
+ export type GetDebugTablesInfoOptions = {
4
+ connection: mysql.Connection;
5
+ tablePattern: sync_rules.TablePattern;
6
+ };
7
+ export declare function getTablesFromPattern(options: GetDebugTablesInfoOptions): Promise<Set<string>>;
@@ -0,0 +1,28 @@
1
+ export async function getTablesFromPattern(options) {
2
+ const { connection, tablePattern } = options;
3
+ const schema = tablePattern.schema;
4
+ if (tablePattern.isWildcard) {
5
+ const [results] = await connection.query(`SELECT
6
+ TABLE_NAME AS table_name
7
+ FROM
8
+ INFORMATION_SCHEMA.TABLES
9
+ WHERE
10
+ TABLE_SCHEMA = ?
11
+ AND TABLE_NAME LIKE ?`, [schema, tablePattern.tablePattern]);
12
+ return new Set(results
13
+ .filter((result) => result.table_name.startsWith(tablePattern.tablePrefix))
14
+ .map((result) => result.table_name));
15
+ }
16
+ else {
17
+ const [[match]] = await connection.query(`SELECT
18
+ TABLE_NAME AS table_name
19
+ FROM
20
+ INFORMATION_SCHEMA.TABLES
21
+ WHERE
22
+ TABLE_SCHEMA = ?
23
+ AND TABLE_NAME = ?`, [tablePattern.schema, tablePattern.tablePattern]);
24
+ // Only return the first result
25
+ return new Set([match.table_name]);
26
+ }
27
+ }
28
+ //# sourceMappingURL=get-tables-from-pattern.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-tables-from-pattern.js","sourceRoot":"","sources":["../../src/common/get-tables-from-pattern.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAkC;IAC3E,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC;IAEnC,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAC5B,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,UAAU,CAAC,KAAK,CACtC;;;;;;kCAM4B,EAC5B,CAAC,MAAM,EAAE,YAAY,CAAC,YAAY,CAAC,CACpC,CAAC;QAEF,OAAO,IAAI,GAAG,CACZ,OAAO;aACJ,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;aAC1E,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CACtC,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,UAAU,CAAC,KAAK,CACtC;;;;;;+BAMyB,EACzB,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,YAAY,CAAC,CACjD,CAAC;QACF,+BAA+B;QAC/B,OAAO,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACrC,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ import * as sync_rules from '@powersync/service-sync-rules';
2
+ import { ExpressionType } from '@powersync/service-sync-rules';
3
+ export declare function toSQLiteRow(row: Record<string, any>): sync_rules.SqliteRow;
4
+ export declare function toExpressionTypeFromMySQLType(mysqlType: string | undefined): ExpressionType;
@@ -0,0 +1,56 @@
1
+ import * as sync_rules from '@powersync/service-sync-rules';
2
+ import { ExpressionType } from '@powersync/service-sync-rules';
3
+ export function toSQLiteRow(row) {
4
+ for (let key in row) {
5
+ if (row[key] instanceof Date) {
6
+ row[key] = row[key].toISOString();
7
+ }
8
+ }
9
+ return sync_rules.toSyncRulesRow(row);
10
+ }
11
+ export function toExpressionTypeFromMySQLType(mysqlType) {
12
+ if (!mysqlType) {
13
+ return ExpressionType.TEXT;
14
+ }
15
+ const upperCaseType = mysqlType.toUpperCase();
16
+ // Handle type with parameters like VARCHAR(255), DECIMAL(10,2), etc.
17
+ const baseType = upperCaseType.split('(')[0];
18
+ switch (baseType) {
19
+ case 'BIT':
20
+ case 'BOOL':
21
+ case 'BOOLEAN':
22
+ case 'TINYINT':
23
+ case 'SMALLINT':
24
+ case 'MEDIUMINT':
25
+ case 'INT':
26
+ case 'INTEGER':
27
+ case 'BIGINT':
28
+ case 'UNSIGNED BIGINT':
29
+ return ExpressionType.INTEGER;
30
+ case 'BINARY':
31
+ case 'VARBINARY':
32
+ case 'TINYBLOB':
33
+ case 'MEDIUMBLOB':
34
+ case 'LONGBLOB':
35
+ case 'BLOB':
36
+ case 'GEOMETRY':
37
+ case 'POINT':
38
+ case 'LINESTRING':
39
+ case 'POLYGON':
40
+ case 'MULTIPOINT':
41
+ case 'MULTILINESTRING':
42
+ case 'MULTIPOLYGON':
43
+ case 'GEOMETRYCOLLECTION':
44
+ return ExpressionType.BLOB;
45
+ case 'FLOAT':
46
+ case 'DOUBLE':
47
+ case 'REAL':
48
+ return ExpressionType.REAL;
49
+ case 'JSON':
50
+ return ExpressionType.TEXT;
51
+ default:
52
+ // In addition to the normal text types, includes: DECIMAL, NUMERIC, DATE, TIME, DATETIME, TIMESTAMP, YEAR, ENUM, SET
53
+ return ExpressionType.TEXT;
54
+ }
55
+ }
56
+ //# sourceMappingURL=mysql-to-sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mysql-to-sqlite.js","sourceRoot":"","sources":["../../src/common/mysql-to-sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,UAAU,WAAW,CAAC,GAAwB;IAClD,KAAK,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;QACpB,IAAI,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;YAC7B,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,SAA6B;IACzE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,cAAc,CAAC,IAAI,CAAC;IAC7B,CAAC;IAED,MAAM,aAAa,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAC9C,qEAAqE;IACrE,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7C,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,SAAS,CAAC;QACf,KAAK,SAAS,CAAC;QACf,KAAK,UAAU,CAAC;QAChB,KAAK,WAAW,CAAC;QACjB,KAAK,KAAK,CAAC;QACX,KAAK,SAAS,CAAC;QACf,KAAK,QAAQ,CAAC;QACd,KAAK,iBAAiB;YACpB,OAAO,cAAc,CAAC,OAAO,CAAC;QAChC,KAAK,QAAQ,CAAC;QACd,KAAK,WAAW,CAAC;QACjB,KAAK,UAAU,CAAC;QAChB,KAAK,YAAY,CAAC;QAClB,KAAK,UAAU,CAAC;QAChB,KAAK,MAAM,CAAC;QACZ,KAAK,UAAU,CAAC;QAChB,KAAK,OAAO,CAAC;QACb,KAAK,YAAY,CAAC;QAClB,KAAK,SAAS,CAAC;QACf,KAAK,YAAY,CAAC;QAClB,KAAK,iBAAiB,CAAC;QACvB,KAAK,cAAc,CAAC;QACpB,KAAK,oBAAoB;YACvB,OAAO,cAAc,CAAC,IAAI,CAAC;QAC7B,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM;YACT,OAAO,cAAc,CAAC,IAAI,CAAC;QAC7B,KAAK,MAAM;YACT,OAAO,cAAc,CAAC,IAAI,CAAC;QAC7B;YACE,qHAAqH;YACrH,OAAO,cAAc,CAAC,IAAI,CAAC;IAC/B,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import mysqlPromise from 'mysql2/promise';
2
+ import { ReplicatedGTID } from './ReplicatedGTID.js';
3
+ /**
4
+ * Gets the current master HEAD GTID
5
+ */
6
+ export declare function readExecutedGtid(connection: mysqlPromise.Connection): Promise<ReplicatedGTID>;
@@ -0,0 +1,40 @@
1
+ import * as mysql_utils from '../utils/mysql_utils.js';
2
+ import { gte } from 'semver';
3
+ import { ReplicatedGTID } from './ReplicatedGTID.js';
4
+ import { getMySQLVersion } from './check-source-configuration.js';
5
+ import { logger } from '@powersync/lib-services-framework';
6
+ /**
7
+ * Gets the current master HEAD GTID
8
+ */
9
+ export async function readExecutedGtid(connection) {
10
+ const version = await getMySQLVersion(connection);
11
+ let binlogStatus;
12
+ if (gte(version, '8.4.0')) {
13
+ // Get the BinLog status
14
+ const [[binLogResult]] = await mysql_utils.retriedQuery({
15
+ connection,
16
+ query: `SHOW BINARY LOG STATUS`
17
+ });
18
+ binlogStatus = binLogResult;
19
+ }
20
+ else {
21
+ // TODO Check if this works for version 5.7
22
+ // Get the BinLog status
23
+ const [[binLogResult]] = await mysql_utils.retriedQuery({
24
+ connection,
25
+ query: `SHOW MASTER STATUS`
26
+ });
27
+ binlogStatus = binLogResult;
28
+ }
29
+ const position = {
30
+ filename: binlogStatus.File,
31
+ offset: parseInt(binlogStatus.Position)
32
+ };
33
+ logger.info('Succesfully read executed GTID', { position });
34
+ return new ReplicatedGTID({
35
+ // The head always points to the next position to start replication from
36
+ position,
37
+ raw_gtid: binlogStatus.Executed_Gtid_Set
38
+ });
39
+ }
40
+ //# sourceMappingURL=read-executed-gtid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-executed-gtid.js","sourceRoot":"","sources":["../../src/common/read-executed-gtid.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAE3D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAmC;IACxE,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,YAAwC,CAAC;IAC7C,IAAI,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QAC1B,wBAAwB;QACxB,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;YACtD,UAAU;YACV,KAAK,EAAE,wBAAwB;SAChC,CAAC,CAAC;QACH,YAAY,GAAG,YAAY,CAAC;IAC9B,CAAC;SAAM,CAAC;QACN,2CAA2C;QAC3C,wBAAwB;QACxB,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC;YACtD,UAAU;YACV,KAAK,EAAE,oBAAoB;SAC5B,CAAC,CAAC;QACH,YAAY,GAAG,YAAY,CAAC;IAC9B,CAAC;IACD,MAAM,QAAQ,GAAG;QACf,QAAQ,EAAE,YAAY,CAAC,IAAI;QAC3B,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC;KACxC,CAAC;IAEF,MAAM,CAAC,IAAI,CAAC,gCAAgC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE5D,OAAO,IAAI,cAAc,CAAC;QACxB,wEAAwE;QACxE,QAAQ;QACR,QAAQ,EAAE,YAAY,CAAC,iBAAiB;KACzC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { MySQLModule } from './module/MySQLModule.js';
2
+ export declare const module: MySQLModule;
3
+ export default module;
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { MySQLModule } from './module/MySQLModule.js';
2
+ export const module = new MySQLModule();
3
+ export default module;
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;AAExC,eAAe,MAAM,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { api, replication, system, TearDownOptions } from '@powersync/service-core';
2
+ import * as types from '../types/types.js';
3
+ export declare class MySQLModule extends replication.ReplicationModule<types.MySQLConnectionConfig> {
4
+ constructor();
5
+ initialize(context: system.ServiceContextContainer): Promise<void>;
6
+ protected createRouteAPIAdapter(): api.RouteAPI;
7
+ protected createReplicator(context: system.ServiceContext): replication.AbstractReplicator;
8
+ /**
9
+ * Combines base config with normalized connection settings
10
+ */
11
+ private resolveConfig;
12
+ teardown(options: TearDownOptions): Promise<void>;
13
+ }
@@ -0,0 +1,46 @@
1
+ import { ConfigurationFileSyncRulesProvider, replication } from '@powersync/service-core';
2
+ import { MySQLRouteAPIAdapter } from '../api/MySQLRouteAPIAdapter.js';
3
+ import { BinLogReplicator } from '../replication/BinLogReplicator.js';
4
+ import { MySQLErrorRateLimiter } from '../replication/MySQLErrorRateLimiter.js';
5
+ import * as types from '../types/types.js';
6
+ import { MySQLConnectionManagerFactory } from '../replication/MySQLConnectionManagerFactory.js';
7
+ export class MySQLModule extends replication.ReplicationModule {
8
+ constructor() {
9
+ super({
10
+ name: 'MySQL',
11
+ type: types.MYSQL_CONNECTION_TYPE,
12
+ configSchema: types.MySQLConnectionConfig
13
+ });
14
+ }
15
+ async initialize(context) {
16
+ await super.initialize(context);
17
+ }
18
+ createRouteAPIAdapter() {
19
+ return new MySQLRouteAPIAdapter(this.resolveConfig(this.decodedConfig));
20
+ }
21
+ createReplicator(context) {
22
+ const normalisedConfig = this.resolveConfig(this.decodedConfig);
23
+ const syncRuleProvider = new ConfigurationFileSyncRulesProvider(context.configuration.sync_rules);
24
+ const connectionFactory = new MySQLConnectionManagerFactory(normalisedConfig);
25
+ return new BinLogReplicator({
26
+ id: this.getDefaultId(normalisedConfig.database),
27
+ syncRuleProvider: syncRuleProvider,
28
+ storageEngine: context.storageEngine,
29
+ connectionFactory: connectionFactory,
30
+ rateLimiter: new MySQLErrorRateLimiter()
31
+ });
32
+ }
33
+ /**
34
+ * Combines base config with normalized connection settings
35
+ */
36
+ resolveConfig(config) {
37
+ return {
38
+ ...config,
39
+ ...types.normalizeConnectionConfig(config)
40
+ };
41
+ }
42
+ async teardown(options) {
43
+ // No specific teardown required for MySQL
44
+ }
45
+ }
46
+ //# sourceMappingURL=MySQLModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MySQLModule.js","sourceRoot":"","sources":["../../src/module/MySQLModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,kCAAkC,EAAE,WAAW,EAA2B,MAAM,yBAAyB,CAAC;AAExH,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,6BAA6B,EAAE,MAAM,iDAAiD,CAAC;AAEhG,MAAM,OAAO,WAAY,SAAQ,WAAW,CAAC,iBAA8C;IACzF;QACE,KAAK,CAAC;YACJ,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,KAAK,CAAC,qBAAqB;YACjC,YAAY,EAAE,KAAK,CAAC,qBAAqB;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAuC;QACtD,MAAM,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAES,qBAAqB;QAC7B,OAAO,IAAI,oBAAoB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAc,CAAC,CAAC,CAAC;IAC3E,CAAC;IAES,gBAAgB,CAAC,OAA8B;QACvD,MAAM,gBAAgB,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAc,CAAC,CAAC;QACjE,MAAM,gBAAgB,GAAG,IAAI,kCAAkC,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QAClG,MAAM,iBAAiB,GAAG,IAAI,6BAA6B,CAAC,gBAAgB,CAAC,CAAC;QAE9E,OAAO,IAAI,gBAAgB,CAAC;YAC1B,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC;YAChD,gBAAgB,EAAE,gBAAgB;YAClC,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,iBAAiB,EAAE,iBAAiB;YACpC,WAAW,EAAE,IAAI,qBAAqB,EAAE;SACzC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,MAAmC;QACvD,OAAO;YACL,GAAG,MAAM;YACT,GAAG,KAAK,CAAC,yBAAyB,CAAC,MAAM,CAAC;SAC3C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAwB;QACrC,0CAA0C;IAC5C,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import { replication } from '@powersync/service-core';
2
+ import { MySQLConnectionManagerFactory } from './MySQLConnectionManagerFactory.js';
3
+ export interface BinLogReplicationJobOptions extends replication.AbstractReplicationJobOptions {
4
+ connectionFactory: MySQLConnectionManagerFactory;
5
+ }
6
+ export declare class BinLogReplicationJob extends replication.AbstractReplicationJob {
7
+ private connectionFactory;
8
+ constructor(options: BinLogReplicationJobOptions);
9
+ get slot_name(): string;
10
+ keepAlive(): Promise<void>;
11
+ replicate(): Promise<void>;
12
+ replicateLoop(): Promise<void>;
13
+ replicateOnce(): Promise<void>;
14
+ }