@oino-ts/db 0.3.4 → 0.4.0
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/OINODbApi.js +43 -2
- package/dist/cjs/OINODbConfig.js +2 -0
- package/dist/cjs/OINODbDataField.js +23 -0
- package/dist/cjs/OINODbDataModel.js +12 -5
- package/dist/cjs/OINODbFactory.js +5 -2
- package/dist/cjs/OINODbModelSet.js +17 -1
- package/dist/cjs/OINODbSqlParams.js +73 -9
- package/dist/cjs/index.js +4 -1
- package/dist/esm/OINODbApi.js +44 -3
- package/dist/esm/OINODbConfig.js +2 -0
- package/dist/esm/OINODbDataField.js +23 -0
- package/dist/esm/OINODbDataModel.js +13 -6
- package/dist/esm/OINODbFactory.js +5 -2
- package/dist/esm/OINODbModelSet.js +17 -1
- package/dist/esm/OINODbSqlParams.js +72 -9
- package/dist/esm/index.js +3 -1
- package/dist/types/OINODb.d.ts +7 -0
- package/dist/types/OINODbApi.d.ts +13 -0
- package/dist/types/OINODbConfig.d.ts +2 -0
- package/dist/types/OINODbDataField.d.ts +8 -0
- package/dist/types/OINODbModelSet.d.ts +5 -2
- package/dist/types/OINODbSqlParams.d.ts +42 -2
- package/dist/types/index.d.ts +6 -2
- package/package.json +3 -3
- package/src/OINODb.ts +8 -0
- package/src/OINODbApi.test.ts +17 -1
- package/src/OINODbApi.ts +42 -3
- package/src/OINODbConfig.ts +3 -0
- package/src/OINODbDataField.ts +24 -0
- package/src/OINODbDataModel.ts +12 -6
- package/src/OINODbFactory.ts +5 -2
- package/src/OINODbModelSet.ts +19 -2
- package/src/OINODbSqlParams.ts +76 -9
- package/src/index.ts +6 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
|
-
import { OINOStr, OINO_ERROR_PREFIX, OINOLog } from "./index.js";
|
|
6
|
+
import { OINOStr, OINO_ERROR_PREFIX, OINOLog, OINODB_UNDEFINED } from "./index.js";
|
|
7
7
|
const OINO_FIELD_NAME_CHARS = "\\w\\s\\-\\_\\#\\¤";
|
|
8
8
|
/**
|
|
9
9
|
* Supported logical conjunctions in filter predicates.
|
|
@@ -404,28 +404,91 @@ export class OINODbSqlAggregate {
|
|
|
404
404
|
result += dataModel.fields[i].printSqlColumnName() + ",";
|
|
405
405
|
}
|
|
406
406
|
}
|
|
407
|
-
OINOLog.debug("OINODbSqlAggregate.toSql", {
|
|
407
|
+
// OINOLog.debug("OINODbSqlAggregate.toSql", {result:result})
|
|
408
408
|
return result.substring(0, result.length - 1);
|
|
409
409
|
}
|
|
410
410
|
/**
|
|
411
411
|
* Print non-aggregated fields as SQL GROUP BY-condition based on the datamodel of the API.
|
|
412
412
|
*
|
|
413
413
|
* @param dataModel data model (and database) to use for formatting of values
|
|
414
|
+
* @param select what fields to select
|
|
414
415
|
*
|
|
415
416
|
*/
|
|
416
|
-
printSqlColumnNames(dataModel) {
|
|
417
|
+
printSqlColumnNames(dataModel, select) {
|
|
417
418
|
let result = "";
|
|
418
419
|
for (let i = 0; i < dataModel.fields.length; i++) {
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
result += this._functions[aggregate_index] + "(" + col_name + ") as " + col_name + ",";
|
|
420
|
+
const f = dataModel.fields[i];
|
|
421
|
+
if (select?.isSelected(f) == false) { // if a field is not selected, we include a constant and correct fieldname instead so that dimensions of the data don't change but no unnecessary data is fetched
|
|
422
|
+
result += f.db.printSqlString(OINODB_UNDEFINED) + " as " + f.printSqlColumnName() + ",";
|
|
423
423
|
}
|
|
424
424
|
else {
|
|
425
|
-
|
|
425
|
+
const aggregate_index = this._fields.indexOf(f.name);
|
|
426
|
+
const col_name = f.printSqlColumnName();
|
|
427
|
+
if (aggregate_index >= 0) {
|
|
428
|
+
result += this._functions[aggregate_index] + "(" + col_name + ") as " + col_name + ",";
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
result += col_name + ",";
|
|
432
|
+
}
|
|
426
433
|
}
|
|
427
434
|
}
|
|
428
|
-
OINOLog.debug("OINODbSqlAggregate.printSqlColumnNames", {
|
|
435
|
+
// OINOLog.debug("OINODbSqlAggregate.printSqlColumnNames", {result:result})
|
|
429
436
|
return result.substring(0, result.length - 1);
|
|
430
437
|
}
|
|
438
|
+
/**
|
|
439
|
+
* Does filter contain any valid conditions.
|
|
440
|
+
*
|
|
441
|
+
* @param field field to check if it is aggregated
|
|
442
|
+
*/
|
|
443
|
+
isAggregated(field) {
|
|
444
|
+
return (this._fields.includes(field.name));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Class for ordering select results on a number of columns.
|
|
449
|
+
*
|
|
450
|
+
*/
|
|
451
|
+
export class OINODbSqlSelect {
|
|
452
|
+
_columns;
|
|
453
|
+
/**
|
|
454
|
+
* Constructor for `OINODbSqlSelect`.
|
|
455
|
+
*
|
|
456
|
+
* @param columns array of columns to select
|
|
457
|
+
*
|
|
458
|
+
*/
|
|
459
|
+
constructor(columns) {
|
|
460
|
+
// OINOLog.debug("OINODbSqlSelect.constructor", {columns:columns})
|
|
461
|
+
this._columns = columns;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Constructor for `OINODbSqlSelect` as parser of http parameter.
|
|
465
|
+
*
|
|
466
|
+
* @param columns comma separatef string selected columns from HTTP-request
|
|
467
|
+
*
|
|
468
|
+
*/
|
|
469
|
+
static parse(columns) {
|
|
470
|
+
if (columns == "") {
|
|
471
|
+
return new OINODbSqlSelect([]);
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
return new OINODbSqlSelect(columns.split(','));
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Does select contain any valid columns.
|
|
479
|
+
*
|
|
480
|
+
*/
|
|
481
|
+
isEmpty() {
|
|
482
|
+
return (this._columns.length == 0);
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Does select include given column.
|
|
486
|
+
*
|
|
487
|
+
* @param field field to check if it is selected
|
|
488
|
+
*
|
|
489
|
+
*/
|
|
490
|
+
isSelected(field) {
|
|
491
|
+
// OINOLog.debug("OINODbSqlSelect.isSelected", {column:column, columns:this._columns})
|
|
492
|
+
return ((this._columns.length == 0) || (field.fieldParams.isPrimaryKey == true) || (this._columns.includes(field.name)));
|
|
493
|
+
}
|
|
431
494
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export { OINODbDataModel } from "./OINODbDataModel.js";
|
|
|
6
6
|
export { OINODbModelSet } from "./OINODbModelSet.js";
|
|
7
7
|
export { OINODbDataField, OINOBooleanDataField, OINONumberDataField, OINOStringDataField, OINOBlobDataField, OINODatetimeDataField } from "./OINODbDataField.js";
|
|
8
8
|
export { OINODbDataSet, OINODbMemoryDataSet, OINODb } from "./OINODb.js";
|
|
9
|
-
export { OINODbSqlFilter, OINODbSqlOrder, OINODbSqlComparison, OINODbSqlLimit, OINODbSqlBooleanOperation, OINODbSqlAggregate, OINODbSqlAggregateFunctions } from "./OINODbSqlParams.js";
|
|
9
|
+
export { OINODbSqlFilter, OINODbSqlOrder, OINODbSqlComparison, OINODbSqlLimit, OINODbSqlBooleanOperation, OINODbSqlAggregate, OINODbSqlAggregateFunctions, OINODbSqlSelect } from "./OINODbSqlParams.js";
|
|
10
10
|
export { OINODbConfig } from "./OINODbConfig.js";
|
|
11
11
|
export { OINODbFactory } from "./OINODbFactory.js";
|
|
12
12
|
export { OINODbSwagger } from "./OINODbSwagger.js";
|
|
@@ -15,3 +15,5 @@ export { OINODbParser } from "./OINODbParser.js";
|
|
|
15
15
|
export const OINODB_EMPTY_ROW = [];
|
|
16
16
|
/** Empty row array instance */
|
|
17
17
|
export const OINODB_EMPTY_ROWS = [OINODB_EMPTY_ROW];
|
|
18
|
+
/** Constant for undefined values */
|
|
19
|
+
export const OINODB_UNDEFINED = ""; // original idea was to have a defined literal that get's swapped back to undefined, but current implementation just leaves it out at serialization (so value does not matter)
|
package/dist/types/OINODb.d.ts
CHANGED
|
@@ -41,6 +41,13 @@ export declare abstract class OINODb {
|
|
|
41
41
|
*
|
|
42
42
|
*/
|
|
43
43
|
abstract printCellAsSqlValue(cellValue: OINODataCell, sqlType: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Print a single string value as valid sql literal
|
|
46
|
+
*
|
|
47
|
+
* @param sqlString string value
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
abstract printSqlString(sqlString: string): string;
|
|
44
51
|
/**
|
|
45
52
|
* Parse a single SQL result value for serialization using the context of the native data
|
|
46
53
|
* type.
|
|
@@ -32,6 +32,19 @@ export declare class OINODbApiResult extends OINOResult {
|
|
|
32
32
|
*
|
|
33
33
|
*/
|
|
34
34
|
export declare class OINODbHtmlTemplate extends OINOHtmlTemplate {
|
|
35
|
+
/** Datetime format string */
|
|
36
|
+
localeStr: string;
|
|
37
|
+
/** Locale formatter */
|
|
38
|
+
protected _locale: Intl.DateTimeFormat | null;
|
|
39
|
+
/**
|
|
40
|
+
* Constructor of OINODbHtmlTemplate.
|
|
41
|
+
*
|
|
42
|
+
* @param template HTML template string
|
|
43
|
+
* @param localeStr Datetime format string, either "iso" for ISO8601 or "default" for system default or valid locale string
|
|
44
|
+
* @param localeStyle Datetime format style, either "short/medium/long/full" or Intl.DateTimeFormat options
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
constructor(template: string, localeStr?: string, localeStyle?: string | any);
|
|
35
48
|
/**
|
|
36
49
|
* Creates HTML Response from API modelset.
|
|
37
50
|
*
|
|
@@ -13,6 +13,8 @@ export declare class OINODbConfig {
|
|
|
13
13
|
static OINODB_SQL_LIMIT_PARAM: string;
|
|
14
14
|
/** Name of the OINODbSqlAggregate-parameter in request */
|
|
15
15
|
static OINODB_SQL_AGGREGATE_PARAM: string;
|
|
16
|
+
/** Name of the OINODbSqlSelect-parameter in request */
|
|
17
|
+
static OINODB_SQL_SELECT_PARAM: string;
|
|
16
18
|
/**
|
|
17
19
|
* Set the name of the OINO ID field
|
|
18
20
|
* @param idField name of the OINO ID field
|
|
@@ -192,6 +192,14 @@ export declare class OINODatetimeDataField extends OINODbDataField {
|
|
|
192
192
|
*
|
|
193
193
|
*/
|
|
194
194
|
serializeCell(cellVal: OINODataCell): string | null | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* Serialize cell value in the given content format.
|
|
197
|
+
*
|
|
198
|
+
* @param cellVal cell value
|
|
199
|
+
* @param locale locale-object to format datetimes with
|
|
200
|
+
*
|
|
201
|
+
*/
|
|
202
|
+
serializeCellWithLocale(cellVal: OINODataCell, locale: Intl.DateTimeFormat): string | null | undefined;
|
|
195
203
|
/**
|
|
196
204
|
* Parce cell value from string using field type specific formatting rules.
|
|
197
205
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OINODbDataSet, OINODbDataModel, OINOContentType, OINODataCell } from "./index.js";
|
|
1
|
+
import { OINODbDataSet, OINODbDataModel, OINOContentType, OINODataCell, OINODbSqlParams } from "./index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Class for dataset based on a data model that can be serialized to
|
|
4
4
|
* a supported format:
|
|
@@ -11,6 +11,8 @@ export declare class OINODbModelSet {
|
|
|
11
11
|
readonly datamodel: OINODbDataModel;
|
|
12
12
|
/** Reference to data set */
|
|
13
13
|
readonly dataset: OINODbDataSet;
|
|
14
|
+
/** SQL parameters */
|
|
15
|
+
readonly sqlParams?: OINODbSqlParams;
|
|
14
16
|
/** Collection of errors */
|
|
15
17
|
errors: string[];
|
|
16
18
|
/**
|
|
@@ -18,8 +20,9 @@ export declare class OINODbModelSet {
|
|
|
18
20
|
*
|
|
19
21
|
* @param datamodel data model
|
|
20
22
|
* @param dataset data set
|
|
23
|
+
* @param sqlParams SQL parameters
|
|
21
24
|
*/
|
|
22
|
-
constructor(datamodel: OINODbDataModel, dataset: OINODbDataSet);
|
|
25
|
+
constructor(datamodel: OINODbDataModel, dataset: OINODbDataSet, sqlParams?: OINODbSqlParams);
|
|
23
26
|
private _encodeAndHashFieldValue;
|
|
24
27
|
private _writeRowJson;
|
|
25
28
|
private _writeStringJson;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OINODbDataModel } from "./index.js";
|
|
1
|
+
import { OINODbDataField, OINODbDataModel } from "./index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Supported logical conjunctions in filter predicates.
|
|
4
4
|
* @enum
|
|
@@ -195,7 +195,47 @@ export declare class OINODbSqlAggregate {
|
|
|
195
195
|
* Print non-aggregated fields as SQL GROUP BY-condition based on the datamodel of the API.
|
|
196
196
|
*
|
|
197
197
|
* @param dataModel data model (and database) to use for formatting of values
|
|
198
|
+
* @param select what fields to select
|
|
198
199
|
*
|
|
199
200
|
*/
|
|
200
|
-
printSqlColumnNames(dataModel: OINODbDataModel): string;
|
|
201
|
+
printSqlColumnNames(dataModel: OINODbDataModel, select?: OINODbSqlSelect): string;
|
|
202
|
+
/**
|
|
203
|
+
* Does filter contain any valid conditions.
|
|
204
|
+
*
|
|
205
|
+
* @param field field to check if it is aggregated
|
|
206
|
+
*/
|
|
207
|
+
isAggregated(field: OINODbDataField): boolean;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Class for ordering select results on a number of columns.
|
|
211
|
+
*
|
|
212
|
+
*/
|
|
213
|
+
export declare class OINODbSqlSelect {
|
|
214
|
+
private _columns;
|
|
215
|
+
/**
|
|
216
|
+
* Constructor for `OINODbSqlSelect`.
|
|
217
|
+
*
|
|
218
|
+
* @param columns array of columns to select
|
|
219
|
+
*
|
|
220
|
+
*/
|
|
221
|
+
constructor(columns: string[]);
|
|
222
|
+
/**
|
|
223
|
+
* Constructor for `OINODbSqlSelect` as parser of http parameter.
|
|
224
|
+
*
|
|
225
|
+
* @param columns comma separatef string selected columns from HTTP-request
|
|
226
|
+
*
|
|
227
|
+
*/
|
|
228
|
+
static parse(columns: string): OINODbSqlSelect;
|
|
229
|
+
/**
|
|
230
|
+
* Does select contain any valid columns.
|
|
231
|
+
*
|
|
232
|
+
*/
|
|
233
|
+
isEmpty(): boolean;
|
|
234
|
+
/**
|
|
235
|
+
* Does select include given column.
|
|
236
|
+
*
|
|
237
|
+
* @param field field to check if it is selected
|
|
238
|
+
*
|
|
239
|
+
*/
|
|
240
|
+
isSelected(field: OINODbDataField): boolean;
|
|
201
241
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3,13 +3,13 @@ export { OINOContentType };
|
|
|
3
3
|
export { OINO_ERROR_PREFIX, OINO_WARNING_PREFIX, OINO_INFO_PREFIX, OINO_DEBUG_PREFIX, OINOStr, OINOBenchmark, OINOLog, OINOLogLevel, OINOConsoleLog, OINOResult, OINOHttpResult, OINOHtmlTemplate } from "@oino-ts/common";
|
|
4
4
|
import { OINODb } from "./OINODb.js";
|
|
5
5
|
import { OINODbDataField } from "./OINODbDataField.js";
|
|
6
|
-
import { OINODbSqlAggregate, OINODbSqlFilter, OINODbSqlLimit, OINODbSqlOrder } from "./OINODbSqlParams.js";
|
|
6
|
+
import { OINODbSqlAggregate, OINODbSqlFilter, OINODbSqlLimit, OINODbSqlOrder, OINODbSqlSelect } from "./OINODbSqlParams.js";
|
|
7
7
|
export { OINODbApiResult, OINODbHtmlTemplate, OINODbApi } from "./OINODbApi.js";
|
|
8
8
|
export { OINODbDataModel } from "./OINODbDataModel.js";
|
|
9
9
|
export { OINODbModelSet } from "./OINODbModelSet.js";
|
|
10
10
|
export { OINODbDataField, OINOBooleanDataField, OINONumberDataField, OINOStringDataField, OINOBlobDataField, OINODatetimeDataField } from "./OINODbDataField.js";
|
|
11
11
|
export { OINODbDataSet, OINODbMemoryDataSet, OINODb } from "./OINODb.js";
|
|
12
|
-
export { OINODbSqlFilter, OINODbSqlOrder, OINODbSqlComparison, OINODbSqlLimit, OINODbSqlBooleanOperation, OINODbSqlAggregate, OINODbSqlAggregateFunctions } from "./OINODbSqlParams.js";
|
|
12
|
+
export { OINODbSqlFilter, OINODbSqlOrder, OINODbSqlComparison, OINODbSqlLimit, OINODbSqlBooleanOperation, OINODbSqlAggregate, OINODbSqlAggregateFunctions, OINODbSqlSelect } from "./OINODbSqlParams.js";
|
|
13
13
|
export { OINODbConfig } from "./OINODbConfig.js";
|
|
14
14
|
export { OINODbFactory } from "./OINODbFactory.js";
|
|
15
15
|
export { OINODbSwagger } from "./OINODbSwagger.js";
|
|
@@ -89,6 +89,8 @@ export type OINODbSqlParams = {
|
|
|
89
89
|
limit?: OINODbSqlLimit;
|
|
90
90
|
/** SQL aggregation functions */
|
|
91
91
|
aggregate?: OINODbSqlAggregate;
|
|
92
|
+
/** SQL select condition */
|
|
93
|
+
select?: OINODbSqlSelect;
|
|
92
94
|
};
|
|
93
95
|
/** Request options */
|
|
94
96
|
export type OINODbApiRequestParams = {
|
|
@@ -113,5 +115,7 @@ export type OINODataRow = Array<OINODataCell>;
|
|
|
113
115
|
export declare const OINODB_EMPTY_ROW: OINODataRow;
|
|
114
116
|
/** Empty row array instance */
|
|
115
117
|
export declare const OINODB_EMPTY_ROWS: OINODataRow[];
|
|
118
|
+
/** Constant for undefined values */
|
|
119
|
+
export declare const OINODB_UNDEFINED = "";
|
|
116
120
|
/** Key-value collection */
|
|
117
121
|
export type OINOValues = Record<string, string>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oino-ts/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "OINO TS library package for publishing an SQL database tables as a REST API.",
|
|
5
5
|
"author": "Matias Kiviniemi (pragmatta)",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
"module": "./dist/esm/index.js",
|
|
20
20
|
"types": "./dist/types/index.d.ts",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@oino-ts/common": "0.
|
|
22
|
+
"@oino-ts/common": "0.4.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^20.14.10",
|
|
26
26
|
"@types/bun": "^1.1.14",
|
|
27
|
-
"@oino-ts/types": "0.
|
|
27
|
+
"@oino-ts/types": "0.4.0",
|
|
28
28
|
"typedoc": "^0.25.13"
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
package/src/OINODb.ts
CHANGED
|
@@ -59,6 +59,14 @@ export abstract class OINODb {
|
|
|
59
59
|
*/
|
|
60
60
|
abstract printCellAsSqlValue(cellValue:OINODataCell, sqlType: string): string
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Print a single string value as valid sql literal
|
|
64
|
+
*
|
|
65
|
+
* @param sqlString string value
|
|
66
|
+
*
|
|
67
|
+
*/
|
|
68
|
+
abstract printSqlString(sqlString:string): string
|
|
69
|
+
|
|
62
70
|
/**
|
|
63
71
|
* Parse a single SQL result value for serialization using the context of the native data
|
|
64
72
|
* type.
|
package/src/OINODbApi.test.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { expect, test } from "bun:test";
|
|
8
8
|
|
|
9
|
-
import { OINODbApi, OINODbApiParams, OINOContentType, OINODataRow, OINODbDataField, OINOStringDataField, OINODb, OINODbFactory, OINODbParams, OINODbMemoryDataSet, OINODbModelSet, OINOBenchmark, OINOConsoleLog, OINODbSqlFilter, OINODbConfig, OINODbSqlOrder, OINOLogLevel, OINOLog, OINODbSqlLimit, OINODbApiResult, OINODbSqlComparison, OINONumberDataField, OINODatetimeDataField, OINODbApiRequestParams } from "./index.js";
|
|
9
|
+
import { OINODbApi, OINODbApiParams, OINOContentType, OINODataRow, OINODbDataField, OINOStringDataField, OINODb, OINODbFactory, OINODbParams, OINODbMemoryDataSet, OINODbModelSet, OINOBenchmark, OINOConsoleLog, OINODbSqlFilter, OINODbConfig, OINODbSqlOrder, OINOLogLevel, OINOLog, OINODbSqlLimit, OINODbApiResult, OINODbSqlComparison, OINONumberDataField, OINODatetimeDataField, OINODbApiRequestParams, OINODbHtmlTemplate } from "./index.js";
|
|
10
10
|
|
|
11
11
|
import { OINODbBunSqlite } from "@oino-ts/db-bunsqlite"
|
|
12
12
|
import { OINODbPostgresql } from "@oino-ts/db-postgresql"
|
|
@@ -130,6 +130,14 @@ function encodeResult(o:any|undefined):string {
|
|
|
130
130
|
})
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
function createApiTemplate(api:OINODbApi):OINODbHtmlTemplate {
|
|
134
|
+
let template_str = ""
|
|
135
|
+
for (let i=0; i<api.datamodel.fields.length; i++) {
|
|
136
|
+
template_str += "<input type='text' name='" + api.datamodel.fields[i].name + "' value='###" + api.datamodel.fields[i].name + "###'></input>"
|
|
137
|
+
}
|
|
138
|
+
return new OINODbHtmlTemplate(template_str, "fi", "medium")
|
|
139
|
+
}
|
|
140
|
+
|
|
133
141
|
export async function OINOTestApi(dbParams:OINODbParams, testParams: OINOTestParams) {
|
|
134
142
|
// OINOLog.info("OINOTestApi", {dbParams:dbParams, apiDataset:apiDataset})
|
|
135
143
|
const db:OINODb = await OINODbFactory.createDb( dbParams )
|
|
@@ -177,6 +185,13 @@ export async function OINOTestApi(dbParams:OINODbParams, testParams: OINOTestPar
|
|
|
177
185
|
expect(encodeData(await (await api.doRequest("GET", "", "", empty_params)).data?.writeString(OINOContentType.csv))).toMatchSnapshot("GET CSV")
|
|
178
186
|
})
|
|
179
187
|
|
|
188
|
+
test(target_name + target_db + target_table + target_group + " select * with template", async () => {
|
|
189
|
+
const template = createApiTemplate(api)
|
|
190
|
+
const api_result:OINODbApiResult = await api.doRequest("GET", "", "", empty_params)
|
|
191
|
+
const html = (await template.renderFromDbData(api_result.data!)).body
|
|
192
|
+
expect(encodeData(html)).toMatchSnapshot("GET HTML")
|
|
193
|
+
})
|
|
194
|
+
|
|
180
195
|
test(target_name + target_db + target_table + target_group + " select * with filter", async () => {
|
|
181
196
|
expect(encodeData(await (await api.doRequest("GET", "", "", request_params_with_filters)).data?.writeString())).toMatchSnapshot("GET JSON FILTER")
|
|
182
197
|
})
|
|
@@ -376,6 +391,7 @@ const snapshots = require("./__snapshots__/OINODbApi.test.ts.snap.js")
|
|
|
376
391
|
|
|
377
392
|
const api_crosschecks:string[] = [
|
|
378
393
|
"[HTTP GET] select *: GET JSON 1",
|
|
394
|
+
"[HTTP GET] select * with template: GET HTML 1",
|
|
379
395
|
"[HTTP POST] insert: GET JSON 1",
|
|
380
396
|
"[HTTP POST] insert: GET CSV 1",
|
|
381
397
|
"[HTTP PUT] update JSON: GET JSON 1",
|
package/src/OINODbApi.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { OINODbApiParams, OINODb, OINODbDataSet, OINODbDataModel, OINODbDataField, OINOStringDataField, OINO_ERROR_PREFIX, OINODataRow, OINODataCell, OINODbModelSet, OINOBenchmark, OINODbApiRequestParams, OINODbConfig, OINOHttpResult, OINOHtmlTemplate, OINONumberDataField, OINODbParser } from "./index.js"
|
|
7
|
+
import { OINODbApiParams, OINODb, OINODbDataSet, OINODbDataModel, OINODbDataField, OINOStringDataField, OINO_ERROR_PREFIX, OINODataRow, OINODataCell, OINODbModelSet, OINOBenchmark, OINODbApiRequestParams, OINODbConfig, OINOHttpResult, OINOHtmlTemplate, OINONumberDataField, OINODbParser, OINODatetimeDataField } from "./index.js"
|
|
8
8
|
import { OINOLog, OINOResult } from "@oino-ts/common";
|
|
9
9
|
import { OINOHashid } from "@oino-ts/hashid"
|
|
10
10
|
|
|
@@ -61,6 +61,40 @@ export class OINODbApiResult extends OINOResult {
|
|
|
61
61
|
*
|
|
62
62
|
*/
|
|
63
63
|
export class OINODbHtmlTemplate extends OINOHtmlTemplate {
|
|
64
|
+
/** Datetime format string */
|
|
65
|
+
localeStr:string
|
|
66
|
+
/** Locale formatter */
|
|
67
|
+
protected _locale:Intl.DateTimeFormat|null
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Constructor of OINODbHtmlTemplate.
|
|
71
|
+
*
|
|
72
|
+
* @param template HTML template string
|
|
73
|
+
* @param localeStr Datetime format string, either "iso" for ISO8601 or "default" for system default or valid locale string
|
|
74
|
+
* @param localeStyle Datetime format style, either "short/medium/long/full" or Intl.DateTimeFormat options
|
|
75
|
+
*
|
|
76
|
+
*/
|
|
77
|
+
constructor (template:string, localeStr:string = "iso", localeStyle:string|any = "medium") {
|
|
78
|
+
super(template)
|
|
79
|
+
const supported_locales = Intl.DateTimeFormat.supportedLocalesOf([localeStr])
|
|
80
|
+
let locale_opts:any
|
|
81
|
+
if (typeof localeStyle == "string") {
|
|
82
|
+
locale_opts = { dateStyle: localeStyle, timeStyle: localeStyle }
|
|
83
|
+
} else {
|
|
84
|
+
locale_opts = localeStyle
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if ((localeStr == "iso") || (localeStr == "") || (supported_locales.length == 0)) {
|
|
88
|
+
this._locale = null
|
|
89
|
+
this.localeStr = "iso"
|
|
90
|
+
} else if (localeStr == "default") {
|
|
91
|
+
this._locale = new Intl.DateTimeFormat(undefined, locale_opts)
|
|
92
|
+
this.localeStr = "default"
|
|
93
|
+
} else {
|
|
94
|
+
this.localeStr = supported_locales[0]
|
|
95
|
+
this._locale = new Intl.DateTimeFormat(supported_locales[0], locale_opts)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
64
98
|
|
|
65
99
|
/**
|
|
66
100
|
* Creates HTML Response from API modelset.
|
|
@@ -92,7 +126,12 @@ export class OINODbHtmlTemplate extends OINOHtmlTemplate {
|
|
|
92
126
|
// let html_row:string = this.template.replaceAll('###' + OINODbConfig.OINODB_ID_FIELD + '###', '###createHtmlFromData_temporary_oinoid###')
|
|
93
127
|
for (let i=0; i<datamodel.fields.length; i++) {
|
|
94
128
|
const f:OINODbDataField = datamodel.fields[i]
|
|
95
|
-
let value:string|null|undefined
|
|
129
|
+
let value:string|null|undefined
|
|
130
|
+
if ((this._locale != null) && (f instanceof OINODatetimeDataField)) {
|
|
131
|
+
value = f.serializeCellWithLocale(row[i], this._locale)
|
|
132
|
+
} else {
|
|
133
|
+
value = f.serializeCell(row[i])
|
|
134
|
+
}
|
|
96
135
|
if (f.fieldParams.isPrimaryKey || f.fieldParams.isForeignKey) {
|
|
97
136
|
if (value && (f instanceof OINONumberDataField) && (datamodel.api.hashid)) {
|
|
98
137
|
value = datamodel.api.hashid.encode(value, f.name + " " + row_id_seed)
|
|
@@ -205,7 +244,7 @@ export class OINODbApi {
|
|
|
205
244
|
result.setError(500, sql_res.getFirstError(), "DoGet")
|
|
206
245
|
result.addDebug("OINO GET SQL [" + sql + "]", "DoPut")
|
|
207
246
|
} else {
|
|
208
|
-
result.data = new OINODbModelSet(this.datamodel, sql_res)
|
|
247
|
+
result.data = new OINODbModelSet(this.datamodel, sql_res, params.sqlParams)
|
|
209
248
|
}
|
|
210
249
|
} catch (e:any) {
|
|
211
250
|
result.setError(500, "Unhandled exception in doGet: " + e.message, "DoGet")
|
package/src/OINODbConfig.ts
CHANGED
|
@@ -19,6 +19,9 @@ export class OINODbConfig {
|
|
|
19
19
|
/** Name of the OINODbSqlAggregate-parameter in request */
|
|
20
20
|
static OINODB_SQL_AGGREGATE_PARAM:string = "oinosqlaggregate"
|
|
21
21
|
|
|
22
|
+
/** Name of the OINODbSqlSelect-parameter in request */
|
|
23
|
+
static OINODB_SQL_SELECT_PARAM:string = "oinosqlselect"
|
|
24
|
+
|
|
22
25
|
/**
|
|
23
26
|
* Set the name of the OINO ID field
|
|
24
27
|
* @param idField name of the OINO ID field
|
package/src/OINODbDataField.ts
CHANGED
|
@@ -364,6 +364,30 @@ export class OINODatetimeDataField extends OINODbDataField {
|
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
/**
|
|
368
|
+
* Serialize cell value in the given content format.
|
|
369
|
+
*
|
|
370
|
+
* @param cellVal cell value
|
|
371
|
+
* @param locale locale-object to format datetimes with
|
|
372
|
+
*
|
|
373
|
+
*/
|
|
374
|
+
serializeCellWithLocale(cellVal: OINODataCell, locale:Intl.DateTimeFormat): string|null|undefined {
|
|
375
|
+
// OINOLog.debug("OINODatetimeDataField.serializeCell", {cellVal:cellVal, type:typeof(cellVal)})
|
|
376
|
+
if (typeof(cellVal) == "string") {
|
|
377
|
+
cellVal = this.db.parseSqlValueAsCell(cellVal, this.sqlType)
|
|
378
|
+
// OINOLog.debug("OINODatetimeDataField.serializeCell parsed", {cellVal:cellVal, type:typeof(cellVal)})
|
|
379
|
+
}
|
|
380
|
+
if ((cellVal === null) || (cellVal === undefined)) {
|
|
381
|
+
return cellVal
|
|
382
|
+
|
|
383
|
+
} else if (cellVal instanceof Date) {
|
|
384
|
+
return locale.format(cellVal)
|
|
385
|
+
|
|
386
|
+
} else {
|
|
387
|
+
return cellVal.toString()
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
367
391
|
/**
|
|
368
392
|
* Parce cell value from string using field type specific formatting rules.
|
|
369
393
|
*
|
package/src/OINODbDataModel.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { OINODbDataField, OINODbApi, OINODataRow, OINO_ERROR_PREFIX, OINODbDataFieldFilter, OINODbConfig, OINODbSqlParams, OINONumberDataField, OINOLog } from "./index.js";
|
|
7
|
+
import { OINODbDataField, OINODbApi, OINODataRow, OINO_ERROR_PREFIX, OINODbDataFieldFilter, OINODbConfig, OINODbSqlParams, OINONumberDataField, OINOLog, OINODbSqlSelect, OINODB_UNDEFINED } from "./index.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* OINO Datamodel object for representing one database table and it's columns.
|
|
@@ -41,10 +41,15 @@ export class OINODbDataModel {
|
|
|
41
41
|
await this.api.db.initializeApiDatamodel(this.api)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
private _printSqlColumnNames(): string {
|
|
44
|
+
private _printSqlColumnNames(select?:OINODbSqlSelect): string {
|
|
45
45
|
let result: string = "";
|
|
46
46
|
for (let i=0; i < this.fields.length; i++) {
|
|
47
|
-
|
|
47
|
+
const f:OINODbDataField = this.fields[i]
|
|
48
|
+
if (select?.isSelected(f) === false) { // if a field is not selected, we include a constant and correct fieldname instead so that dimensions of the data don't change but no unnecessary data is fetched
|
|
49
|
+
result += f.db.printSqlString(OINODB_UNDEFINED) + " as " + f.printSqlColumnName()+","
|
|
50
|
+
} else {
|
|
51
|
+
result += f.printSqlColumnName()+","
|
|
52
|
+
}
|
|
48
53
|
}
|
|
49
54
|
return result.substring(0, result.length-1)
|
|
50
55
|
}
|
|
@@ -230,17 +235,18 @@ export class OINODbDataModel {
|
|
|
230
235
|
printSqlSelect(id: string, params:OINODbSqlParams): string {
|
|
231
236
|
let column_names = ""
|
|
232
237
|
if (params.aggregate) {
|
|
233
|
-
column_names = params.aggregate.printSqlColumnNames(this)
|
|
238
|
+
column_names = params.aggregate.printSqlColumnNames(this, params.select)
|
|
234
239
|
} else {
|
|
235
|
-
column_names = this._printSqlColumnNames()
|
|
240
|
+
column_names = this._printSqlColumnNames(params.select)
|
|
236
241
|
}
|
|
242
|
+
// OINOLog.debug("OINODbDataModel.printSqlSelect", {column_names:column_names})
|
|
237
243
|
const order_sql = params.order?.toSql(this) || ""
|
|
238
244
|
const limit_sql = params.limit?.toSql(this) || ""
|
|
239
245
|
const filter_sql = params.filter?.toSql(this) || ""
|
|
240
246
|
const aggregate_sql = params.aggregate?.toSql(this) || ""
|
|
241
247
|
|
|
242
248
|
let where_sql = ""
|
|
243
|
-
// OINOLog.debug("OINODbDataModel.printSqlSelect", {
|
|
249
|
+
// OINOLog.debug("OINODbDataModel.printSqlSelect", {order_sql:order_sql, limit_sql:limit_sql, filter_sql:filter_sql, aggregate_sql:aggregate_sql})
|
|
244
250
|
if ((id != null) && (id != "") && (filter_sql != "")) {
|
|
245
251
|
where_sql = this._printSqlPrimaryKeyCondition(id) + " AND " + filter_sql
|
|
246
252
|
} else if ((id != null) && (id != "")) {
|
package/src/OINODbFactory.ts
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { OINODbApi, OINODbApiParams, OINODbParams, OINOContentType, OINODb, OINODbConstructor, OINODbApiRequestParams, OINODbSqlFilter, OINODbConfig, OINODbSqlOrder, OINODbSqlLimit, OINODbSqlParams } from "./index.js"
|
|
8
|
-
import { OINODbSqlAggregate } from "./OINODbSqlParams.js"
|
|
7
|
+
import { OINODbApi, OINODbApiParams, OINODbParams, OINOContentType, OINODb, OINODbConstructor, OINODbApiRequestParams, OINODbSqlFilter, OINODbConfig, OINODbSqlOrder, OINODbSqlLimit, OINODbSqlParams, OINODbSqlAggregate, OINODbSqlSelect } from "./index.js"
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Static factory class for easily creating things based on data
|
|
@@ -80,6 +79,10 @@ export class OINODbFactory {
|
|
|
80
79
|
if (aggregate) {
|
|
81
80
|
sql_params.aggregate = OINODbSqlAggregate.parse(aggregate)
|
|
82
81
|
}
|
|
82
|
+
const select = url.searchParams.get(OINODbConfig.OINODB_SQL_SELECT_PARAM)
|
|
83
|
+
if (select) {
|
|
84
|
+
sql_params.select = OINODbSqlSelect.parse(select)
|
|
85
|
+
}
|
|
83
86
|
|
|
84
87
|
let result:OINODbApiRequestParams = { sqlParams: sql_params }
|
|
85
88
|
|
package/src/OINODbModelSet.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { OINODbDataSet, OINODbDataModel, OINODbDataField, OINODataRow, OINOContentType, OINOBlobDataField, OINOStr, OINODbConfig, OINONumberDataField, OINOBooleanDataField, OINODataCell, OINOLog } from "./index.js";
|
|
7
|
+
import { OINODbDataSet, OINODbDataModel, OINODbDataField, OINODataRow, OINOContentType, OINOBlobDataField, OINOStr, OINODbConfig, OINONumberDataField, OINOBooleanDataField, OINODataCell, OINOLog, OINODbSqlSelect, OINODbSqlParams } from "./index.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Class for dataset based on a data model that can be serialized to
|
|
@@ -21,6 +21,9 @@ export class OINODbModelSet {
|
|
|
21
21
|
/** Reference to data set */
|
|
22
22
|
readonly dataset: OINODbDataSet
|
|
23
23
|
|
|
24
|
+
/** SQL parameters */
|
|
25
|
+
readonly sqlParams?: OINODbSqlParams
|
|
26
|
+
|
|
24
27
|
/** Collection of errors */
|
|
25
28
|
errors: string[]
|
|
26
29
|
|
|
@@ -29,10 +32,12 @@ export class OINODbModelSet {
|
|
|
29
32
|
*
|
|
30
33
|
* @param datamodel data model
|
|
31
34
|
* @param dataset data set
|
|
35
|
+
* @param sqlParams SQL parameters
|
|
32
36
|
*/
|
|
33
|
-
constructor(datamodel: OINODbDataModel, dataset: OINODbDataSet) {
|
|
37
|
+
constructor(datamodel: OINODbDataModel, dataset: OINODbDataSet, sqlParams?: OINODbSqlParams) {
|
|
34
38
|
this.datamodel = datamodel
|
|
35
39
|
this.dataset = dataset
|
|
40
|
+
this.sqlParams = sqlParams
|
|
36
41
|
this.errors = this.dataset.messages
|
|
37
42
|
}
|
|
38
43
|
|
|
@@ -59,6 +64,9 @@ export class OINODbModelSet {
|
|
|
59
64
|
let json_row:string = ""
|
|
60
65
|
for (let i=0; i<fields.length; i++) {
|
|
61
66
|
const f = fields[i]
|
|
67
|
+
if (this.sqlParams?.select?.isSelected(f) === false) {
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
62
70
|
let value:string|null|undefined = f.serializeCell(row[i])
|
|
63
71
|
if (value === undefined) {
|
|
64
72
|
// OINOLog.info("OINODbModelSet._writeRowJson: undefined value skipped", {field_name:f.name})
|
|
@@ -118,6 +126,9 @@ export class OINODbModelSet {
|
|
|
118
126
|
let csv_row:string = ""
|
|
119
127
|
for (let i=0; i<fields.length; i++) {
|
|
120
128
|
const f = fields[i]
|
|
129
|
+
if (this.sqlParams?.select?.isSelected(f) === false) {
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
121
132
|
let value:string|null|undefined = f.serializeCell(row[i])
|
|
122
133
|
if (value == null) {
|
|
123
134
|
csv_row += "," + OINOStr.encode(value, OINOContentType.csv) // either null or undefined
|
|
@@ -169,6 +180,9 @@ export class OINODbModelSet {
|
|
|
169
180
|
let result:string = ""
|
|
170
181
|
for (let i=0; i<fields.length; i++) {
|
|
171
182
|
const f = fields[i]
|
|
183
|
+
if (this.sqlParams?.select?.isSelected(f) === false) {
|
|
184
|
+
continue
|
|
185
|
+
}
|
|
172
186
|
let value:string|null|undefined = f.serializeCell(row[i])
|
|
173
187
|
let formdata_block:string = ""
|
|
174
188
|
let is_file = (f instanceof OINOBlobDataField)
|
|
@@ -213,6 +227,9 @@ export class OINODbModelSet {
|
|
|
213
227
|
let urlencode_row:string = ""
|
|
214
228
|
for (let i=0; i<fields.length; i++) {
|
|
215
229
|
const f = fields[i]
|
|
230
|
+
if (this.sqlParams?.select?.isSelected(f) === false) {
|
|
231
|
+
continue
|
|
232
|
+
}
|
|
216
233
|
let value:string|null|undefined = f.serializeCell(row[i])
|
|
217
234
|
if ((value === undefined)) { // || (value === null)) {
|
|
218
235
|
// console.log("OINODbModelSet._writeRowUrlencode undefined field value:" + fields[i].name)
|