mysqlsyncr 1.1.10 → 1.2.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 (62) hide show
  1. package/README.md +246 -186
  2. package/__tests__/acceptCurrent.test.js +117 -0
  3. package/__tests__/columnAttributes.test.js +101 -0
  4. package/__tests__/options.test.js +259 -0
  5. package/__tests__/parser.test.js +167 -166
  6. package/__tests__/parser2.test.js +155 -152
  7. package/__tests__/paths.test.js +21 -0
  8. package/__tests__/prompt.test.js +106 -0
  9. package/__tests__/sync.test.js +348 -0
  10. package/__tests__/templateDrift.test.js +72 -0
  11. package/__tests__/versions.test.js +138 -0
  12. package/dist/index.cjs +4070 -1730
  13. package/dist/index.js +4106 -1768
  14. package/package.json +66 -59
  15. package/rollup.config.js +25 -24
  16. package/src/DBStructureChecker.js +47 -0
  17. package/src/acceptCurrent.js +225 -0
  18. package/src/apply.js +481 -348
  19. package/src/cli.js +61 -34
  20. package/src/compare.js +106 -92
  21. package/src/differences.js +258 -212
  22. package/src/dump.js +63 -54
  23. package/src/getters.js +151 -139
  24. package/src/index.js +223 -170
  25. package/src/loggers.js +156 -139
  26. package/src/normalizers.js +28 -6
  27. package/src/options.js +133 -0
  28. package/src/parsers.js +197 -145
  29. package/src/paths.js +41 -0
  30. package/src/prompt.js +109 -0
  31. package/src/rebuild.js +106 -0
  32. package/src/rows.js +46 -0
  33. package/src/socketServer.js +311 -229
  34. package/src/templateDrift.js +93 -0
  35. package/src/versions.js +112 -0
  36. package/ui/README.md +55 -40
  37. package/ui/dist/spa/assets/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWuYjalmUiAw-k1h7X_-h.woff +0 -0
  38. package/ui/dist/spa/assets/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWuZtalmUiAw-B7du-70m.woff +0 -0
  39. package/ui/dist/spa/assets/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWuaabVmUiAw-CoAZ_DKt.woff +0 -0
  40. package/ui/dist/spa/assets/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWub2bVmUiAw-D0406B4n.woff +0 -0
  41. package/ui/dist/spa/assets/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbFmUiAw-CnAg2DeQ.woff +0 -0
  42. package/ui/dist/spa/assets/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmUiAw-BG9VWE5v.woff +0 -0
  43. package/ui/dist/spa/assets/MainLayout-DLH1Kfg-.js +1 -0
  44. package/ui/dist/spa/assets/axios-2hQ_j_Tz.js +1 -0
  45. package/ui/dist/spa/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa-OUIwM9U8.woff +0 -0
  46. package/ui/dist/spa/assets/index-Cqrg985P.js +23 -0
  47. package/ui/dist/spa/assets/index-pOWtXlXQ.css +1 -0
  48. package/ui/dist/spa/index.html +2 -2
  49. package/ui/package.json +43 -42
  50. package/ui/src/components/DefinitionDiff.vue +169 -0
  51. package/ui/src/pages/MainComponent.vue +704 -78
  52. package/ui/dist/spa/assets/KFOkCnqEu92Fr1MmgVxIIzQ-Y2mpUUkw.woff +0 -0
  53. package/ui/dist/spa/assets/KFOlCnqEu92Fr1MmEU9fBBc--ViM7Ag4Q.woff +0 -0
  54. package/ui/dist/spa/assets/KFOlCnqEu92Fr1MmSU5fBBc--CrFzpgl6.woff +0 -0
  55. package/ui/dist/spa/assets/KFOlCnqEu92Fr1MmWUlfBBc--CW3_XjG_.woff +0 -0
  56. package/ui/dist/spa/assets/KFOlCnqEu92Fr1MmYUtfBBc--Dr8fnyGc.woff +0 -0
  57. package/ui/dist/spa/assets/KFOmCnqEu92Fr1Mu4mxM-DAYh6T4l.woff +0 -0
  58. package/ui/dist/spa/assets/MainLayout-CvQD3xKr.js +0 -1
  59. package/ui/dist/spa/assets/axios-C0XcclIb.js +0 -1
  60. package/ui/dist/spa/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa-Dr0goTwe.woff +0 -0
  61. package/ui/dist/spa/assets/index-CwWo8xmP.js +0 -40
  62. package/ui/dist/spa/assets/index-kXpA8n8r.css +0 -5
