extract-mysql-schema 0.7.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +126 -54
  2. package/package.json +2 -2
package/index.js CHANGED
@@ -29,59 +29,130 @@ const extractSchemas = async function (connection, options) {
29
29
  const schemaName = connection.database;
30
30
  options = options || {};
31
31
 
32
+
32
33
  let c = await mysql.createConnection(connection);
33
- let [queryProcedures] = await c.query(`
34
- SELECT * FROM INFORMATION_SCHEMA.ROUTINES where ROUTINE_SCHEMA = '${schemaName}'
35
- `);
36
-
37
- let [queryParameters] = await c.query(`
38
- SELECT p.* FROM INFORMATION_SCHEMA.PARAMETERS as p join INFORMATION_SCHEMA.ROUTINES as r on p.SPECIFIC_NAME=r.SPECIFIC_NAME and p.SPECIFIC_SCHEMA=r.ROUTINE_SCHEMA
39
- WHERE ROUTINE_SCHEMA='${schemaName}'
40
- ORDER BY p.SPECIFIC_NAME,p.ORDINAL_POSITION
41
- `);
42
-
43
- let [queryFkey] = await c.query(`
44
- SELECT iif.*, iifc.FOR_COL_NAME, iifc.REF_COL_NAME
45
- FROM INFORMATION_SCHEMA.INNODB_FOREIGN as iif
46
- JOIN INFORMATION_SCHEMA.INNODB_FOREIGN_COLS as iifc on iifc.ID=iif.ID
47
- WHERE iif.ID LIKE '${schemaName}/%'
48
- `);
49
-
50
- let [queryIndexes] = await c.query(`
51
- select
52
- T2.TABLE_SCHEMA,T2.TABLE_NAME,I.NAME as INDEX_NAME,
53
- C.COLUMN_TYPE as FIELD_TYPE,
54
- F.POS,I.TYPE,I.*,
55
- CASE WHEN I.TYPE=2 OR I.TYPE=3 THEN 'YES' ELSE 'NO' END AS IS_UNIQUE,
56
- CASE WHEN I.TYPE=3 THEN 'YES' ELSE 'NO' END AS IS_PRIMARY,
57
- CASE WHEN I.TYPE=0 THEN (CASE WHEN iif.id is not null THEN 'YES' ELSE 'NO' END) ELSE 'NO' END AS IS_FK,
58
- CASE WHEN C.EXTRA='auto_increment' THEN 'YES' ELSE 'NO' END AS IS_AUTONUMBER,
59
- F2.INDEX_KEYS as FIELD_NAME
60
- FROM INFORMATION_SCHEMA.INNODB_INDEXES I
61
- JOIN INFORMATION_SCHEMA.INNODB_FIELDS F on F.INDEX_ID=I.INDEX_ID
62
- JOIN (
63
- SELECT group_concat(FF.NAME ORDER BY FF.POS) as INDEX_KEYS,FF.INDEX_ID
64
- FROM INFORMATION_SCHEMA.INNODB_FIELDS as FF
65
- GROUP BY FF.INDEX_ID
66
- ) as F2 ON F2.INDEX_ID=F.INDEX_ID
67
- JOIN INFORMATION_SCHEMA.INNODB_TABLES T1 ON T1.TABLE_ID=I.TABLE_ID
68
- LEFT JOIN INFORMATION_SCHEMA.INNODB_FOREIGN as iif on iif.id= concat('${schemaName}','/',I.NAME)
69
- LEFT JOIN INFORMATION_SCHEMA.TABLES T2 ON T1.NAME=CONCAT(T2.TABLE_SCHEMA,'/',T2.TABLE_NAME)
70
- JOIN information_schema.COLUMNS C on C.TABLE_SCHEMA=T2.TABLE_SCHEMA and C.TABLE_NAME=T2.TABLE_NAME and C.COLUMN_NAME=F.NAME
71
- WHERE T2.TABLE_SCHEMA = '${schemaName}' and F.POS=0
72
- ORDER BY T2.TABLE_SCHEMA,T2.TABLE_NAME,I.NAME,F.POS
73
- `);
74
-
75
- let [queryColumns] = await c.query(`
76
- SELECT T.TABLE_TYPE,C.*,
77
- CASE WHEN EXISTS(SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS C2 WHERE C2.TABLE_SCHEMA=C.TABLE_SCHEMA and C2.TABLE_NAME=C.TABLE_NAME AND C2.COLUMN_KEY='PRI' AND C.COLUMN_KEY='PRI' AND C2.COLUMN_NAME<>C.COLUMN_NAME) THEN 'YES' ELSE 'NO' END AS IS_COMPOUND_KEY
78
- ,TP.PARTITION_METHOD,TP.PARTITION_EXPRESSION
79
- FROM INFORMATION_SCHEMA.COLUMNS C
80
- LEFT JOIN INFORMATION_SCHEMA.TABLES T ON T.TABLE_SCHEMA=C.TABLE_SCHEMA AND T.TABLE_NAME=C.TABLE_NAME
81
- LEFT JOIN INFORMATION_SCHEMA.PARTITIONS TP ON TP.TABLE_SCHEMA=C.TABLE_SCHEMA AND TP.TABLE_NAME=C.TABLE_NAME AND TP.PARTITION_NAME IS NOT NULL
82
- where C.TABLE_SCHEMA ='${schemaName}'
83
- order by C.TABLE_NAME,C.ORDINAL_POSITION
84
- `);
34
+
35
+ let queryProcedures = [];
36
+ let queryParameters = [];
37
+ let queryColumns = [];
38
+ let queryFkey = [];
39
+ let queryIndexes = [];
40
+ let [tablenames] = await c.query('SHOW TABLES');
41
+ let [proceduresResult] = await c.query(`SHOW PROCEDURE STATUS`);
42
+
43
+ const tableKey = Object.keys(tablenames[0])[0];
44
+
45
+ for (const row of tablenames) {
46
+ const tableName = row[tableKey];
47
+ const [columnsResult] = await c.query( `SHOW COLUMNS FROM \`${tableName}\`` );
48
+ const [indexResult] = await c.query( `SHOW INDEX FROM \`${tableName}\`` );
49
+ const [keysResult] = await c.query( `SHOW KEYS FROM \`${tableName}\`` );
50
+
51
+
52
+ for(let col in columnsResult) {
53
+ let column = {
54
+ "TABLE_TYPE": "BASE TABLE",
55
+ "TABLE_CATALOG": "def",
56
+ "TABLE_SCHEMA": schemaName,
57
+ "TABLE_NAME": tableName,
58
+ "COLUMN_NAME": columnsResult[col]['Field'],
59
+ "ORDINAL_POSITION": col,
60
+ "COLUMN_KEY": columnsResult[col]['Key'],
61
+ "EXTRA": columnsResult[col]['Extra'],
62
+ "IS_NULLABLE": columnsResult[col]['Null']==='YES' ? 'YES' : 'NO',
63
+ "COLUMN_DEFAULT": columnsResult[col]['Default'],
64
+ "COLUMN_TYPE": columnsResult[col]['Type'],
65
+ "DATA_TYPE": columnsResult[col]['Type'].split('(')[0],
66
+ "GENERATION_EXPRESSION": columnsResult[col]['Extra'].indexOf('GENERATED')>=0 ? columnsResult[col]['Default'] || '' : '',
67
+ "CHARACTER_MAXIMUM_LENGTH": columnsResult[col]['Type'].split('(')[1] ? parseInt(columnsResult[col]['Type'].split('(')[1]) : 0,
68
+ };
69
+
70
+ for(let idx in indexResult) {
71
+ if(indexResult[idx]['Column_name']===column['COLUMN_NAME']) {
72
+ column['IS_COMPOUND_KEY'] = indexResult[idx]['Key_name'] !== 'PRIMARY' && indexResult[idx]['Seq_in_index'] > 1 ? 'YES' : 'NO';
73
+ column["IS_PRIMARY_KEY"] = indexResult[idx]['Key_name'] === 'PRIMARY' ? 'YES' : 'NO';
74
+ }
75
+ }
76
+ queryColumns.push(column)
77
+ }
78
+
79
+ for(let key in keysResult) {
80
+ if(keysResult[key]['Key_name']!=='PRIMARY' && keysResult[key]['Referenced_table_name']) {
81
+ let fkey = {
82
+ "ID": schemaName + '/' + keysResult[key]['Key_name'],
83
+ "FOR_NAME": schemaName + '/' + tableName,
84
+ "FOR_COL_NAME": keysResult[key]['Column_name'],
85
+ "REF_NAME": schemaName + '/' + keysResult[key]['Referenced_table_name'],
86
+ "REF_COL_NAME": keysResult[key]['Referenced_column_name']
87
+ };
88
+ queryFkey.push(fkey);
89
+ }
90
+ }
91
+
92
+ queryIndexes=[]
93
+ for(let idx in indexResult) {
94
+ let isUnique = indexResult[idx]['Non_unique'] === 0 ? 'YES' : 'NO';
95
+ let isPrimary = indexResult[idx]['Key_name'] === 'PRIMARY' ? 'YES' : 'NO';
96
+ let isFK = 'NO';
97
+ for(let key in keysResult) {
98
+ if(keysResult[key]['Key_name']===indexResult[idx]['Key_name'] && keysResult[key]['Referenced_table_name']) {
99
+ isFK = 'YES';
100
+ }
101
+ }
102
+ queryIndexes.push({
103
+ "TABLE_SCHEMA": schemaName,
104
+ "TABLE_NAME": tableName,
105
+ "INDEX_NAME": indexResult[idx]['Key_name'],
106
+ "FIELD_TYPE": indexResult[idx]['Index_type'],
107
+ "POS": indexResult[idx]['Seq_in_index'] - 1,
108
+ "TYPE": indexResult[idx]['Index_type'],
109
+ "IS_UNIQUE": isUnique,
110
+ "IS_PRIMARY": isPrimary,
111
+ "IS_FK": isFK,
112
+ "IS_AUTONUMBER": 'NO',
113
+ "FIELD_NAME": indexResult[idx]['Column_name']
114
+ });
115
+ }
116
+ }
117
+
118
+ for(let proc of proceduresResult) {
119
+ if(proc['Db']!==schemaName) continue;
120
+ const [procDefResult] = await c.query( `SHOW CREATE PROCEDURE \`${proc['Name']}\`` );
121
+ let procedure = {
122
+ "SPECIFIC_NAME": proc['Name'],
123
+ "ROUTINE_DEFINITION": procDefResult[0]['Create Procedure']
124
+ };
125
+ queryProcedures.push(procedure);
126
+
127
+ const match = procDefResult[0]['Create Procedure'].match(/\(([\s\S]*?)\)/);
128
+ if (!match) { console.log('No parameters found'); return []; }
129
+ const paramString = match[1].trim();
130
+ const params = paramString .split(',') .map(p => p.trim()) .filter(p => p.length > 0);
131
+
132
+ for (let i = 0; i < params.length; i++) {
133
+ const paramParts = params[i].split(/\s+/);
134
+ let paramMode = 'IN';
135
+ let paramName, paramType;
136
+ if (paramParts.length === 2) {
137
+ paramName = paramParts[0];
138
+ paramType = paramParts[1];
139
+ } else if (paramParts.length === 3) {
140
+ paramMode = paramParts[0];
141
+ paramName = paramParts[1];
142
+ paramType = paramParts[2];
143
+ }
144
+ let parameter = {
145
+ "SPECIFIC_NAME": proc['Name'],
146
+ "PARAMETER_NAME": paramName,
147
+ "ORDINAL_POSITION": i + 1,
148
+ "PARAMETER_MODE": paramMode,
149
+ "DATA_TYPE": paramType.split('(')[0],
150
+ "DTD_IDENTIFIER": paramType,
151
+ "CHARACTER_MAXIMUM_LENGTH": paramType.split('(')[1] ? parseInt(paramType.split('(')[1]) : 0,
152
+ };
153
+ queryParameters.push(parameter);
154
+ }
155
+ }
85
156
 
86
157
  c.end();
87
158
 
@@ -181,7 +252,7 @@ const extractSchemas = async function (connection, options) {
181
252
  else def=`('${def}')`;
182
253
  }
183
254
  }
