1 | "use strict";
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4 | return new (P || (P = Promise))(function (resolve, reject) {
|
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9 | });
|
10 | };
|
11 | Object.defineProperty(exports, "__esModule", { value: true });
|
12 | const change_case = require("change-case");
|
13 | const LIST_TYPE_VIEW = "VIEW";
|
14 | const LIST_TYPE_TABLE = "BASE TABLE";
|
15 | class ModelBuilder {
|
16 | constructor(knex, databaseName) {
|
17 | this.knex = knex;
|
18 | this.databaseName = databaseName;
|
19 | }
|
20 | static init(knex) {
|
21 | return new ModelBuilder(knex).renderDatabaseSchema();
|
22 | }
|
23 | |
24 |
|
25 |
|
26 | static keysToLower(obj) {
|
27 | const newobj = {};
|
28 | Object.keys(obj).forEach(key => newobj[key.toLowerCase()] = obj[key]);
|
29 | return newobj;
|
30 | }
|
31 | |
32 |
|
33 |
|
34 |
|
35 |
|
36 | static getMysqlLength(strType) {
|
37 | const strip = strType.replace(/\D/g, "");
|
38 | return strip.length === 0 ? 0 : parseInt(strip, undefined);
|
39 | }
|
40 | |
41 |
|
42 |
|
43 |
|
44 | static stripMysqlLength(type) {
|
45 | const pos = type.indexOf("(");
|
46 | if (pos > -1) {
|
47 | return type.substr(0, pos);
|
48 | }
|
49 | return type;
|
50 | }
|
51 | static getEnumValues(type) {
|
52 | if (type.startsWith("enum")) {
|
53 | const strList = type.replace("enum(", "").replace(")", "");
|
54 | const list = strList.split(",").map(s => s.replace("'", "").replace("'", ""));
|
55 | return list;
|
56 | }
|
57 | return null;
|
58 | }
|
59 | renderDatabaseSchema() {
|
60 | return __awaiter(this, void 0, void 0, function* () {
|
61 | if (!this.databaseName) {
|
62 | this.databaseName = yield this.getDatabaseName();
|
63 | }
|
64 | const schema = {
|
65 | storedProcedures: yield this.renderStoredProcedures(),
|
66 | tables: yield this.renderTableModel(),
|
67 | views: yield this.renderViewModel()
|
68 | };
|
69 | return schema;
|
70 | });
|
71 | }
|
72 | getDatabaseName() {
|
73 | return __awaiter(this, void 0, void 0, function* () {
|
74 | const resp = yield this.knex.raw("SELECT DATABASE() as db");
|
75 | return resp[0][0].db;
|
76 | });
|
77 | }
|
78 | |
79 |
|
80 |
|
81 | listFromDatabase(listType) {
|
82 | if (listType !== "BASE TABLE" && listType !== "VIEW") {
|
83 | throw new Error("Illegal listtype");
|
84 | }
|
85 | const select = "`information_schema`.`TABLES`.`TABLE_NAME` AS `tname`";
|
86 | const from = "`information_schema`.`TABLES`";
|
87 | const dbClause = "`information_schema`.`TABLES`.`TABLE_SCHEMA` = '" + this.databaseName + "'";
|
88 | const baseTable = "`information_schema`.`TABLES`.`TABLE_TYPE` = '" + listType + "'";
|
89 | return `SELECT ${select} FROM ${from} WHERE ${dbClause} AND ${baseTable} `;
|
90 | }
|
91 | listViews() {
|
92 | return __awaiter(this, void 0, void 0, function* () {
|
93 | const rows = yield this.knex.raw(this.listFromDatabase(LIST_TYPE_VIEW));
|
94 | return rows[0].map(item => item.tname);
|
95 | });
|
96 | }
|
97 | |
98 |
|
99 |
|
100 | listTables() {
|
101 | return __awaiter(this, void 0, void 0, function* () {
|
102 | const rows = yield this.knex.raw(this.listFromDatabase(LIST_TYPE_TABLE));
|
103 | return rows[0].map(item => item.tname);
|
104 | });
|
105 | }
|
106 | columnArrayToDatabaseSchema(colArrMap) {
|
107 | const schema = {};
|
108 | for (const tableName in colArrMap) {
|
109 | colArrMap[tableName] = colArrMap[tableName].map((col, i) => {
|
110 | col = ModelBuilder.keysToLower(col);
|
111 | col.length = ModelBuilder.getMysqlLength(col.type);
|
112 | col.enumValues = ModelBuilder.getEnumValues(col.type);
|
113 | col.isPrimary = col.key === "PRI";
|
114 | col.index = i;
|
115 | col.type = ModelBuilder.stripMysqlLength(col.type);
|
116 | return col;
|
117 | });
|
118 | const newTable = {};
|
119 | colArrMap[tableName].forEach(col => newTable[col.field] = col);
|
120 | schema[tableName] = newTable;
|
121 | }
|
122 | return schema;
|
123 | }
|
124 | |
125 |
|
126 |
|
127 | listColumns(tableName) {
|
128 | return __awaiter(this, void 0, void 0, function* () {
|
129 | return yield this.knex.raw("SHOW COLUMNS FROM " + tableName).then(colData => colData[0]);
|
130 | });
|
131 | }
|
132 | renderModel(tables) {
|
133 | return __awaiter(this, void 0, void 0, function* () {
|
134 |
|
135 | const columnArrayMap = {};
|
136 | const promises = tables.map((tableName) => __awaiter(this, void 0, void 0, function* () {
|
137 | columnArrayMap[tableName] = yield this.listColumns(tableName);
|
138 | }));
|
139 | yield Promise.all(promises);
|
140 | return this.columnArrayToDatabaseSchema(columnArrayMap);
|
141 | });
|
142 | }
|
143 | listStoredProcedures() {
|
144 | return __awaiter(this, void 0, void 0, function* () {
|
145 | const SHOW_DB_QUERY = `SHOW PROCEDURE STATUS WHERE Db = ?`;
|
146 | const sps = yield this.knex.raw(SHOW_DB_QUERY, [this.databaseName]);
|
147 | return sps[0].map(sp => sp.Name);
|
148 | });
|
149 | }
|
150 | listStoredProcedureParams() {
|
151 | return __awaiter(this, void 0, void 0, function* () {
|
152 | const LIST_PARAM_QUERY = `SELECT * FROM information_schema.parameters WHERE specific_schema = ?`;
|
153 | const params = yield this.knex.raw(LIST_PARAM_QUERY, [this.databaseName]);
|
154 | return params[0].map(item => {
|
155 | const copy = {};
|
156 | for (const key in item) {
|
157 | copy[change_case.camelCase(key)] = item[key];
|
158 | }
|
159 | return copy;
|
160 | });
|
161 | });
|
162 | }
|
163 | renderStoredProcedures() {
|
164 | return __awaiter(this, void 0, void 0, function* () {
|
165 | const storedProcedures = yield this.listStoredProcedures();
|
166 | const mapped = yield this.listStoredProcedureParams();
|
167 | const storedProcedureDictionary = {};
|
168 | storedProcedures.forEach(spName => storedProcedureDictionary[spName] = { name: spName, parameters: {} });
|
169 | mapped.forEach(item => storedProcedureDictionary[item.specificName].parameters[item.parameterName] = item);
|
170 | return storedProcedureDictionary;
|
171 | });
|
172 | }
|
173 | renderViewModel() {
|
174 | return __awaiter(this, void 0, void 0, function* () {
|
175 | const tables = yield this.listViews();
|
176 | return yield this.renderModel(tables);
|
177 | });
|
178 | }
|
179 | renderTableModel() {
|
180 | return __awaiter(this, void 0, void 0, function* () {
|
181 | const tables = yield this.listTables();
|
182 | return this.renderModel(tables);
|
183 | });
|
184 | }
|
185 | }
|
186 | exports.default = ModelBuilder;
|
187 |
|
\ | No newline at end of file |