@cap-js/db-service 2.8.0 → 2.8.2
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/CHANGELOG.md +18 -0
- package/lib/cql-functions.js +5 -1
- package/lib/cqn2sql.js +5 -3
- package/lib/infer/index.js +10 -19
- package/lib/infer/pseudos.js +12 -11
- package/lib/search.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@
|
|
|
4
4
|
- The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
5
5
|
- This project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [2.8.2](https://github.com/cap-js/cds-dbs/compare/db-service-v2.8.1...db-service-v2.8.2) (2026-02-03)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
* compare conversion for right hand `null` transformation ([#1469](https://github.com/cap-js/cds-dbs/issues/1469)) ([ec1d0c6](https://github.com/cap-js/cds-dbs/commit/ec1d0c6fa08db1f75e9b72eed382a507b49815cc))
|
|
13
|
+
* **cqn4sql:** calculated elements with function expr in from ([#1452](https://github.com/cap-js/cds-dbs/issues/1452)) ([970407e](https://github.com/cap-js/cds-dbs/commit/970407e29e4c98ee9c25d15277dff80c246b9523))
|
|
14
|
+
* hierarchy with $top ([#1460](https://github.com/cap-js/cds-dbs/issues/1460)) ([dfc6226](https://github.com/cap-js/cds-dbs/commit/dfc62261681ced388e9c35aa8ce3e49e1c09f4e2))
|
|
15
|
+
* search aggregate functions ([#1463](https://github.com/cap-js/cds-dbs/issues/1463)) ([a8db1f3](https://github.com/cap-js/cds-dbs/commit/a8db1f38e219bd7818c3cfc9f45e108bcab1dd95))
|
|
16
|
+
* support all types for casting in queries ([#1481](https://github.com/cap-js/cds-dbs/issues/1481)) ([8392232](https://github.com/cap-js/cds-dbs/commit/8392232aafdcfa025a7dce597bf65fb6344acd1f))
|
|
17
|
+
|
|
18
|
+
## [2.8.1](https://github.com/cap-js/cds-dbs/compare/db-service-v2.8.0...db-service-v2.8.1) (2025-12-19)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
* hierarchy node_id as alias ([#1450](https://github.com/cap-js/cds-dbs/issues/1450)) ([d115345](https://github.com/cap-js/cds-dbs/commit/d115345e5acc30046159ede98d99a864df55e2af))
|
|
24
|
+
|
|
7
25
|
## [2.8.0](https://github.com/cap-js/cds-dbs/compare/db-service-v2.7.0...db-service-v2.8.0) (2025-12-15)
|
|
8
26
|
|
|
9
27
|
|
package/lib/cql-functions.js
CHANGED
|
@@ -244,7 +244,11 @@ const HANAFunctions = {
|
|
|
244
244
|
let src = args.xpr[1]
|
|
245
245
|
|
|
246
246
|
// Ensure that the orderBy column are exposed by the source for hierarchy sorting
|
|
247
|
-
|
|
247
|
+
let orderBy = args.xpr.find((_, i, arr) => /ORDER/i.test(arr[i - 2]) && /BY/i.test(arr[i - 1]))
|
|
248
|
+
// use ![] instead of ""
|
|
249
|
+
if (orderBy && typeof orderBy === 'string') {
|
|
250
|
+
orderBy = orderBy.replace(/"([^"]*)"/g, '![$1]');
|
|
251
|
+
}
|
|
248
252
|
|
|
249
253
|
const passThroughColumns = src.SELECT.columns.map(c => ({ ref: ['Source', this.column_name(c)] }))
|
|
250
254
|
src.as = 'H' + (uniqueCounter++)
|
package/lib/cqn2sql.js
CHANGED
|
@@ -298,6 +298,7 @@ class CQN2SQLRenderer {
|
|
|
298
298
|
const clone = q.clone()
|
|
299
299
|
clone.columns(keys)
|
|
300
300
|
clone.SELECT.recurse = undefined
|
|
301
|
+
clone.SELECT.limit = undefined
|
|
301
302
|
clone.SELECT.expand = undefined // omits JSON
|
|
302
303
|
where = [{ list: keys }, 'in', clone]
|
|
303
304
|
}
|
|
@@ -380,7 +381,8 @@ class CQN2SQLRenderer {
|
|
|
380
381
|
|
|
381
382
|
if (orderBy) {
|
|
382
383
|
orderBy = orderBy.map(r => {
|
|
383
|
-
|
|
384
|
+
let col = r.ref.at(-1)
|
|
385
|
+
if (col.toUpperCase() in reservedColumnNames) col = `$$${col}$$`
|
|
384
386
|
if (!columnsIn.find(c => this.column_name(c) === col)) {
|
|
385
387
|
columnsIn.push({ ref: [col] })
|
|
386
388
|
}
|
|
@@ -1223,7 +1225,7 @@ class CQN2SQLRenderer {
|
|
|
1223
1225
|
? _inline_null(xpr[i + 1]) || 'is'
|
|
1224
1226
|
: '='
|
|
1225
1227
|
|
|
1226
|
-
// Translate == to IS
|
|
1228
|
+
// Translate == to IS NULL for rhs operand being NULL literal, otherwise ...
|
|
1227
1229
|
// Translate == to IS NOT DISTINCT FROM, unless both operands cannot be NULL
|
|
1228
1230
|
if (x === '==') return xpr[i + 1]?.val === null
|
|
1229
1231
|
? _inline_null(xpr[i + 1]) || 'is'
|
|
@@ -1231,7 +1233,7 @@ class CQN2SQLRenderer {
|
|
|
1231
1233
|
? '='
|
|
1232
1234
|
: this.is_not_distinct_from_
|
|
1233
1235
|
|
|
1234
|
-
// Translate != to IS NULL for rhs operand being NULL literal, otherwise...
|
|
1236
|
+
// Translate != to IS NOT NULL for rhs operand being NULL literal, otherwise...
|
|
1235
1237
|
// Translate != to IS DISTINCT FROM, unless both operands cannot be NULL
|
|
1236
1238
|
if (x === '!=') return xpr[i + 1]?.val === null
|
|
1237
1239
|
? _inline_null(xpr[i + 1]) || 'is not'
|
package/lib/infer/index.js
CHANGED
|
@@ -5,19 +5,7 @@ const cds = require('@sap/cds')
|
|
|
5
5
|
const JoinTree = require('./join-tree')
|
|
6
6
|
const { pseudos } = require('./pseudos')
|
|
7
7
|
const { isCalculatedOnRead, getImplicitAlias, getModelUtils, defineProperty, hasOwnSkip } = require('../utils')
|
|
8
|
-
const cdsTypes = cds.
|
|
9
|
-
definitions: {
|
|
10
|
-
Timestamp: { type: 'cds.Timestamp' },
|
|
11
|
-
DateTime: { type: 'cds.DateTime' },
|
|
12
|
-
Date: { type: 'cds.Date' },
|
|
13
|
-
Time: { type: 'cds.Time' },
|
|
14
|
-
String: { type: 'cds.String' },
|
|
15
|
-
Decimal: { type: 'cds.Decimal' },
|
|
16
|
-
Integer: { type: 'cds.Integer' },
|
|
17
|
-
Boolean: { type: 'cds.Boolean' },
|
|
18
|
-
},
|
|
19
|
-
}).definitions
|
|
20
|
-
for (const each in cdsTypes) cdsTypes[`cds.${each}`] = cdsTypes[each]
|
|
8
|
+
const cdsTypes = cds.builtin.types
|
|
21
9
|
/**
|
|
22
10
|
* @param {import('@sap/cds/apis/cqn').Query|string} originalQuery
|
|
23
11
|
* @param {import('@sap/cds/apis/csn').CSN} [model]
|
|
@@ -746,7 +734,7 @@ function infer(originalQuery, model) {
|
|
|
746
734
|
const expandElements = resolveExpand(inlineCol)
|
|
747
735
|
elements = { ...elements, [name]: expandElements }
|
|
748
736
|
} else if (inlineCol.val) {
|
|
749
|
-
elements[name] =
|
|
737
|
+
elements[name] = getCdsTypeForVal(inlineCol.val)
|
|
750
738
|
} else if (inlineCol.func) {
|
|
751
739
|
elements[name] = {}
|
|
752
740
|
} else {
|
|
@@ -867,7 +855,7 @@ function infer(originalQuery, model) {
|
|
|
867
855
|
arg,
|
|
868
856
|
null,
|
|
869
857
|
{ definition: parentElementDefinition, target: parentElementDefinition },
|
|
870
|
-
{ inCalcElement: true },
|
|
858
|
+
{ inCalcElement: true, ...context },
|
|
871
859
|
)
|
|
872
860
|
const basePath =
|
|
873
861
|
column.$refLinks?.length > 1
|
|
@@ -1091,7 +1079,10 @@ function infer(originalQuery, model) {
|
|
|
1091
1079
|
if ($refLinks?.[$refLinks.length - 1].definition.elements)
|
|
1092
1080
|
// no cast on structure
|
|
1093
1081
|
cds.error`Structured elements can't be cast to a different type`
|
|
1094
|
-
|
|
1082
|
+
const cdsType = cdsTypes[cast.type]
|
|
1083
|
+
thing.cast = cdsType ? new cdsType.constructor(cast) : cast
|
|
1084
|
+
if (cdsType)
|
|
1085
|
+
thing.cast.type = cdsType._type
|
|
1095
1086
|
return thing.cast
|
|
1096
1087
|
}
|
|
1097
1088
|
|
|
@@ -1121,11 +1112,11 @@ function infer(originalQuery, model) {
|
|
|
1121
1112
|
// if(val === null) return {type:'cds.String'}
|
|
1122
1113
|
switch (typeof val) {
|
|
1123
1114
|
case 'string':
|
|
1124
|
-
return cdsTypes.String
|
|
1115
|
+
return new cdsTypes.String.constructor()
|
|
1125
1116
|
case 'boolean':
|
|
1126
|
-
return cdsTypes.Boolean
|
|
1117
|
+
return new cdsTypes.Boolean.constructor()
|
|
1127
1118
|
case 'number':
|
|
1128
|
-
return Number.isSafeInteger(val) ? cdsTypes.Integer : cdsTypes.Decimal
|
|
1119
|
+
return Number.isSafeInteger(val) ? new cdsTypes.Integer.constructor() : new cdsTypes.Decimal.constructor()
|
|
1129
1120
|
default:
|
|
1130
1121
|
return {}
|
|
1131
1122
|
}
|
package/lib/infer/pseudos.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const cds = require('@sap/cds')
|
|
4
|
+
const { String, Timestamp } = cds.builtin.types
|
|
5
|
+
|
|
5
6
|
const pseudos = {
|
|
6
7
|
elements: {
|
|
7
8
|
$user: {
|
|
8
9
|
elements: {
|
|
9
|
-
id:
|
|
10
|
-
locale:
|
|
11
|
-
tenant:
|
|
10
|
+
id: String,
|
|
11
|
+
locale: String, // deprecated
|
|
12
|
+
tenant: String, // deprecated
|
|
12
13
|
},
|
|
13
14
|
},
|
|
14
|
-
$now:
|
|
15
|
-
$at:
|
|
16
|
-
$from:
|
|
17
|
-
$to:
|
|
18
|
-
$locale:
|
|
19
|
-
$tenant:
|
|
15
|
+
$now: Timestamp,
|
|
16
|
+
$at: Timestamp,
|
|
17
|
+
$from: Timestamp,
|
|
18
|
+
$to: Timestamp,
|
|
19
|
+
$locale: String,
|
|
20
|
+
$tenant: String,
|
|
20
21
|
},
|
|
21
22
|
}
|
|
22
23
|
|
package/lib/search.js
CHANGED
|
@@ -174,7 +174,7 @@ const computeColumnsToBeSearched = (cqn, entity = { __searchableColumns: [] }) =
|
|
|
174
174
|
// only strings can be searched
|
|
175
175
|
if (element?.type !== DEFAULT_SEARCHABLE_TYPE) {
|
|
176
176
|
if (column.xpr) return
|
|
177
|
-
if (column.func && !(column.func in aggregateFunctions)) return
|
|
177
|
+
if (column.func && !(column.func.toUpperCase() in aggregateFunctions)) return
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
const searchTerm = {}
|
package/package.json
CHANGED