extract-mysql-schema 0.4.0 → 0.6.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 (3) hide show
  1. package/index.js +61 -58
  2. package/package.json +1 -1
  3. package/run.js +38 -16
package/index.js CHANGED
@@ -68,25 +68,37 @@ const extractSchemas = async function (connection, options) {
68
68
  queryFkey=queryFkey[0];
69
69
 
70
70
  let queryIndexes = await adapter.query(`
71
- select T2.TABLE_SCHEMA,T2.TABLE_NAME,I.NAME as INDEX_NAME,F.NAME AS FIELD_NAME,F.POS,
72
- CASE WHEN I.TYPE=2 OR I.TYPE=3 THEN 'YES' ELSE 'NO' END AS IS_UNIQUE,
73
- CASE WHEN I.TYPE=3 THEN 'YES' ELSE 'NO' END AS IS_PRIMARY,
74
- CASE WHEN I.TYPE=0 THEN 'YES' ELSE 'NO' END AS IS_FK
75
- from INFORMATION_SCHEMA.INNODB_INDEXES I
71
+ select
72
+ T2.TABLE_SCHEMA,T2.TABLE_NAME,I.NAME as INDEX_NAME,
73
+ C.COLUMN_TYPE as FIELD_TYPE,
74
+ F.POS,I.TYPE,I.*,
75
+ CASE WHEN I.TYPE=2 OR I.TYPE=3 THEN 'YES' ELSE 'NO' END AS IS_UNIQUE,
76
+ CASE WHEN I.TYPE=3 THEN 'YES' ELSE 'NO' END AS IS_PRIMARY,
77
+ CASE WHEN I.TYPE=0 THEN 'YES' ELSE 'NO' END AS IS_FK,
78
+ CASE WHEN C.EXTRA='auto_increment' THEN 'YES' ELSE 'NO' END AS IS_AUTONUMBER,
79
+ F2.INDEX_KEYS as FIELD_NAME
80
+ FROM INFORMATION_SCHEMA.INNODB_INDEXES I
76
81
  JOIN INFORMATION_SCHEMA.INNODB_FIELDS F on F.INDEX_ID=I.INDEX_ID
82
+ JOIN (
83
+ SELECT group_concat(FF.NAME) as INDEX_KEYS,FF.INDEX_ID
84
+ FROM INFORMATION_SCHEMA.INNODB_FIELDS as FF
85
+ GROUP BY FF.INDEX_ID
86
+ ) as F2 ON F2.INDEX_ID=F.INDEX_ID
77
87
  JOIN INFORMATION_SCHEMA.INNODB_TABLES T1 ON T1.TABLE_ID=I.TABLE_ID
78
88
  LEFT JOIN INFORMATION_SCHEMA.TABLES T2 ON T1.NAME=CONCAT(T2.TABLE_SCHEMA,'/',T2.TABLE_NAME)
79
- WHERE T2.TABLE_SCHEMA = '${schemaName}'
89
+ 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
90
+ WHERE T2.TABLE_SCHEMA = 'litservices' and F.POS=0
80
91
  ORDER BY T2.TABLE_SCHEMA,T2.TABLE_NAME,I.NAME,F.POS
81
92
  `);
82
93
  queryIndexes=queryIndexes[0];
83
94
 
84
95
  let queryColumns = await adapter.query(`
85
- SELECT T.TABLE_TYPE,C.*
96
+ SELECT T.TABLE_TYPE,C.*,
97
+ 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
86
98
  FROM INFORMATION_SCHEMA.COLUMNS C
87
99
  LEFT JOIN INFORMATION_SCHEMA.TABLES T ON T.TABLE_SCHEMA=C.TABLE_SCHEMA AND T.TABLE_NAME=C.TABLE_NAME
88
100
  where C.TABLE_SCHEMA ='${schemaName}'
89
- ORDER BY C.TABLE_NAME,C.ORDINAL_POSITION
101
+ order by C.TABLE_NAME,C.ORDINAL_POSITION
90
102
  `);
91
103
  queryColumns = queryColumns[0];
92
104
 
@@ -166,6 +178,7 @@ const extractSchemas = async function (connection, options) {
166
178
  sqltype: queryColumns[i]['COLUMN_TYPE'],
167
179
  maxLength: queryColumns[i]['CHARACTER_MAXIMUM_LENGTH'],
168
180
  isPrimaryKey: queryColumns[i]['COLUMN_KEY'] === 'PRI',
181
+ isCompoundKey: queryColumns[i]['IS_COMPOUND_KEY'] === 'YES',
169
182
  isNullable: queryColumns[i]['IS_NULLABLE'] === 'YES',
170
183
  isAutoNumber: queryColumns[i]['EXTRA'] === 'auto_increment',
171
184
  generated: queryColumns[i]['EXTRA'].indexOf('DEFAULT_GENERATED') >= 0 ? (queryColumns[i]['EXTRA'].indexOf('on update') > 0 ? "ALWAYS" : "BY DEFAULT") : "NEVER",
@@ -179,10 +192,13 @@ const extractSchemas = async function (connection, options) {
179
192
  let def = column.defaultValue?(column.defaultValue):"";
180
193
  if(def!=="CURRENT_TIMESTAMP" && def) {
181
194
  if(def.indexOf('(')>0) def=`(${def})`;
182
- else if(column.type.indexOf('char')>=0 || column.type.indexOf('text')>=0) def=`'${def}'`;
195
+ else if(column.type.indexOf('char')>=0 || column.type.indexOf('text')>=0) {
196
+ if(def.indexOf("'")>=0) def='('+def.replace(/\\'/g,"'")+')';
197
+ else def=`('${def}')`;
198
+ }
183
199
  }
184
200
  if(def) def=`DEFAULT ${def}`;
185
- definition.push(`${name}\t${column.sqltype}\t${column.isAutoNumber?" auto_increment":""}${def}\t${column.isNullable?"NULL":"NOT NULL"}${column.isPrimaryKey?" PRIMARY KEY":""}${extra}`);
201
+ definition.push(`${name}\t${column.sqltype}\t${column.isAutoNumber && column.isPrimaryKey ?" auto_increment":""}${def}\t${column.isNullable?"NULL":"NOT NULL"}${column.isPrimaryKey && !column.isCompoundKey?" PRIMARY KEY":""}${extra}`);
186
202
 
187
203
  if(foreign[tableName+"_"+name]!==undefined) {
188
204
  column.references.push(foreign[tableName+"_"+name]);
@@ -208,75 +224,62 @@ const extractSchemas = async function (connection, options) {
208
224
  let isConstraint = idx['IS_UNIQUE']==='YES' || idx['IS_PRIMARY']==='YES' || idx['IS_FK']==='YES';
209
225
 
210
226
  if(isConstraint) {
211
- if(idx['IS_PRIMARY']==='YES') return;
212
- else if(idx['IS_UNIQUE']==='YES') {
213
- definitions.push(`
227
+ if(idx['IS_PRIMARY']==='YES') {
228
+ if(idx['FIELD_NAME'].indexOf(',')>0) {
229
+ definitions.push(`
214
230
  alter table ${idx['TABLE_NAME']}
215
- add constraint ${idx['INDEX_NAME']}
216
- unique (${idx['FIELD_NAME']});
231
+ add primary key (${idx['FIELD_NAME']});
217
232
  `)
218
- } else {
219
- let ref = foreign[name+"_"+idx['FIELD_NAME']];
220
- //console.log("HERE",name+"_"+idx['FIELD_NAME'],ref);
221
- if(ref===undefined) return;
222
-
233
+ }
234
+ } else if(idx['IS_UNIQUE']==='YES') {
223
235
  definitions.push(`
224
236
  alter table ${idx['TABLE_NAME']}
225
237
  add constraint ${idx['INDEX_NAME']}
226
- foreign key (${idx['FIELD_NAME']}) references ${ref['tableName']} (${ref['columnName']});
238
+ unique (${idx['FIELD_NAME']});
227
239
  `)
240
+ if(idx['IS_AUTONUMBER']==='YES') {
241
+ definitions.push(`
242
+ alter table ${idx['TABLE_NAME']}
243
+ modify ${idx['FIELD_NAME']} ${idx['FIELD_TYPE']} auto_increment;`);
244
+ definitions.push(`
245
+ alter table ${idx['TABLE_NAME']}
246
+ auto_increment = 1;`);
247
+ }
228
248
  }
229
249
  } else {
230
250
  definitions.push(`
231
251
  create index ${idx['INDEX_NAME']}
232
- on ${idx['TABLE_NAME']} (${idx['FIELD_NAME']});
233
- `)
252
+ on ${idx['TABLE_NAME']} (${idx['FIELD_NAME']});`)
234
253
  }
235
254
  });
236
255
 
237
256
  wrapper.definition = definitions.join('\n');
238
- // if(name==="application") console.log(wrapper.definition);
239
257
  });
240
258
 
241
- let noparent = [];
259
+ let tableOrder = [];
242
260
  for (let i = 0; i < tables.length; i++) {
243
261
  if(hasParent.indexOf(tables[i].name)<0) {
244
- noparent.push(tables[i].name);
245
- }
246
- }
247
- noparent.sort();
248
-
249
- let byCounts = {};
250
- for (let i = 0; i < hasParent.length; i++) {
251
- let tableName = hasParent[i];
252
- let table = schema[hasParent[i]];
253
- for (let j = 0; j < table.length; j++) {
254
- var column = table[j];
255
- var references = column.references;
256
- if(column.references.length==0) continue;
257
-
258
- for (let k = 0; k < references.length; k++) {
259
- var reference = references[k];
260
- if(byCounts[reference.tableName]===undefined) byCounts[reference.tableName]={name:reference.tableName,count:0,children:[]};
261
- byCounts[reference.tableName].count++;
262
- byCounts[reference.tableName].children.push(tableName);
263
- }
262
+ tableOrder.push(tables[i].name);
264
263
  }
265
264
  }
266
- byCounts = orderBy(byCounts,['count']).reverse();
267
- let tableOrder = noparent;
268
- for(let i=0;i<byCounts.length;i++){
269
- if(tableOrder.indexOf(byCounts[i].name)<0)
270
- tableOrder.push(byCounts[i].name);
271
-
272
- let children = byCounts[i].children;
273
- for(let j=0;j<children.length;j++){
274
- let child=children[j];
275
- if(tableOrder.indexOf(child)<0 && byCounts.indexOf(child)<0) {
276
- tableOrder.push(child);
277
- }
265
+ tableOrder.sort();
266
+
267
+ hasParent.forEach((child)=>{
268
+ let tableColumns = schema[child];
269
+ let pos=-1;
270
+ tableColumns.forEach((column)=>{
271
+ column.references.forEach((reference)=>{
272
+ let pos2 = tableOrder.indexOf(reference.tableName);
273
+ //console.log(child,reference.tableName,pos,pos2);
274
+ if(pos2<0) { if(tableOrder.indexOf(reference.tableName)<0) { tableOrder.push(reference.tableName); } }
275
+ else if(pos2+1>pos) pos=pos2+1;
276
+ });
277
+ });
278
+ if(tableOrder.indexOf(child)<0) {
279
+ if(pos<0) tableOrder.push(child);
280
+ else tableOrder.splice(pos,0,child);
278
281
  }
279
- }
282
+ });
280
283
 
281
284
  const procedures = [];
282
285
  for(let i=0;i<queryProcedures.length;i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extract-mysql-schema",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": "./run.js",
package/run.js CHANGED
@@ -7,53 +7,75 @@ async function main(options) {
7
7
  const result = await extractSchemas(config.connection,options);
8
8
 
9
9
  if(options.writeSql){
10
-
10
+ const done = [];
11
11
  const content = [];
12
+ const processFolder = function(seedPath) {
13
+ if(fs.existsSync(seedPath)) {
14
+ fs.readdirSync(seedPath).forEach(file => {
15
+ file = path.join(seedPath,file);
16
+ if(done.indexOf(file)<0){
17
+ content.push(fs.readFileSync(file,"utf8"));
18
+ }
19
+ });
20
+ }
21
+ };
22
+
23
+ const tablesPath=path.join(process.cwd(),"tables");
12
24
  if(result[config.connection.database].tables.length>0) {
13
25
  // write table sql
14
- const tablesPath=path.join(process.cwd(),"tables")
15
26
  if (!fs.existsSync(tablesPath)){
16
27
  fs.mkdirSync(tablesPath);
17
28
  }
18
29
  const byName = {};
19
30
  result[config.connection.database].tables.forEach(table => {
20
31
  byName[table.name] = table.definition;
21
- if(options.verbose) console.log("writing",path.join(tablesPath,table.name+".sql"));
22
- fs.writeFileSync(path.join(tablesPath,table.name+".sql"), table.definition ,"utf8")
32
+ let file = path.join(tablesPath,table.name+".sql");
33
+ done.push(file);
34
+ if(options.verbose) console.log("writing",file);
35
+ fs.writeFileSync(file, table.definition ,"utf8")
23
36
  });
24
37
 
25
38
  result[config.connection.database].tableOrder.forEach(table => {
26
39
  content.push(byName[table]);
27
40
  })
28
41
  }
42
+ processFolder(tablesPath);
29
43
 
44
+ const proceduresPath=path.join(process.cwd(),"procedures");
30
45
  if(result[config.connection.database].procedures.length>0) {
31
46
  // write routines
32
- const proceduresPath=path.join(process.cwd(),"procedures")
33
47
  if (!fs.existsSync(proceduresPath)){
34
48
  fs.mkdirSync(proceduresPath);
35
49
  }
36
50
  result[config.connection.database].procedures.forEach(proc => {
37
- if(options.verbose) console.log("writing",path.join(proceduresPath,proc.name+".sql"));
51
+ let file = path.join(proceduresPath,proc.name+".sql");
52
+ done.push(file);
53
+ if(options.verbose) console.log("writing",file);
38
54
  content.push(proc.definition);
39
- fs.writeFileSync(path.join(proceduresPath,proc.name+".sql"), proc.definition ,"utf8")
55
+ fs.writeFileSync(file, proc.definition ,"utf8")
56
+ });
57
+ }
58
+ processFolder(proceduresPath);
59
+
60
+ const seedPath = path.join(process.cwd(),"seed");
61
+ if(fs.existsSync(seedPath)) {
62
+ result[config.connection.database].tableOrder.forEach(table => {
63
+ let seedfile = path.join(seedPath,table+'.sql');
64
+ if (fs.existsSync(seedfile)){
65
+ done.push(seedfile);
66
+ content.push(fs.readFileSync(seedfile,"utf8"));
67
+ }
40
68
  });
41
69
  }
70
+ processFolder(seedPath);
71
+
72
+ processFolder(path.join(process.cwd(),"override"));
42
73
 
43
74
  if(content.length>0) {
44
75
  fs.writeFileSync(path.join(process.cwd(),"init.sql"), content.join('\n\n') ,"utf8");
45
76
  }
46
77
  }
47
78
 
48
- const seedList = [];
49
- result[config.connection.database].tableOrder.forEach(table => {
50
- let seedfile = path.join(process.cwd(),"seed",table+'.sql');
51
- seedList.push(seedfile);
52
- if (!fs.existsSync(seedfile)){
53
- content.push(fs.readFileSync(seedfile,"utf8"));
54
- }
55
- })
56
-
57
79
  if(options.outputFile) {
58
80
  fs.writeFileSync(path.join(process.cwd(),options.outputFile), JSON.stringify(result,null,2) ,"utf8")
59
81
  } else console.log(JSON.stringify(result,null,2));