@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.
- package/CHANGELOG.md +20 -0
- package/LICENSE +67 -0
- package/README.md +3 -0
- package/dev/.env.template +2 -0
- package/dev/README.md +9 -0
- package/dev/config/sync_rules.yaml +12 -0
- package/dev/docker/mysql/docker-compose.yaml +17 -0
- package/dev/docker/mysql/init-scripts/my.cnf +9 -0
- package/dev/docker/mysql/init-scripts/mysql.sql +38 -0
- package/dist/api/MySQLRouteAPIAdapter.d.ts +24 -0
- package/dist/api/MySQLRouteAPIAdapter.js +311 -0
- package/dist/api/MySQLRouteAPIAdapter.js.map +1 -0
- package/dist/common/ReplicatedGTID.d.ts +59 -0
- package/dist/common/ReplicatedGTID.js +110 -0
- package/dist/common/ReplicatedGTID.js.map +1 -0
- package/dist/common/check-source-configuration.d.ts +3 -0
- package/dist/common/check-source-configuration.js +46 -0
- package/dist/common/check-source-configuration.js.map +1 -0
- package/dist/common/common-index.d.ts +6 -0
- package/dist/common/common-index.js +7 -0
- package/dist/common/common-index.js.map +1 -0
- package/dist/common/get-replication-columns.d.ts +12 -0
- package/dist/common/get-replication-columns.js +103 -0
- package/dist/common/get-replication-columns.js.map +1 -0
- package/dist/common/get-tables-from-pattern.d.ts +7 -0
- package/dist/common/get-tables-from-pattern.js +28 -0
- package/dist/common/get-tables-from-pattern.js.map +1 -0
- package/dist/common/mysql-to-sqlite.d.ts +4 -0
- package/dist/common/mysql-to-sqlite.js +56 -0
- package/dist/common/mysql-to-sqlite.js.map +1 -0
- package/dist/common/read-executed-gtid.d.ts +6 -0
- package/dist/common/read-executed-gtid.js +40 -0
- package/dist/common/read-executed-gtid.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/module/MySQLModule.d.ts +13 -0
- package/dist/module/MySQLModule.js +46 -0
- package/dist/module/MySQLModule.js.map +1 -0
- package/dist/replication/BinLogReplicationJob.d.ts +14 -0
- package/dist/replication/BinLogReplicationJob.js +88 -0
- package/dist/replication/BinLogReplicationJob.js.map +1 -0
- package/dist/replication/BinLogReplicator.d.ts +13 -0
- package/dist/replication/BinLogReplicator.js +25 -0
- package/dist/replication/BinLogReplicator.js.map +1 -0
- package/dist/replication/BinLogStream.d.ts +43 -0
- package/dist/replication/BinLogStream.js +421 -0
- package/dist/replication/BinLogStream.js.map +1 -0
- package/dist/replication/MySQLConnectionManager.d.ts +43 -0
- package/dist/replication/MySQLConnectionManager.js +81 -0
- package/dist/replication/MySQLConnectionManager.js.map +1 -0
- package/dist/replication/MySQLConnectionManagerFactory.d.ts +10 -0
- package/dist/replication/MySQLConnectionManagerFactory.js +21 -0
- package/dist/replication/MySQLConnectionManagerFactory.js.map +1 -0
- package/dist/replication/MySQLErrorRateLimiter.d.ts +10 -0
- package/dist/replication/MySQLErrorRateLimiter.js +43 -0
- package/dist/replication/MySQLErrorRateLimiter.js.map +1 -0
- package/dist/replication/zongji/zongji-utils.d.ts +7 -0
- package/dist/replication/zongji/zongji-utils.js +19 -0
- package/dist/replication/zongji/zongji-utils.js.map +1 -0
- package/dist/types/types.d.ts +50 -0
- package/dist/types/types.js +61 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils/mysql_utils.d.ts +14 -0
- package/dist/utils/mysql_utils.js +38 -0
- package/dist/utils/mysql_utils.js.map +1 -0
- package/package.json +51 -0
- package/src/api/MySQLRouteAPIAdapter.ts +357 -0
- package/src/common/ReplicatedGTID.ts +158 -0
- package/src/common/check-source-configuration.ts +59 -0
- package/src/common/common-index.ts +6 -0
- package/src/common/get-replication-columns.ts +124 -0
- package/src/common/get-tables-from-pattern.ts +44 -0
- package/src/common/mysql-to-sqlite.ts +59 -0
- package/src/common/read-executed-gtid.ts +43 -0
- package/src/index.ts +5 -0
- package/src/module/MySQLModule.ts +53 -0
- package/src/replication/BinLogReplicationJob.ts +97 -0
- package/src/replication/BinLogReplicator.ts +35 -0
- package/src/replication/BinLogStream.ts +547 -0
- package/src/replication/MySQLConnectionManager.ts +104 -0
- package/src/replication/MySQLConnectionManagerFactory.ts +28 -0
- package/src/replication/MySQLErrorRateLimiter.ts +44 -0
- package/src/replication/zongji/zongji-utils.ts +32 -0
- package/src/replication/zongji/zongji.d.ts +98 -0
- package/src/types/types.ts +102 -0
- package/src/utils/mysql_utils.ts +47 -0
- package/test/src/binlog_stream.test.ts +288 -0
- package/test/src/binlog_stream_utils.ts +152 -0
- package/test/src/env.ts +7 -0
- package/test/src/setup.ts +7 -0
- package/test/src/util.ts +62 -0
- package/test/tsconfig.json +28 -0
- package/tsconfig.json +26 -0
- package/tsconfig.tsbuildinfo +1 -0
- 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,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,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,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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -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
|
+
}
|