@oino-ts/db 0.0.11

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.
Files changed (48) hide show
  1. package/README.md +222 -0
  2. package/dist/cjs/OINODb.js +27 -0
  3. package/dist/cjs/OINODbApi.js +270 -0
  4. package/dist/cjs/OINODbConfig.js +86 -0
  5. package/dist/cjs/OINODbDataField.js +354 -0
  6. package/dist/cjs/OINODbDataModel.js +279 -0
  7. package/dist/cjs/OINODbDataSet.js +139 -0
  8. package/dist/cjs/OINODbFactory.js +563 -0
  9. package/dist/cjs/OINODbModelSet.js +267 -0
  10. package/dist/cjs/OINODbParams.js +280 -0
  11. package/dist/cjs/OINODbRequestParams.js +280 -0
  12. package/dist/cjs/OINODbSwagger.js +201 -0
  13. package/dist/cjs/index.js +51 -0
  14. package/dist/esm/OINODb.js +23 -0
  15. package/dist/esm/OINODbApi.js +265 -0
  16. package/dist/esm/OINODbConfig.js +82 -0
  17. package/dist/esm/OINODbDataField.js +345 -0
  18. package/dist/esm/OINODbDataModel.js +275 -0
  19. package/dist/esm/OINODbDataSet.js +134 -0
  20. package/dist/esm/OINODbFactory.js +559 -0
  21. package/dist/esm/OINODbModelSet.js +263 -0
  22. package/dist/esm/OINODbRequestParams.js +274 -0
  23. package/dist/esm/OINODbSwagger.js +197 -0
  24. package/dist/esm/index.js +17 -0
  25. package/dist/types/OINODb.d.ts +75 -0
  26. package/dist/types/OINODbApi.d.ts +57 -0
  27. package/dist/types/OINODbConfig.d.ts +52 -0
  28. package/dist/types/OINODbDataField.d.ts +202 -0
  29. package/dist/types/OINODbDataModel.d.ts +108 -0
  30. package/dist/types/OINODbDataSet.d.ts +95 -0
  31. package/dist/types/OINODbFactory.d.ts +99 -0
  32. package/dist/types/OINODbModelSet.d.ts +50 -0
  33. package/dist/types/OINODbRequestParams.d.ts +130 -0
  34. package/dist/types/OINODbSwagger.d.ts +25 -0
  35. package/dist/types/index.d.ts +103 -0
  36. package/package.json +35 -0
  37. package/src/OINODb.ts +98 -0
  38. package/src/OINODbApi.test.ts +243 -0
  39. package/src/OINODbApi.ts +270 -0
  40. package/src/OINODbConfig.ts +92 -0
  41. package/src/OINODbDataField.ts +372 -0
  42. package/src/OINODbDataModel.ts +290 -0
  43. package/src/OINODbDataSet.ts +170 -0
  44. package/src/OINODbFactory.ts +570 -0
  45. package/src/OINODbModelSet.ts +286 -0
  46. package/src/OINODbRequestParams.ts +281 -0
  47. package/src/OINODbSwagger.ts +209 -0
  48. package/src/index.ts +116 -0
