@oino-ts/db 0.21.2 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/OINODb.js +6 -144
- package/dist/cjs/OINODbApi.js +50 -318
- package/dist/cjs/OINODbConfig.js +10 -10
- package/dist/cjs/OINODbConstants.js +10 -0
- package/dist/cjs/OINODbDataField.js +28 -70
- package/dist/cjs/OINODbDataModel.js +30 -144
- package/dist/cjs/OINODbFactory.js +2 -2
- package/dist/cjs/OINODbModelSet.js +23 -23
- package/dist/cjs/OINODbQueryParams.js +201 -0
- package/dist/cjs/index.js +12 -41
- package/dist/esm/OINODb.js +6 -142
- package/dist/esm/OINODbApi.js +49 -314
- package/dist/esm/OINODbConstants.js +7 -0
- package/dist/esm/OINODbDataModel.js +31 -145
- package/dist/esm/OINODbFactory.js +1 -1
- package/dist/esm/OINODbQueryParams.js +194 -0
- package/dist/esm/index.js +4 -14
- package/dist/types/OINODb.d.ts +6 -173
- package/dist/types/OINODbApi.d.ts +18 -104
- package/dist/types/OINODbConstants.d.ts +23 -0
- package/dist/types/OINODbDataModel.d.ts +7 -61
- package/dist/types/OINODbFactory.d.ts +5 -2
- package/dist/types/OINODbQueryParams.d.ts +72 -0
- package/dist/types/index.d.ts +4 -108
- package/package.json +37 -37
- package/src/OINODb.ts +99 -348
- package/src/OINODbApi.test.ts +507 -498
- package/src/OINODbApi.ts +389 -667
- package/src/OINODbConstants.ts +32 -0
- package/src/OINODbDataModel.ts +191 -307
- package/src/OINODbFactory.ts +73 -68
- package/src/OINODbQueryParams.ts +203 -0
- package/src/index.ts +6 -118
- package/src/OINODbConfig.ts +0 -98
- package/src/OINODbDataField.ts +0 -405
- package/src/OINODbModelSet.ts +0 -353
- package/src/OINODbParser.ts +0 -438
- package/src/OINODbSqlParams.ts +0 -593
- package/src/OINODbSwagger.ts +0 -209
package/src/OINODbSqlParams.ts
DELETED
|
@@ -1,593 +0,0 @@
|
|
|
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 { OINOStr, OINO_ERROR_PREFIX, OINOLog } from "@oino-ts/common"
|
|
8
|
-
import { OINODbDataField, OINODbDataModel, OINODB_UNDEFINED } from "./index.js"
|
|
9
|
-
|
|
10
|
-
const OINO_FIELD_NAME_CHARS:string = "\\w\\s\\-\\_\\#\\¤"
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Supported logical conjunctions in filter predicates.
|
|
14
|
-
* @enum
|
|
15
|
-
*/
|
|
16
|
-
export enum OINODbSqlBooleanOperation { and = "and", or = "or", not = "not" }
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Supported logical conjunctions in filter predicates.
|
|
20
|
-
* @enum
|
|
21
|
-
*/
|
|
22
|
-
export enum OINODbSqlComparison { lt = "lt", le = "le", eq = "eq", ne = "ne", ge = "ge", gt = "gt", like = "like" }
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Supported logical conjunctions in filter predicates.
|
|
26
|
-
* @enum
|
|
27
|
-
*/
|
|
28
|
-
export enum OINODbSqlNullCheck { isnull = "isnull", isnotnull = "isnotnull" }
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Class for recursively parsing of filters and printing them as SQL conditions.
|
|
33
|
-
* Supports three types of statements
|
|
34
|
-
* - comparison: (field)-lt|le|eq|ge|gt|like(value)
|
|
35
|
-
* - negation: -not(filter)
|
|
36
|
-
* - conjunction/disjunction: (filter)-and|or(filter)
|
|
37
|
-
* Supported conditions are comparisons (<, <=, =, >=, >) and substring match (LIKE).
|
|
38
|
-
*
|
|
39
|
-
*/
|
|
40
|
-
export class OINODbSqlFilter {
|
|
41
|
-
private static _booleanOperationRegex = /^\s?\-(and|or)\s?$/i
|
|
42
|
-
private static _negationRegex = /^-(not)\((.+)\)$/i
|
|
43
|
-
private static _filterComparisonRegex = /^\(([^'"\(\)]+)\)\s?\-(lt|le|eq|ne|ge|gt|like)\s?\(([^'"\(\)]+)\)$/i
|
|
44
|
-
private static _filterNullCheckRegex = /^-(isnull|isnotnull)\((.+)\)$/i
|
|
45
|
-
|
|
46
|
-
private _leftSide: OINODbSqlFilter | string
|
|
47
|
-
private _rightSide: OINODbSqlFilter | string
|
|
48
|
-
private _operator:OINODbSqlComparison|OINODbSqlBooleanOperation|OINODbSqlNullCheck|null
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Constructor of `OINODbSqlFilter`
|
|
52
|
-
* @param leftSide left side of the filter, either another filter or a column name
|
|
53
|
-
* @param operation operation of the filter, either `OINODbSqlComparison` or `OINODbSqlBooleanOperation`
|
|
54
|
-
* @param rightSide right side of the filter, either another filter or a value
|
|
55
|
-
*/
|
|
56
|
-
constructor(leftSide:OINODbSqlFilter|string, operation:OINODbSqlComparison|OINODbSqlBooleanOperation|OINODbSqlNullCheck|null, rightSide:OINODbSqlFilter|string) {
|
|
57
|
-
if (!(
|
|
58
|
-
((operation === null) && (leftSide == "") && (rightSide == "")) ||
|
|
59
|
-
((operation !== null) && (Object.values(OINODbSqlComparison).includes(operation as OINODbSqlComparison)) && (typeof(leftSide) == "string") && (leftSide != "") && (typeof(rightSide) == "string") && (rightSide != "")) ||
|
|
60
|
-
((operation == OINODbSqlBooleanOperation.not) && (leftSide == "") && (rightSide instanceof OINODbSqlFilter)) ||
|
|
61
|
-
(((operation == OINODbSqlNullCheck.isnull) || (operation == OINODbSqlNullCheck.isnotnull)) && (typeof(leftSide) == "string") && (rightSide == "")) ||
|
|
62
|
-
(((operation == OINODbSqlBooleanOperation.and) || (operation == OINODbSqlBooleanOperation.or)) && (leftSide instanceof OINODbSqlFilter) && (rightSide instanceof OINODbSqlFilter))
|
|
63
|
-
)) {
|
|
64
|
-
OINOLog.error("@oino-ts/db", "OINODbSqlFilter", "constructor", "Unsupported OINODbSqlFilter format", {leftSide:leftSide, operation:operation, rightSide:rightSide})
|
|
65
|
-
throw new Error(OINO_ERROR_PREFIX + ": Unsupported OINODbSqlFilter format!")
|
|
66
|
-
}
|
|
67
|
-
this._leftSide = leftSide
|
|
68
|
-
this._operator = operation
|
|
69
|
-
this._rightSide = rightSide
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Constructor for `OINODbSqlFilter` as parser of http parameter.
|
|
74
|
-
*
|
|
75
|
-
* Supports three types of statements:
|
|
76
|
-
* - comparison: (field)-lt|le|eq|ge|gt|like(value)
|
|
77
|
-
* - negation: -not(filter)
|
|
78
|
-
* - conjunction/disjunction: (filter)-and|or(filter)
|
|
79
|
-
* - null check: -isnull(field) or -isnotnull(field)
|
|
80
|
-
*
|
|
81
|
-
* @param filterString string representation of filter from HTTP-request
|
|
82
|
-
*
|
|
83
|
-
*/
|
|
84
|
-
static parse(filterString: string):OINODbSqlFilter {
|
|
85
|
-
if (!filterString) {
|
|
86
|
-
return new OINODbSqlFilter("", null, "")
|
|
87
|
-
|
|
88
|
-
} else {
|
|
89
|
-
let match = OINODbSqlFilter._filterComparisonRegex.exec(filterString)
|
|
90
|
-
if ((match != null) && (match.length == 4)) {
|
|
91
|
-
return new OINODbSqlFilter(match[1], match[2].toLowerCase() as OINODbSqlComparison, match[3])
|
|
92
|
-
|
|
93
|
-
} else {
|
|
94
|
-
let match = OINODbSqlFilter._negationRegex.exec(filterString)
|
|
95
|
-
if (match != null) {
|
|
96
|
-
return new OINODbSqlFilter("", OINODbSqlBooleanOperation.not, OINODbSqlFilter.parse(match[3]))
|
|
97
|
-
|
|
98
|
-
} else {
|
|
99
|
-
let boolean_parts = OINOStr.splitByBrackets(filterString, true, false, '(', ')')
|
|
100
|
-
if (boolean_parts.length == 3 && (boolean_parts[1].match(OINODbSqlFilter._booleanOperationRegex))) {
|
|
101
|
-
return new OINODbSqlFilter(OINODbSqlFilter.parse(boolean_parts[0]), boolean_parts[1].trim().toLowerCase().substring(1) as OINODbSqlBooleanOperation, OINODbSqlFilter.parse(boolean_parts[2]))
|
|
102
|
-
|
|
103
|
-
} else {
|
|
104
|
-
let match = OINODbSqlFilter._filterNullCheckRegex.exec(filterString)
|
|
105
|
-
if ((match != null)) {
|
|
106
|
-
return new OINODbSqlFilter(match[2], match[1].toLowerCase() as OINODbSqlComparison, "")
|
|
107
|
-
|
|
108
|
-
} else {
|
|
109
|
-
OINOLog.error("@oino-ts/db", "OINODbSqlFilter", "constructor", "Invalid filter", {filterString:filterString})
|
|
110
|
-
throw new Error(OINO_ERROR_PREFIX + ": Invalid filter '" + filterString + "'") // invalid filter could be a security risk, stop processing
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Construct a new `OINODbSqlFilter` as combination of (boolean and/or) of two filters.
|
|
120
|
-
*
|
|
121
|
-
* @param leftSide left side to combine
|
|
122
|
-
* @param operation boolean operation to use in combination
|
|
123
|
-
* @param rightSide right side to combine
|
|
124
|
-
*
|
|
125
|
-
*/
|
|
126
|
-
static combine(leftSide:OINODbSqlFilter|undefined, operation:OINODbSqlBooleanOperation, rightSide:OINODbSqlFilter|undefined):OINODbSqlFilter|undefined {
|
|
127
|
-
if ((leftSide) && (!leftSide.isEmpty()) && (rightSide) && (!rightSide.isEmpty())) {
|
|
128
|
-
return new OINODbSqlFilter(leftSide, operation, rightSide)
|
|
129
|
-
|
|
130
|
-
} else if ((leftSide) && (!leftSide.isEmpty())) {
|
|
131
|
-
return leftSide
|
|
132
|
-
|
|
133
|
-
} else if ((rightSide) && (!rightSide.isEmpty())) {
|
|
134
|
-
return rightSide
|
|
135
|
-
|
|
136
|
-
} else {
|
|
137
|
-
return undefined
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Combine two filters with an AND operation.
|
|
143
|
-
*
|
|
144
|
-
* @param leftSide left side filter
|
|
145
|
-
* @param rightSide right side filter
|
|
146
|
-
*
|
|
147
|
-
*/
|
|
148
|
-
static and(leftSide:OINODbSqlFilter, rightSide:OINODbSqlFilter):OINODbSqlFilter|undefined {
|
|
149
|
-
if ((leftSide) && (!leftSide.isEmpty()) && (rightSide) && (!rightSide.isEmpty())) {
|
|
150
|
-
return new OINODbSqlFilter(leftSide, OINODbSqlBooleanOperation.and, rightSide)
|
|
151
|
-
|
|
152
|
-
} else {
|
|
153
|
-
return undefined
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Combine two filters with an OR operation.
|
|
159
|
-
*
|
|
160
|
-
* @param leftSide left side filter
|
|
161
|
-
* @param rightSide right side filter
|
|
162
|
-
*
|
|
163
|
-
*/
|
|
164
|
-
static or(leftSide:OINODbSqlFilter, rightSide:OINODbSqlFilter):OINODbSqlFilter|undefined {
|
|
165
|
-
if ((leftSide) && (!leftSide.isEmpty()) && (rightSide) && (!rightSide.isEmpty())) {
|
|
166
|
-
return new OINODbSqlFilter(leftSide, OINODbSqlBooleanOperation.or, rightSide)
|
|
167
|
-
|
|
168
|
-
} else {
|
|
169
|
-
return undefined
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Negate a filter with a NOT operation.
|
|
175
|
-
*
|
|
176
|
-
* @param leftSide left side filter
|
|
177
|
-
*
|
|
178
|
-
*/
|
|
179
|
-
static not(leftSide:OINODbSqlFilter):OINODbSqlFilter|undefined {
|
|
180
|
-
if ((leftSide) && (!leftSide.isEmpty())) {
|
|
181
|
-
return new OINODbSqlFilter(leftSide, OINODbSqlBooleanOperation.not, "")
|
|
182
|
-
|
|
183
|
-
} else {
|
|
184
|
-
return undefined
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
private _operatorToSql():string {
|
|
190
|
-
switch (this._operator) {
|
|
191
|
-
case "and": return " AND "
|
|
192
|
-
case "or": return " OR "
|
|
193
|
-
case "not": return "NOT "
|
|
194
|
-
case "lt": return " < "
|
|
195
|
-
case "le": return " <= "
|
|
196
|
-
case "eq": return " = "
|
|
197
|
-
case "ne": return " != "
|
|
198
|
-
case "ge": return " >= "
|
|
199
|
-
case "gt": return " > "
|
|
200
|
-
case "like": return " LIKE "
|
|
201
|
-
case "isnull": return " IS NULL"
|
|
202
|
-
case "isnotnull": return " IS NOT NULL"
|
|
203
|
-
}
|
|
204
|
-
return " "
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Does filter contain any valid conditions.
|
|
209
|
-
*
|
|
210
|
-
*/
|
|
211
|
-
isEmpty():boolean {
|
|
212
|
-
return (this._leftSide == "") && (this._operator == null) && (this._rightSide == "")
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Print filter as SQL condition based on the datamodel of the API.
|
|
217
|
-
*
|
|
218
|
-
* @param dataModel data model (and database) to use for formatting of values
|
|
219
|
-
*
|
|
220
|
-
*/
|
|
221
|
-
toSql(dataModel:OINODbDataModel):string {
|
|
222
|
-
if (this.isEmpty()) {
|
|
223
|
-
return ""
|
|
224
|
-
}
|
|
225
|
-
let result:string = ""
|
|
226
|
-
let field:OINODbDataField|null = null
|
|
227
|
-
if (this._leftSide instanceof OINODbSqlFilter) {
|
|
228
|
-
result += this._leftSide.toSql(dataModel)
|
|
229
|
-
} else {
|
|
230
|
-
field = dataModel.findFieldByName(this._leftSide)
|
|
231
|
-
if (!field) {
|
|
232
|
-
OINOLog.error("@oino-ts/db", "OINODbSqlFilter", "toSql", "Invalid field!", {field:this._leftSide})
|
|
233
|
-
throw new Error(OINO_ERROR_PREFIX + ": OINODbSqlFilter.toSql - Invalid field '" + this._leftSide + "'") // invalid field name could be a security risk, stop processing
|
|
234
|
-
}
|
|
235
|
-
result += dataModel.api.db.printSqlColumnname(field?.name || this._leftSide)
|
|
236
|
-
}
|
|
237
|
-
result += this._operatorToSql()
|
|
238
|
-
if (this._rightSide instanceof OINODbSqlFilter) {
|
|
239
|
-
result += this._rightSide.toSql(dataModel)
|
|
240
|
-
} else if (this._operator == OINODbSqlNullCheck.isnull || this._operator == OINODbSqlNullCheck.isnotnull) {
|
|
241
|
-
// nothing to do, IS NULL and IS NOT NULL do not have a right side
|
|
242
|
-
} else {
|
|
243
|
-
const value = field!.deserializeCell(this._rightSide)
|
|
244
|
-
if ((value == null) || (value === "")) {
|
|
245
|
-
OINOLog.error("@oino-ts/db", "OINODbSqlFilter", "toSql", "Invalid value!", {value:value})
|
|
246
|
-
throw new Error(OINO_ERROR_PREFIX + ": OINODbSqlFilter.toSql - Invalid value '" + value + "'") // invalid value could be a security risk, stop processing
|
|
247
|
-
}
|
|
248
|
-
result += field!.printCellAsSqlValue(value)
|
|
249
|
-
}
|
|
250
|
-
result = "(" + result + ")"
|
|
251
|
-
OINOLog.debug("@oino-ts/db", "OINODbSqlFilter", "toSql", "Result", {sql:result})
|
|
252
|
-
return result
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Class for ordering select results on a number of columns.
|
|
258
|
-
*
|
|
259
|
-
*/
|
|
260
|
-
export class OINODbSqlOrder {
|
|
261
|
-
private static _orderColumnRegex = /^\s*(\w+)\s?(ASC|DESC|\+|\-)?\s*?$/i
|
|
262
|
-
|
|
263
|
-
private _columns: string[]
|
|
264
|
-
private _descending: boolean[]
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Constructor for `OINODbSqlOrder`.
|
|
268
|
-
*
|
|
269
|
-
* @param column_or_array single or array of columns to order on
|
|
270
|
-
* @param descending_or_array single or array of booleans if ordes is descending
|
|
271
|
-
*
|
|
272
|
-
*/
|
|
273
|
-
constructor(column_or_array:string[]|string, descending_or_array:boolean[]|boolean) {
|
|
274
|
-
if (Array.isArray(column_or_array)) {
|
|
275
|
-
this._columns = column_or_array
|
|
276
|
-
} else {
|
|
277
|
-
this._columns = [column_or_array]
|
|
278
|
-
}
|
|
279
|
-
if (Array.isArray(descending_or_array)) {
|
|
280
|
-
this._descending = descending_or_array
|
|
281
|
-
} else {
|
|
282
|
-
this._descending = [descending_or_array]
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Constructor for `OINODbSqlOrder` as parser of http parameter.
|
|
288
|
-
*
|
|
289
|
-
* Supports comma separated list of column orders formatted as :
|
|
290
|
-
* - `column` - order by column in ascending order
|
|
291
|
-
* - `column ASC|DESC` - order by single either ascending or descending order
|
|
292
|
-
* - `column+|-` - order by single either ascending or descending order
|
|
293
|
-
*
|
|
294
|
-
* @param orderString string representation of order from HTTP-request
|
|
295
|
-
*
|
|
296
|
-
*/
|
|
297
|
-
static parse(orderString: string):OINODbSqlOrder {
|
|
298
|
-
let columns:string[] = []
|
|
299
|
-
let directions:boolean[] = []
|
|
300
|
-
|
|
301
|
-
const column_strings = orderString.split(',')
|
|
302
|
-
|
|
303
|
-
for (let i=0; i<column_strings.length; i++) {
|
|
304
|
-
let match = OINODbSqlOrder._orderColumnRegex.exec(column_strings[i])
|
|
305
|
-
if (match != null) {
|
|
306
|
-
columns.push(match[1])
|
|
307
|
-
const dir:string = (match[2] || "ASC").toUpperCase()
|
|
308
|
-
directions.push((dir == "DESC") || (dir == "-"))
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return new OINODbSqlOrder(columns, directions)
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Does filter contain any valid conditions.
|
|
316
|
-
*
|
|
317
|
-
*/
|
|
318
|
-
isEmpty():boolean {
|
|
319
|
-
return (this._columns.length == 0)
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Print order as SQL condition based on the datamodel of the API.
|
|
324
|
-
*
|
|
325
|
-
* @param dataModel data model (and database) to use for formatting of values
|
|
326
|
-
*
|
|
327
|
-
*/
|
|
328
|
-
toSql(dataModel:OINODbDataModel):string {
|
|
329
|
-
if (this.isEmpty()) {
|
|
330
|
-
return ""
|
|
331
|
-
}
|
|
332
|
-
let result:string = ""
|
|
333
|
-
for (let i=0; i<this._columns.length; i++) {
|
|
334
|
-
const field:OINODbDataField|null = dataModel.findFieldByName(this._columns[i])
|
|
335
|
-
if (!field) {
|
|
336
|
-
OINOLog.error("@oino-ts/db", "OINODbSqlOrder", "toSql", "Invalid field!", {field:this._columns[i]})
|
|
337
|
-
throw new Error(OINO_ERROR_PREFIX + ": OINODbSqlOrder.toSql - Invalid field '" + this._columns[i] + "'") // invalid field name could be a security risk, stop processing
|
|
338
|
-
}
|
|
339
|
-
if (result) {
|
|
340
|
-
result += ","
|
|
341
|
-
}
|
|
342
|
-
result += dataModel.api.db.printSqlColumnname(field.name) + " "
|
|
343
|
-
if (this._descending[i]) {
|
|
344
|
-
result += "DESC"
|
|
345
|
-
} else {
|
|
346
|
-
result += "ASC"
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
OINOLog.debug("@oino-ts/db", "OINODbSqlOrder", "toSql", "Result", {sql:result})
|
|
350
|
-
return result
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Class for limiting the number of results.
|
|
356
|
-
*
|
|
357
|
-
*/
|
|
358
|
-
export class OINODbSqlLimit {
|
|
359
|
-
private static _limitRegex = /^(\d+)(\spage\s|\.)?(\d+)?$/i
|
|
360
|
-
|
|
361
|
-
private _limit: number
|
|
362
|
-
private _page: number
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Constructor for `OINODbSqlLimit`.
|
|
366
|
-
*
|
|
367
|
-
* @param limit maximum number of items to return
|
|
368
|
-
* @param page page number to return starting from 1
|
|
369
|
-
*
|
|
370
|
-
*/
|
|
371
|
-
constructor(limit: number, page: number = -1) {
|
|
372
|
-
this._limit = limit
|
|
373
|
-
this._page = page
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Constructor for `OINODbSqlLimit` as parser of http parameter.
|
|
377
|
-
*
|
|
378
|
-
* Supports limit and page formatted as:
|
|
379
|
-
* - `limit` - limit number of items to return
|
|
380
|
-
* - `limit page n` - limit number of items to return and return page n (starting from 1)
|
|
381
|
-
* - `limit.n` - limit number of items to return and return page n (starting from 1)
|
|
382
|
-
*
|
|
383
|
-
* @param limitString string representation of limit from HTTP-request
|
|
384
|
-
*
|
|
385
|
-
*/
|
|
386
|
-
static parse(limitString: string):OINODbSqlLimit {
|
|
387
|
-
let match = OINODbSqlLimit._limitRegex.exec(limitString)
|
|
388
|
-
if ((match != null) && (match.length == 4)) {
|
|
389
|
-
return new OINODbSqlLimit(Number.parseInt(match[1]), Number.parseInt(match[3]))
|
|
390
|
-
} else if (match != null) {
|
|
391
|
-
return new OINODbSqlLimit(Number.parseInt(match[1]))
|
|
392
|
-
} else {
|
|
393
|
-
return new OINODbSqlLimit(-1)
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Does filter contain any valid conditions.
|
|
399
|
-
*
|
|
400
|
-
*/
|
|
401
|
-
isEmpty():boolean {
|
|
402
|
-
return (this._limit <= 0)
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Print order as SQL condition based on the datamodel of the API.
|
|
407
|
-
*
|
|
408
|
-
* @param dataModel data model (and database) to use for formatting of values
|
|
409
|
-
*
|
|
410
|
-
*/
|
|
411
|
-
toSql(dataModel:OINODbDataModel):string {
|
|
412
|
-
if (this.isEmpty()) {
|
|
413
|
-
return ""
|
|
414
|
-
}
|
|
415
|
-
let result:string = this._limit.toString()
|
|
416
|
-
if (this._page > 0) {
|
|
417
|
-
result += " OFFSET " + (this._limit * (this._page-1) + 1).toString()
|
|
418
|
-
}
|
|
419
|
-
OINOLog.debug("@oino-ts/db", "OINODbSqlLimit", "toSql", "Result", {sql:result})
|
|
420
|
-
return result
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Supported aggregation functions in OINODbSqlAggregate.
|
|
426
|
-
* @enum
|
|
427
|
-
*/
|
|
428
|
-
export enum OINODbSqlAggregateFunctions { count = "count", sum = "sum", avg = "avg", min = "min", max = "max" }
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Class for limiting the number of results.
|
|
432
|
-
*
|
|
433
|
-
*/
|
|
434
|
-
export class OINODbSqlAggregate {
|
|
435
|
-
private static _aggregateRegex:RegExp = new RegExp("^(count|sum|avg|min|max)\\(([" + OINO_FIELD_NAME_CHARS + "]+)\\)$", "mi")
|
|
436
|
-
|
|
437
|
-
private _functions: OINODbSqlAggregateFunctions[]
|
|
438
|
-
private _fields: string[]
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* Constructor for `OINODbSqlAggregate`.
|
|
442
|
-
*
|
|
443
|
-
* @param functions aggregate function to use
|
|
444
|
-
* @param fields fields to aggregate
|
|
445
|
-
*
|
|
446
|
-
*/
|
|
447
|
-
constructor(functions: OINODbSqlAggregateFunctions[], fields: string[]) {
|
|
448
|
-
this._functions = functions
|
|
449
|
-
this._fields = fields
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Constructor for `OINODbSqlAggregate` as parser of http parameter.
|
|
453
|
-
*
|
|
454
|
-
* Supports comma separated list of aggregates formatted as:
|
|
455
|
-
* - `function(field)`
|
|
456
|
-
*
|
|
457
|
-
* Supported functions are count, sum, avg, min, max.
|
|
458
|
-
*
|
|
459
|
-
* @param aggregatorString string representation of limit from HTTP-request
|
|
460
|
-
*
|
|
461
|
-
*/
|
|
462
|
-
static parse(aggregatorString: string):OINODbSqlAggregate {
|
|
463
|
-
let funtions:OINODbSqlAggregateFunctions[] = []
|
|
464
|
-
let fields:string[] = []
|
|
465
|
-
const aggregator_parts = aggregatorString.split(',')
|
|
466
|
-
for (let i=0; i<aggregator_parts.length; i++) {
|
|
467
|
-
let match = OINODbSqlAggregate._aggregateRegex.exec(aggregator_parts[i])
|
|
468
|
-
if ((match != null) && (match.length == 3)) {
|
|
469
|
-
funtions.push(match[1] as OINODbSqlAggregateFunctions)
|
|
470
|
-
fields.push(match[2])
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return new OINODbSqlAggregate(funtions, fields)
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/**
|
|
477
|
-
* Does filter contain any valid conditions.
|
|
478
|
-
*
|
|
479
|
-
*/
|
|
480
|
-
isEmpty():boolean {
|
|
481
|
-
return (this._functions.length <= 0)
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
/**
|
|
485
|
-
* Print non-aggregated fields as SQL GROUP BY-condition based on the datamodel of the API.
|
|
486
|
-
*
|
|
487
|
-
* @param dataModel data model (and database) to use for formatting of values
|
|
488
|
-
* @param select what fields to select
|
|
489
|
-
*
|
|
490
|
-
*/
|
|
491
|
-
toSql(dataModel:OINODbDataModel, select?:OINODbSqlSelect):string {
|
|
492
|
-
if (this.isEmpty()) {
|
|
493
|
-
return ""
|
|
494
|
-
}
|
|
495
|
-
let result:string = ""
|
|
496
|
-
for (let i=0; i<dataModel.fields.length; i++) {
|
|
497
|
-
const f = dataModel.fields[i]
|
|
498
|
-
if (select?.isSelected(f) && (this._fields.includes(f.name) == false)) {
|
|
499
|
-
result += f.printSqlColumnName() + ","
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
result = result.substring(0, result.length-1)
|
|
503
|
-
OINOLog.debug("@oino-ts/db", "OINODbSqlAggregate", "toSql", "Result", {sql:result})
|
|
504
|
-
return result
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* Print non-aggregated fields as SQL GROUP BY-condition based on the datamodel of the API.
|
|
509
|
-
*
|
|
510
|
-
* @param dataModel data model (and database) to use for formatting of values
|
|
511
|
-
* @param select what fields to select
|
|
512
|
-
*
|
|
513
|
-
*/
|
|
514
|
-
printSqlColumnNames(dataModel:OINODbDataModel, select?:OINODbSqlSelect):string {
|
|
515
|
-
let result:string = ""
|
|
516
|
-
for (let i=0; i<dataModel.fields.length; i++) {
|
|
517
|
-
const f:OINODbDataField = dataModel.fields[i]
|
|
518
|
-
if (select?.isSelected(f)==false) { // if a field is not selected, we include an aggregated constant (min of const string) and correct fieldname instead so that dimensions of the data don't change, it does not need a group by but no unnecessary data is fetched
|
|
519
|
-
result += OINODbSqlAggregateFunctions.min + "(" + f.db.printSqlString(OINODB_UNDEFINED) + ") as " + f.printSqlColumnName()+","
|
|
520
|
-
|
|
521
|
-
} else {
|
|
522
|
-
const aggregate_index = this._fields.indexOf(f.name)
|
|
523
|
-
const col_name = f.printSqlColumnName()
|
|
524
|
-
if (aggregate_index >= 0) {
|
|
525
|
-
result += this._functions[aggregate_index] + "(" + col_name + ") as " + col_name + ","
|
|
526
|
-
} else {
|
|
527
|
-
result += col_name + ","
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
return result.substring(0, result.length-1)
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
/**
|
|
535
|
-
* Does filter contain any valid conditions.
|
|
536
|
-
*
|
|
537
|
-
* @param field field to check if it is aggregated
|
|
538
|
-
*/
|
|
539
|
-
isAggregated(field:OINODbDataField):boolean {
|
|
540
|
-
return (this._fields.includes(field.name))
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* Class for ordering select results on a number of columns.
|
|
547
|
-
*
|
|
548
|
-
*/
|
|
549
|
-
export class OINODbSqlSelect {
|
|
550
|
-
private _columns: string[]
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* Constructor for `OINODbSqlSelect`.
|
|
554
|
-
*
|
|
555
|
-
* @param columns array of columns to select
|
|
556
|
-
*
|
|
557
|
-
*/
|
|
558
|
-
constructor(columns:string[]) {
|
|
559
|
-
this._columns = columns
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* Constructor for `OINODbSqlSelect` as parser of http parameter.
|
|
564
|
-
*
|
|
565
|
-
* @param columns comma separated string selected columns from HTTP-request
|
|
566
|
-
*
|
|
567
|
-
*/
|
|
568
|
-
static parse(columns: string):OINODbSqlSelect {
|
|
569
|
-
if (columns == "") {
|
|
570
|
-
return new OINODbSqlSelect([])
|
|
571
|
-
} else {
|
|
572
|
-
return new OINODbSqlSelect(columns.split(','))
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
/**
|
|
577
|
-
* Does select contain any valid columns.
|
|
578
|
-
*
|
|
579
|
-
*/
|
|
580
|
-
isEmpty():boolean {
|
|
581
|
-
return (this._columns.length == 0)
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/**
|
|
585
|
-
* Does select include given column.
|
|
586
|
-
*
|
|
587
|
-
* @param field field to check if it is selected
|
|
588
|
-
*
|
|
589
|
-
*/
|
|
590
|
-
isSelected(field:OINODbDataField):boolean {
|
|
591
|
-
return ((this._columns.length == 0) || (field.fieldParams.isPrimaryKey == true) || (this._columns.includes(field.name)))
|
|
592
|
-
}
|
|
593
|
-
}
|