@oino-ts/db 0.3.3 → 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.
Files changed (39) hide show
  1. package/dist/cjs/OINODb.js +3 -3
  2. package/dist/cjs/OINODbApi.js +43 -2
  3. package/dist/cjs/OINODbConfig.js +2 -0
  4. package/dist/cjs/OINODbDataField.js +23 -0
  5. package/dist/cjs/OINODbDataModel.js +12 -5
  6. package/dist/cjs/OINODbFactory.js +5 -2
  7. package/dist/cjs/OINODbModelSet.js +17 -1
  8. package/dist/cjs/OINODbSqlParams.js +76 -11
  9. package/dist/cjs/index.js +4 -1
  10. package/dist/esm/OINODb.js +3 -3
  11. package/dist/esm/OINODbApi.js +44 -3
  12. package/dist/esm/OINODbConfig.js +2 -0
  13. package/dist/esm/OINODbDataField.js +23 -0
  14. package/dist/esm/OINODbDataModel.js +13 -6
  15. package/dist/esm/OINODbFactory.js +5 -2
  16. package/dist/esm/OINODbModelSet.js +17 -1
  17. package/dist/esm/OINODbSqlParams.js +75 -11
  18. package/dist/esm/index.js +3 -1
  19. package/dist/types/OINODb.d.ts +7 -0
  20. package/dist/types/OINODbApi.d.ts +13 -0
  21. package/dist/types/OINODbConfig.d.ts +2 -0
  22. package/dist/types/OINODbDataField.d.ts +8 -0
  23. package/dist/types/OINODbModelSet.d.ts +5 -2
  24. package/dist/types/OINODbSqlParams.d.ts +44 -4
  25. package/dist/types/index.d.ts +6 -2
  26. package/package.json +36 -36
  27. package/src/OINODb.ts +299 -291
  28. package/src/OINODbApi.test.ts +427 -411
  29. package/src/OINODbApi.ts +423 -384
  30. package/src/OINODbConfig.ts +98 -95
  31. package/src/OINODbDataField.ts +406 -382
  32. package/src/OINODbDataModel.ts +295 -289
  33. package/src/OINODbFactory.ts +127 -124
  34. package/src/OINODbModelSet.ts +315 -298
  35. package/src/OINODbParser.ts +457 -457
  36. package/src/OINODbSqlParams.ts +505 -437
  37. package/src/OINODbSwagger.ts +208 -208
  38. package/src/index.ts +134 -130
  39. package/README.md +0 -190
