gg-mysql-connector 1.0.37 → 1.0.39
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/app_INF.ts +24 -0
- package/app_model_const.ts +24 -0
- package/dist/app_INF.d.ts +8 -1
- package/dist/app_model_const.d.ts +24 -0
- package/dist/app_model_const.js +27 -0
- package/dist/seed_INF.d.ts +6 -0
- package/dist/seed_INF.js +2 -0
- package/dist/src/GGMySQLConnector/GGMySQLConnector.d.ts +72 -0
- package/dist/src/GGMySQLConnector/GGMySQLConnector.js +296 -0
- package/dist/src/ModelGenerator/ModelGenerator.d.ts +39 -0
- package/dist/src/ModelGenerator/ModelGenerator.js +317 -0
- package/dist/src/ModelGenerator/SeedGenerator.d.ts +0 -0
- package/dist/src/ModelGenerator/SeedGenerator.js +30 -0
- package/dist/src/MyDBMigrator/MyDBMigrator.d.ts +24 -0
- package/dist/src/MyDBMigrator/MyDBMigrator.js +196 -0
- package/dist/src/app_INF.d.ts +17 -0
- package/dist/src/app_INF.js +2 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +10 -0
- package/dist/src/myModel.d.ts +21 -0
- package/dist/src/myModel.js +2 -0
- package/package.json +4 -3
- package/seed_INF.ts +3 -0
- package/src/ModelGenerator/ModelGenerator.ts +44 -19
- package/src/ModelGenerator/SeedGenerator.ts +32 -2
- package/src/MyDBMigrator/MyDBMigrator.ts +65 -7
- package/src/myModel.ts +7 -5
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const promise_1 = __importDefault(require("mysql2/promise"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const MyDBMigrator_1 = __importDefault(require("../MyDBMigrator/MyDBMigrator"));
|
|
12
|
+
class ModelGenerator {
|
|
13
|
+
constructor(dbInfo, model) {
|
|
14
|
+
this.printResultLength = (results, executionTime, queryResult) => {
|
|
15
|
+
if (results.length) {
|
|
16
|
+
const executionTimeMessage = executionTime > 1000
|
|
17
|
+
? chalk_1.default.bgRed(`${executionTime} ` + " ms")
|
|
18
|
+
: chalk_1.default.yellow(`${executionTime} ` + " ms");
|
|
19
|
+
console.log(`${chalk_1.default.green(queryResult.sql)} ${chalk_1.default.cyan(`found ${results.length} rows.`)} ${executionTimeMessage}`);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
this.model = model;
|
|
23
|
+
this.dbInfo = dbInfo;
|
|
24
|
+
this.isConnected = false;
|
|
25
|
+
}
|
|
26
|
+
async init() {
|
|
27
|
+
console.log("init");
|
|
28
|
+
this.connection = await promise_1.default.createConnection({
|
|
29
|
+
host: this.dbInfo.host,
|
|
30
|
+
user: this.dbInfo.user,
|
|
31
|
+
password: this.dbInfo.password,
|
|
32
|
+
});
|
|
33
|
+
this.isConnected = true;
|
|
34
|
+
await this.createDatabaseIfNotExist();
|
|
35
|
+
}
|
|
36
|
+
async createDatabaseIfNotExist() {
|
|
37
|
+
const databaseName = this.dbInfo.database;
|
|
38
|
+
await this.connection.query(`CREATE DATABASE IF NOT EXISTS ${databaseName}`);
|
|
39
|
+
await this.connection.query(`USE ${databaseName}`);
|
|
40
|
+
}
|
|
41
|
+
async pushModelToDB() {
|
|
42
|
+
const migrator = new MyDBMigrator_1.default(this);
|
|
43
|
+
await migrator.migrateTable(this.model);
|
|
44
|
+
}
|
|
45
|
+
async pushViewToDB(viewDirectory) {
|
|
46
|
+
const migrator = new MyDBMigrator_1.default(this);
|
|
47
|
+
await migrator.migrateView(viewDirectory);
|
|
48
|
+
}
|
|
49
|
+
async pushViewToDB_v2(viewModel) {
|
|
50
|
+
const migrator = new MyDBMigrator_1.default(this);
|
|
51
|
+
await migrator.migrateView_v2(viewModel);
|
|
52
|
+
}
|
|
53
|
+
waitUntilInitSuccess(interval) {
|
|
54
|
+
if (this.isConnected === true)
|
|
55
|
+
return true;
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
if (this.isConnected === false) {
|
|
59
|
+
console.log(`${this.dbInfo.database} > wait for database connection . . .`);
|
|
60
|
+
this.waitUntilInitSuccess(interval);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return resolve(true);
|
|
64
|
+
}
|
|
65
|
+
}, interval);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async query(statment, parameter, isPrint) {
|
|
69
|
+
await this.waitUntilInitSuccess(1000);
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
const uniqueTime = `${(0, crypto_1.randomUUID)()} ${statment}`;
|
|
72
|
+
console.time(uniqueTime);
|
|
73
|
+
const startTime = new Date();
|
|
74
|
+
const queryResult = this.connection
|
|
75
|
+
.query(statment, parameter)
|
|
76
|
+
.then((result) => {
|
|
77
|
+
const endTime = new Date();
|
|
78
|
+
const executionTime = endTime.getTime() - startTime.getTime();
|
|
79
|
+
if (isPrint === true)
|
|
80
|
+
this.printResultLength(result, executionTime, queryResult);
|
|
81
|
+
resolve(result[0]);
|
|
82
|
+
})
|
|
83
|
+
.catch((error) => {
|
|
84
|
+
// _getCallerFile()
|
|
85
|
+
console.log(chalk_1.default.bgRed("Query Error"));
|
|
86
|
+
console.log(chalk_1.default.bgRed(error));
|
|
87
|
+
console.log(chalk_1.default.bgRed("Statement : "));
|
|
88
|
+
console.log(statment);
|
|
89
|
+
console.log(chalk_1.default.bgRed("Parameter : "));
|
|
90
|
+
console.log(parameter);
|
|
91
|
+
console.log("------------------------------------------------");
|
|
92
|
+
console.log(chalk_1.default.bgRed(queryResult.sql));
|
|
93
|
+
reject(error);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async getTableNameList() {
|
|
98
|
+
let data = [];
|
|
99
|
+
let result = (await this.query("SELECT * FROM information_schema.tables WHERE table_schema = ? AND TABLE_TYPE = 'BASE TABLE'", [this.dbInfo.database], false));
|
|
100
|
+
for (let row of result)
|
|
101
|
+
data.push(row.TABLE_NAME || row.row.table_name);
|
|
102
|
+
return data;
|
|
103
|
+
}
|
|
104
|
+
async getViewNameList() {
|
|
105
|
+
let data = [];
|
|
106
|
+
let result = (await this.query("SELECT * FROM information_schema.tables WHERE table_schema = ? AND TABLE_TYPE = 'VIEW'", [this.dbInfo.database], false));
|
|
107
|
+
for (let row of result)
|
|
108
|
+
data.push(row.TABLE_NAME || row.row.table_name);
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
async getColumnFullList(tableName) {
|
|
112
|
+
const result = (await this.query(`SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.dbInfo.database}' AND TABLE_NAME = '${tableName}'`, undefined, false));
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
isTableNameExistInModel(model, tableName) {
|
|
116
|
+
if (tableName === "sessions")
|
|
117
|
+
return true;
|
|
118
|
+
const table = model.find((row) => row.tableName === tableName);
|
|
119
|
+
return table ? true : false;
|
|
120
|
+
}
|
|
121
|
+
isColumnExistInModel(model, tableName, columnName) {
|
|
122
|
+
if (tableName === "sessions")
|
|
123
|
+
return true;
|
|
124
|
+
const table = model.find((row) => row.tableName === tableName);
|
|
125
|
+
if (table) {
|
|
126
|
+
const column = table.columns.find((row) => row.COLUMN_NAME === columnName);
|
|
127
|
+
if (column)
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
getPossibleColumnValue(model, tableName, columnName, columnType) {
|
|
133
|
+
const foundTable = model.find((row) => row.tableName === tableName);
|
|
134
|
+
// search in table model
|
|
135
|
+
if (foundTable) {
|
|
136
|
+
const foundColumn = foundTable["columns"].find((row) => row.COLUMN_NAME === columnName);
|
|
137
|
+
// find in possible value in table model first
|
|
138
|
+
if (foundColumn && foundColumn.POSSIBLE_VALUE) {
|
|
139
|
+
return foundColumn.POSSIBLE_VALUE;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// search in database view data structure
|
|
147
|
+
// if not found. search in view stucture in db engine structure
|
|
148
|
+
if (columnType.search("enum") >= 0) {
|
|
149
|
+
let temp = columnType.replace("enum(", "");
|
|
150
|
+
temp = temp.slice(0, -1);
|
|
151
|
+
temp = temp.replace(/"/g, "");
|
|
152
|
+
temp = temp.replace(/'/g, "");
|
|
153
|
+
let word = temp.split(",");
|
|
154
|
+
return word;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async generateModelInterface(params) {
|
|
159
|
+
const tableList = [
|
|
160
|
+
...(await this.getTableNameList()),
|
|
161
|
+
...(await this.getViewNameList()),
|
|
162
|
+
];
|
|
163
|
+
const arrayOfColumnKeyValue = [];
|
|
164
|
+
const arrayOfSeedColumnKeyValue = [];
|
|
165
|
+
for (let i = 0; i < tableList.length; i++) {
|
|
166
|
+
const tableName = tableList[i];
|
|
167
|
+
if (this.isTableNameExistInModel(params.model, tableName) ||
|
|
168
|
+
tableName.search("_view") >= 0) {
|
|
169
|
+
const columnList = await this.getColumnFullList(tableName);
|
|
170
|
+
let stringOfRawColumnKeyAndValue = "";
|
|
171
|
+
for (const cRow of columnList) {
|
|
172
|
+
// console.log("cRow", cRow.COLUMN_TYPE)
|
|
173
|
+
const isColumnExistInModel = this.isColumnExistInModel(params.model, tableName, cRow.COLUMN_NAME);
|
|
174
|
+
if (isColumnExistInModel || tableName.search("_view") >= 0) {
|
|
175
|
+
const possibleValue = this.getPossibleColumnValue(params.model, cRow.TABLE_NAME, cRow.COLUMN_NAME, cRow.COLUMN_TYPE);
|
|
176
|
+
if (possibleValue) {
|
|
177
|
+
stringOfRawColumnKeyAndValue = `${stringOfRawColumnKeyAndValue} \n ${cRow.COLUMN_NAME}: ${possibleValue.map((row) => `"${row}"`).join(" | ")};`;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
stringOfRawColumnKeyAndValue = `${stringOfRawColumnKeyAndValue} \n ${cRow.COLUMN_NAME}: ${convertDataType(cRow.DATA_TYPE)};`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
console.log(`${tableName}-${cRow.COLUMN_NAME} not exist in model `);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// normal app model code
|
|
188
|
+
const str = ` ${tableName} : { ${stringOfRawColumnKeyAndValue} }`;
|
|
189
|
+
arrayOfColumnKeyValue.push(str);
|
|
190
|
+
// only seed model code
|
|
191
|
+
const tempSeedModel = params.model.find((row) => row.tableName === tableName && row.isSeed);
|
|
192
|
+
if (tempSeedModel)
|
|
193
|
+
arrayOfSeedColumnKeyValue.push(str);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// normal app model code
|
|
197
|
+
const fileName = `${params.appName}_INF.ts`;
|
|
198
|
+
const seedFileName = `seed_INF.ts`;
|
|
199
|
+
const code = `export default interface ${params.appName}_INF { ${arrayOfColumnKeyValue.join("\n")} }`;
|
|
200
|
+
const seedCode = `export default interface seed_INF { ${arrayOfSeedColumnKeyValue.join("\n")} }`;
|
|
201
|
+
for (let row of params.outputDirectory) {
|
|
202
|
+
// normal app model code
|
|
203
|
+
const serverFilePath = path_1.default.join(row, fileName);
|
|
204
|
+
await fs_1.default.writeFileSync(serverFilePath, code);
|
|
205
|
+
console.log("save app model to ", serverFilePath);
|
|
206
|
+
// only seed model code
|
|
207
|
+
const seedServerFilePath = path_1.default.join(row, seedFileName);
|
|
208
|
+
await fs_1.default.writeFileSync(seedServerFilePath, seedCode);
|
|
209
|
+
console.log("save seed model to ", seedServerFilePath);
|
|
210
|
+
}
|
|
211
|
+
console.log(`generate interface ${params.appName} ${chalk_1.default.bgGreen(" SUCCESS ")}`);
|
|
212
|
+
return code;
|
|
213
|
+
}
|
|
214
|
+
async generateModelConstStructure(params) {
|
|
215
|
+
const isTableNameExistInModel = (tableName) => {
|
|
216
|
+
if (tableName === "sessions")
|
|
217
|
+
return true;
|
|
218
|
+
const table = params.model.find((row) => row.tableName === tableName);
|
|
219
|
+
if (table)
|
|
220
|
+
return true;
|
|
221
|
+
return false;
|
|
222
|
+
};
|
|
223
|
+
const isColumnExistInModel = (tableName, columnName) => {
|
|
224
|
+
if (tableName === "sessions")
|
|
225
|
+
return true;
|
|
226
|
+
const table = params.model.find((row) => row.tableName === tableName);
|
|
227
|
+
if (table) {
|
|
228
|
+
const column = table.columns.find((row) => row.COLUMN_NAME === columnName);
|
|
229
|
+
if (column)
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
return false;
|
|
233
|
+
};
|
|
234
|
+
// const getPossibleColumnValue = (tableName: string, columnName: string) => {
|
|
235
|
+
// const foundTable = params.model.find((row) => row.tableName === tableName)
|
|
236
|
+
// if (foundTable) {
|
|
237
|
+
// const foundColumn = foundTable["columns"].find(
|
|
238
|
+
// (row) => row.COLUMN_NAME === columnName
|
|
239
|
+
// )
|
|
240
|
+
// if (foundColumn) {
|
|
241
|
+
// if (foundColumn.POSSIBLE_VALUE) return foundColumn.POSSIBLE_VALUE
|
|
242
|
+
// } else return false
|
|
243
|
+
// }
|
|
244
|
+
// }
|
|
245
|
+
const tableList = [
|
|
246
|
+
...(await this.getTableNameList()),
|
|
247
|
+
...(await this.getViewNameList()),
|
|
248
|
+
];
|
|
249
|
+
const array = [];
|
|
250
|
+
for (let i = 0; i < tableList.length; i++) {
|
|
251
|
+
const tableName = tableList[i];
|
|
252
|
+
if (isTableNameExistInModel(tableName) ||
|
|
253
|
+
tableName.search("_view") >= 0) {
|
|
254
|
+
const columnList = await this.getColumnFullList(tableName);
|
|
255
|
+
let value = "";
|
|
256
|
+
for (const cRow of columnList) {
|
|
257
|
+
const columnChecker = isColumnExistInModel(tableName, cRow.COLUMN_NAME);
|
|
258
|
+
if (columnChecker || tableName.search("_view") >= 0) {
|
|
259
|
+
const possibleValue = this.getPossibleColumnValue(params.model, cRow.TABLE_NAME, cRow.COLUMN_NAME, cRow.COLUMN_TYPE);
|
|
260
|
+
if (possibleValue) {
|
|
261
|
+
value = `${value} \n ${cRow.COLUMN_NAME}: [${possibleValue
|
|
262
|
+
.map((row) => {
|
|
263
|
+
if (typeof row === "string")
|
|
264
|
+
return `"${row}"`;
|
|
265
|
+
else if (typeof row === "number")
|
|
266
|
+
return `${row}`;
|
|
267
|
+
})
|
|
268
|
+
.join(" , ")}] as ${typeof possibleValue[0]}[],`;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
value = `${value} \n ${cRow.COLUMN_NAME}: "${convertDataType(cRow.DATA_TYPE)}",`;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
console.log(`${tableName}-${cRow.COLUMN_NAME} not exist in model `);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const str = ` ${tableName} : { ${value} }`;
|
|
279
|
+
array.push(str);
|
|
280
|
+
// console.log(`generate interface from ${tableName}`)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const fileName = `${params.appName}_model_const.ts`;
|
|
284
|
+
const code = `
|
|
285
|
+
export const ${params.appName}_model_const = { ${array.join(",")} } as const`;
|
|
286
|
+
for (let row of params.outputDirectory) {
|
|
287
|
+
const serverFilePath = path_1.default.join(row, fileName);
|
|
288
|
+
await fs_1.default.writeFileSync(serverFilePath, code);
|
|
289
|
+
console.log("save to ", serverFilePath);
|
|
290
|
+
}
|
|
291
|
+
console.log(`generate interface ${params.appName} ${chalk_1.default.bgGreen(" SUCCESS ")}`);
|
|
292
|
+
return code;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
exports.default = ModelGenerator;
|
|
296
|
+
function convertDataType(inputDataType) {
|
|
297
|
+
let result = "string";
|
|
298
|
+
if (inputDataType === "int") {
|
|
299
|
+
result = "number";
|
|
300
|
+
}
|
|
301
|
+
else if (inputDataType === "tinyint") {
|
|
302
|
+
result = "number";
|
|
303
|
+
}
|
|
304
|
+
else if (inputDataType === "bigint") {
|
|
305
|
+
result = "number";
|
|
306
|
+
}
|
|
307
|
+
else if (inputDataType === "date") {
|
|
308
|
+
result = "string";
|
|
309
|
+
}
|
|
310
|
+
else if (inputDataType === "float") {
|
|
311
|
+
result = "number";
|
|
312
|
+
}
|
|
313
|
+
else if (inputDataType === "double") {
|
|
314
|
+
result = "number";
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// import { MyModel } from "../myModel"
|
|
3
|
+
// function generateSeedInterfaceNoDBConnection(models: MyModel[]) {
|
|
4
|
+
// for (const tableModel of models) {
|
|
5
|
+
// const arrayOfColumnKeyValue = []
|
|
6
|
+
// const arrayOfSeedColumnKeyValue = []
|
|
7
|
+
// const columnList = tableModel.columns
|
|
8
|
+
// let stringOfRawColumnKeyAndValue = ""
|
|
9
|
+
// for (const cRow of columnList) {
|
|
10
|
+
// const possibleValue = cRow.POSSIBLE_VALUE
|
|
11
|
+
// if (possibleValue) {
|
|
12
|
+
// stringOfRawColumnKeyAndValue = `${stringOfRawColumnKeyAndValue} \n ${
|
|
13
|
+
// cRow.COLUMN_NAME
|
|
14
|
+
// }: ${possibleValue.map((row) => `"${row}"`).join(" | ")};`
|
|
15
|
+
// } else {
|
|
16
|
+
// stringOfRawColumnKeyAndValue = `${stringOfRawColumnKeyAndValue} \n ${
|
|
17
|
+
// cRow.COLUMN_NAME
|
|
18
|
+
// }: ${convertDataType(cRow.DATA_TYPE)};`
|
|
19
|
+
// }
|
|
20
|
+
// }
|
|
21
|
+
// // normal app model code
|
|
22
|
+
// const str = ` ${tableName} : { ${stringOfRawColumnKeyAndValue} }`
|
|
23
|
+
// arrayOfColumnKeyValue.push(str)
|
|
24
|
+
// // only seed model code
|
|
25
|
+
// const tempSeedModel = params.model.find(
|
|
26
|
+
// (row) => row.tableName === tableName && row.isSeed
|
|
27
|
+
// )
|
|
28
|
+
// if (tempSeedModel) arrayOfSeedColumnKeyValue.push(str)
|
|
29
|
+
// }
|
|
30
|
+
// }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import ModelGenerator from "../ModelGenerator/ModelGenerator";
|
|
2
|
+
import { columnType, MyModel, MyViewModel } from "../myModel";
|
|
3
|
+
export default class MyDBMigrator {
|
|
4
|
+
MyDB: ModelGenerator;
|
|
5
|
+
onetimeLoadColumnContent: {
|
|
6
|
+
COLUMN_NAME: string;
|
|
7
|
+
DATA_TYPE: columnType;
|
|
8
|
+
TABLE_NAME: string;
|
|
9
|
+
COLUMN_DEFAULT: string;
|
|
10
|
+
COLUMN_KEY: string;
|
|
11
|
+
}[];
|
|
12
|
+
constructor(connection: ModelGenerator);
|
|
13
|
+
migrateTable(model: MyModel[]): Promise<void>;
|
|
14
|
+
private createTableIfNotExist;
|
|
15
|
+
private columnInTableExist;
|
|
16
|
+
private loadColumnContentIfEmpty;
|
|
17
|
+
private checkIsColumnDataTypeChange;
|
|
18
|
+
alterUniqueKey(tableName: string, columnName: string, IS_UNIQUE: boolean | undefined): Promise<void>;
|
|
19
|
+
alterIndex(tableName: string, columnName: string, IS_INDEX: boolean | undefined): Promise<void>;
|
|
20
|
+
alterPossibleEnum(tableName: string, columnName: string, possibleValue?: string[]): Promise<null | undefined>;
|
|
21
|
+
migrateView(viewDirectory: string): Promise<0 | undefined>;
|
|
22
|
+
migrateView_v2(viewModel: MyViewModel[]): Promise<void>;
|
|
23
|
+
checkIsPrimaryKey(databaseName: string, tableName: string, columnName: string): Promise<boolean>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
class MyDBMigrator {
|
|
10
|
+
constructor(connection) {
|
|
11
|
+
this.MyDB = connection;
|
|
12
|
+
this.onetimeLoadColumnContent = [];
|
|
13
|
+
}
|
|
14
|
+
async migrateTable(model) {
|
|
15
|
+
let data = model.filter((row) => row.tableName !== "sessions" && row.tableName.search("prisma") < 0);
|
|
16
|
+
let index = 1;
|
|
17
|
+
for (let row of data) {
|
|
18
|
+
console.log(chalk_1.default.bgBlue(`${index}/${data.length} ${row.tableName}`));
|
|
19
|
+
await this.createTableIfNotExist(row.tableName);
|
|
20
|
+
this.onetimeLoadColumnContent = [];
|
|
21
|
+
await this.loadColumnContentIfEmpty();
|
|
22
|
+
index++;
|
|
23
|
+
for (let col of row.columns) {
|
|
24
|
+
console.log(`${row.tableName} (${col.DATA_TYPE}) - ${col.COLUMN_NAME} `);
|
|
25
|
+
if (col.COLUMN_NAME === "id" && col.AUTO_INCREMENT === true) {
|
|
26
|
+
const isPrimaryKey = await this.checkIsPrimaryKey(this.MyDB.dbInfo.database, row.tableName, col.COLUMN_NAME);
|
|
27
|
+
if (isPrimaryKey === false)
|
|
28
|
+
await this.MyDB.query(`ALTER TABLE ${row.tableName} ADD PRIMARY KEY(id);`);
|
|
29
|
+
}
|
|
30
|
+
const AutoIncrement = col.AUTO_INCREMENT ? "AUTO_INCREMENT" : "";
|
|
31
|
+
const columnDefault = col.COLUMN_DEFAULT
|
|
32
|
+
? `DEFAULT ${col.COLUMN_DEFAULT}`
|
|
33
|
+
: "";
|
|
34
|
+
const isColumnChange = await this.checkIsColumnDataTypeChange(row.tableName, col.COLUMN_NAME, col.DATA_TYPE, col.COLUMN_DEFAULT);
|
|
35
|
+
if (isColumnChange) {
|
|
36
|
+
const isColumnExist = await this.columnInTableExist(row.tableName, col.COLUMN_NAME);
|
|
37
|
+
if (!isColumnExist) {
|
|
38
|
+
await this.MyDB.query(`ALTER TABLE ${row.tableName} ADD COLUMN ${col.COLUMN_NAME} ${col.DATA_TYPE} ${AutoIncrement} ${columnDefault}`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
await this.MyDB.query(`ALTER TABLE ${row.tableName} MODIFY COLUMN ${col.COLUMN_NAME} ${col.DATA_TYPE} ${AutoIncrement} ${columnDefault}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
await this.alterUniqueKey(row.tableName, col.COLUMN_NAME, col.IS_UNIQUE);
|
|
45
|
+
await this.alterIndex(row.tableName, col.COLUMN_NAME, col.IS_INDEX);
|
|
46
|
+
await this.alterPossibleEnum(row.tableName, col.COLUMN_NAME, col.POSSIBLE_VALUE);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
console.log("migrate table done");
|
|
50
|
+
}
|
|
51
|
+
async createTableIfNotExist(tableName) {
|
|
52
|
+
await this.MyDB.query(`CREATE TABLE IF NOT EXISTS ${tableName} (id INT(11) AUTO_INCREMENT PRIMARY KEY)`);
|
|
53
|
+
}
|
|
54
|
+
async columnInTableExist(tableName, columnName) {
|
|
55
|
+
await this.loadColumnContentIfEmpty();
|
|
56
|
+
let result = this.onetimeLoadColumnContent.filter((row) => row.COLUMN_NAME === columnName && row.TABLE_NAME === tableName);
|
|
57
|
+
if (result.length)
|
|
58
|
+
return true;
|
|
59
|
+
else
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
async loadColumnContentIfEmpty() {
|
|
63
|
+
if (this.onetimeLoadColumnContent.length === 0) {
|
|
64
|
+
this.onetimeLoadColumnContent = (await this.MyDB.query(`SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.MyDB.dbInfo.database}'`, undefined, false));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async checkIsColumnDataTypeChange(tableName, columnName, dataType, columnDefault) {
|
|
68
|
+
await this.loadColumnContentIfEmpty();
|
|
69
|
+
let temp = this.onetimeLoadColumnContent.filter((row) => row.TABLE_NAME === tableName && row.COLUMN_NAME === columnName);
|
|
70
|
+
if (columnDefault === undefined)
|
|
71
|
+
columnDefault = "NULL";
|
|
72
|
+
if (columnDefault === null)
|
|
73
|
+
columnDefault = "NULL";
|
|
74
|
+
if (temp.length > 0) {
|
|
75
|
+
if (temp[0].DATA_TYPE !== dataType) {
|
|
76
|
+
console.log(chalk_1.default.green `${temp[0].DATA_TYPE} change to ${dataType}`);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
if (temp[0].COLUMN_DEFAULT !== columnDefault) {
|
|
80
|
+
console.log(chalk_1.default.green `${temp[0].COLUMN_DEFAULT} change to ${columnDefault}`);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.log(chalk_1.default.red `${columnName} not found`);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async alterUniqueKey(tableName, columnName, IS_UNIQUE) {
|
|
91
|
+
const data = this.onetimeLoadColumnContent.find((row) => row.COLUMN_NAME === columnName && row.TABLE_NAME === tableName);
|
|
92
|
+
if (data) {
|
|
93
|
+
if ((data.COLUMN_KEY === "UNI" && !IS_UNIQUE) ||
|
|
94
|
+
(data.COLUMN_KEY !== "UNI" && IS_UNIQUE === true))
|
|
95
|
+
if (IS_UNIQUE === true) {
|
|
96
|
+
await this.MyDB.query(`ALTER TABLE ${tableName} ADD UNIQUE (${columnName});`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
await this.MyDB.query(`ALTER TABLE ${tableName} DROP INDEX ${columnName};`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async alterIndex(tableName, columnName, IS_INDEX) {
|
|
104
|
+
const data = this.onetimeLoadColumnContent.find((row) => row.COLUMN_NAME === columnName && row.TABLE_NAME === tableName);
|
|
105
|
+
if (data) {
|
|
106
|
+
if ((data.COLUMN_KEY === "MUL" && !IS_INDEX) ||
|
|
107
|
+
(data.COLUMN_KEY !== "MUL" && IS_INDEX === true))
|
|
108
|
+
if (IS_INDEX === true) {
|
|
109
|
+
await this.MyDB.query(`ALTER TABLE ${tableName} ADD INDEX (${columnName});`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
await this.MyDB.query(`DROP INDEX ${columnName} ON ${tableName};`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async alterPossibleEnum(tableName, columnName, possibleValue) {
|
|
117
|
+
if (!possibleValue)
|
|
118
|
+
return null;
|
|
119
|
+
const data = this.onetimeLoadColumnContent.find((row) => row.COLUMN_NAME === columnName && row.TABLE_NAME === tableName);
|
|
120
|
+
if (data) {
|
|
121
|
+
const possibleValueString = possibleValue
|
|
122
|
+
.map((row) => `"${row}"`)
|
|
123
|
+
.join(", ");
|
|
124
|
+
await this.MyDB.query(`ALTER TABLE ${tableName} MODIFY COLUMN ${columnName} ENUM(${possibleValueString}) NOT NULL;`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async migrateView(viewDirectory) {
|
|
128
|
+
if (!fs_1.default.existsSync(viewDirectory)) {
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
let fileList = (await fs_1.default.readdirSync(path_1.default.join(viewDirectory)));
|
|
132
|
+
let unSuccessUpdateViewList = fileList;
|
|
133
|
+
let loopCount = 0;
|
|
134
|
+
while (unSuccessUpdateViewList.length > 0) {
|
|
135
|
+
for (const viewFileName of unSuccessUpdateViewList) {
|
|
136
|
+
const filePath = path_1.default.join(viewDirectory, viewFileName);
|
|
137
|
+
const content = fs_1.default.readFileSync(filePath, "utf8");
|
|
138
|
+
process.stdout.write(`loop : ${loopCount} unUpdate : ${unSuccessUpdateViewList.length} update view ${viewFileName}`);
|
|
139
|
+
await this.MyDB.query(content)
|
|
140
|
+
.then((result) => {
|
|
141
|
+
process.stdout.write(" " + chalk_1.default.bgGreen(`success`));
|
|
142
|
+
unSuccessUpdateViewList = unSuccessUpdateViewList.filter((row) => row !== viewFileName);
|
|
143
|
+
})
|
|
144
|
+
.catch((_error) => {
|
|
145
|
+
process.stdout.write(" " + chalk_1.default.bgRed(`fail`));
|
|
146
|
+
})
|
|
147
|
+
.finally(() => {
|
|
148
|
+
console.log("");
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async migrateView_v2(viewModel) {
|
|
154
|
+
let unSuccessUpdateViewList = viewModel;
|
|
155
|
+
let loopCount = 0;
|
|
156
|
+
while (unSuccessUpdateViewList.length > 0) {
|
|
157
|
+
for (const viewRow of unSuccessUpdateViewList) {
|
|
158
|
+
const content = viewRow.sqlStatement;
|
|
159
|
+
process.stdout.write(`loop : ${loopCount} unUpdate : ${unSuccessUpdateViewList.length} update view ${viewRow.viewName}`);
|
|
160
|
+
await this.MyDB.query(content)
|
|
161
|
+
.then((result) => {
|
|
162
|
+
process.stdout.write(" " + chalk_1.default.bgGreen(`success`));
|
|
163
|
+
unSuccessUpdateViewList = unSuccessUpdateViewList.filter((row) => row.viewName !== viewRow.viewName);
|
|
164
|
+
})
|
|
165
|
+
.catch((_error) => {
|
|
166
|
+
process.stdout.write(" " + chalk_1.default.bgRed(`fail`));
|
|
167
|
+
})
|
|
168
|
+
.finally(() => {
|
|
169
|
+
console.log("");
|
|
170
|
+
});
|
|
171
|
+
loopCount++;
|
|
172
|
+
if (loopCount > viewModel.length * 5) {
|
|
173
|
+
console.log("error while updating view, reason is loop update counter is over 5 time fail");
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async checkIsPrimaryKey(databaseName, tableName, columnName) {
|
|
180
|
+
let result = await this.MyDB.query(`SELECT *
|
|
181
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
182
|
+
WHERE TABLE_SCHEMA='${databaseName}'
|
|
183
|
+
AND TABLE_NAME='${tableName}'
|
|
184
|
+
AND COLUMN_NAME='${columnName}'`);
|
|
185
|
+
console.log("result", result);
|
|
186
|
+
if (result.length) {
|
|
187
|
+
if (result[0].COLUMN_KEY === "PRI")
|
|
188
|
+
return true;
|
|
189
|
+
else
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
else
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
exports.default = MyDBMigrator;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default interface app_INF {
|
|
2
|
+
item: {
|
|
3
|
+
id: number;
|
|
4
|
+
name: "pen" | "ruler";
|
|
5
|
+
price: number;
|
|
6
|
+
description: string;
|
|
7
|
+
};
|
|
8
|
+
user: {
|
|
9
|
+
id: number;
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
test_view: {
|
|
13
|
+
id: number;
|
|
14
|
+
name: string;
|
|
15
|
+
itemName: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { MyModel, columnContent, columnType } from "./myModel";
|
|
2
|
+
export { DatabaseConfigInterface } from "./ModelGenerator/ModelGenerator";
|
|
3
|
+
export { default as ModelGenerator } from "./ModelGenerator/ModelGenerator";
|
|
4
|
+
export { default as GGMySQLConnector } from "./GGMySQLConnector/GGMySQLConnector";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.GGMySQLConnector = exports.ModelGenerator = void 0;
|
|
7
|
+
var ModelGenerator_1 = require("./ModelGenerator/ModelGenerator");
|
|
8
|
+
Object.defineProperty(exports, "ModelGenerator", { enumerable: true, get: function () { return __importDefault(ModelGenerator_1).default; } });
|
|
9
|
+
var GGMySQLConnector_1 = require("./GGMySQLConnector/GGMySQLConnector");
|
|
10
|
+
Object.defineProperty(exports, "GGMySQLConnector", { enumerable: true, get: function () { return __importDefault(GGMySQLConnector_1).default; } });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SQLStatement } from "sql-template-strings";
|
|
2
|
+
export type columnType = "int" | "tinyint" | "float" | "double" | "text" | "varchar(8)" | "varchar(16)" | "varchar(32)" | "varchar(64)" | "varchar(128)" | "varchar(256)" | "varchar(512)" | "longtext" | "date" | "time" | "datetime";
|
|
3
|
+
export interface columnContent {
|
|
4
|
+
COLUMN_NAME: string;
|
|
5
|
+
DATA_TYPE: columnType;
|
|
6
|
+
COLUMN_DEFAULT?: string | number | null;
|
|
7
|
+
AUTO_INCREMENT?: boolean;
|
|
8
|
+
POSSIBLE_VALUE?: string[];
|
|
9
|
+
IS_UNIQUE?: boolean;
|
|
10
|
+
IS_INDEX?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface MyModel {
|
|
13
|
+
isSeed: boolean;
|
|
14
|
+
tableName: string;
|
|
15
|
+
columns: [...columnContent[]];
|
|
16
|
+
meaning?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface MyViewModel {
|
|
19
|
+
viewName: string;
|
|
20
|
+
sqlStatement: string | SQLStatement;
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gg-mysql-connector",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
"chalk": "^4.1.2",
|
|
15
15
|
"fs": "^0.0.1-security",
|
|
16
16
|
"mysql2": "^3.11.3",
|
|
17
|
-
"path": "^0.12.7"
|
|
17
|
+
"path": "^0.12.7",
|
|
18
|
+
"sql-template-strings": "^2.2.2"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@types/node": "^22.7.5",
|
|
21
|
-
"typescript": "^5.
|
|
22
|
+
"typescript": "^5.8.2"
|
|
22
23
|
}
|
|
23
24
|
}
|
package/seed_INF.ts
ADDED