@oino-ts/db-bunsqlite 0.21.2 → 1.0.1
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/dist/cjs/OINODbBunSqlite.js +40 -38
- package/dist/esm/OINODbBunSqlite.js +32 -30
- package/dist/types/OINODbBunSqlite.d.ts +12 -12
- package/package.json +37 -37
- package/src/OINODbBunSqlite.ts +395 -391
- package/src/index.ts +1 -1
package/src/OINODbBunSqlite.ts
CHANGED
|
@@ -1,391 +1,395 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
-
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
private static
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
*
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return "
|
|
94
|
-
|
|
95
|
-
} else if (
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
} else if (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
} else {
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
*
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return
|
|
139
|
-
|
|
140
|
-
} else if (
|
|
141
|
-
return
|
|
142
|
-
|
|
143
|
-
} else if ((
|
|
144
|
-
return sqlValue
|
|
145
|
-
|
|
146
|
-
} else if ((
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
result.setError(400, "DB returned no
|
|
200
|
-
|
|
201
|
-
} else if (sql_res.getRow()
|
|
202
|
-
result.setError(400, "DB returned no
|
|
203
|
-
|
|
204
|
-
} else {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
*
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
*
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
api.datamodel
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Buffer } from "node:buffer"
|
|
8
|
+
|
|
9
|
+
import { OINO_ERROR_PREFIX, OINOBenchmark, OINOStr, OINOLog, OINOResult, OINODataSet, OINOBooleanDataField, OINONumberDataField, OINOStringDataField, OINODataFieldParams, OINOMemoryDataset, OINODataCell, OINOBlobDataField, OINODatetimeDataField, OINO_EMPTY_ROWS } from "@oino-ts/common";
|
|
10
|
+
|
|
11
|
+
import { OINODb, OINODbApi, OINODbParams, OINODbDataModel } from "@oino-ts/db";
|
|
12
|
+
|
|
13
|
+
import { Database as BunSqliteDb } from "bun:sqlite";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Implmentation of OINODataSet for BunSqlite.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
class OINOBunSqliteDataset extends OINOMemoryDataset {
|
|
20
|
+
constructor(data: unknown, messages:string[]=[]) {
|
|
21
|
+
super(data, messages)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Implementation of BunSqlite-database.
|
|
27
|
+
*
|
|
28
|
+
*/
|
|
29
|
+
export class OINODbBunSqlite extends OINODb {
|
|
30
|
+
private static _tableDescriptionRegex = /^CREATE TABLE\s*[\"\[]?\w+[\"\]]?\s*\(\s*(.*)\s*\)\s*(WITHOUT ROWID)?$/msi
|
|
31
|
+
private static _tablePrimarykeyRegex = /PRIMARY KEY \(([^\)]+)\)/i
|
|
32
|
+
private static _tableForeignkeyRegex = /FOREIGN KEY \(\[([^\)]+)\]\)/i
|
|
33
|
+
private static _tableFieldTypeRegex = /[\"\[\s]?(\w+)[\"\]\s]\s?(INTEGER|REAL|DOUBLE|NUMERIC|DECIMAL|TEXT|BLOB|VARCHAR|DATETIME|DATE|BOOLEAN)(\s?\((\d+)\s?\,?\s?(\d*)?\))?/i
|
|
34
|
+
|
|
35
|
+
private _db:BunSqliteDb|null
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* OINODbBunSqlite constructor
|
|
39
|
+
* @param params database parameters
|
|
40
|
+
*/
|
|
41
|
+
constructor(params:OINODbParams) {
|
|
42
|
+
super(params)
|
|
43
|
+
this._db = null
|
|
44
|
+
if (!this.dbParams.url.startsWith("file://")) {
|
|
45
|
+
throw new Error(OINO_ERROR_PREFIX + ": OINODbBunSqlite url must be a file://-url!")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (this.dbParams.type !== "OINODbBunSqlite") {
|
|
49
|
+
throw new Error(OINO_ERROR_PREFIX + ": Not OINODbBunSqlite-type: " + this.dbParams.type)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private _parseDbFieldParams(fieldStr:string): OINODataFieldParams {
|
|
54
|
+
const result:OINODataFieldParams = {
|
|
55
|
+
isPrimaryKey: fieldStr.indexOf("PRIMARY KEY") >= 0,
|
|
56
|
+
isForeignKey: false,
|
|
57
|
+
isAutoInc: fieldStr.indexOf("AUTOINCREMENT") >= 0,
|
|
58
|
+
isNotNull: fieldStr.indexOf("NOT NULL") >= 0
|
|
59
|
+
}
|
|
60
|
+
return result
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Print a table name using database specific SQL escaping.
|
|
65
|
+
*
|
|
66
|
+
* @param sqlTable name of the table
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
printTableName(sqlTable:string): string {
|
|
70
|
+
return "["+sqlTable+"]"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Print a column name with correct SQL escaping.
|
|
75
|
+
*
|
|
76
|
+
* @param sqlColumn name of the column
|
|
77
|
+
*
|
|
78
|
+
*/
|
|
79
|
+
printColumnName(sqlColumn:string): string {
|
|
80
|
+
return "\""+sqlColumn+"\""
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Print a single data value from serialization using the context of the native data
|
|
85
|
+
* type with the correct SQL escaping.
|
|
86
|
+
*
|
|
87
|
+
* @param cellValue data from sql results
|
|
88
|
+
* @param nativeType native type name for table column
|
|
89
|
+
*
|
|
90
|
+
*/
|
|
91
|
+
printCellAsValue(cellValue:OINODataCell, nativeType: string): string {
|
|
92
|
+
if (cellValue === null) {
|
|
93
|
+
return "NULL"
|
|
94
|
+
|
|
95
|
+
} else if (cellValue === undefined) {
|
|
96
|
+
return "UNDEFINED"
|
|
97
|
+
|
|
98
|
+
} else if ((nativeType == "INTEGER") || (nativeType == "REAL") || (nativeType == "DOUBLE" || (nativeType == "NUMERIC") || (nativeType == "DECIMAL"))) {
|
|
99
|
+
return cellValue.toString()
|
|
100
|
+
|
|
101
|
+
} else if (nativeType == "BLOB") {
|
|
102
|
+
if (cellValue instanceof Buffer) {
|
|
103
|
+
return "X'" + (cellValue as Buffer).toString("hex") + "'"
|
|
104
|
+
} else if (cellValue instanceof Uint8Array) {
|
|
105
|
+
return "X'" + Buffer.from(cellValue as Uint8Array).toString("hex") + "'"
|
|
106
|
+
} else {
|
|
107
|
+
return "'" + cellValue?.toString() + "'"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
} else if (((nativeType == "DATETIME") || (nativeType == "DATE")) && (cellValue instanceof Date)) {
|
|
111
|
+
return "\'" + cellValue.toISOString() + "\'"
|
|
112
|
+
|
|
113
|
+
} else {
|
|
114
|
+
return this.printStringValue(cellValue.toString())
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Print a single string value as valid sql literal
|
|
120
|
+
*
|
|
121
|
+
* @param sqlString string value
|
|
122
|
+
*
|
|
123
|
+
*/
|
|
124
|
+
printStringValue(sqlString:string): string {
|
|
125
|
+
return "\"" + sqlString.replaceAll("\"", "\"\"") + "\""
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Parse a single SQL result value for serialization using the context of the native data
|
|
130
|
+
* type.
|
|
131
|
+
*
|
|
132
|
+
* @param sqlValue data from serialization
|
|
133
|
+
* @param nativeType native type name for table column
|
|
134
|
+
*
|
|
135
|
+
*/
|
|
136
|
+
parseValueAsCell(sqlValue:OINODataCell, nativeType: string): OINODataCell {
|
|
137
|
+
if ((sqlValue === null) || (sqlValue == "NULL")) {
|
|
138
|
+
return null
|
|
139
|
+
|
|
140
|
+
} else if (sqlValue === undefined) {
|
|
141
|
+
return undefined
|
|
142
|
+
|
|
143
|
+
} else if (((nativeType == "DATETIME") || (nativeType == "DATE")) && (typeof(sqlValue) == "string") && (sqlValue != "")) {
|
|
144
|
+
return new Date(sqlValue)
|
|
145
|
+
|
|
146
|
+
} else if ((nativeType == "BOOLEAN")) {
|
|
147
|
+
return sqlValue == 1
|
|
148
|
+
|
|
149
|
+
} else if ((nativeType == "BLOB")) {
|
|
150
|
+
if (sqlValue instanceof Uint8Array) {
|
|
151
|
+
return Buffer.from(sqlValue)
|
|
152
|
+
} else {
|
|
153
|
+
return sqlValue
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
return sqlValue
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Connect to database.
|
|
164
|
+
*
|
|
165
|
+
*/
|
|
166
|
+
async connect(): Promise<OINOResult> {
|
|
167
|
+
OINOBenchmark.startMetric("OINODb", "connect")
|
|
168
|
+
let result:OINOResult = new OINOResult()
|
|
169
|
+
if (this.isConnected) {
|
|
170
|
+
return result
|
|
171
|
+
}
|
|
172
|
+
const filepath:string = this.dbParams.url.substring(7)
|
|
173
|
+
try {
|
|
174
|
+
this._db = BunSqliteDb.open(filepath, { create: true, readonly: false, readwrite: true })
|
|
175
|
+
this.isConnected = true
|
|
176
|
+
} catch (e:any) {
|
|
177
|
+
result.setError(500, "Exception connecting to database: " + e.message, "OINODbBunSqlite.connect")
|
|
178
|
+
OINOLog.exception("@oino-ts/db-bunsqlite", "OINODbBunSqlite", "connect", "exception in connect", {message:e.message, stack:e.stack})
|
|
179
|
+
}
|
|
180
|
+
OINOBenchmark.endMetric("OINODb", "connect", result.status != 500)
|
|
181
|
+
return result
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Validate connection to database is working.
|
|
186
|
+
*
|
|
187
|
+
*/
|
|
188
|
+
async validate(): Promise<OINOResult> {
|
|
189
|
+
if (!this.isConnected) {
|
|
190
|
+
return new OINOResult().setError(400, "Database not connected!", "OINODbBunSqlite.validate")
|
|
191
|
+
}
|
|
192
|
+
OINOBenchmark.startMetric("OINODb", "validate")
|
|
193
|
+
let result:OINOResult = new OINOResult()
|
|
194
|
+
try {
|
|
195
|
+
this.isValidated = false
|
|
196
|
+
const sql = this._getValidateSql(this.dbParams.database)
|
|
197
|
+
const sql_res:OINODataSet = await this._query(sql)
|
|
198
|
+
if (sql_res.isEmpty()) {
|
|
199
|
+
result.setError(400, "DB returned no rows for select!", "OINODbBunSqlite.validate")
|
|
200
|
+
|
|
201
|
+
} else if (sql_res.getRow().length == 0) {
|
|
202
|
+
result.setError(400, "DB returned no values for database!", "OINODbBunSqlite.validate")
|
|
203
|
+
|
|
204
|
+
} else if (sql_res.getRow()[0] == "0") {
|
|
205
|
+
result.setError(400, "DB returned no schema for database!", "OINODbBunSqlite.validate")
|
|
206
|
+
|
|
207
|
+
} else {
|
|
208
|
+
this.isValidated = true
|
|
209
|
+
}
|
|
210
|
+
} catch (e:any) {
|
|
211
|
+
result.setError(500, OINO_ERROR_PREFIX + " (OINODbBunSqlite.validate): Exception in db query: " + e.message, "OINODbBunSqlite.validate")
|
|
212
|
+
}
|
|
213
|
+
OINOBenchmark.endMetric("OINODb", "validate", result.status != 500)
|
|
214
|
+
return result
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Connect to database.
|
|
219
|
+
*
|
|
220
|
+
*/
|
|
221
|
+
async disconnect(): Promise<void> {
|
|
222
|
+
this.isConnected = false
|
|
223
|
+
this.isValidated = false
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
private async _query(sql:string): Promise<OINODataSet> {
|
|
228
|
+
let result:OINODataSet
|
|
229
|
+
try {
|
|
230
|
+
const sql_res = this._db?.query(sql).values()
|
|
231
|
+
if (sql_res) {
|
|
232
|
+
// console.log("OINODbBunSqlite._query: res", sql_res)
|
|
233
|
+
result = new OINOBunSqliteDataset(sql_res, [])
|
|
234
|
+
} else {
|
|
235
|
+
result = new OINOBunSqliteDataset(OINO_EMPTY_ROWS, [])
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
} catch (e:any) {
|
|
239
|
+
result = new OINOBunSqliteDataset(OINO_EMPTY_ROWS, []).setError(500, OINO_ERROR_PREFIX + " (OINODbBunSqlite._query): Exception in db query: " + e.message, "OINODbBunSqlite._query") as OINOBunSqliteDataset
|
|
240
|
+
}
|
|
241
|
+
return result
|
|
242
|
+
}
|
|
243
|
+
private async _exec(sql:string): Promise<OINODataSet> {
|
|
244
|
+
let result:OINODataSet
|
|
245
|
+
try {
|
|
246
|
+
const sql_res = this._db?.query(sql).values()
|
|
247
|
+
if (sql_res) {
|
|
248
|
+
// console.log("OINODbBunSqlite._exec: res", sql_res)
|
|
249
|
+
result = new OINOBunSqliteDataset(sql_res, [])
|
|
250
|
+
} else {
|
|
251
|
+
result = new OINOBunSqliteDataset(OINO_EMPTY_ROWS, [])
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
} catch (e:any) {
|
|
255
|
+
result = new OINOBunSqliteDataset(OINO_EMPTY_ROWS, []).setError(500, OINO_ERROR_PREFIX + ": Exception in db exec: " + e.message, "OINODbBunSqlite._exec") as OINOBunSqliteDataset
|
|
256
|
+
}
|
|
257
|
+
return result
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Execute a select operation.
|
|
262
|
+
*
|
|
263
|
+
* @param sql SQL statement.
|
|
264
|
+
*
|
|
265
|
+
*/
|
|
266
|
+
async sqlSelect(sql:string): Promise<OINODataSet> {
|
|
267
|
+
if (!this.isValidated) {
|
|
268
|
+
throw new Error(OINO_ERROR_PREFIX + ": Database connection not validated!")
|
|
269
|
+
}
|
|
270
|
+
OINOBenchmark.startMetric("OINODb", "sqlSelect")
|
|
271
|
+
let result:OINODataSet = await this._query(sql)
|
|
272
|
+
OINOBenchmark.endMetric("OINODb", "sqlSelect", result.status != 500)
|
|
273
|
+
return result
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Execute other sql operations.
|
|
278
|
+
*
|
|
279
|
+
* @param sql SQL statement.
|
|
280
|
+
*
|
|
281
|
+
*/
|
|
282
|
+
async sqlExec(sql:string): Promise<OINODataSet> {
|
|
283
|
+
if (!this.isValidated) {
|
|
284
|
+
return new OINOBunSqliteDataset(OINO_EMPTY_ROWS, [OINO_ERROR_PREFIX + " (OINODbBunSqlite.sqlExec): Database connection not validated!"])
|
|
285
|
+
}
|
|
286
|
+
OINOBenchmark.startMetric("OINODb", "sqlExec")
|
|
287
|
+
let result:OINODataSet = await this._exec(sql)
|
|
288
|
+
OINOBenchmark.endMetric("OINODb", "sqlExec", result.status != 500)
|
|
289
|
+
return result
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private _getSchemaSql(dbName:string, tableName:string):string {
|
|
293
|
+
const sql = "SELECT sql from sqlite_schema WHERE name='" + tableName + "'"
|
|
294
|
+
return sql
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private _getValidateSql(dbName:string):string {
|
|
298
|
+
const sql = "SELECT count(*) as COLUMN_COUNT from sqlite_schema"
|
|
299
|
+
return sql
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Initialize a data model by getting the SQL schema and populating OINODataFields of
|
|
304
|
+
* the model.
|
|
305
|
+
*
|
|
306
|
+
* @param api api which data model to initialize.
|
|
307
|
+
*
|
|
308
|
+
*/
|
|
309
|
+
async initializeApiDatamodel(api:OINODbApi): Promise<void> {
|
|
310
|
+
api.initializeDatamodel(new OINODbDataModel(api))
|
|
311
|
+
const schema_sql:string = this._getSchemaSql(this.dbParams.database, api.params.tableName)
|
|
312
|
+
const res:OINODataSet|null = await this._query(schema_sql)
|
|
313
|
+
const sql_desc:string = (res?.getRow()[0]) as string
|
|
314
|
+
const excluded_fields:string[] = []
|
|
315
|
+
let table_matches = OINODbBunSqlite._tableDescriptionRegex.exec(sql_desc)
|
|
316
|
+
if (!table_matches || table_matches?.length < 2) {
|
|
317
|
+
throw new Error("Table " + api.params.tableName + " not recognized as a valid Sqlite table!")
|
|
318
|
+
|
|
319
|
+
} else {
|
|
320
|
+
let field_strings:string[] = OINOStr.splitExcludingBrackets(table_matches[1], ',', '(', ')')
|
|
321
|
+
for (let field_str of field_strings) {
|
|
322
|
+
field_str = field_str.trim()
|
|
323
|
+
let field_params = this._parseDbFieldParams(field_str)
|
|
324
|
+
let field_match = OINODbBunSqlite._tableFieldTypeRegex.exec(field_str)
|
|
325
|
+
// console.log("OINODbBunSqlite.initializeApiDatamodel: field_match", field_match)
|
|
326
|
+
if ((!field_match) || (field_match.length < 3)) {
|
|
327
|
+
let primarykey_match = OINODbBunSqlite._tablePrimarykeyRegex.exec(field_str)
|
|
328
|
+
let foreignkey_match = OINODbBunSqlite._tableForeignkeyRegex.exec(field_str)
|
|
329
|
+
if (primarykey_match && primarykey_match.length >= 2) {
|
|
330
|
+
const primary_keys:string[] = primarykey_match[1].replaceAll("\"", "").split(',') // not sure if will have space or not so split by comma and trim later
|
|
331
|
+
for (let i:number=0; i<primary_keys.length; i++) {
|
|
332
|
+
const pk:string = primary_keys[i].trim() //..the trim
|
|
333
|
+
if (excluded_fields.indexOf(pk) >= 0) {
|
|
334
|
+
throw new Error(OINO_ERROR_PREFIX + "Primary key field excluded in API parameters: " + pk)
|
|
335
|
+
}
|
|
336
|
+
for (let j:number=0; j<api.datamodel!.fields.length; j++) {
|
|
337
|
+
if (api.datamodel!.fields[j].name == pk) {
|
|
338
|
+
api.datamodel!.fields[j].fieldParams.isPrimaryKey = true
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
} else if (foreignkey_match && foreignkey_match.length >= 2) {
|
|
344
|
+
const fk:string = foreignkey_match[1].trim()
|
|
345
|
+
for (let j:number=0; j<api.datamodel!.fields.length; j++) {
|
|
346
|
+
if (api.datamodel!.fields[j].name == fk) {
|
|
347
|
+
api.datamodel!.fields[j].fieldParams.isForeignKey = true
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
} else {
|
|
352
|
+
OINOLog.info("@oino-ts/db-bunsqlite", "OINODbBunSqlite", "initializeApiDatamodel", "Unsupported field definition skipped.", { field: field_str })
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
} else {
|
|
356
|
+
// field_str = "NAME TYPE (M, N)" -> 1:NAME, 2:TYPE, 4:M, 5:N
|
|
357
|
+
const field_name:string = field_match[1]
|
|
358
|
+
const sql_type:string = field_match[2]
|
|
359
|
+
const field_length:number = parseInt(field_match[4]) || 0
|
|
360
|
+
if (api.isFieldIncluded(field_name) == false) {
|
|
361
|
+
excluded_fields.push(field_name)
|
|
362
|
+
OINOLog.info("@oino-ts/db-bunsqlite", "OINODbBunSqlite", "initializeApiDatamodel", "Field excluded in API parameters.", {field:field_name})
|
|
363
|
+
|
|
364
|
+
} else {
|
|
365
|
+
if ((sql_type == "INTEGER") || (sql_type == "REAL") || (sql_type == "DOUBLE") || (sql_type == "NUMERIC") || (sql_type == "DECIMAL")) {
|
|
366
|
+
api.datamodel!.addField(new OINONumberDataField(this, field_name, sql_type, field_params ))
|
|
367
|
+
|
|
368
|
+
} else if ((sql_type == "BLOB") ) {
|
|
369
|
+
api.datamodel!.addField(new OINOBlobDataField(this, field_name, sql_type, field_params, field_length))
|
|
370
|
+
|
|
371
|
+
} else if ((sql_type == "TEXT")) {
|
|
372
|
+
api.datamodel!.addField(new OINOStringDataField(this, field_name, sql_type, field_params, field_length))
|
|
373
|
+
|
|
374
|
+
} else if ((sql_type == "DATETIME") || (sql_type == "DATE")) {
|
|
375
|
+
if (api.params.useDatesAsString) {
|
|
376
|
+
api.datamodel!.addField(new OINOStringDataField(this, field_name, sql_type, field_params, 0))
|
|
377
|
+
} else {
|
|
378
|
+
api.datamodel!.addField(new OINODatetimeDataField(this, field_name, sql_type, field_params))
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
} else if ((sql_type == "BOOLEAN")) {
|
|
382
|
+
api.datamodel!.addField(new OINOBooleanDataField(this, field_name, sql_type, field_params))
|
|
383
|
+
|
|
384
|
+
} else {
|
|
385
|
+
OINOLog.info("@oino-ts/db-bunsqlite", "OINODbBunSqlite", "initializeApiDatamodel", "Unrecognized field type treated as string", {field_name: field_name, sql_type:sql_type, field_length:field_length, field_params:field_params })
|
|
386
|
+
api.datamodel!.addField(new OINOStringDataField(this, field_name, sql_type, field_params, 0))
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
OINOLog.info("@oino-ts/db-bunsqlite", "OINODbBunSqlite", "initializeApiDatamodel", "\n" + api.datamodel!.printDebug("\n"))
|
|
392
|
+
return Promise.resolve()
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|