@@ -1,289 +1,295 @@
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 { OINODbDataField, OINODbApi, OINODataRow, OINO_ERROR_PREFIX, OINODbDataFieldFilter, OINODbConfig, OINODbSqlParams, OINONumberDataField, OINOLog } from "./index.js";
8
-
9
- /**
10
- * OINO Datamodel object for representing one database table and it's columns.
11
- *
12
- */
13
- export class OINODbDataModel {
14
- private _columnLookup:Record<string, number>;
15
-
16
- /** Database refererence of the table */
17
- readonly api:OINODbApi
18
-
19
- /** Field refererences of the API */
20
- readonly fields: OINODbDataField[]
21
-
22
- /**
23
- * Constructor of the data model.
24
- * NOTE! OINODbDataModel.initialize must be called after constructor to populate fields.
25
- *
26
- * @param api api of the data model
27
- *
28
- */
29
- constructor(api:OINODbApi) {
30
- this._columnLookup = {}
31
- this.api = api
32
- this.fields = []
33
-
34
- // OINOLog_debug("OINODbDataModel (" + tableName + "):\n" + this._printTableDebug("\n"))
35
- }
36
- /**
37
- * Initialize datamodel from SQL schema.
38
- *
39
- */
40
- async initialize() {
41
- await this.api.db.initializeApiDatamodel(this.api)
42
- }
43
-
44
- private _printSqlColumnNames(): string {
45
- let result: string = "";
46
- for (let i=0; i < this.fields.length; i++) {
47
- result += this.fields[i].printSqlColumnName()+","
48
- }
49
- return result.substring(0, result.length-1)
50
- }
51
-
52
- private _printSqlInsertColumnsAndValues(row: OINODataRow): string {
53
- let columns: string = "";
54
- let values: string = "";
55
- for (let i=0; i< this.fields.length; i++) {
56
- const val = row[i];
57
- // console.log("_printSqlInsertColumnsAndValues: row[" + i + "]=" + val)
58
- if (val !== undefined) {
59
- const f = this.fields[i]
60
- if (values != "") {
61
- columns += ",";
62
- values += ",";
63
- }
64
- columns += f.printSqlColumnName();
65
- values += f.printCellAsSqlValue(val);
66
- }
67
- }
68
- // console.log("_printSqlInsertColumnsAndValues: columns=" + columns + ", values=" + values)
69
- return "(" + columns + ") VALUES (" + values + ")";
70
- }
71
-
72
- private _printSqlUpdateValues(row: OINODataRow): string {
73
- let result: string = "";
74
- for (let i=0; i< this.fields.length; i++) {
75
- const f = this.fields[i]
76
- const val = row[i];
77
- // OINOLog_debug("OINODbDataModel._printSqlUpdateValues", {field:f.name, primary_key:f.fieldParams.isPrimaryKey, val:val})
78
- if ((!f.fieldParams.isPrimaryKey) && (val !== undefined)) {
79
- if (result != "") {
80
- result += ",";
81
- }
82
- result += f.printSqlColumnName() + "=" + f.printCellAsSqlValue(val);
83
- }
84
- }
85
- return result;
86
- }
87
-
88
- private _printSqlPrimaryKeyCondition(id_value: string): string {
89
- let result: string = ""
90
- let i:number = 0
91
- const id_parts = id_value.split(OINODbConfig.OINODB_ID_SEPARATOR)
92
- for (let f of this.fields) {
93
- if (f.fieldParams.isPrimaryKey) {
94
- if (result != "") {
95
- result += " AND "
96
- }
97
- let value = decodeURIComponent(id_parts[i])
98
- if ((f instanceof OINONumberDataField) && (this.api.hashid)) {
99
- value = this.api.hashid.decode(value)
100
- }
101
- result += f.printSqlColumnName() + "=" + f.printCellAsSqlValue(value);
102
- i = i + 1
103
- }
104
- }
105
- if (i != id_parts.length) {
106
- throw new Error(OINO_ERROR_PREFIX + ": id '" + id_value + "' is not a valid key for table " + this.api.params.tableName)
107
- }
108
- return "(" + result + ")";
109
- }
110
-
111
- /**
112
- * Add a field to the datamodel.
113
- *
114
- * @param field dataset field
115
- *
116
- */
117
- addField(field:OINODbDataField) {
118
- this.fields.push(field)
119
- this._columnLookup[field.name] = this.fields.length-1
120
- }
121
-
122
- /**
123
- * Find a field of a given name if any.
124
- *
125
- * @param name name of the field to find
126
- *
127
- */
128
- findFieldByName(name:string):OINODbDataField|null {
129
- // OINOLog.debug("OINODbDataModel.findFieldByName", {_columnLookup:this._columnLookup})
130
- const i:number = this._columnLookup[name]
131
- if (i >= 0) {
132
- return this.fields[i]
133
- } else {
134
- return null
135
- }
136
- }
137
-
138
- /**
139
- * Find index of a field of a given name if any.
140
- *
141
- * @param name name of the field to find
142
- *
143
- */
144
- findFieldIndexByName(name:string):number {
145
- // OINOLog.debug("OINODbDataModel.findFieldIndexByName", {_columnLookup:this._columnLookup})
146
- const i:number = this._columnLookup[name]
147
- if (i >= 0) {
148
- return i
149
- } else {
150
- return -1
151
- }
152
- }
153
-
154
- /**
155
- * Find all fields based of given filter callback criteria (e.g. fields of certain data type, primary keys etc.)
156
- *
157
- * @param filter callback called for each field to include or not
158
- *
159
- */
160
- filterFields(filter:OINODbDataFieldFilter):OINODbDataField[] {
161
- let result:OINODbDataField[] = []
162
- for (let f of this.fields) {
163
- if (filter(f)) {
164
- result.push(f)
165
- }
166
- }
167
- return result
168
- }
169
-
170
- /**
171
- * Return the primary key values of one row in order of the data model
172
- *
173
- * @param row data row
174
- * @param hashidValues apply hashid when applicable
175
- *
176
- */
177
- getRowPrimarykeyValues(row: OINODataRow, hashidValues:boolean = false): string[] {
178
- let values: string[] = [];
179
- for (let i=0; i< this.fields.length; i++) {
180
- const f = this.fields[i]
181
- if (f.fieldParams.isPrimaryKey) {
182
- const value:string = row[i]?.toString() || ""
183
- if (hashidValues && value && (f instanceof OINONumberDataField) && this.api.hashid) {
184
- values.push(this.api.hashid.encode(value))
185
- } else {
186
- values.push(value)
187
- }
188
- }
189
- }
190
- return values
191
- }
192
-
193
- /**
194
- * Print debug information about the fields.
195
- *
196
- * @param separator string to separate field prints
197
- *
198
- */
199
- printDebug(separator:string = ""): string {
200
- let result: string = this.api.params.tableName + ":" + separator;
201
- for (let f of this.fields) {
202
- result += f.printColumnDebug() + separator;
203
- }
204
- return result;
205
- }
206
-
207
- /**
208
- * Print all public properties (db, table name, fields) of the datamodel. Used
209
- * in automated testing validate schema has stayed the same.
210
- *
211
- */
212
- printFieldPublicPropertiesJson():string {
213
- const result:string = JSON.stringify(this.fields, (key:any, value:any) => {
214
- if (key.startsWith("_")) {
215
- return undefined
216
- } else {
217
- return value
218
- }
219
- })
220
- return result
221
- }
222
-
223
- /**
224
- * Print SQL select statement using optional id and filter.
225
- *
226
- * @param id OINO ID (i.e. combined primary key values)
227
- * @param params OINO reqest params
228
- *
229
- */
230
- printSqlSelect(id: string, params:OINODbSqlParams): string {
231
- let column_names = ""
232
- if (params.aggregate) {
233
- column_names = params.aggregate.printSqlColumnNames(this)
234
- } else {
235
- column_names = this._printSqlColumnNames()
236
- }
237
- const order_sql = params.order?.toSql(this) || ""
238
- const limit_sql = params.limit?.toSql(this) || ""
239
- const filter_sql = params.filter?.toSql(this) || ""
240
- const aggregate_sql = params.aggregate?.toSql(this) || ""
241
-
242
- let where_sql = ""
243
- // OINOLog.debug("OINODbDataModel.printSqlSelect", {id:id, select_sql:result, filter_sql:filter_sql, order_sql:order_sql})
244
- if ((id != null) && (id != "") && (filter_sql != "")) {
245
- where_sql = this._printSqlPrimaryKeyCondition(id) + " AND " + filter_sql
246
- } else if ((id != null) && (id != "")) {
247
- where_sql = this._printSqlPrimaryKeyCondition(id)
248
- } else if (filter_sql != "") {
249
- where_sql = filter_sql
250
- }
251
- const result = this.api.db.printSqlSelect(this.api.params.tableName, column_names, where_sql, order_sql, limit_sql, aggregate_sql)
252
- // OINOLog.debug("OINODbDataModel.printSqlSelect", {result:result})
253
- return result;
254
- }
255
-
256
- /**
257
- * Print SQL insert statement from one data row.
258
- *
259
- * @param row one row of data in the data model
260
- *
261
- */
262
- printSqlInsert(row: OINODataRow): string {
263
- let result: string = "INSERT INTO " + this.api.db.printSqlTablename(this.api.params.tableName) + " " + this._printSqlInsertColumnsAndValues(row) + ";";
264
- return result;
265
- }
266
-
267
- /**
268
- * Print SQL insert statement from one data row.
269
- *
270
- * @param id OINO ID (i.e. combined primary key values)
271
- * @param row one row of data in the data model
272
- *
273
- */
274
- printSqlUpdate(id: string, row: OINODataRow): string {
275
- let result: string = "UPDATE " + this.api.db.printSqlTablename(this.api.params.tableName) + " SET " + this._printSqlUpdateValues(row) + " WHERE " + this._printSqlPrimaryKeyCondition(id) + ";";
276
- return result;
277
- }
278
-
279
- /**
280
- * Print SQL delete statement for id.
281
- *
282
- * @param id OINO ID (i.e. combined primary key values)
283
- *
284
- */
285
- printSqlDelete(id: string): string {
286
- let result: string = "DELETE FROM " + this.api.db.printSqlTablename(this.api.params.tableName) + " WHERE " + this._printSqlPrimaryKeyCondition(id) + ";";
287
- return result;
288
- }
289
- }
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 { OINODbDataField, OINODbApi, OINODataRow, OINO_ERROR_PREFIX, OINODbDataFieldFilter, OINODbConfig, OINODbSqlParams, OINONumberDataField, OINOLog, OINODbSqlSelect, OINODB_UNDEFINED } from "./index.js";
8
+
9
+ /**
10
+ * OINO Datamodel object for representing one database table and it's columns.
11
+ *
12
+ */
13
+ export class OINODbDataModel {
14
+ private _columnLookup:Record<string, number>;
15
+
16
+ /** Database refererence of the table */
17
+ readonly api:OINODbApi
18
+
19
+ /** Field refererences of the API */
20
+ readonly fields: OINODbDataField[]
21
+
22
+ /**
23
+ * Constructor of the data model.
24
+ * NOTE! OINODbDataModel.initialize must be called after constructor to populate fields.
25
+ *
26
+ * @param api api of the data model
27
+ *
28
+ */
29
+ constructor(api:OINODbApi) {
30
+ this._columnLookup = {}
31
+ this.api = api
32
+ this.fields = []
33
+
34
+ // OINOLog_debug("OINODbDataModel (" + tableName + "):\n" + this._printTableDebug("\n"))
35
+ }
36
+ /**
37
+ * Initialize datamodel from SQL schema.
38
+ *
39
+ */
40
+ async initialize() {
41
+ await this.api.db.initializeApiDatamodel(this.api)
42
+ }
43
+
44
+ private _printSqlColumnNames(select?:OINODbSqlSelect): string {
45
+ let result: string = "";
46
+ for (let i=0; i < this.fields.length; i++) {
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
+ }
53
+ }
54
+ return result.substring(0, result.length-1)
55
+ }
56
+
57
+ private _printSqlInsertColumnsAndValues(row: OINODataRow): string {
58
+ let columns: string = "";
59
+ let values: string = "";
60
+ for (let i=0; i< this.fields.length; i++) {
61
+ const val = row[i];
62
+ // console.log("_printSqlInsertColumnsAndValues: row[" + i + "]=" + val)
63
+ if (val !== undefined) {
64
+ const f = this.fields[i]
65
+ if (values != "") {
66
+ columns += ",";
67
+ values += ",";
68
+ }
69
+ columns += f.printSqlColumnName();
70
+ values += f.printCellAsSqlValue(val);
71
+ }
72
+ }
73
+ // console.log("_printSqlInsertColumnsAndValues: columns=" + columns + ", values=" + values)
74
+ return "(" + columns + ") VALUES (" + values + ")";
75
+ }
76
+
77
+ private _printSqlUpdateValues(row: OINODataRow): string {
78
+ let result: string = "";
79
+ for (let i=0; i< this.fields.length; i++) {
80
+ const f = this.fields[i]
81
+ const val = row[i];
82
+ // OINOLog_debug("OINODbDataModel._printSqlUpdateValues", {field:f.name, primary_key:f.fieldParams.isPrimaryKey, val:val})
83
+ if ((!f.fieldParams.isPrimaryKey) && (val !== undefined)) {
84
+ if (result != "") {
85
+ result += ",";
86
+ }
87
+ result += f.printSqlColumnName() + "=" + f.printCellAsSqlValue(val);
88
+ }
89
+ }
90
+ return result;
91
+ }
92
+
93
+ private _printSqlPrimaryKeyCondition(id_value: string): string {
94
+ let result: string = ""
95
+ let i:number = 0
96
+ const id_parts = id_value.split(OINODbConfig.OINODB_ID_SEPARATOR)
97
+ for (let f of this.fields) {
98
+ if (f.fieldParams.isPrimaryKey) {
99
+ if (result != "") {
100
+ result += " AND "
101
+ }
102
+ let value = decodeURIComponent(id_parts[i])
103
+ if ((f instanceof OINONumberDataField) && (this.api.hashid)) {
104
+ value = this.api.hashid.decode(value)
105
+ }
106
+ result += f.printSqlColumnName() + "=" + f.printCellAsSqlValue(value);
107
+ i = i + 1
108
+ }
109
+ }
110
+ if (i != id_parts.length) {
111
+ throw new Error(OINO_ERROR_PREFIX + ": id '" + id_value + "' is not a valid key for table " + this.api.params.tableName)
112
+ }
113
+ return "(" + result + ")";
114
+ }
115
+
116
+ /**
117
+ * Add a field to the datamodel.
118
+ *
119
+ * @param field dataset field
120
+ *
121
+ */
122
+ addField(field:OINODbDataField) {
123
+ this.fields.push(field)
124
+ this._columnLookup[field.name] = this.fields.length-1
125
+ }
126
+
127
+ /**
128
+ * Find a field of a given name if any.
129
+ *
130
+ * @param name name of the field to find
131
+ *
132
+ */
133
+ findFieldByName(name:string):OINODbDataField|null {
134
+ // OINOLog.debug("OINODbDataModel.findFieldByName", {_columnLookup:this._columnLookup})
135
+ const i:number = this._columnLookup[name]
136
+ if (i >= 0) {
137
+ return this.fields[i]
138
+ } else {
139
+ return null
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Find index of a field of a given name if any.
145
+ *
146
+ * @param name name of the field to find
147
+ *
148
+ */
149
+ findFieldIndexByName(name:string):number {
150
+ // OINOLog.debug("OINODbDataModel.findFieldIndexByName", {_columnLookup:this._columnLookup})
151
+ const i:number = this._columnLookup[name]
152
+ if (i >= 0) {
153
+ return i
154
+ } else {
155
+ return -1
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Find all fields based of given filter callback criteria (e.g. fields of certain data type, primary keys etc.)
161
+ *
162
+ * @param filter callback called for each field to include or not
163
+ *
164
+ */
165
+ filterFields(filter:OINODbDataFieldFilter):OINODbDataField[] {
166
+ let result:OINODbDataField[] = []
167
+ for (let f of this.fields) {
168
+ if (filter(f)) {
169
+ result.push(f)
170
+ }
171
+ }
172
+ return result
173
+ }
174
+
175
+ /**
176
+ * Return the primary key values of one row in order of the data model
177
+ *
178
+ * @param row data row
179
+ * @param hashidValues apply hashid when applicable
180
+ *
181
+ */
182
+ getRowPrimarykeyValues(row: OINODataRow, hashidValues:boolean = false): string[] {
183
+ let values: string[] = [];
184
+ for (let i=0; i< this.fields.length; i++) {
185
+ const f = this.fields[i]
186
+ if (f.fieldParams.isPrimaryKey) {
187
+ const value:string = row[i]?.toString() || ""
188
+ if (hashidValues && value && (f instanceof OINONumberDataField) && this.api.hashid) {
189
+ values.push(this.api.hashid.encode(value))
190
+ } else {
191
+ values.push(value)
192
+ }
193
+ }
194
+ }
195
+ return values
196
+ }
197
+
198
+ /**
199
+ * Print debug information about the fields.
200
+ *
201
+ * @param separator string to separate field prints
202
+ *
203
+ */
204
+ printDebug(separator:string = ""): string {
205
+ let result: string = this.api.params.tableName + ":" + separator;
206
+ for (let f of this.fields) {
207
+ result += f.printColumnDebug() + separator;
208
+ }
209
+ return result;
210
+ }
211
+
212
+ /**
213
+ * Print all public properties (db, table name, fields) of the datamodel. Used
214
+ * in automated testing validate schema has stayed the same.
215
+ *
216
+ */
217
+ printFieldPublicPropertiesJson():string {
218
+ const result:string = JSON.stringify(this.fields, (key:any, value:any) => {
219
+ if (key.startsWith("_")) {
220
+ return undefined
221
+ } else {
222
+ return value
223
+ }
224
+ })
225
+ return result
226
+ }
227
+
228
+ /**
229
+ * Print SQL select statement using optional id and filter.
230
+ *
231
+ * @param id OINO ID (i.e. combined primary key values)
232
+ * @param params OINO reqest params
233
+ *
234
+ */
235
+ printSqlSelect(id: string, params:OINODbSqlParams): string {
236
+ let column_names = ""
237
+ if (params.aggregate) {
238
+ column_names = params.aggregate.printSqlColumnNames(this, params.select)
239
+ } else {
240
+ column_names = this._printSqlColumnNames(params.select)
241
+ }
242
+ // OINOLog.debug("OINODbDataModel.printSqlSelect", {column_names:column_names})
243
+ const order_sql = params.order?.toSql(this) || ""
244
+ const limit_sql = params.limit?.toSql(this) || ""
245
+ const filter_sql = params.filter?.toSql(this) || ""
246
+ const aggregate_sql = params.aggregate?.toSql(this) || ""
247
+
248
+ let where_sql = ""
249
+ // OINOLog.debug("OINODbDataModel.printSqlSelect", {order_sql:order_sql, limit_sql:limit_sql, filter_sql:filter_sql, aggregate_sql:aggregate_sql})
250
+ if ((id != null) && (id != "") && (filter_sql != "")) {
251
+ where_sql = this._printSqlPrimaryKeyCondition(id) + " AND " + filter_sql
252
+ } else if ((id != null) && (id != "")) {
253
+ where_sql = this._printSqlPrimaryKeyCondition(id)
254
+ } else if (filter_sql != "") {
255
+ where_sql = filter_sql
256
+ }
257
+ const result = this.api.db.printSqlSelect(this.api.params.tableName, column_names, where_sql, order_sql, limit_sql, aggregate_sql)
258
+ // OINOLog.debug("OINODbDataModel.printSqlSelect", {result:result})
259
+ return result;
260
+ }
261
+
262
+ /**
263
+ * Print SQL insert statement from one data row.
264
+ *
265
+ * @param row one row of data in the data model
266
+ *
267
+ */
268
+ printSqlInsert(row: OINODataRow): string {
269
+ let result: string = "INSERT INTO " + this.api.db.printSqlTablename(this.api.params.tableName) + " " + this._printSqlInsertColumnsAndValues(row) + ";";
270
+ return result;
271
+ }
272
+
273
+ /**
274
+ * Print SQL insert statement from one data row.
275
+ *
276
+ * @param id OINO ID (i.e. combined primary key values)
277
+ * @param row one row of data in the data model
278
+ *
279
+ */
280
+ printSqlUpdate(id: string, row: OINODataRow): string {
281
+ let result: string = "UPDATE " + this.api.db.printSqlTablename(this.api.params.tableName) + " SET " + this._printSqlUpdateValues(row) + " WHERE " + this._printSqlPrimaryKeyCondition(id) + ";";
282
+ return result;
283
+ }
284
+
285
+ /**
286
+ * Print SQL delete statement for id.
287
+ *
288
+ * @param id OINO ID (i.e. combined primary key values)
289
+ *
290
+ */
291
+ printSqlDelete(id: string): string {
292
+ let result: string = "DELETE FROM " + this.api.db.printSqlTablename(this.api.params.tableName) + " WHERE " + this._printSqlPrimaryKeyCondition(id) + ";";
293
+ return result;
294
+ }
295
+ }