gg-mysql-connector 1.0.5
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/.vscode/settings.json +3 -0
- package/dist/GGMySQLConnector.d.ts +70 -0
- package/dist/GGMySQLConnector.js +278 -0
- package/dist/ModelGenerator.d.ts +24 -0
- package/dist/ModelGenerator.js +189 -0
- package/dist/MyDBMigration.d.ts +22 -0
- package/dist/MyDBMigration.js +157 -0
- package/dist/app_INF.d.ts +17 -0
- package/dist/app_INF.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +10 -0
- package/dist/myModel.d.ts +17 -0
- package/dist/myModel.js +6 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +47 -0
- package/package.json +22 -0
- package/src/GGMySQLConnector.ts +457 -0
- package/src/ModelGenerator.ts +238 -0
- package/src/MyDBMigration.ts +233 -0
- package/src/app_INF.ts +12 -0
- package/src/index.ts +4 -0
- package/src/myModel.ts +38 -0
- package/src/views/test_view.sql +4 -0
- package/tsconfig.json +110 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import chalk from "chalk"
|
|
2
|
+
import { randomUUID } from "crypto"
|
|
3
|
+
import mysql, { QueryResult, RowDataPacket } from "mysql2"
|
|
4
|
+
import { DatabaseConfigInterface } from "./ModelGenerator"
|
|
5
|
+
|
|
6
|
+
export interface ClassDBInterface<Main> {
|
|
7
|
+
connection: mysql.Connection
|
|
8
|
+
query<T>(
|
|
9
|
+
statement: string,
|
|
10
|
+
parameter?: object,
|
|
11
|
+
isPrint?: boolean
|
|
12
|
+
): Promise<T | QueryResult>
|
|
13
|
+
|
|
14
|
+
getColumnList(tableName: string): Promise<string[]>
|
|
15
|
+
select<T extends keyof Main>(
|
|
16
|
+
tableName: T extends string ? T : string
|
|
17
|
+
): Promise<Main[T][]>
|
|
18
|
+
selectByID<T extends keyof Main>(
|
|
19
|
+
tableName: T extends string ? T : string,
|
|
20
|
+
id: number
|
|
21
|
+
): Promise<Main[T][]>
|
|
22
|
+
selectByMatchParams<T extends keyof Main>(
|
|
23
|
+
tableName: T extends string ? T : string,
|
|
24
|
+
params: object
|
|
25
|
+
): Promise<Main[T][]>
|
|
26
|
+
selectBySearchTextInRow(
|
|
27
|
+
tableName: string,
|
|
28
|
+
textToSearch: string
|
|
29
|
+
): Promise<RowDataPacket[]>
|
|
30
|
+
insert<T extends keyof Main>(
|
|
31
|
+
tableName: T,
|
|
32
|
+
params: any
|
|
33
|
+
): Promise<mysql.OkPacket>
|
|
34
|
+
update(
|
|
35
|
+
tableName: string,
|
|
36
|
+
parameter: object | object[]
|
|
37
|
+
): Promise<mysql.OkPacket>
|
|
38
|
+
updateOnlyID<T extends keyof Main extends string ? keyof Main : string>(
|
|
39
|
+
tableName: T,
|
|
40
|
+
params: { oldID: number; newID: number }
|
|
41
|
+
): Promise<mysql.OkPacket | null>
|
|
42
|
+
deleteByID(tableName: string, id: number): Promise<mysql.OkPacket>
|
|
43
|
+
deleteByMatchParams(
|
|
44
|
+
tableName: string,
|
|
45
|
+
parameter: any
|
|
46
|
+
): Promise<mysql.OkPacket | null>
|
|
47
|
+
getTableNameList(): Promise<string[]>
|
|
48
|
+
getViewNameList(): Promise<string[]>
|
|
49
|
+
getViewNameIfExist(tableName: string): Promise<string>
|
|
50
|
+
loadTableAndViewNameList(): Promise<string[]>
|
|
51
|
+
createDatabaseIfNotExist(tempConnection: mysql.Connection): Promise<void>
|
|
52
|
+
}
|
|
53
|
+
export type Unarray<T> = T extends Array<infer U> ? U : T
|
|
54
|
+
export default class GGMySQLConnector<Main> implements ClassDBInterface<Main> {
|
|
55
|
+
DBInfo: DatabaseConfigInterface
|
|
56
|
+
connection!: mysql.Connection
|
|
57
|
+
isPrintStatement: boolean
|
|
58
|
+
tableAndViewNameList: string[]
|
|
59
|
+
columnAndTableListCache:
|
|
60
|
+
| { COLUMN_NAME: string; TABLE_NAME: string; DATA_TYPE: string }[]
|
|
61
|
+
| null
|
|
62
|
+
|
|
63
|
+
constructor(DBInfo: DatabaseConfigInterface) {
|
|
64
|
+
this.isPrintStatement = false
|
|
65
|
+
this.tableAndViewNameList = []
|
|
66
|
+
this.columnAndTableListCache = null
|
|
67
|
+
this.DBInfo = DBInfo
|
|
68
|
+
}
|
|
69
|
+
async createDatabaseIfNotExist(
|
|
70
|
+
tempConnection: mysql.Connection
|
|
71
|
+
): Promise<void> {
|
|
72
|
+
const currentDatabaseName = this.DBInfo.database
|
|
73
|
+
console.log("currentDatabaseName", currentDatabaseName)
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
tempConnection.query(
|
|
76
|
+
`CREATE DATABASE IF NOT EXISTS ${currentDatabaseName}`,
|
|
77
|
+
() => {
|
|
78
|
+
resolve()
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async selectBySearchTextInRow(
|
|
85
|
+
tableName: string,
|
|
86
|
+
textToSearch: string
|
|
87
|
+
): Promise<mysql.RowDataPacket[]> {
|
|
88
|
+
const result = (await this.query(`SELECT * FROM ${tableName}`)) as any
|
|
89
|
+
const wordList = textToSearch.split(" ")
|
|
90
|
+
const temp = result.filter((row: any) => {
|
|
91
|
+
const rawText = Object.values(row).flat().join(" ")
|
|
92
|
+
const wordFilterResult = wordList.filter(
|
|
93
|
+
(wRow) => rawText.search(wRow) >= 0
|
|
94
|
+
)
|
|
95
|
+
if (wordFilterResult.length === wordList.length) return true
|
|
96
|
+
return false
|
|
97
|
+
})
|
|
98
|
+
return temp
|
|
99
|
+
}
|
|
100
|
+
async loadTableAndViewNameList(): Promise<string[]> {
|
|
101
|
+
let result = (await this.query(
|
|
102
|
+
"SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = ?",
|
|
103
|
+
[this.DBInfo.database],
|
|
104
|
+
false
|
|
105
|
+
)) as { TABLE_NAME: string }[]
|
|
106
|
+
this.tableAndViewNameList = result.map((row) => row.TABLE_NAME)
|
|
107
|
+
return this.tableAndViewNameList
|
|
108
|
+
}
|
|
109
|
+
async getViewNameIfExist(tableName: string): Promise<string> {
|
|
110
|
+
const tableList: string[] = this.tableAndViewNameList
|
|
111
|
+
const viewPostFixArray = ["_view", "__view", "__view_list"]
|
|
112
|
+
|
|
113
|
+
for (let i = 0; i < viewPostFixArray.length; i++) {
|
|
114
|
+
const expectViewName: string = tableName + viewPostFixArray[i]
|
|
115
|
+
for (let j = 0; j < tableList.length; j++) {
|
|
116
|
+
const row = tableList[j]
|
|
117
|
+
if (row === expectViewName) {
|
|
118
|
+
return expectViewName
|
|
119
|
+
} else if (
|
|
120
|
+
i == viewPostFixArray.length - 1 &&
|
|
121
|
+
j == tableList.length - 1
|
|
122
|
+
) {
|
|
123
|
+
return tableName
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return tableName
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async selectByMatchParams<T extends keyof Main>(
|
|
131
|
+
tableName: T extends string ? T : string,
|
|
132
|
+
params: Partial<{
|
|
133
|
+
[K in keyof Main[T]]: string | number | undefined | null
|
|
134
|
+
}>
|
|
135
|
+
): Promise<Main[T][]> {
|
|
136
|
+
const columnList = await this.getColumnList(tableName)
|
|
137
|
+
const keyList = Object.keys(params)
|
|
138
|
+
const keyToSearchList = []
|
|
139
|
+
const valueToSearchList = []
|
|
140
|
+
for (const key of keyList) {
|
|
141
|
+
const temp = columnList.find((fkey) => key === fkey)
|
|
142
|
+
if (temp) {
|
|
143
|
+
keyToSearchList.push(` ${key} = ? `)
|
|
144
|
+
valueToSearchList.push(params[key as keyof Unarray<T>])
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (keyToSearchList.length === 0) {
|
|
148
|
+
return [] as any
|
|
149
|
+
}
|
|
150
|
+
let result = (await this.query(
|
|
151
|
+
`SELECT * FROM ${tableName} WHERE ${keyToSearchList.join(" AND ")}`,
|
|
152
|
+
valueToSearchList
|
|
153
|
+
)) as any
|
|
154
|
+
return result
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async selectByID<T extends keyof Main>(
|
|
158
|
+
tableName: T extends string ? T : string,
|
|
159
|
+
id: number
|
|
160
|
+
): Promise<Main[T][]> {
|
|
161
|
+
let result = (await this.query(
|
|
162
|
+
`SELECT * FROM ${tableName} WHERE id = ? LIMIT 1`,
|
|
163
|
+
[id]
|
|
164
|
+
)) as any
|
|
165
|
+
|
|
166
|
+
return result
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async select<T extends keyof Main>(
|
|
170
|
+
tableName: T extends string ? T : string
|
|
171
|
+
): Promise<Main[T][]> {
|
|
172
|
+
let result = (await this.query(`SELECT * FROM ${tableName}`)) as any
|
|
173
|
+
return result
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async getTableNameList(): Promise<string[]> {
|
|
177
|
+
let data: string[] = []
|
|
178
|
+
let result = (await this.query(
|
|
179
|
+
"SELECT * FROM information_schema.tables WHERE table_schema = ? AND TABLE_TYPE = 'BASE TABLE'",
|
|
180
|
+
[this.DBInfo.database],
|
|
181
|
+
false
|
|
182
|
+
)) as mysql.RowDataPacket[]
|
|
183
|
+
for (let row of result) data.push(row.TABLE_NAME || row.row.table_name)
|
|
184
|
+
return data
|
|
185
|
+
}
|
|
186
|
+
async getViewNameList(): Promise<string[]> {
|
|
187
|
+
let data: string[] = []
|
|
188
|
+
let result = (await this.query(
|
|
189
|
+
"SELECT * FROM information_schema.tables WHERE table_schema = ? AND TABLE_TYPE = 'VIEW'",
|
|
190
|
+
[this.DBInfo.database],
|
|
191
|
+
false
|
|
192
|
+
)) as mysql.RowDataPacket[]
|
|
193
|
+
for (let row of result) data.push(row.TABLE_NAME || row.row.table_name)
|
|
194
|
+
return data
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async deleteByMatchParams<T>(
|
|
198
|
+
tableName: string,
|
|
199
|
+
params: Partial<{
|
|
200
|
+
[K in keyof Unarray<T>]: string | number | undefined | null
|
|
201
|
+
}>
|
|
202
|
+
) {
|
|
203
|
+
const columnList = await this.getColumnList(tableName)
|
|
204
|
+
const keyList = Object.keys(params)
|
|
205
|
+
const keyToSearchList = [] as string[]
|
|
206
|
+
const valueToSearchList = []
|
|
207
|
+
for (const key of keyList) {
|
|
208
|
+
const temp = columnList.find((fkey: any) => key === fkey)
|
|
209
|
+
if (temp) {
|
|
210
|
+
keyToSearchList.push(` ${key} = ? `)
|
|
211
|
+
valueToSearchList.push(params[key as keyof Unarray<T>])
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (keyToSearchList.length === 0) return null
|
|
215
|
+
let result = (await this.query(
|
|
216
|
+
`DELETE FROM ${tableName} WHERE ${keyToSearchList.join(" AND ")}`,
|
|
217
|
+
valueToSearchList
|
|
218
|
+
)) as mysql.OkPacket
|
|
219
|
+
// this.webSocket.sendByURL("/websocket/watchTableChange", tableName)
|
|
220
|
+
return result
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async deleteByID(tableName: string, id: number): Promise<mysql.OkPacket> {
|
|
224
|
+
let result = (await this.query(`DELETE FROM ${tableName} WHERE id = ?`, [
|
|
225
|
+
id,
|
|
226
|
+
])) as mysql.OkPacket
|
|
227
|
+
console.log("Delete Success")
|
|
228
|
+
// this.webSocket.sendByURL("/websocket/watchTableChange", tableName)
|
|
229
|
+
return result
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async insert<T extends keyof Main>(
|
|
233
|
+
tableName: T,
|
|
234
|
+
parameter:
|
|
235
|
+
| Partial<{
|
|
236
|
+
[R in keyof Unarray<Main[T]>]: any
|
|
237
|
+
}>
|
|
238
|
+
| Partial<{
|
|
239
|
+
[R in keyof Unarray<Main[T]>]: any
|
|
240
|
+
}>[]
|
|
241
|
+
) {
|
|
242
|
+
let params = [] as any
|
|
243
|
+
if (Array.isArray(parameter) === true) {
|
|
244
|
+
params = parameter
|
|
245
|
+
} else params = [parameter]
|
|
246
|
+
|
|
247
|
+
const columnList = await this.getColumnList(tableName as string)
|
|
248
|
+
const exampleParams = params[0]
|
|
249
|
+
const keyList = Object.keys(exampleParams)
|
|
250
|
+
const keyListToInsert = []
|
|
251
|
+
for (const row of keyList) {
|
|
252
|
+
const temp = columnList.find((fRow) => row === fRow)
|
|
253
|
+
if (temp) keyListToInsert.push(row)
|
|
254
|
+
}
|
|
255
|
+
const valueArrayToInsertInQuery = []
|
|
256
|
+
for (let i = 0; i < params.length; i++) {
|
|
257
|
+
const valueListToInsert = []
|
|
258
|
+
for (const row of keyList) {
|
|
259
|
+
const temp = columnList.find((fRow: any) => row === fRow)
|
|
260
|
+
if (temp) {
|
|
261
|
+
valueListToInsert.push(params[i][row])
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
valueArrayToInsertInQuery.push(valueListToInsert)
|
|
265
|
+
}
|
|
266
|
+
console.log(valueArrayToInsertInQuery.slice(0, 5))
|
|
267
|
+
const result = (await this.query(
|
|
268
|
+
`INSERT INTO ${tableName as string} (${keyListToInsert.join(
|
|
269
|
+
","
|
|
270
|
+
)}) VALUES ?`,
|
|
271
|
+
[valueArrayToInsertInQuery]
|
|
272
|
+
)) as mysql.OkPacket
|
|
273
|
+
console.log("Insert Success")
|
|
274
|
+
// this.webSocket.sendByURL("/websocket/watchTableChange", String(tableName))
|
|
275
|
+
return result
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async updateOnlyID<T extends keyof Main extends string ? keyof Main : string>(
|
|
279
|
+
tableName: T,
|
|
280
|
+
params: { oldID: number; newID: number }
|
|
281
|
+
) {
|
|
282
|
+
const isNewIdExist: any = await this.query(
|
|
283
|
+
`SELECT * FROM ${tableName} WHERE id = ? `,
|
|
284
|
+
[params.newID]
|
|
285
|
+
)
|
|
286
|
+
if (isNewIdExist.length >= 1) {
|
|
287
|
+
console.log(`error : newID (${params.newID}) is already exist`)
|
|
288
|
+
return null
|
|
289
|
+
}
|
|
290
|
+
let result = (await this.query(
|
|
291
|
+
`UPDATE ${tableName} SET id = ? WHERE id = ?`,
|
|
292
|
+
[params.newID, params.oldID],
|
|
293
|
+
false
|
|
294
|
+
)) as mysql.OkPacket
|
|
295
|
+
|
|
296
|
+
console.log("UpdateOnlyID Success")
|
|
297
|
+
// this.webSocket.sendByURL("/websocket/watchTableChange", String(tableName))
|
|
298
|
+
return result
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async update<T extends keyof Main>(
|
|
302
|
+
tableName: T extends string ? T : string,
|
|
303
|
+
parameter: Partial<{
|
|
304
|
+
[K in keyof Main[T]]: Main[T][K]
|
|
305
|
+
}>
|
|
306
|
+
) {
|
|
307
|
+
const columnList = await this.getColumnList(tableName)
|
|
308
|
+
console.log(parameter)
|
|
309
|
+
const keyList = Object.keys(parameter)
|
|
310
|
+
const keyListToInsert = []
|
|
311
|
+
const valueListToInsert = []
|
|
312
|
+
for (const row of keyList) {
|
|
313
|
+
const temp = columnList.find((fRow: any) => row === fRow)
|
|
314
|
+
if (temp) {
|
|
315
|
+
keyListToInsert.push(row)
|
|
316
|
+
valueListToInsert.push((parameter as any)[row])
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// build set sql
|
|
320
|
+
const temp = []
|
|
321
|
+
let index = 0
|
|
322
|
+
for (const row of keyListToInsert) {
|
|
323
|
+
if (valueListToInsert[index] === null) {
|
|
324
|
+
temp.push(`${row} = NULL`)
|
|
325
|
+
} else {
|
|
326
|
+
let value = valueListToInsert[index]
|
|
327
|
+
if (typeof value === "string") {
|
|
328
|
+
value = value.replace(/'/g, "")
|
|
329
|
+
}
|
|
330
|
+
temp.push(`${row} = '${value}'`)
|
|
331
|
+
}
|
|
332
|
+
index++
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
let result = (await this.query(
|
|
336
|
+
`UPDATE ${tableName} SET ${temp.join(",")} WHERE id = ${
|
|
337
|
+
(parameter as any).id
|
|
338
|
+
}`,
|
|
339
|
+
[],
|
|
340
|
+
false
|
|
341
|
+
)) as mysql.OkPacket
|
|
342
|
+
|
|
343
|
+
console.log("Update Success")
|
|
344
|
+
// this.webSocket.sendByURL("/websocket/watchTableChange", String(tableName))
|
|
345
|
+
return result
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async init() {
|
|
349
|
+
const currentConnection = mysql.createConnection({
|
|
350
|
+
host: this.DBInfo.host,
|
|
351
|
+
user: this.DBInfo.user,
|
|
352
|
+
password: this.DBInfo.password,
|
|
353
|
+
})
|
|
354
|
+
await this.createDatabaseIfNotExist(currentConnection)
|
|
355
|
+
// await currentConnection.end()
|
|
356
|
+
|
|
357
|
+
this.connection = mysql.createConnection({ ...this.DBInfo })
|
|
358
|
+
// await this.query("SET global sql_mode=''")
|
|
359
|
+
// await this.query("SET global query_cache_type='ON'")
|
|
360
|
+
// await this.query("SET global query_cache_size=16777216")
|
|
361
|
+
// await this.query("SET global query_cache_limit=16777216")
|
|
362
|
+
await this.loadTableAndViewNameList()
|
|
363
|
+
await this.loadColumnListToCache()
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async loadColumnListToCache() {
|
|
367
|
+
const result: {
|
|
368
|
+
COLUMN_NAME: string
|
|
369
|
+
TABLE_NAME: string
|
|
370
|
+
DATA_TYPE: string
|
|
371
|
+
}[] = (await this.query(
|
|
372
|
+
`SELECT COLUMN_NAME,TABLE_NAME,DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.DBInfo.database}'`,
|
|
373
|
+
undefined,
|
|
374
|
+
false
|
|
375
|
+
)) as { COLUMN_NAME: string; TABLE_NAME: string; DATA_TYPE: string }[]
|
|
376
|
+
|
|
377
|
+
this.columnAndTableListCache = result
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async getColumnList(tableName: string) {
|
|
381
|
+
if (this.columnAndTableListCache !== null) {
|
|
382
|
+
return this.columnAndTableListCache
|
|
383
|
+
.filter((row) => row.TABLE_NAME === tableName)
|
|
384
|
+
.map((row) => row.COLUMN_NAME)
|
|
385
|
+
}
|
|
386
|
+
const result: any = await this.query(
|
|
387
|
+
`SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.DBInfo.database}' AND TABLE_NAME = '${tableName}'`,
|
|
388
|
+
undefined,
|
|
389
|
+
false
|
|
390
|
+
)
|
|
391
|
+
return result.map((row: any) => row.COLUMN_NAME) as string[]
|
|
392
|
+
}
|
|
393
|
+
async getColumnFullList(tableName: string) {
|
|
394
|
+
const result = (await this.query(
|
|
395
|
+
`SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.DBInfo.database}' AND TABLE_NAME = '${tableName}'`,
|
|
396
|
+
undefined,
|
|
397
|
+
false
|
|
398
|
+
)) as mysql.RowDataPacket[]
|
|
399
|
+
return result
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async query<T>(
|
|
403
|
+
statment: string,
|
|
404
|
+
parameter?: any[],
|
|
405
|
+
isPrint?: boolean
|
|
406
|
+
): Promise<T | QueryResult> {
|
|
407
|
+
return new Promise((resolve, reject) => {
|
|
408
|
+
const uniqueTime = `${randomUUID()} ${statment}`
|
|
409
|
+
console.time(uniqueTime)
|
|
410
|
+
const startTime = new Date()
|
|
411
|
+
const queryResult = this.connection.query(
|
|
412
|
+
statment,
|
|
413
|
+
parameter,
|
|
414
|
+
(error, results, fields) => {
|
|
415
|
+
if (error) {
|
|
416
|
+
// _getCallerFile()
|
|
417
|
+
console.log(chalk.bgRed("Query Error"))
|
|
418
|
+
console.log(chalk.bgRed(error))
|
|
419
|
+
console.log(chalk.bgRed("Statement : "))
|
|
420
|
+
console.log(statment)
|
|
421
|
+
console.log(chalk.bgRed("Parameter : "))
|
|
422
|
+
console.log(parameter)
|
|
423
|
+
console.log("------------------------------------------------")
|
|
424
|
+
console.log(chalk.bgRed(queryResult.sql))
|
|
425
|
+
reject(error)
|
|
426
|
+
} else {
|
|
427
|
+
const endTime = new Date()
|
|
428
|
+
const executionTime = endTime.getTime() - startTime.getTime()
|
|
429
|
+
if (isPrint === true) {
|
|
430
|
+
this.printResultLength(results, executionTime, queryResult)
|
|
431
|
+
} else if (this.isPrintStatement) {
|
|
432
|
+
this.printResultLength(results, executionTime, queryResult)
|
|
433
|
+
}
|
|
434
|
+
resolve(results)
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
)
|
|
438
|
+
})
|
|
439
|
+
}
|
|
440
|
+
private printResultLength = (
|
|
441
|
+
results: any,
|
|
442
|
+
executionTime: number,
|
|
443
|
+
queryResult: any
|
|
444
|
+
) => {
|
|
445
|
+
if (results.length) {
|
|
446
|
+
const executionTimeMessage =
|
|
447
|
+
executionTime > 1000
|
|
448
|
+
? chalk.bgRed(`${executionTime} ` + " ms")
|
|
449
|
+
: chalk.yellow(`${executionTime} ` + " ms")
|
|
450
|
+
console.log(
|
|
451
|
+
`${this.DBInfo.database} > ${chalk.green(queryResult.sql)} ${chalk.cyan(
|
|
452
|
+
`found ${results.length} rows.`
|
|
453
|
+
)} ${executionTimeMessage}`
|
|
454
|
+
)
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import chalk from "chalk"
|
|
2
|
+
import { randomUUID } from "crypto"
|
|
3
|
+
import fs from "fs"
|
|
4
|
+
import mysql from "mysql2/promise"
|
|
5
|
+
import path from "path"
|
|
6
|
+
import MyDBMigration from "./MyDBMigration"
|
|
7
|
+
import { MyModel } from "./myModel"
|
|
8
|
+
export interface DatabaseConfigInterface {
|
|
9
|
+
host: string
|
|
10
|
+
user: string
|
|
11
|
+
password: string
|
|
12
|
+
database: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default class ModelGenerator {
|
|
16
|
+
model: MyModel[]
|
|
17
|
+
dbInfo: DatabaseConfigInterface
|
|
18
|
+
connection!: mysql.Connection
|
|
19
|
+
constructor(dbInfo: DatabaseConfigInterface, model: MyModel[]) {
|
|
20
|
+
this.model = model
|
|
21
|
+
this.dbInfo = dbInfo
|
|
22
|
+
}
|
|
23
|
+
async init() {
|
|
24
|
+
console.log("init")
|
|
25
|
+
this.connection = await mysql.createConnection({
|
|
26
|
+
host: this.dbInfo.host,
|
|
27
|
+
user: this.dbInfo.user,
|
|
28
|
+
password: this.dbInfo.password,
|
|
29
|
+
})
|
|
30
|
+
await this.createDatabaseIfNotExist()
|
|
31
|
+
}
|
|
32
|
+
private async createDatabaseIfNotExist() {
|
|
33
|
+
const databaseName = this.dbInfo.database
|
|
34
|
+
await this.connection.query(`CREATE DATABASE IF NOT EXISTS ${databaseName}`)
|
|
35
|
+
await this.connection.query(`USE ${databaseName}`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async pushModelToDB() {
|
|
39
|
+
const migrator = new MyDBMigration(this)
|
|
40
|
+
await migrator.migrateTable(this.model)
|
|
41
|
+
}
|
|
42
|
+
async pushViewToDB(viewDirectory: string) {
|
|
43
|
+
const migrator = new MyDBMigration(this)
|
|
44
|
+
await migrator.migrateView(viewDirectory)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async query<T>(
|
|
48
|
+
statment: string,
|
|
49
|
+
parameter?: any[],
|
|
50
|
+
isPrint?: boolean
|
|
51
|
+
): Promise<T> {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const uniqueTime = `${randomUUID()} ${statment}`
|
|
54
|
+
console.time(uniqueTime)
|
|
55
|
+
const startTime = new Date()
|
|
56
|
+
const queryResult = this.connection
|
|
57
|
+
.query(statment, parameter)
|
|
58
|
+
.then((result) => {
|
|
59
|
+
const endTime = new Date()
|
|
60
|
+
const executionTime = endTime.getTime() - startTime.getTime()
|
|
61
|
+
if (isPrint === true)
|
|
62
|
+
this.printResultLength(result, executionTime, queryResult)
|
|
63
|
+
|
|
64
|
+
resolve(result[0] as any)
|
|
65
|
+
})
|
|
66
|
+
.catch((error) => {
|
|
67
|
+
// _getCallerFile()
|
|
68
|
+
console.log(chalk.bgRed("Query Error"))
|
|
69
|
+
console.log(chalk.bgRed(error))
|
|
70
|
+
console.log(chalk.bgRed("Statement : "))
|
|
71
|
+
console.log(statment)
|
|
72
|
+
console.log(chalk.bgRed("Parameter : "))
|
|
73
|
+
console.log(parameter)
|
|
74
|
+
console.log("------------------------------------------------")
|
|
75
|
+
console.log(chalk.bgRed((queryResult as any).sql))
|
|
76
|
+
|
|
77
|
+
reject(error)
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
private printResultLength = (
|
|
82
|
+
results: any,
|
|
83
|
+
executionTime: number,
|
|
84
|
+
queryResult: any
|
|
85
|
+
) => {
|
|
86
|
+
if (results.length) {
|
|
87
|
+
const executionTimeMessage =
|
|
88
|
+
executionTime > 1000
|
|
89
|
+
? chalk.bgRed(`${executionTime} ` + " ms")
|
|
90
|
+
: chalk.yellow(`${executionTime} ` + " ms")
|
|
91
|
+
console.log(
|
|
92
|
+
`${chalk.green(queryResult.sql)} ${chalk.cyan(
|
|
93
|
+
`found ${results.length} rows.`
|
|
94
|
+
)} ${executionTimeMessage}`
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async getTableNameList(): Promise<string[]> {
|
|
99
|
+
let data: string[] = []
|
|
100
|
+
let result = (await this.query(
|
|
101
|
+
"SELECT * FROM information_schema.tables WHERE table_schema = ? AND TABLE_TYPE = 'BASE TABLE'",
|
|
102
|
+
[this.dbInfo.database],
|
|
103
|
+
false
|
|
104
|
+
)) as mysql.RowDataPacket[]
|
|
105
|
+
for (let row of result) data.push(row.TABLE_NAME || row.row.table_name)
|
|
106
|
+
return data
|
|
107
|
+
}
|
|
108
|
+
async getViewNameList(): Promise<string[]> {
|
|
109
|
+
let data: string[] = []
|
|
110
|
+
let result = (await this.query(
|
|
111
|
+
"SELECT * FROM information_schema.tables WHERE table_schema = ? AND TABLE_TYPE = 'VIEW'",
|
|
112
|
+
[this.dbInfo.database],
|
|
113
|
+
false
|
|
114
|
+
)) as mysql.RowDataPacket[]
|
|
115
|
+
for (let row of result) data.push(row.TABLE_NAME || row.row.table_name)
|
|
116
|
+
return data
|
|
117
|
+
}
|
|
118
|
+
async getColumnFullList(tableName: string) {
|
|
119
|
+
const result = (await this.query(
|
|
120
|
+
`SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.dbInfo.database}' AND TABLE_NAME = '${tableName}'`,
|
|
121
|
+
undefined,
|
|
122
|
+
false
|
|
123
|
+
)) as mysql.RowDataPacket[]
|
|
124
|
+
return result
|
|
125
|
+
}
|
|
126
|
+
async generateModelInterface(
|
|
127
|
+
DBType: string,
|
|
128
|
+
model: MyModel[],
|
|
129
|
+
ouputDirectory: string[]
|
|
130
|
+
) {
|
|
131
|
+
const isTableNameExistInModel = (tableName: string) => {
|
|
132
|
+
if (tableName === "sessions") return true
|
|
133
|
+
const table = model.find((row) => row.tableName === tableName)
|
|
134
|
+
if (table) return true
|
|
135
|
+
|
|
136
|
+
return false
|
|
137
|
+
}
|
|
138
|
+
const isColumnExistInModel = (tableName: string, columnName: string) => {
|
|
139
|
+
if (tableName === "sessions") return true
|
|
140
|
+
|
|
141
|
+
const table = model.find((row) => row.tableName === tableName)
|
|
142
|
+
if (table) {
|
|
143
|
+
const column = table.columns.find(
|
|
144
|
+
(row) => row.COLUMN_NAME === columnName
|
|
145
|
+
)
|
|
146
|
+
if (column) return true
|
|
147
|
+
}
|
|
148
|
+
return false
|
|
149
|
+
}
|
|
150
|
+
const getPossibleColumnValue = (tableName: string, columnName: string) => {
|
|
151
|
+
const foundTable = model.find((row) => row.tableName === tableName)
|
|
152
|
+
if (foundTable) {
|
|
153
|
+
const foundColumn = foundTable["columns"].find(
|
|
154
|
+
(row) => row.COLUMN_NAME === columnName
|
|
155
|
+
)
|
|
156
|
+
if (foundColumn) {
|
|
157
|
+
if (foundColumn.POSSIBLE_VALUE) return foundColumn.POSSIBLE_VALUE
|
|
158
|
+
} else return false
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const tableList = [
|
|
162
|
+
...(await this.getTableNameList()),
|
|
163
|
+
...(await this.getViewNameList()),
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
const array = []
|
|
167
|
+
for (let i = 0; i < tableList.length; i++) {
|
|
168
|
+
const tableName = tableList[i]
|
|
169
|
+
if (
|
|
170
|
+
isTableNameExistInModel(tableName) ||
|
|
171
|
+
tableName.search("_view") >= 0
|
|
172
|
+
) {
|
|
173
|
+
const columnList = await this.getColumnFullList(tableName)
|
|
174
|
+
|
|
175
|
+
let singleInterfaceContent = ""
|
|
176
|
+
for (const cRow of columnList) {
|
|
177
|
+
const columnChecker = isColumnExistInModel(
|
|
178
|
+
tableName,
|
|
179
|
+
cRow.COLUMN_NAME
|
|
180
|
+
)
|
|
181
|
+
if (columnChecker || tableName.search("_view") >= 0) {
|
|
182
|
+
const possibleValue = getPossibleColumnValue(
|
|
183
|
+
cRow.TABLE_NAME,
|
|
184
|
+
cRow.COLUMN_NAME
|
|
185
|
+
)
|
|
186
|
+
if (possibleValue) {
|
|
187
|
+
singleInterfaceContent = `${singleInterfaceContent} \n ${
|
|
188
|
+
cRow.COLUMN_NAME
|
|
189
|
+
}: ${possibleValue.map((row) => `"${row}"`).join(" | ")};`
|
|
190
|
+
} else {
|
|
191
|
+
singleInterfaceContent = `${singleInterfaceContent} \n ${
|
|
192
|
+
cRow.COLUMN_NAME
|
|
193
|
+
}: ${convertDataType(cRow.DATA_TYPE)};`
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
console.log(`${tableName}-${cRow.COLUMN_NAME} not exist in model `)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const str = ` ${tableName} : { ${singleInterfaceContent} }`
|
|
201
|
+
array.push(str)
|
|
202
|
+
// console.log(`generate interface from ${tableName}`)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const fileName = `${DBType}_INF.ts`
|
|
206
|
+
const code = `export default interface ${DBType}_INF { ${array.join(
|
|
207
|
+
"\n"
|
|
208
|
+
)} }`
|
|
209
|
+
|
|
210
|
+
ouputDirectory.forEach(async (tempPath) => {
|
|
211
|
+
const serverFilePath = path.join(tempPath, fileName)
|
|
212
|
+
await fs.writeFileSync(serverFilePath, code)
|
|
213
|
+
console.log("save to ", serverFilePath)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
console.log(`generate interface ${DBType} ${chalk.bgGreen(" SUCCESS ")}`)
|
|
217
|
+
|
|
218
|
+
return code
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function convertDataType(inputDataType: string): "string" | "number" {
|
|
223
|
+
let result: "string" | "number" = "string"
|
|
224
|
+
if (inputDataType === "int") {
|
|
225
|
+
result = "number"
|
|
226
|
+
} else if (inputDataType === "tinyint") {
|
|
227
|
+
result = "number"
|
|
228
|
+
} else if (inputDataType === "bigint") {
|
|
229
|
+
result = "number"
|
|
230
|
+
} else if (inputDataType === "date") {
|
|
231
|
+
result = "string"
|
|
232
|
+
} else if (inputDataType === "float") {
|
|
233
|
+
result = "number"
|
|
234
|
+
} else if (inputDataType === "double") {
|
|
235
|
+
result = "number"
|
|
236
|
+
}
|
|
237
|
+
return result
|
|
238
|
+
}
|