@@ -0,0 +1,263 @@
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
+ import { OINOContentType, OINOBlobDataField, OINOStr, OINODbConfig, OINONumberDataField, OINOBooleanDataField, OINOLog } from "./index.js";
7
+ /**
8
+ * Class for dataset based on a data model that can be serialized to
9
+ * a supported format:
10
+ * - JSON (application/json)
11
+ * - CSV (text/csv)
12
+ *
13
+ */
14
+ export class OINODbModelSet {
15
+ /** Reference to datamodel */
16
+ datamodel;
17
+ /** Reference to data set */
18
+ dataset;
19
+ /** Collection of errors */
20
+ errors;
21
+ /**
22
+ * Constructor for `OINODbModelSet`.
23
+ *
24
+ * @param datamodel data model
25
+ * @param dataset data set
26
+ */
27
+ constructor(datamodel, dataset) {
28
+ this.datamodel = datamodel;
29
+ this.dataset = dataset;
30
+ this.errors = this.dataset.messages;
31
+ }
32
+ _encodeAndHashFieldValue(field, value, contentType, primaryKeyValues, rowIdSeed) {
33
+ if (field.fieldParams.isPrimaryKey) {
34
+ if (value && (field instanceof OINONumberDataField) && (this.datamodel.api.hashid)) {
35
+ value = this.datamodel.api.hashid.encode(value, rowIdSeed);
36
+ }
37
+ primaryKeyValues.push(value || "");
38
+ }
39
+ value = OINOStr.encode(value, contentType);
40
+ return value;
41
+ }
42
+ _writeRowJson(row) {
43
+ // console.log("OINODbModelSet._writeRowJson: row=" + row)
44
+ const model = this.datamodel;
45
+ const fields = model.fields;
46
+ let row_id_seed = model.getRowPrimarykeyValues(row).join(' ');
47
+ let primary_key_values = [];
48
+ let json_row = "";
49
+ for (let i = 0; i < fields.length; i++) {
50
+ const f = fields[i];
51
+ let value = f.serializeCell(row[i]);
52
+ if (value === undefined) {
53
+ OINOLog.info("OINODbModelSet._writeRowJson: undefined value skipped", { field_name: f.name });
54
+ }
55
+ else if (value === null) {
56
+ json_row += "," + OINOStr.encode(f.name, OINOContentType.json) + ":null";
57
+ }
58
+ else {
59
+ let is_hashed = f.fieldParams.isPrimaryKey && (f instanceof OINONumberDataField) && (this.datamodel.api.hashid != null);
60
+ let is_value = (f instanceof OINOBooleanDataField) || ((f instanceof OINONumberDataField) && !is_hashed);
61
+ value = this._encodeAndHashFieldValue(f, value, OINOContentType.json, primary_key_values, f.name + " " + row_id_seed);
62
+ if (is_value) {
63
+ value = value.substring(1, value.length - 1);
64
+ }
65
+ json_row += "," + OINOStr.encode(f.name, OINOContentType.json) + ":" + value;
66
+ }
67
+ }
68
+ json_row = OINOStr.encode(OINODbConfig.OINODB_ID_FIELD, OINOContentType.json) + ":" + OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.json) + json_row;
69
+ // OINOLog_debug("OINODbModelSet._writeRowJson="+json_row)
70
+ return "{" + json_row + "}";
71
+ }
72
+ _writeStringJson() {
73
+ let result = "";
74
+ while (!this.dataset.isEof()) {
75
+ if (result != "") {
76
+ result += ",\r\n";
77
+ }
78
+ result += this._writeRowJson(this.dataset.getRow());
79
+ this.dataset.next();
80
+ }
81
+ result = "[\r\n" + result + "\r\n]";
82
+ // OINOLog_debug("OINODbModelSet._writeStringJson="+result)
83
+ return result;
84
+ }
85
+ _writeHeaderCsv() {
86
+ const model = this.datamodel;
87
+ const fields = model.fields;
88
+ let csv_header = "\"" + OINODbConfig.OINODB_ID_FIELD + "\"";
89
+ for (let i = 0; i < fields.length; i++) {
90
+ csv_header += ",\"" + fields[i].name + "\"";
91
+ }
92
+ // OINOLog_debug("OINODbModelSet._writeHeaderCsv="+csv_header)
93
+ return csv_header;
94
+ }
95
+ _writeRowCsv(row) {
96
+ // OINOLog_debug("OINODbModelSet._writeRowCsv", {row:row})
97
+ const model = this.datamodel;
98
+ const fields = model.fields;
99
+ let row_id_seed = model.getRowPrimarykeyValues(row).join(' ');
100
+ let primary_key_values = [];
101
+ let csv_row = "";
102
+ for (let i = 0; i < fields.length; i++) {
103
+ const f = fields[i];
104
+ let value = f.serializeCell(row[i]);
105
+ if (value == null) {
106
+ csv_row += "," + OINOStr.encode(value, OINOContentType.csv); // either null or undefined
107
+ }
108
+ else {
109
+ value = this._encodeAndHashFieldValue(f, value, OINOContentType.csv, primary_key_values, f.name + " " + row_id_seed);
110
+ csv_row += "," + value;
111
+ }
112
+ }
113
+ csv_row = OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.csv) + csv_row;
114
+ // OINOLog_debug("OINODbModelSet._writeRowCsv="+csv_row)
115
+ return csv_row;
116
+ }
117
+ _writeStringCsv() {
118
+ let result = this._writeHeaderCsv();
119
+ while (!this.dataset.isEof()) {
120
+ if (result != "") {
121
+ result += "\r\n";
122
+ }
123
+ result += this._writeRowCsv(this.dataset.getRow());
124
+ this.dataset.next();
125
+ }
126
+ // OINOLog_debug("OINODbModelSet._writeStringCsv="+result)
127
+ return result;
128
+ }
129
+ _writeRowFormdataParameterBlock(blockName, blockValue, multipartBoundary) {
130
+ if (blockValue === null) {
131
+ return multipartBoundary + "\r\n" + "Content-Disposition: form-data; name=\"" + blockName + "\"\r\n\r\n";
132
+ }
133
+ else {
134
+ return multipartBoundary + "\r\n" + "Content-Disposition: form-data; name=\"" + blockName + "\"\r\n\r\n" + blockValue + "\r\n";
135
+ }
136
+ }
137
+ _writeRowFormdataFileBlock(blockName, blockValue, multipartBoundary) {
138
+ return multipartBoundary + "\r\n" + "Content-Disposition: form-data; name=\"" + blockName + "\"; filename=" + blockName + "\"\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: BASE64\r\n\r\n" + blockValue + "\r\n";
139
+ }
140
+ _writeRowFormdata(row) {
141
+ const multipart_boundary = "---------OINOMultipartBoundary35424568"; // this method is just used for test data generation and we want it to be static
142
+ const model = this.datamodel;
143
+ const fields = model.fields;
144
+ let row_id_seed = model.getRowPrimarykeyValues(row).join(' ');
145
+ let primary_key_values = [];
146
+ let result = "";
147
+ for (let i = 0; i < fields.length; i++) {
148
+ const f = fields[i];
149
+ let value = f.serializeCell(row[i]);
150
+ let formdata_block = "";
151
+ let is_file = (f instanceof OINOBlobDataField);
152
+ if (value === undefined) {
153
+ OINOLog.info("OINODbModelSet._writeRowFormdata: undefined value skipped.", { field: f.name });
154
+ }
155
+ else if (value === null) {
156
+ formdata_block = this._writeRowFormdataParameterBlock(fields[i].name, null, multipart_boundary);
157
+ }
158
+ else {
159
+ value = this._encodeAndHashFieldValue(f, value, OINOContentType.formdata, primary_key_values, f.name + " " + row_id_seed);
160
+ if (is_file) {
161
+ formdata_block = this._writeRowFormdataFileBlock(f.name, value, multipart_boundary);
162
+ }
163
+ else {
164
+ formdata_block = this._writeRowFormdataParameterBlock(fields[i].name, value, multipart_boundary);
165
+ }
166
+ }
167
+ // OINOLog.debug("OINODbModelSet._writeRowFormdata next block", {formdata_block:formdata_block})
168
+ result += formdata_block;
169
+ }
170
+ result = this._writeRowFormdataParameterBlock(OINODbConfig.OINODB_ID_FIELD, OINODbConfig.printOINOId(primary_key_values), multipart_boundary) + result;
171
+ return result;
172
+ }
173
+ _writeStringFormdata() {
174
+ let result = this._writeRowFormdata(this.dataset.getRow());
175
+ this.dataset.next();
176
+ if (!this.dataset.isEof()) {
177
+ OINOLog.warning("OINODbModelSet._writeStringUrlencode: content type " + OINOContentType.formdata + " does not mixed part content and only first row has been written!");
178
+ }
179
+ return result;
180
+ }
181
+ _writeRowUrlencode(row) {
182
+ // console.log("OINODbModelSet._writeRowCsv row=" + row)
183
+ const model = this.datamodel;
184
+ const fields = model.fields;
185
+ let row_id_seed = model.getRowPrimarykeyValues(row).join(' ');
186
+ let primary_key_values = [];
187
+ let urlencode_row = "";
188
+ for (let i = 0; i < fields.length; i++) {
189
+ const f = fields[i];
190
+ let value = f.serializeCell(row[i]);
191
+ if ((value === undefined)) { // || (value === null)) {
192
+ // console.log("OINODbModelSet._writeRowUrlencode undefined field value:" + fields[i].name)
193
+ }
194
+ else {
195
+ value = this._encodeAndHashFieldValue(f, value, OINOContentType.urlencode, primary_key_values, f.name + " " + row_id_seed);
196
+ if (urlencode_row != "") {
197
+ urlencode_row += "&";
198
+ }
199
+ urlencode_row += OINOStr.encode(f.name, OINOContentType.urlencode) + "=" + value;
200
+ }
201
+ }
202
+ urlencode_row = OINOStr.encode(OINODbConfig.OINODB_ID_FIELD, OINOContentType.urlencode) + "=" + OINOStr.encode(OINODbConfig.printOINOId(primary_key_values), OINOContentType.urlencode) + "&" + urlencode_row;
203
+ // OINOLog_debug("OINODbModelSet._writeRowCsv="+csv_row)
204
+ return urlencode_row;
205
+ }
206
+ _writeStringUrlencode() {
207
+ let result = "";
208
+ let line_count = 0;
209
+ while (!this.dataset.isEof()) {
210
+ result += this._writeRowUrlencode(this.dataset.getRow()) + "\r\n";
211
+ this.dataset.next();
212
+ line_count += 1;
213
+ }
214
+ // OINOLog_debug("OINODbModelSet._writeStringCsv="+result)
215
+ if (line_count > 1) {
216
+ OINOLog.warning("OINODbModelSet._writeStringUrlencode: content type " + OINOContentType.urlencode + " does not officially support multiline content!");
217
+ }
218
+ return result;
219
+ }
220
+ /**
221
+ * Serialize model set in the given format.
222
+ *
223
+ * @param [contentType=OINOContentType.json] serialization content type
224
+ *
225
+ */
226
+ writeString(contentType = OINOContentType.json) {
227
+ let result = "";
228
+ if (contentType == OINOContentType.csv) {
229
+ result += this._writeStringCsv();
230
+ }
231
+ else if (contentType == OINOContentType.json) {
232
+ result += this._writeStringJson();
233
+ }
234
+ else if (contentType == OINOContentType.formdata) {
235
+ result += this._writeStringFormdata();
236
+ }
237
+ else if (contentType == OINOContentType.urlencode) {
238
+ result += this._writeStringUrlencode();
239
+ }
240
+ else {
241
+ OINOLog.error("OINODbModelSet.writeString: content type is only for input!", { contentType: contentType });
242
+ }
243
+ return result;
244
+ }
245
+ /**
246
+ * Get value of given field in the current row. Undefined if no rows,
247
+ * field not found or value does not exist.
248
+ *
249
+ * @param fieldName name of the field
250
+ *
251
+ */
252
+ getValueByFieldName(fieldName) {
253
+ let result = undefined;
254
+ if (!this.dataset.isEof()) {
255
+ const current_row = this.dataset.getRow();
256
+ const field_index = this.datamodel.findFieldIndexByName(fieldName);
257
+ if (field_index >= 0) {
258
+ result = current_row[field_index];
259
+ }
260
+ }
261
+ return result;
262
+ }
263
+ }
@@ -0,0 +1,274 @@
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
+ import { OINOStr, OINO_ERROR_PREFIX, OINOLog } from "./index.js";
7
+ /**
8
+ * Supported logical conjunctions in filter predicates.
9
+ * @enum
10
+ */
11
+ export var OINODbSqlBooleanOperation;
12
+ (function (OINODbSqlBooleanOperation) {
13
+ OINODbSqlBooleanOperation["and"] = "and";
14
+ OINODbSqlBooleanOperation["or"] = "or";
15
+ OINODbSqlBooleanOperation["not"] = "not";
16
+ })(OINODbSqlBooleanOperation || (OINODbSqlBooleanOperation = {}));
17
+ /**
18
+ * Supported logical conjunctions in filter predicates.
19
+ * @enum
20
+ */
21
+ export var OINODbSqlComparison;
22
+ (function (OINODbSqlComparison) {
23
+ OINODbSqlComparison["lt"] = "lt";
24
+ OINODbSqlComparison["le"] = "le";
25
+ OINODbSqlComparison["eq"] = "eq";
26
+ OINODbSqlComparison["ge"] = "ge";
27
+ OINODbSqlComparison["gt"] = "gt";
28
+ OINODbSqlComparison["like"] = "like";
29
+ })(OINODbSqlComparison || (OINODbSqlComparison = {}));
30
+ /**
31
+ * Class for recursively parsing of filters and printing them as SQL conditions.
32
+ * Supports three types of statements
33
+ * - comparison: (field)-lt|le|eq|ge|gt|like(value)
34
+ * - negation: -not(filter)
35
+ * - conjunction/disjunction: (filter)-and|or(filter)
36
+ * Supported conditions are comparisons (<, <=, =, >=, >) and substring match (LIKE).
37
+ *
38
+ */
39
+ export class OINODbSqlFilter {
40
+ static _booleanOperationRegex = /^\s?\-(and|or)\s?$/i;
41
+ static _negationRegex = /^-(not|)\((.+)\)$/i;
42
+ static _filterComparisonRegex = /^\(([^'"\(\)]+)\)\s?\-(lt|le|eq|ge|gt|like)\s?\(([^'"\(\)]+)\)$/i;
43
+ _leftSide;
44
+ _rightSide;
45
+ _operator;
46
+ /**
47
+ * Constructor of `OINODbSqlFilter`
48
+ * @param leftSide left side of the filter, either another filter or a column name
49
+ * @param operation operation of the filter, either `OINODbSqlComparison` or `OINODbSqlBooleanOperation`
50
+ * @param rightSide right side of the filter, either another filter or a value
51
+ */
52
+ constructor(leftSide, operation, rightSide) {
53
+ if (!(((operation === null) && (leftSide == "") && (rightSide == "")) ||
54
+ ((operation !== null) && (Object.values(OINODbSqlComparison).includes(operation)) && (typeof (leftSide) == "string") && (leftSide != "") && (typeof (rightSide) == "string") && (rightSide != "")) ||
55
+ ((operation == OINODbSqlBooleanOperation.not) && (leftSide == "") && (rightSide instanceof OINODbSqlFilter)) ||
56
+ (((operation == OINODbSqlBooleanOperation.and) || (operation == OINODbSqlBooleanOperation.or)) && (leftSide instanceof OINODbSqlFilter) && (rightSide instanceof OINODbSqlFilter)))) {
57
+ OINOLog.debug("Unsupported OINODbSqlFilter format!", { leftSide: leftSide, operation: operation, rightSide: rightSide });
58
+ throw new Error(OINO_ERROR_PREFIX + ": Unsupported OINODbSqlFilter format!");
59
+ }
60
+ this._leftSide = leftSide;
61
+ this._operator = operation;
62
+ this._rightSide = rightSide;
63
+ }
64
+ /**
65
+ * Constructor for `OINOFilter` as parser of http parameter.
66
+ *
67
+ * @param filterString string representation of filter from HTTP-request
68
+ *
69
+ */
70
+ static parse(filterString) {
71
+ // OINOLog_debug("OINOFilter.constructor", {filterString:filterString})
72
+ if (!filterString) {
73
+ return new OINODbSqlFilter("", null, "");
74
+ }
75
+ else {
76
+ let match = OINODbSqlFilter._filterComparisonRegex.exec(filterString);
77
+ if (match != null) {
78
+ return new OINODbSqlFilter(match[1], match[2].toLowerCase(), match[3]);
79
+ }
80
+ else {
81
+ let match = OINODbSqlFilter._negationRegex.exec(filterString);
82
+ if (match != null) {
83
+ return new OINODbSqlFilter("", OINODbSqlBooleanOperation.not, OINODbSqlFilter.parse(match[3]));
84
+ }
85
+ else {
86
+ let boolean_parts = OINOStr.splitByBrackets(filterString, true, false, '(', ')');
87
+ // OINOLog_debug("OINOFilter.constructor", {boolean_parts:boolean_parts})
88
+ if (boolean_parts.length == 3 && (boolean_parts[1].match(OINODbSqlFilter._booleanOperationRegex))) {
89
+ return new OINODbSqlFilter(OINODbSqlFilter.parse(boolean_parts[0]), boolean_parts[1].trim().toLowerCase().substring(1), OINODbSqlFilter.parse(boolean_parts[2]));
90
+ }
91
+ else {
92
+ throw new Error(OINO_ERROR_PREFIX + ": Invalid filter '" + filterString + "'");
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ /**
99
+ * Construct a new `OINOFilter` as combination of (boolean and/or) of two filters.
100
+ *
101
+ * @param leftSide left side to combine
102
+ * @param operation boolean operation to use in combination
103
+ * @param rightSide right side to combine
104
+ *
105
+ */
106
+ static combine(leftSide, operation, rightSide) {
107
+ if ((leftSide) && (!leftSide.isEmpty()) && (rightSide) && (!rightSide.isEmpty())) {
108
+ return new OINODbSqlFilter(leftSide, operation, rightSide);
109
+ }
110
+ else if ((leftSide) && (!leftSide.isEmpty())) {
111
+ return leftSide;
112
+ }
113
+ else if ((rightSide) && (!rightSide.isEmpty())) {
114
+ return rightSide;
115
+ }
116
+ else {
117
+ return undefined;
118
+ }
119
+ }
120
+ _operatorToSql() {
121
+ switch (this._operator) {
122
+ case "and": return " AND ";
123
+ case "or": return " OR ";
124
+ case "not": return "NOT ";
125
+ case "lt": return " < ";
126
+ case "le": return " <= ";
127
+ case "eq": return " = ";
128
+ case "ge": return " >= ";
129
+ case "gt": return " > ";
130
+ case "like": return " LIKE ";
131
+ }
132
+ return " ";
133
+ }
134
+ /**
135
+ * Does filter contain any valid conditions.
136
+ *
137
+ */
138
+ isEmpty() {
139
+ return (this._leftSide == "") && (this._operator == null) && (this._rightSide == "");
140
+ }
141
+ /**
142
+ * Print filter as SQL condition based on the datamodel of the API.
143
+ *
144
+ * @param dataModel data model (and database) to use for formatting of values
145
+ *
146
+ */
147
+ toSql(dataModel) {
148
+ // OINOLog.debug("OINOFilter.toSql", {_leftSide:this._leftSide, _operator:this._operator, _rightSide:this._rightSide})
149
+ if (this.isEmpty()) {
150
+ return "";
151
+ }
152
+ let result = "";
153
+ let field = null;
154
+ if (this._leftSide instanceof OINODbSqlFilter) {
155
+ result += this._leftSide.toSql(dataModel);
156
+ }
157
+ else {
158
+ result += dataModel.api.db.printSqlColumnname(this._leftSide);
159
+ field = dataModel.findFieldByName(this._leftSide);
160
+ }
161
+ result += this._operatorToSql();
162
+ if (this._rightSide instanceof OINODbSqlFilter) {
163
+ result += this._rightSide.toSql(dataModel);
164
+ }
165
+ else {
166
+ if (field) {
167
+ result += field.printCellAsSqlValue(this._rightSide);
168
+ }
169
+ else {
170
+ result += this._rightSide;
171
+ }
172
+ }
173
+ OINOLog.debug("OINOFilter.toSql", { result: result });
174
+ return "(" + result + ")";
175
+ }
176
+ }
177
+ /**
178
+ * Class for ordering select results on a number of columns.
179
+ *
180
+ */
181
+ export class OINODbSqlOrder {
182
+ static _orderColumnRegex = /^\s*(\w+)\s?(ASC|DESC)?\s*?$/i;
183
+ _columns;
184
+ _directions;
185
+ /**
186
+ * Constructor for `OINODbSqlOrder`.
187
+ *
188
+ * @param orderString string representation of filter from HTTP-request
189
+ *
190
+ */
191
+ constructor(orderString) {
192
+ // OINOLog.debug("OINODbSqlOrder.constructor", {orderString:orderString})
193
+ this._columns = [];
194
+ this._directions = [];
195
+ const column_strings = orderString.split(',');
196
+ for (let i = 0; i < column_strings.length; i++) {
197
+ let match = OINODbSqlOrder._orderColumnRegex.exec(column_strings[i]);
198
+ if (match != null) {
199
+ this._columns.push(match[1]);
200
+ this._directions.push((match[2] || "ASC").toUpperCase());
201
+ }
202
+ }
203
+ // OINOLog.debug("OINODbSqlOrder.constructor", {columns:this._columns, directions:this._directions})
204
+ }
205
+ /**
206
+ * Does filter contain any valid conditions.
207
+ *
208
+ */
209
+ isEmpty() {
210
+ return (this._columns.length == 0);
211
+ }
212
+ /**
213
+ * Print order as SQL condition based on the datamodel of the API.
214
+ *
215
+ * @param dataModel data model (and database) to use for formatting of values
216
+ *
217
+ */
218
+ toSql(dataModel) {
219
+ if (this.isEmpty()) {
220
+ return "";
221
+ }
222
+ // OINOLog.debug("OINODbSqlOrder.toSql", {columns:this._columns, directions:this._directions})
223
+ let result = "";
224
+ for (let i = 0; i < this._columns.length; i++) {
225
+ const field = dataModel.findFieldByName(this._columns[i]);
226
+ if (field) {
227
+ if (result) {
228
+ result += ",";
229
+ }
230
+ result += dataModel.api.db.printSqlColumnname(field.name) + " " + this._directions[i];
231
+ }
232
+ }
233
+ // OINOLog.debug("OINODbSqlOrder.toSql", {result:result})
234
+ return result;
235
+ }
236
+ }
237
+ /**
238
+ * Class for limiting the number of results.
239
+ *
240
+ */
241
+ export class OINODbSqlLimit {
242
+ static _orderColumnRegex = /^(\d+)?$/i;
243
+ _limit;
244
+ /**
245
+ * Constructor for `OINODbSqlLimit`.
246
+ *
247
+ * @param limitString string representation of filter from HTTP-request
248
+ *
249
+ */
250
+ constructor(limitString) {
251
+ this._limit = 0;
252
+ this._limit = Number.parseInt(limitString);
253
+ }
254
+ /**
255
+ * Does filter contain any valid conditions.
256
+ *
257
+ */
258
+ isEmpty() {
259
+ return (this._limit <= 0);
260
+ }
261
+ /**
262
+ * Print order as SQL condition based on the datamodel of the API.
263
+ *
264
+ * @param dataModel data model (and database) to use for formatting of values
265
+ *
266
+ */
267
+ toSql(dataModel) {
268
+ if (this.isEmpty()) {
269
+ return "";
270
+ }
271
+ let result = this._limit.toString();
272
+ return result;
273
+ }
274
+ }