@oino-ts/db 0.17.1 → 0.17.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/src/OINODb.ts CHANGED
@@ -1,321 +1,321 @@
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 { OINODbParams, OINODbApi, OINODataCell, OINO_ERROR_PREFIX, OINODataRow, OINODB_EMPTY_ROW, OINOResult, OINOLog } from "./index.js"
8
-
9
- /**
10
- * Base class for database abstraction, implementing methods for connecting, making queries and parsing/formatting data
11
- * between SQL and serialization formats.
12
- *
13
- */
14
- export abstract class OINODb {
15
-
16
- protected _params:OINODbParams
17
-
18
- /** Name of the database */
19
- readonly name:string
20
-
21
- isConnected:boolean = false
22
- isValidated:boolean = false
23
-
24
- /**
25
- * Constructor for `OINODb`.
26
- * @param params database parameters
27
- */
28
- constructor(params:OINODbParams) {
29
- this._params = { ...params } // make a shallow copy of params so that changes to them do not affect the original object
30
- this.name = this._params.database
31
- }
32
-
33
- /**
34
- * Connect to database.
35
- *
36
- */
37
- abstract connect(): Promise<OINOResult>
38
-
39
- /**
40
- * Validate connection to database is working.
41
- *
42
- */
43
- abstract validate(): Promise<OINOResult>
44
-
45
- /**
46
- * Print a table name using database specific SQL escaping.
47
- *
48
- * @param sqlTable name of the table
49
- *
50
- */
51
- abstract printSqlTablename(sqlTable:string): string
52
-
53
- /**
54
- * Print a column name with correct SQL escaping.
55
- *
56
- * @param sqlColumn name of the column
57
- *
58
- */
59
- abstract printSqlColumnname(sqlColumn:string): string
60
-
61
- /**
62
- * Print a single data value from serialization using the context of the native data
63
- * type with the correct SQL escaping.
64
- *
65
- * @param cellValue data from sql results
66
- * @param sqlType native type name for table column
67
- *
68
- */
69
- abstract printCellAsSqlValue(cellValue:OINODataCell, sqlType: string): string
70
-
71
- /**
72
- * Print a single string value as valid sql literal
73
- *
74
- * @param sqlString string value
75
- *
76
- */
77
- abstract printSqlString(sqlString:string): string
78
-
79
- /**
80
- * Parse a single SQL result value for serialization using the context of the native data
81
- * type.
82
- *
83
- * @param sqlValue data from serialization
84
- * @param sqlType native type name for table column
85
- *
86
- */
87
- abstract parseSqlValueAsCell(sqlValue:OINODataCell, sqlType: string): OINODataCell
88
-
89
- /**
90
- * Execute a select operation.
91
- *
92
- * @param sql SQL statement.
93
- *
94
- */
95
- abstract sqlSelect(sql:string): Promise<OINODbDataSet>
96
-
97
- /**
98
- * Execute other sql operations.
99
- *
100
- * @param sql SQL statement.
101
- *
102
- */
103
- abstract sqlExec(sql:string): Promise<OINODbDataSet>
104
-
105
- /**
106
- * Initialize a data model by getting the SQL schema and populating OINODbDataFields of
107
- * the model.
108
- *
109
- * @param api api which data model to initialize.
110
- *
111
- */
112
- abstract initializeApiDatamodel(api:OINODbApi): Promise<void>
113
-
114
- /**
115
- * Print SQL select statement with DB specific formatting.
116
- *
117
- * @param tableName - The name of the table to select from.
118
- * @param columnNames - The columns to be selected.
119
- * @param whereCondition - The WHERE clause to filter the results.
120
- * @param orderCondition - The ORDER BY clause to sort the results.
121
- * @param limitCondition - The LIMIT clause to limit the number of results.
122
- * @param groupByCondition - The GROUP BY clause to group the results.
123
- *
124
- */
125
- printSqlSelect(tableName:string, columnNames:string, whereCondition:string, orderCondition:string, limitCondition:string, groupByCondition: string): string {
126
- let result:string = "SELECT " + columnNames + " FROM " + tableName;
127
- if (whereCondition != "") {
128
- result += " WHERE " + whereCondition
129
- }
130
- if (groupByCondition != "") {
131
- result += " GROUP BY " + groupByCondition
132
- }
133
- if (orderCondition != "") {
134
- result += " ORDER BY " + orderCondition
135
- }
136
- if (limitCondition != "") {
137
- result += " LIMIT " + limitCondition
138
- }
139
- result += ";"
140
- return result;
141
- }
142
- }
143
-
144
- /**
145
- * Base class for SQL results that can be asynchronously iterated (but
146
- * not necessarity rewinded). Idea is to handle database specific mechanisms
147
- * for returning and formatting conventions in the database specific
148
- * implementation. Data might be in memory or streamed in chunks and
149
- * `OINODbDataSet` will serve it out consistently.
150
- *
151
- */
152
-
153
- export abstract class OINODbDataSet {
154
- private _data: unknown;
155
-
156
- /** Error messages */
157
- readonly messages: string[];
158
-
159
- /**
160
- * Constructor for `OINODbDataSet`.
161
- *
162
- * @param data internal database specific data type (constructor will throw if invalid)
163
- * @param messages error messages from SQL-query
164
- *
165
- */
166
- constructor(data: unknown, messages: string[] = []) {
167
- this._data = data;
168
- this.messages = messages;
169
- }
170
-
171
- /**
172
- * Is data set empty.
173
- *
174
- */
175
- abstract isEmpty(): boolean;
176
-
177
- /**
178
- * Is there no more content, i.e. either dataset is empty or we have moved beyond last line
179
- *
180
- */
181
- abstract isEof(): boolean;
182
-
183
- /**
184
- * Attempts to moves dataset to the next row, possibly waiting for more data to become available. Returns !isEof().
185
- *
186
- */
187
- abstract next(): Promise<boolean>;
188
-
189
- /**
190
- * Gets current row of data.
191
- *
192
- */
193
- abstract getRow(): OINODataRow;
194
-
195
- /**
196
- * Gets all rows of data.
197
- *
198
- * NOTE: This is left abstract instead of just using `getRow()` so that DB implementations can hopefully optimize not duplicating data *
199
- */
200
- abstract getAllRows(): Promise<OINODataRow[]>;
201
-
202
- /**
203
- * Checks if the messages contain errors.
204
- *
205
- */
206
- hasErrors(): boolean {
207
- for (let i = 0; i < this.messages.length; i++) {
208
- if (this.messages[i].startsWith(OINO_ERROR_PREFIX)) {
209
- return true;
210
- }
211
- }
212
- return false;
213
- }
214
- /**
215
- * Checks if the messages contain errors.
216
- *
217
- */
218
- getFirstError(): string {
219
- for (let i = 0; i < this.messages.length; i++) {
220
- if (this.messages[i].startsWith(OINO_ERROR_PREFIX)) {
221
- return this.messages[i];
222
- }
223
- }
224
- return "";
225
- }
226
- }
227
-
228
- /**
229
- * Generic in memory implementation of a data set where data is an array of rows. Used
230
- * by BunSqlite and automated testing. Can be rewinded.
231
- *
232
- */
233
-
234
- export class OINODbMemoryDataSet extends OINODbDataSet {
235
- private _rows: OINODataRow[];
236
- private _currentRow: number;
237
- private _eof: boolean;
238
-
239
- /**
240
- * Constructor of `OINODbMemoryDataSet`.
241
- *
242
- * @param data data as OINODataRow[] (constructor will throw if invalid)
243
- * @param errors error messages from SQL-query
244
- *
245
- */
246
- constructor(data: unknown, errors: string[] = []) {
247
- super(data, errors);
248
- if ((data == null) || !(Array.isArray(data))) {
249
- throw new Error(OINO_ERROR_PREFIX + ": Data needs to be compatible with OINORow[]!"); // TODO: maybe check all rows
250
- }
251
- this._rows = data as OINODataRow[];
252
- if (this.isEmpty()) {
253
- this._currentRow = -1;
254
- this._eof = true;
255
- } else {
256
- this._currentRow = 0;
257
- this._eof = false;
258
- }
259
- }
260
-
261
- /**
262
- * Is data set empty.
263
- *
264
- */
265
- isEmpty(): boolean {
266
- return (this._rows.length == 0);
267
- }
268
-
269
- /**
270
- * Is there no more content, i.e. either dataset is empty or we have moved beyond last line
271
- *
272
- */
273
- isEof(): boolean {
274
- return (this._eof);
275
- }
276
-
277
- /**
278
- * Attempts to moves dataset to the next row, possibly waiting for more data to become available. Returns !isEof().
279
- *
280
- */
281
- async next(): Promise<boolean> {
282
- if (this._currentRow < this._rows.length - 1) {
283
- this._currentRow = this._currentRow + 1;
284
- } else {
285
- this._eof = true;
286
- }
287
- return Promise.resolve(!this._eof);
288
- }
289
-
290
- /**
291
- * Gets current row of data.
292
- *
293
- */
294
- getRow(): OINODataRow {
295
- if ((this._currentRow >= 0) && (this._currentRow < this._rows.length)) {
296
- return this._rows[this._currentRow];
297
- } else {
298
- return OINODB_EMPTY_ROW;
299
- }
300
- }
301
-
302
- /**
303
- * Gets all rows of data.
304
- *
305
- */
306
- async getAllRows(): Promise<OINODataRow[]> {
307
- return this._rows // at the moment theres no result streaming, so we can just return the rows
308
- }
309
-
310
- /**
311
- * Rewinds data set to the first row, returns !isEof().
312
- *
313
- */
314
- first(): boolean {
315
- this._currentRow = 0;
316
- this._eof = this._rows.length == 0;
317
- return !this._eof;
318
- }
319
- }
320
-
321
-
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 { OINODbParams, OINODbApi, OINODataCell, OINO_ERROR_PREFIX, OINODataRow, OINODB_EMPTY_ROW, OINOResult, OINOLog } from "./index.js"
8
+
9
+ /**
10
+ * Base class for database abstraction, implementing methods for connecting, making queries and parsing/formatting data
11
+ * between SQL and serialization formats.
12
+ *
13
+ */
14
+ export abstract class OINODb {
15
+
16
+ protected _params:OINODbParams
17
+
18
+ /** Name of the database */
19
+ readonly name:string
20
+
21
+ isConnected:boolean = false
22
+ isValidated:boolean = false
23
+
24
+ /**
25
+ * Constructor for `OINODb`.
26
+ * @param params database parameters
27
+ */
28
+ constructor(params:OINODbParams) {
29
+ this._params = { ...params } // make a shallow copy of params so that changes to them do not affect the original object
30
+ this.name = this._params.database
31
+ }
32
+
33
+ /**
34
+ * Connect to database.
35
+ *
36
+ */
37
+ abstract connect(): Promise<OINOResult>
38
+
39
+ /**
40
+ * Validate connection to database is working.
41
+ *
42
+ */
43
+ abstract validate(): Promise<OINOResult>
44
+
45
+ /**
46
+ * Print a table name using database specific SQL escaping.
47
+ *
48
+ * @param sqlTable name of the table
49
+ *
50
+ */
51
+ abstract printSqlTablename(sqlTable:string): string
52
+
53
+ /**
54
+ * Print a column name with correct SQL escaping.
55
+ *
56
+ * @param sqlColumn name of the column
57
+ *
58
+ */
59
+ abstract printSqlColumnname(sqlColumn:string): string
60
+
61
+ /**
62
+ * Print a single data value from serialization using the context of the native data
63
+ * type with the correct SQL escaping.
64
+ *
65
+ * @param cellValue data from sql results
66
+ * @param sqlType native type name for table column
67
+ *
68
+ */
69
+ abstract printCellAsSqlValue(cellValue:OINODataCell, sqlType: string): string
70
+
71
+ /**
72
+ * Print a single string value as valid sql literal
73
+ *
74
+ * @param sqlString string value
75
+ *
76
+ */
77
+ abstract printSqlString(sqlString:string): string
78
+
79
+ /**
80
+ * Parse a single SQL result value for serialization using the context of the native data
81
+ * type.
82
+ *
83
+ * @param sqlValue data from serialization
84
+ * @param sqlType native type name for table column
85
+ *
86
+ */
87
+ abstract parseSqlValueAsCell(sqlValue:OINODataCell, sqlType: string): OINODataCell
88
+
89
+ /**
90
+ * Execute a select operation.
91
+ *
92
+ * @param sql SQL statement.
93
+ *
94
+ */
95
+ abstract sqlSelect(sql:string): Promise<OINODbDataSet>
96
+
97
+ /**
98
+ * Execute other sql operations.
99
+ *
100
+ * @param sql SQL statement.
101
+ *
102
+ */
103
+ abstract sqlExec(sql:string): Promise<OINODbDataSet>
104
+
105
+ /**
106
+ * Initialize a data model by getting the SQL schema and populating OINODbDataFields of
107
+ * the model.
108
+ *
109
+ * @param api api which data model to initialize.
110
+ *
111
+ */
112
+ abstract initializeApiDatamodel(api:OINODbApi): Promise<void>
113
+
114
+ /**
115
+ * Print SQL select statement with DB specific formatting.
116
+ *
117
+ * @param tableName - The name of the table to select from.
118
+ * @param columnNames - The columns to be selected.
119
+ * @param whereCondition - The WHERE clause to filter the results.
120
+ * @param orderCondition - The ORDER BY clause to sort the results.
121
+ * @param limitCondition - The LIMIT clause to limit the number of results.
122
+ * @param groupByCondition - The GROUP BY clause to group the results.
123
+ *
124
+ */
125
+ printSqlSelect(tableName:string, columnNames:string, whereCondition:string, orderCondition:string, limitCondition:string, groupByCondition: string): string {
126
+ let result:string = "SELECT " + columnNames + " FROM " + tableName;
127
+ if (whereCondition != "") {
128
+ result += " WHERE " + whereCondition
129
+ }
130
+ if (groupByCondition != "") {
131
+ result += " GROUP BY " + groupByCondition
132
+ }
133
+ if (orderCondition != "") {
134
+ result += " ORDER BY " + orderCondition
135
+ }
136
+ if (limitCondition != "") {
137
+ result += " LIMIT " + limitCondition
138
+ }
139
+ result += ";"
140
+ return result;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Base class for SQL results that can be asynchronously iterated (but
146
+ * not necessarity rewinded). Idea is to handle database specific mechanisms
147
+ * for returning and formatting conventions in the database specific
148
+ * implementation. Data might be in memory or streamed in chunks and
149
+ * `OINODbDataSet` will serve it out consistently.
150
+ *
151
+ */
152
+
153
+ export abstract class OINODbDataSet {
154
+ private _data: unknown;
155
+
156
+ /** Error messages */
157
+ readonly messages: string[];
158
+
159
+ /**
160
+ * Constructor for `OINODbDataSet`.
161
+ *
162
+ * @param data internal database specific data type (constructor will throw if invalid)
163
+ * @param messages error messages from SQL-query
164
+ *
165
+ */
166
+ constructor(data: unknown, messages: string[] = []) {
167
+ this._data = data;
168
+ this.messages = messages;
169
+ }
170
+
171
+ /**
172
+ * Is data set empty.
173
+ *
174
+ */
175
+ abstract isEmpty(): boolean;
176
+
177
+ /**
178
+ * Is there no more content, i.e. either dataset is empty or we have moved beyond last line
179
+ *
180
+ */
181
+ abstract isEof(): boolean;
182
+
183
+ /**
184
+ * Attempts to moves dataset to the next row, possibly waiting for more data to become available. Returns !isEof().
185
+ *
186
+ */
187
+ abstract next(): Promise<boolean>;
188
+
189
+ /**
190
+ * Gets current row of data.
191
+ *
192
+ */
193
+ abstract getRow(): OINODataRow;
194
+
195
+ /**
196
+ * Gets all rows of data.
197
+ *
198
+ * NOTE: This is left abstract instead of just using `getRow()` so that DB implementations can hopefully optimize not duplicating data *
199
+ */
200
+ abstract getAllRows(): Promise<OINODataRow[]>;
201
+
202
+ /**
203
+ * Checks if the messages contain errors.
204
+ *
205
+ */
206
+ hasErrors(): boolean {
207
+ for (let i = 0; i < this.messages.length; i++) {
208
+ if (this.messages[i].startsWith(OINO_ERROR_PREFIX)) {
209
+ return true;
210
+ }
211
+ }
212
+ return false;
213
+ }
214
+ /**
215
+ * Checks if the messages contain errors.
216
+ *
217
+ */
218
+ getFirstError(): string {
219
+ for (let i = 0; i < this.messages.length; i++) {
220
+ if (this.messages[i].startsWith(OINO_ERROR_PREFIX)) {
221
+ return this.messages[i];
222
+ }
223
+ }
224
+ return "";
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Generic in memory implementation of a data set where data is an array of rows. Used
230
+ * by BunSqlite and automated testing. Can be rewinded.
231
+ *
232
+ */
233
+
234
+ export class OINODbMemoryDataSet extends OINODbDataSet {
235
+ private _rows: OINODataRow[];
236
+ private _currentRow: number;
237
+ private _eof: boolean;
238
+
239
+ /**
240
+ * Constructor of `OINODbMemoryDataSet`.
241
+ *
242
+ * @param data data as OINODataRow[] (constructor will throw if invalid)
243
+ * @param errors error messages from SQL-query
244
+ *
245
+ */
246
+ constructor(data: unknown, errors: string[] = []) {
247
+ super(data, errors);
248
+ if ((data == null) || !(Array.isArray(data))) {
249
+ throw new Error(OINO_ERROR_PREFIX + ": Data needs to be compatible with OINORow[]!"); // TODO: maybe check all rows
250
+ }
251
+ this._rows = data as OINODataRow[];
252
+ if (this.isEmpty()) {
253
+ this._currentRow = -1;
254
+ this._eof = true;
255
+ } else {
256
+ this._currentRow = 0;
257
+ this._eof = false;
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Is data set empty.
263
+ *
264
+ */
265
+ isEmpty(): boolean {
266
+ return (this._rows.length == 0);
267
+ }
268
+
269
+ /**
270
+ * Is there no more content, i.e. either dataset is empty or we have moved beyond last line
271
+ *
272
+ */
273
+ isEof(): boolean {
274
+ return (this._eof);
275
+ }
276
+
277
+ /**
278
+ * Attempts to moves dataset to the next row, possibly waiting for more data to become available. Returns !isEof().
279
+ *
280
+ */
281
+ async next(): Promise<boolean> {
282
+ if (this._currentRow < this._rows.length - 1) {
283
+ this._currentRow = this._currentRow + 1;
284
+ } else {
285
+ this._eof = true;
286
+ }
287
+ return Promise.resolve(!this._eof);
288
+ }
289
+
290
+ /**
291
+ * Gets current row of data.
292
+ *
293
+ */
294
+ getRow(): OINODataRow {
295
+ if ((this._currentRow >= 0) && (this._currentRow < this._rows.length)) {
296
+ return this._rows[this._currentRow];
297
+ } else {
298
+ return OINODB_EMPTY_ROW;
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Gets all rows of data.
304
+ *
305
+ */
306
+ async getAllRows(): Promise<OINODataRow[]> {
307
+ return this._rows // at the moment theres no result streaming, so we can just return the rows
308
+ }
309
+
310
+ /**
311
+ * Rewinds data set to the first row, returns !isEof().
312
+ *
313
+ */
314
+ first(): boolean {
315
+ this._currentRow = 0;
316
+ this._eof = this._rows.length == 0;
317
+ return !this._eof;
318
+ }
319
+ }
320
+
321
+