@egi/smart-db 2.3.1 → 2.3.2
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/.eslintrc.json +212 -0
- package/README.md +2 -0
- package/bin/copy-assets +6 -0
- package/package.json +1 -1
- package/src/drivers/smart-db-better-sqlite3.ts +284 -0
- package/src/drivers/smart-db-mysql.ts +159 -0
- package/src/drivers/smart-db-mysql2.ts +159 -0
- package/src/drivers/smart-db-sqlite3.ts +198 -0
- package/src/helpers/extract-db-api.ts +465 -0
- package/src/helpers/terser-tree.ts +39 -0
- package/src/models/abstract-model.ts +209 -0
- package/src/models/smart-db-core-table-model.ts +161 -0
- package/src/models/smart-db-dictionary.ts +28 -0
- package/src/models/smart-db-log-model.ts +316 -0
- package/src/models/smart-db-version-model.ts +316 -0
- package/src/models/smart-db-version-view-model.ts +347 -0
- package/src/models/sqlite-master-model.ts +140 -0
- package/src/models/sqlite-sequence-model.ts +91 -0
- package/{smart-db-api.d.ts → src/smart-db-api.ts} +3 -0
- package/src/smart-db-globals.ts +136 -0
- package/{smart-db-interfaces.d.ts → src/smart-db-interfaces.ts} +82 -34
- package/src/smart-db-log.ts +262 -0
- package/src/smart-db-sql-build-data.ts +28 -0
- package/src/smart-db-upgrade-manager.ts +171 -0
- package/src/smart-db.ts +854 -0
- package/test/data/sql-engine-tests.json +232 -0
- package/test/db/mysql/database-init.sql +11 -0
- package/test/db/sqlite3/database-init.sql +11 -0
- package/test/exer.js +28 -0
- package/test/model/smart-db-dictionary.ts +19 -0
- package/test/model/test-table-model.ts +214 -0
- package/test/test.js +273 -0
- package/test/test2.js +252 -0
- package/tsconfig.json +32 -0
- package/tsconfig.pro.json +32 -0
- package/tsconfig.test-model.json +23 -0
- package/drivers/smart-db-better-sqlite3.d.ts +0 -36
- package/drivers/smart-db-better-sqlite3.js +0 -1
- package/drivers/smart-db-mysql.d.ts +0 -26
- package/drivers/smart-db-mysql.js +0 -1
- package/drivers/smart-db-mysql2.d.ts +0 -26
- package/drivers/smart-db-mysql2.js +0 -1
- package/drivers/smart-db-sqlite3.d.ts +0 -30
- package/drivers/smart-db-sqlite3.js +0 -1
- package/helpers/extract-db-api.d.ts +0 -1
- package/helpers/extract-db-api.js +0 -1
- package/models/abstract-model.d.ts +0 -22
- package/models/abstract-model.js +0 -1
- package/models/smart-db-core-table-model.d.ts +0 -35
- package/models/smart-db-core-table-model.js +0 -1
- package/models/smart-db-dictionary.d.ts +0 -13
- package/models/smart-db-dictionary.js +0 -1
- package/models/smart-db-log-model.d.ts +0 -65
- package/models/smart-db-log-model.js +0 -1
- package/models/smart-db-version-model.d.ts +0 -65
- package/models/smart-db-version-model.js +0 -1
- package/models/smart-db-version-view-model.d.ts +0 -71
- package/models/smart-db-version-view-model.js +0 -1
- package/models/sqlite-master-model.d.ts +0 -36
- package/models/sqlite-master-model.js +0 -1
- package/models/sqlite-sequence-model.d.ts +0 -24
- package/models/sqlite-sequence-model.js +0 -1
- package/smart-db-api.js +0 -1
- package/smart-db-globals.d.ts +0 -22
- package/smart-db-globals.js +0 -1
- package/smart-db-interfaces.js +0 -1
- package/smart-db-log.d.ts +0 -58
- package/smart-db-log.js +0 -1
- package/smart-db-sql-build-data.d.ts +0 -9
- package/smart-db-sql-build-data.js +0 -1
- package/smart-db-upgrade-manager.d.ts +0 -13
- package/smart-db-upgrade-manager.js +0 -1
- package/smart-db.d.ts +0 -67
- package/smart-db.js +0 -1
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
// noinspection JSUnusedGlobalSymbols
|
|
2
|
+
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
import {SmartDbLogModel, SmartDbLogModelData} from "./models/smart-db-log-model";
|
|
5
|
+
import {SmartDbDateRegexp, SmartDbTimestampRegexp, toSmartDbTimestamp} from "./smart-db-globals";
|
|
6
|
+
import {SmartDbApi} from "./smart-db-interfaces";
|
|
7
|
+
|
|
8
|
+
export const SmartDbLogLocation = {
|
|
9
|
+
Frontend: "frontend",
|
|
10
|
+
Backend: "backend",
|
|
11
|
+
Database: "database",
|
|
12
|
+
UpgradeManager: "upgrade-manager",
|
|
13
|
+
Other: "other"
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type SmartDbLogLocationType = typeof SmartDbLogLocation;
|
|
17
|
+
export type SmartDbLogLocationKey = keyof SmartDbLogLocationType;
|
|
18
|
+
export type SmartDbLogLocationValue = SmartDbLogLocationType[keyof SmartDbLogLocationType];
|
|
19
|
+
|
|
20
|
+
export const SeverityCode = {
|
|
21
|
+
Fatal: "F", Error: "E", Warning: "W", Info: "I", Debug: "D", Local: "L"
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
export type SeverityCodeType = typeof SeverityCode;
|
|
25
|
+
export type SeverityCodeKey = keyof SeverityCodeType;
|
|
26
|
+
export type SeverityCodeValue = SeverityCodeType[keyof SeverityCodeType];
|
|
27
|
+
|
|
28
|
+
export const SeverityLevel = {
|
|
29
|
+
None: 0, Fatal: 1, Error: 2, Warning: 3, Info: 4, Debug: 5, All: 9
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
export type SeverityLevelType = typeof SeverityLevel;
|
|
33
|
+
export type SeverityLevelKey = keyof SeverityLevelType;
|
|
34
|
+
export type SeverityLevelValue = SeverityLevelType[keyof SeverityLevelType];
|
|
35
|
+
|
|
36
|
+
export class SmartDbLog {
|
|
37
|
+
private db: SmartDbApi;
|
|
38
|
+
private dbLogLevel: SeverityLevelValue; // = SeverityLevel.Info;
|
|
39
|
+
private consoleLogLevel: SeverityLevelValue; //= SeverityLevel.Info;
|
|
40
|
+
private userId: string | number = null;
|
|
41
|
+
private dbLogging: boolean = true;
|
|
42
|
+
private isLogging: boolean = false;
|
|
43
|
+
|
|
44
|
+
constructor(db?: SmartDbApi) {
|
|
45
|
+
this.db = db;
|
|
46
|
+
this.dbLogLevel = SeverityLevel.Info;
|
|
47
|
+
this.consoleLogLevel = SeverityLevel.Info;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// noinspection JSUnusedGlobalSymbols
|
|
51
|
+
public getConsoleLogLevel(): SeverityLevelValue {
|
|
52
|
+
return this.consoleLogLevel;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public setConsoleLogLevel(consoleLogLevel: SeverityLevelValue): void {
|
|
56
|
+
this.consoleLogLevel = consoleLogLevel;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// noinspection JSUnusedGlobalSymbols
|
|
60
|
+
public getDbLogLevel(): SeverityLevelValue {
|
|
61
|
+
return this.dbLogLevel;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public setDbLogLevel(dbLogLevel: SeverityLevelValue): void {
|
|
65
|
+
this.dbLogLevel = dbLogLevel;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public setDb(db: SmartDbApi): void {
|
|
69
|
+
this.db = db;
|
|
70
|
+
|
|
71
|
+
if (this.db) {
|
|
72
|
+
this.db.exists(SmartDbLogModel).then((exists) => {
|
|
73
|
+
this.dbLogging = exists;
|
|
74
|
+
}).catch((err) => {
|
|
75
|
+
throw err;
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
this.dbLogging = false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public setUserId(userId: string | number): void {
|
|
83
|
+
this.userId = userId;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public setDbLogging(dbLogging: boolean) {
|
|
87
|
+
this.dbLogging = dbLogging;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public getDbLogging(): boolean {
|
|
91
|
+
return this.dbLogging;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public logFatal(type: SmartDbLogLocationValue, location: string, message: string | Error, data?: any): void {
|
|
95
|
+
this.writeLog(type, location, SeverityCode.Fatal, message, data);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public logError(type: SmartDbLogLocationValue, location: string, message: string | Error, data?: any): void {
|
|
99
|
+
this.writeLog(type, location, SeverityCode.Error, message, data);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public logWarning(type: SmartDbLogLocationValue, location: string, message: string | Error, data?: any): void {
|
|
103
|
+
this.writeLog(type, location, SeverityCode.Warning, message, data);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public logInfo(type: SmartDbLogLocationValue, location: string, message: string | Error, data?: any): void {
|
|
107
|
+
this.writeLog(type, location, SeverityCode.Info, message, data);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public logDebug(type: SmartDbLogLocationValue, location: string, message: string | Error, data?: any): void {
|
|
111
|
+
this.writeLog(type, location, SeverityCode.Debug, message, data);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// noinspection OverlyComplexFunctionJS,FunctionTooLongJS
|
|
115
|
+
public writeLog(type: SmartDbLogLocationValue, location: string, severity: SeverityCodeValue, message: string | Error, data: unknown, timestamp?: Date | string | number): void {
|
|
116
|
+
try {
|
|
117
|
+
if (this.isLogging) {
|
|
118
|
+
console.error("recursive logging error:", type, location, severity, message, data);
|
|
119
|
+
} else {
|
|
120
|
+
this.isLogging = true;
|
|
121
|
+
|
|
122
|
+
let logLevel: SeverityLevelValue = SeverityLevel.None;
|
|
123
|
+
let logFn: (message?: any, ...args: any[]) => void;
|
|
124
|
+
|
|
125
|
+
switch (severity) {
|
|
126
|
+
case SeverityCode.Fatal:
|
|
127
|
+
logFn = console.error;
|
|
128
|
+
logLevel = SeverityLevel.Fatal;
|
|
129
|
+
break;
|
|
130
|
+
|
|
131
|
+
case SeverityCode.Error:
|
|
132
|
+
logFn = console.error;
|
|
133
|
+
logLevel = SeverityLevel.Error;
|
|
134
|
+
break;
|
|
135
|
+
|
|
136
|
+
case SeverityCode.Warning:
|
|
137
|
+
logFn = console.warn;
|
|
138
|
+
logLevel = SeverityLevel.Warning;
|
|
139
|
+
break;
|
|
140
|
+
|
|
141
|
+
case SeverityCode.Info:
|
|
142
|
+
logFn = console.info;
|
|
143
|
+
logLevel = SeverityLevel.Info;
|
|
144
|
+
break;
|
|
145
|
+
|
|
146
|
+
case SeverityCode.Debug:
|
|
147
|
+
logFn = console.debug;
|
|
148
|
+
logLevel = SeverityLevel.Debug;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let timestampString: string;
|
|
153
|
+
|
|
154
|
+
if (_.isString(timestamp)) {
|
|
155
|
+
const timestampMatch = timestamp.match(SmartDbTimestampRegexp);
|
|
156
|
+
const dateMatch = timestampMatch && timestamp.match(SmartDbDateRegexp);
|
|
157
|
+
if (timestampMatch) {
|
|
158
|
+
timestampString = timestampMatch[1];
|
|
159
|
+
} else if (dateMatch) {
|
|
160
|
+
timestampString = dateMatch[1] + ".000";
|
|
161
|
+
} else {
|
|
162
|
+
timestampString = toSmartDbTimestamp(new Date());
|
|
163
|
+
}
|
|
164
|
+
} else if (_.isDate(timestamp)) {
|
|
165
|
+
timestampString = toSmartDbTimestamp(timestamp);
|
|
166
|
+
} else if (_.isNumber(timestamp)) {
|
|
167
|
+
timestampString = toSmartDbTimestamp(new Date(timestamp));
|
|
168
|
+
} else {
|
|
169
|
+
timestampString = toSmartDbTimestamp(new Date());
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (_.isObjectLike(message)) {
|
|
173
|
+
if (message instanceof Error) {
|
|
174
|
+
if (!data) {
|
|
175
|
+
data = message;
|
|
176
|
+
}
|
|
177
|
+
message = message.message;
|
|
178
|
+
} else {
|
|
179
|
+
try {
|
|
180
|
+
message = JSON.stringify(message);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
message = message.toString();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} else if (typeof <any>message === "boolean") {
|
|
186
|
+
message = message ? "<true>" : "<false>";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (data) {
|
|
190
|
+
if (data instanceof Error) {
|
|
191
|
+
data = data.stack;
|
|
192
|
+
} else if (_.isObject(data)) {
|
|
193
|
+
try {
|
|
194
|
+
data = JSON.stringify(data);
|
|
195
|
+
} catch (err) {
|
|
196
|
+
data = data.toString();
|
|
197
|
+
|
|
198
|
+
if (this.db && this.dbLogLevel >= logLevel) {
|
|
199
|
+
console.error("unable to stringify log data", data);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} else if (data.toString) {
|
|
203
|
+
data = data.toString();
|
|
204
|
+
} else {
|
|
205
|
+
data = null;
|
|
206
|
+
|
|
207
|
+
if (this.db && this.dbLogLevel >= logLevel) {
|
|
208
|
+
console.error("unable to store log data", data);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (data) {
|
|
213
|
+
message += ` (${data})`;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (this.consoleLogLevel >= logLevel) {
|
|
218
|
+
const shortType = type.substr(0, 1).toUpperCase();
|
|
219
|
+
if (type == SmartDbLogLocation.Database && this.db) {
|
|
220
|
+
logFn(`${severity}-${shortType}-${timestampString}: last statement:`, this.db.getLastBuildData());
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
logFn(`${severity}-${shortType}-${timestampString}: ${message}`);
|
|
224
|
+
|
|
225
|
+
if (this.dbLogging) {
|
|
226
|
+
try {
|
|
227
|
+
if (type == SmartDbLogLocation.Database) {
|
|
228
|
+
if (!data) {
|
|
229
|
+
data = JSON.stringify(this.db.getLastBuildData());
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.db.insertSync(SmartDbLogModel, <SmartDbLogModelData>{
|
|
234
|
+
severity: severity,
|
|
235
|
+
type: type,
|
|
236
|
+
location: location,
|
|
237
|
+
info: message || "<empty>",
|
|
238
|
+
data: data as string,
|
|
239
|
+
user: this.userId,
|
|
240
|
+
timestamp: new Date(timestampString)
|
|
241
|
+
});
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.error(`F-B-${timestampString}: unable to write the log statement below to database`, error, error.code, error.name, error.message);
|
|
244
|
+
try {
|
|
245
|
+
logFn(`F-B-${timestampString}: last statement:`, this.db.getLastBuildData());
|
|
246
|
+
} catch {
|
|
247
|
+
logFn(`F-B-${timestampString}: last statement not available`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
this.isLogging = false;
|
|
255
|
+
} catch (error) {
|
|
256
|
+
this.isLogging = false;
|
|
257
|
+
console.error("fatal logging error", error);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export const smartDbLog: SmartDbLog = new SmartDbLog();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import _ from "lodash";
|
|
2
|
+
import {SmartDbSqlBuildDataResults, SqlValueType} from "./smart-db-interfaces";
|
|
3
|
+
|
|
4
|
+
export class SmartDbSqlBuildData {
|
|
5
|
+
public sql: string;
|
|
6
|
+
public values: SqlValueType[];
|
|
7
|
+
|
|
8
|
+
constructor(sql?: string, values?: SqlValueType[]) {
|
|
9
|
+
this.sql = sql || "";
|
|
10
|
+
this.values = values || [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public append(data: SmartDbSqlBuildData): void {
|
|
14
|
+
this.sql = this.sql.trim() + " " + data.sql.trim();
|
|
15
|
+
this.values = _.concat(this.values, data.values);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public toString() {
|
|
19
|
+
return this.sql + " <= (" + this.values.join(", ") + ")";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public results(): SmartDbSqlBuildDataResults {
|
|
23
|
+
return {
|
|
24
|
+
sql: this.sql,
|
|
25
|
+
values: this.values
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import _ from "lodash";
|
|
3
|
+
import {SmartDbVersionViewModel} from "./models/smart-db-version-view-model";
|
|
4
|
+
import {SmartDb} from "./smart-db";
|
|
5
|
+
import {SmartDbOptions} from "./smart-db-interfaces";
|
|
6
|
+
import {SmartDbLog, SmartDbLogLocation} from "./smart-db-log";
|
|
7
|
+
|
|
8
|
+
export class SmartDbUpgradeManager {
|
|
9
|
+
private db: SmartDb;
|
|
10
|
+
private log: SmartDbLog;
|
|
11
|
+
|
|
12
|
+
constructor(db: SmartDb) {
|
|
13
|
+
this.db = db;
|
|
14
|
+
this.log = db.getLogger();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public hasDatabaseModule(module: string): Promise<boolean> {
|
|
18
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
19
|
+
this.db.exists(SmartDbVersionViewModel).then((exists) => {
|
|
20
|
+
if (exists) {
|
|
21
|
+
this.db.getFirst(SmartDbVersionViewModel, {
|
|
22
|
+
module: module
|
|
23
|
+
}).then((row) => {
|
|
24
|
+
resolve(!!row);
|
|
25
|
+
}).catch((err) => {
|
|
26
|
+
reject(err);
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
resolve(false);
|
|
30
|
+
}
|
|
31
|
+
}).catch((err) => {
|
|
32
|
+
reject(err);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public prepareDatabase(options: SmartDbOptions): Promise<SmartDbVersionViewModel> {
|
|
38
|
+
return new Promise<SmartDbVersionViewModel>((resolve, reject) => {
|
|
39
|
+
try {
|
|
40
|
+
const dirStat = fs.existsSync(options.sqlFilesDirectory) && fs.statSync(options.sqlFilesDirectory);
|
|
41
|
+
if (dirStat && dirStat.isDirectory()) {
|
|
42
|
+
const initFile = options.sqlFilesDirectory + `/${options.module}-init.sql`;
|
|
43
|
+
if (fs.existsSync(initFile)) {
|
|
44
|
+
this.hasDatabaseModule(options.module).then((hasDatabase) => {
|
|
45
|
+
if (hasDatabase) {
|
|
46
|
+
this.log.logInfo(SmartDbLogLocation.UpgradeManager, "prepareDatabase", `database module '${options.module}' exists`);
|
|
47
|
+
this.upgradeDatabase(options).then((finalVersionRow) => {
|
|
48
|
+
this.log.logInfo(SmartDbLogLocation.UpgradeManager, "prepareDatabase", `connected to module '${options.module}' version ${finalVersionRow.versionString}`);
|
|
49
|
+
resolve(finalVersionRow);
|
|
50
|
+
}).catch((err) => {
|
|
51
|
+
reject(err);
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
this.log.setDbLogging(false);
|
|
55
|
+
this.log.logInfo(SmartDbLogLocation.UpgradeManager, "prepareDatabase", `database '${options.module}' doesn't exists - begin creation`);
|
|
56
|
+
this.executeSqlScript(initFile).then(() => {
|
|
57
|
+
this.log.setDbLogging(true);
|
|
58
|
+
this.log.logInfo(SmartDbLogLocation.UpgradeManager, "prepareDatabase", `database module creation complete`);
|
|
59
|
+
this.hasDatabaseModule(options.module).then((hasDatabase) => {
|
|
60
|
+
if (hasDatabase) {
|
|
61
|
+
this.log.logInfo(SmartDbLogLocation.UpgradeManager, "prepareDatabase", `successfully initialized database for new module ${options.module}`);
|
|
62
|
+
this.upgradeDatabase(options).then((finalVersionRow) => {
|
|
63
|
+
this.log.logInfo(SmartDbLogLocation.UpgradeManager, "prepareDatabase", `connected to module '${options.module}' version ${finalVersionRow.versionString}`);
|
|
64
|
+
resolve(finalVersionRow);
|
|
65
|
+
}).catch((err) => {
|
|
66
|
+
reject(err);
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
reject("error running database initialization script");
|
|
70
|
+
}
|
|
71
|
+
}).catch((err) => {
|
|
72
|
+
reject(err);
|
|
73
|
+
});
|
|
74
|
+
}).catch((err) => {
|
|
75
|
+
reject(err);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}).catch((err) => {
|
|
79
|
+
reject(err);
|
|
80
|
+
});
|
|
81
|
+
} else {
|
|
82
|
+
reject(`missing mandatory '${options.module}-init.sql' file in ${initFile}`);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
reject(`option 'sqlFilesDirectory' (${options.sqlFilesDirectory}) must point to an existing directory (absolute or relative to ${fs.realpathSync(".")})`);
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
reject(err);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private executeSqlScript(script: string): Promise<void> {
|
|
94
|
+
const sqlData = fs.readFileSync(script, "utf8");
|
|
95
|
+
return this.db.exec(sqlData);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private upgradeDatabase(options: SmartDbOptions): Promise<SmartDbVersionViewModel> {
|
|
99
|
+
return new Promise<SmartDbVersionViewModel>((resolve, reject) => {
|
|
100
|
+
this.db.getFirst(SmartDbVersionViewModel, {
|
|
101
|
+
module: options.module
|
|
102
|
+
}).then((versionRow) => {
|
|
103
|
+
if (versionRow) {
|
|
104
|
+
fs.readdir(options.sqlFilesDirectory, (err, files) => {
|
|
105
|
+
if (err) {
|
|
106
|
+
reject(`unable to read database files from ${options.sqlFilesDirectory}`);
|
|
107
|
+
} else {
|
|
108
|
+
let upgradeScripts: string[] = [];
|
|
109
|
+
files.forEach((file) => {
|
|
110
|
+
const regExp = new RegExp(`^${options.module}-update.([0-9]{3})\\..*\\.sql$`);
|
|
111
|
+
const match = file.match(regExp);
|
|
112
|
+
if (match) {
|
|
113
|
+
const sequence = parseInt(match[1], 10);
|
|
114
|
+
if (sequence > versionRow.sequence) {
|
|
115
|
+
upgradeScripts.push(file);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
upgradeScripts = _.sortBy(upgradeScripts);
|
|
121
|
+
|
|
122
|
+
this.executeScriptSequentially(upgradeScripts, options).then(() => {
|
|
123
|
+
this.db.getFirst(SmartDbVersionViewModel, {module: options.module}, "*", "sequence DESC").then((finalVersionRow) => {
|
|
124
|
+
if (finalVersionRow) {
|
|
125
|
+
resolve(SmartDbVersionViewModel.from(finalVersionRow));
|
|
126
|
+
} else {
|
|
127
|
+
reject("unable to determine final smart db version");
|
|
128
|
+
}
|
|
129
|
+
}).catch((err) => {
|
|
130
|
+
reject(err);
|
|
131
|
+
});
|
|
132
|
+
}).catch((err) => {
|
|
133
|
+
reject(err);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
} else {
|
|
138
|
+
reject(`missing version entry for module ${options.module} - add the mandatory insert into smart_db_version statement to your database creation script!`);
|
|
139
|
+
}
|
|
140
|
+
}).catch((err) => {
|
|
141
|
+
reject(err);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private executeScriptSequentially(scripts: string[], options: SmartDbOptions): Promise<boolean> {
|
|
147
|
+
return new Promise<boolean>(async (resolve, reject) => {
|
|
148
|
+
if (scripts && scripts.length > 0) {
|
|
149
|
+
this.log.logInfo(SmartDbLogLocation.UpgradeManager, "upgradeDatabase", `execute update script '${scripts[0]}' for module ${options.module}`);
|
|
150
|
+
await this.executeSqlScript(`${options.sqlFilesDirectory}/${scripts[0]}`).then(() => {
|
|
151
|
+
this.log.logInfo(SmartDbLogLocation.UpgradeManager, "upgradeDatabase", `successfully executed update script '${scripts[0]}' for module ${options.module}`);
|
|
152
|
+
if (scripts.length == 1) {
|
|
153
|
+
resolve(true);
|
|
154
|
+
}
|
|
155
|
+
}).catch((err) => {
|
|
156
|
+
reject(err);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (scripts.length > 1) {
|
|
160
|
+
this.executeScriptSequentially(scripts.splice(1), options).then((status) => {
|
|
161
|
+
resolve(status);
|
|
162
|
+
}).catch((err) => {
|
|
163
|
+
reject(err);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
resolve(true);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|