184
- if(wrapper.partition===undefined && queryColumns[i]['PARTITION_METHOD']!==null) wrapper.partition=`PARTITION BY ${queryColumns[i]['PARTITION_METHOD']}(${queryColumns[i]['PARTITION_EXPRESSION']})`;
255
+ if(wrapper.partition!==undefined && queryColumns[i]['PARTITION_METHOD']!==null) wrapper.partition=`PARTITION BY ${queryColumns[i]['PARTITION_METHOD']}(${queryColumns[i]['PARTITION_EXPRESSION']})`;
185
256
  if(def) def=`DEFAULT ${def}`;
186
257
  if(column.generated==="STORED") def = `${column.expression} STORED`;
187
258
  let notNull = column.isNullable?"NULL":"NOT NULL";
@@ -324,8 +395,9 @@ create index ${idx['INDEX_NAME']}
324
395
  if(paramsDefinition) paramsDefinition=`\n\t ${paramsDefinition}\n`;
325
396
 
326
397
  definition = `
327
- DELIMITER //
398
+
328
399
  DROP PROCEDURE IF EXISTS ${name};
400
+ DELIMITER //
329
401
  CREATE PROCEDURE ${name}(${paramsDefinition})
330
402
  ${definition};
331
403
  //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extract-mysql-schema",
3
- "version": "0.7.7",
3
+ "version": "1.0.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": "./run.js",
@@ -18,6 +18,6 @@
18
18
  "author": "Chris Doty",
19
19
  "license": "MIT",
20
20
  "dependencies": {
21
- "mysql2": "^3.9.3"
21
+ "mysql2": "^3.16.0"
22
22
  }
23
23
  }