package/src/getters.js CHANGED
@@ -1,140 +1,152 @@
1
- import { parseCreateTableSQL } from './parsers.js';
2
- import path from 'path';
3
- import fs from 'fs/promises';
4
- import { logger } from './loggers.js';
5
-
6
- export const getDatabases = async (connection) => {
7
- const databases = await connection.query('SHOW DATABASES');
8
- return databases
9
- .map(db => db.Database)
10
- .filter(db => !['information_schema', 'mysql', 'performance_schema', 'sys'].includes(db));
11
- }
12
-
13
-
14
- export const getDatabaseStructure = async (connection, database, command, options) => {
15
- if (connection.state === 'disconnected') {
16
- await connection.reconnect(); // Ensure the connection is open
17
- }
18
- await connection.query(`USE \`${database}\``); // Switch to the target database
19
- const tables = {};
20
- const procedures = [];
21
- const views = {};
22
- const dbDir = path.join(options.output, database); // Use argv.output for the base path
23
-
24
- // Create the output directory for the database if it doesn't exist
25
- if (command === 'dump') {
26
- const tableDir = path.join(dbDir, 'tables'); // Subfolder for table SQL files
27
- await fs.mkdir(tableDir, { recursive: true }); // Create the tables directory
28
- }
29
-
30
- // Get tables and their structures
31
- const tableRows = await connection.query('SHOW FULL TABLES WHERE Table_Type != "VIEW"');
32
-
33
-
34
- for (const row of tableRows) {
35
- const tableName = Object.values(row)[0]; // Get the first value in the row object
36
- if (!tableName) {
37
- logger(`Undefined table name found in database ${database}`, row);
38
- continue; // Skip undefined table names
39
- }
40
-
41
- // Get the CREATE TABLE statement
42
- const createTableRow = await connection.query(`SHOW CREATE TABLE \`${tableName}\``);
43
- const createTableSQL = createTableRow[0]['Create Table'];
44
-
45
- const parsedTable = parseCreateTableSQL(createTableSQL);
46
-
47
- // Structure the table object
48
- tables[tableName] = {
49
- columns: parsedTable.columns, // Array of columns
50
- indexes: parsedTable.indexes, // Array of indexes
51
- constraints: parsedTable.constraints, // Array of constraints
52
- triggers: [], // Initialize triggers array
53
- createSQL: createTableSQL // Store the CREATE TABLE SQL if needed
54
- };
55
-
56
- // Save the CREATE TABLE statement to an individual SQL file for each table
57
- if (command === 'dump') {
58
- const tableDir = path.join(dbDir, 'tables'); // Subfolder for table SQL files
59
- const filePath = path.join(tableDir, `${tableName}.sql`); // Use the table directory for file saving
60
- await fs.mkdir(path.dirname(filePath), { recursive: true }); // Create the tables directory if it doesn't exist
61
- await fs.writeFile(filePath, `${createTableSQL}\n`, 'utf-8');
62
- logger(`Table structure saved to: ${filePath}`);
63
- }
64
- }
65
-
66
- // Get stored procedures
67
- const routineRows = await connection.query(`SHOW PROCEDURE STATUS WHERE Db = ?`, [database]);
68
-
69
- for (const row of routineRows) {
70
- let createSQLrow = await connection.query(`SHOW CREATE PROCEDURE \`${row.Name}\``);
71
- let createSQL = createSQLrow[0]['Create Procedure'];
72
- procedures.push({
73
- Name: row.Name,
74
- Definition: createSQL
75
- }); // Add procedure names to the array
76
- if (command === 'dump') {
77
- const filePath = path.join(dbDir, 'procedures', `${row.Name}.sql`); // Use the table directory for file saving
78
- await fs.mkdir(path.dirname(filePath), { recursive: true }); // Create the procedures directory if it doesn't exist
79
- await fs.writeFile(filePath, `${createSQL}\n`, 'utf-8');
80
- logger(`Procedure definition saved to: ${filePath}`);
81
- }
82
- }
83
-
84
- // Get triggers
85
- const triggerRows = await connection.query(`
86
- SELECT TRIGGER_NAME, EVENT_OBJECT_TABLE
87
- FROM INFORMATION_SCHEMA.TRIGGERS
88
- WHERE TRIGGER_SCHEMA = ?
89
- `, [database]);
90
-
91
- for (const row of triggerRows) {
92
- const triggerName = row.TRIGGER_NAME;
93
- const tableName = row.EVENT_OBJECT_TABLE;
94
-
95
- // Ensure triggerDefinition is defined before using it
96
- const triggerDefinitionRow = await connection.query(`SHOW CREATE TRIGGER \`${triggerName}\``);
97
- const triggerDefinition = triggerDefinitionRow[0]['SQL Original Statement'];
98
-
99
- if (triggerDefinition) {
100
-
101
- tables[tableName].triggers.push({
102
- Name: triggerName,
103
- Definition: triggerDefinition
104
- });
105
- if (command === 'dump') {
106
- const tableDir = path.join(dbDir, 'tables'); // Subfolder for table SQL files
107
- const triggerFilePath = path.join(tableDir, 'triggers', `${triggerName}.sql`);
108
- await fs.mkdir(path.dirname(triggerFilePath), { recursive: true }); // Create the triggers directory if it doesn't exist
109
- await fs.writeFile(triggerFilePath, `${triggerDefinition}\n`, 'utf-8');
110
- logger(`Trigger definition saved to: ${triggerFilePath}`);
111
- }
112
-
113
- } else {
114
- logger(`Trigger ${triggerName} has no action statement.`);
115
- }
116
- }
117
-
118
- // Get views
119
- const viewRows = await connection.query(`SHOW FULL TABLES IN \`${database}\` WHERE TABLE_TYPE LIKE 'VIEW'`);
120
- for (const row of viewRows) {
121
- let viewName = row[`Tables_in_${database.toLowerCase()}`];
122
- if (!viewName) viewName = row[`Tables_in_${database}`];
123
- logger(`getting view Tables_in_${database}`, viewName);
124
- try {
125
- const viewDefinition = await connection.query(`SHOW CREATE VIEW \`${viewName}\``);
126
- views[viewName] = viewDefinition[0]['Create View'];
127
- if (command === 'dump') {
128
- const filePath = path.join(dbDir, 'views', `${viewName}.sql`); // Use the table directory for file saving
129
- await fs.mkdir(path.dirname(filePath), { recursive: true }); // Create the views directory if it doesn't exist
130
- await fs.writeFile(filePath, `${viewDefinition[0]['Create View']}\n`, 'utf-8');
131
- logger(`View definition saved to: ${filePath}`);
132
- }
133
- } catch (error) {
134
- logger(`Error retrieving definition for view ${viewName}:`, error.message);
135
- logger(row)
136
- }
137
- }
138
-
139
- return { tables, procedures, views };
1
+ import { parseCreateTableSQL } from './parsers.js';
2
+ import path from 'path';
3
+ import fs from 'fs/promises';
4
+ import { logger } from './loggers.js';
5
+ import { applyAutoIncrementOption, applyDefiner, getTableOptions } from './options.js';
6
+
7
+ export const getDatabases = async (connection) => {
8
+ const databases = await connection.query('SHOW DATABASES');
9
+ return databases
10
+ .map(db => db.Database)
11
+ .filter(db => !['information_schema', 'mysql', 'performance_schema', 'sys'].includes(db));
12
+ }
13
+
14
+
15
+ /**
16
+ * @param syncOptions options from syncOptions.json; when dumping, each table's
17
+ * autoIncrement option is applied to its saved CREATE TABLE,
18
+ * and the definer option to procedures, triggers and views
19
+ */
20
+ export const getDatabaseStructure = async (connection, database, command, options, syncOptions = {}) => {
21
+ if (connection.state === 'disconnected') {
22
+ await connection.reconnect(); // Ensure the connection is open
23
+ }
24
+ await connection.query(`USE \`${database}\``); // Switch to the target database
25
+ const tables = {};
26
+ const procedures = [];
27
+ const views = {};
28
+ const dbDir = path.join(options.output, database); // Use argv.output for the base path
29
+
30
+ // Create the output directory for the database if it doesn't exist
31
+ if (command === 'dump') {
32
+ const tableDir = path.join(dbDir, 'tables'); // Subfolder for table SQL files
33
+ await fs.mkdir(tableDir, { recursive: true }); // Create the tables directory
34
+ }
35
+
36
+ // Get tables and their structures
37
+ const tableRows = await connection.query('SHOW FULL TABLES WHERE Table_Type != "VIEW"');
38
+
39
+
40
+ for (const row of tableRows) {
41
+ const tableName = Object.values(row)[0]; // Get the first value in the row object
42
+ if (!tableName) {
43
+ logger(`Undefined table name found in database ${database}`, row);
44
+ continue; // Skip undefined table names
45
+ }
46
+
47
+ // Get the CREATE TABLE statement
48
+ const createTableRow = await connection.query(`SHOW CREATE TABLE \`${tableName}\``);
49
+ const liveCreateTableSQL = createTableRow[0]['Create Table'];
50
+ const createTableSQL = command === 'dump'
51
+ ? applyAutoIncrementOption(liveCreateTableSQL, getTableOptions(syncOptions, database, tableName).autoIncrement)
52
+ : liveCreateTableSQL;
53
+
54
+ const parsedTable = parseCreateTableSQL(createTableSQL);
55
+
56
+ // Structure the table object
57
+ tables[tableName] = {
58
+ columns: parsedTable.columns, // Array of columns
59
+ indexes: parsedTable.indexes, // Array of indexes
60
+ constraints: parsedTable.constraints, // Array of constraints
61
+ triggers: [], // Initialize triggers array
62
+ createSQL: createTableSQL // Store the CREATE TABLE SQL if needed
63
+ };
64
+
65
+ // Save the CREATE TABLE statement to an individual SQL file for each table
66
+ if (command === 'dump') {
67
+ const tableDir = path.join(dbDir, 'tables'); // Subfolder for table SQL files
68
+ const filePath = path.join(tableDir, `${tableName}.sql`); // Use the table directory for file saving
69
+ await fs.mkdir(path.dirname(filePath), { recursive: true }); // Create the tables directory if it doesn't exist
70
+ await fs.writeFile(filePath, `${createTableSQL}\n`, 'utf-8');
71
+ logger(`Table structure saved to: ${filePath}`);
72
+ }
73
+ }
74
+
75
+ // Get stored procedures
76
+ const routineRows = await connection.query(`SHOW PROCEDURE STATUS WHERE Db = ?`, [database]);
77
+
78
+ for (const row of routineRows) {
79
+ let createSQLrow = await connection.query(`SHOW CREATE PROCEDURE \`${row.Name}\``);
80
+ let createSQL = createSQLrow[0]['Create Procedure'];
81
+ if (command === 'dump') createSQL = applyDefiner(createSQL, syncOptions.definer);
82
+ procedures.push({
83
+ Name: row.Name,
84
+ Definition: createSQL
85
+ }); // Add procedure names to the array
86
+ if (command === 'dump') {
87
+ const filePath = path.join(dbDir, 'procedures', `${row.Name}.sql`); // Use the table directory for file saving
88
+ await fs.mkdir(path.dirname(filePath), { recursive: true }); // Create the procedures directory if it doesn't exist
89
+ await fs.writeFile(filePath, `${createSQL}\n`, 'utf-8');
90
+ logger(`Procedure definition saved to: ${filePath}`);
91
+ }
92
+ }
93
+
94
+ // Get triggers
95
+ const triggerRows = await connection.query(`
96
+ SELECT TRIGGER_NAME, EVENT_OBJECT_TABLE
97
+ FROM INFORMATION_SCHEMA.TRIGGERS
98
+ WHERE TRIGGER_SCHEMA = ?
99
+ `, [database]);
100
+
101
+ for (const row of triggerRows) {
102
+ const triggerName = row.TRIGGER_NAME;
103
+ const tableName = row.EVENT_OBJECT_TABLE;
104
+
105
+ // Ensure triggerDefinition is defined before using it
106
+ const triggerDefinitionRow = await connection.query(`SHOW CREATE TRIGGER \`${triggerName}\``);
107
+ const liveTriggerDefinition = triggerDefinitionRow[0]['SQL Original Statement'];
108
+ const triggerDefinition = command === 'dump' ? applyDefiner(liveTriggerDefinition, syncOptions.definer) : liveTriggerDefinition;
109
+
110
+ if (triggerDefinition) {
111
+
112
+ tables[tableName].triggers.push({
113
+ Name: triggerName,
114
+ Definition: triggerDefinition
115
+ });
116
+ if (command === 'dump') {
117
+ const tableDir = path.join(dbDir, 'tables'); // Subfolder for table SQL files
118
+ const triggerFilePath = path.join(tableDir, 'triggers', `${triggerName}.sql`);
119
+ await fs.mkdir(path.dirname(triggerFilePath), { recursive: true }); // Create the triggers directory if it doesn't exist
120
+ await fs.writeFile(triggerFilePath, `${triggerDefinition}\n`, 'utf-8');
121
+ logger(`Trigger definition saved to: ${triggerFilePath}`);
122
+ }
123
+
124
+ } else {
125
+ logger(`Trigger ${triggerName} has no action statement.`);
126
+ }
127
+ }
128
+
129
+ // Get views
130
+ const viewRows = await connection.query(`SHOW FULL TABLES IN \`${database}\` WHERE TABLE_TYPE LIKE 'VIEW'`);
131
+ for (const row of viewRows) {
132
+ let viewName = row[`Tables_in_${database.toLowerCase()}`];
133
+ if (!viewName) viewName = row[`Tables_in_${database}`];
134
+ logger(`getting view Tables_in_${database}`, viewName);
135
+ try {
136
+ const viewDefinition = await connection.query(`SHOW CREATE VIEW \`${viewName}\``);
137
+ const liveViewDefinition = viewDefinition[0]['Create View'];
138
+ views[viewName] = command === 'dump' ? applyDefiner(liveViewDefinition, syncOptions.definer) : liveViewDefinition;
139
+ if (command === 'dump') {
140
+ const filePath = path.join(dbDir, 'views', `${viewName}.sql`); // Use the table directory for file saving
141
+ await fs.mkdir(path.dirname(filePath), { recursive: true }); // Create the views directory if it doesn't exist
142
+ await fs.writeFile(filePath, `${views[viewName]}\n`, 'utf-8');
143
+ logger(`View definition saved to: ${filePath}`);
144
+ }
145
+ } catch (error) {
146
+ logger(`Error retrieving definition for view ${viewName}:`, error.message);
147
+ logger(row)
148
+ }
149
+ }
150
+
151
+ return { tables, procedures, views };
140
152
  }