@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.
@@ -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", { result: result });
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 aggregate_index = this._fields.indexOf(dataModel.fields[i].name);
420
- const col_name = dataModel.fields[i].printSqlColumnName();
421
- if (aggregate_index >= 0) {
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
- result += col_name + ",";
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", { result: result });
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)
@@ -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
  }
@@ -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.4",
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.3.4"
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.3.4",
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.
@@ -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 = f.serializeCell(row[i])
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")
@@ -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
@@ -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
  *
@@ -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
- result += this.fields[i].printSqlColumnName()+","
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", {id:id, select_sql:result, filter_sql:filter_sql, order_sql:order_sql})
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 != "")) {
@@ -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
 
@@ -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)