@cap-js/db-service 1.17.2 → 1.19.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.
- package/CHANGELOG.md +29 -0
- package/lib/InsertResults.js +1 -1
- package/lib/SQLService.js +5 -5
- package/lib/common/session-context.js +2 -2
- package/lib/cql-functions.js +88 -256
- package/lib/cqn2sql.js +57 -45
- package/lib/cqn4sql.js +102 -75
- package/lib/deep-queries.js +4 -4
- package/lib/fill-in-keys.js +1 -1
- package/lib/infer/index.js +9 -14
- package/lib/utils.js +26 -1
- package/package.json +1 -2
package/lib/fill-in-keys.js
CHANGED
|
@@ -59,7 +59,7 @@ module.exports = async function fill_in_keys(req, next) {
|
|
|
59
59
|
// REVISIT dummy handler until we have input processing
|
|
60
60
|
if (!req.target || !this.model || req.target._unresolved) return next()
|
|
61
61
|
// only for deep update
|
|
62
|
-
if (req.event === 'UPDATE' && hasDeep(req.query
|
|
62
|
+
if (req.event === 'UPDATE' && hasDeep(req.query)) {
|
|
63
63
|
// REVISIT for deep update we need to inject the keys first
|
|
64
64
|
enrichDataWithKeysFromWhere(req.data, req, this)
|
|
65
65
|
}
|
package/lib/infer/index.js
CHANGED
|
@@ -4,7 +4,7 @@ const cds = require('@sap/cds')
|
|
|
4
4
|
|
|
5
5
|
const JoinTree = require('./join-tree')
|
|
6
6
|
const { pseudos } = require('./pseudos')
|
|
7
|
-
const { isCalculatedOnRead } = require('../utils')
|
|
7
|
+
const { isCalculatedOnRead, getImplicitAlias } = require('../utils')
|
|
8
8
|
const cdsTypes = cds.linked({
|
|
9
9
|
definitions: {
|
|
10
10
|
Timestamp: { type: 'cds.Timestamp' },
|
|
@@ -47,21 +47,16 @@ function infer(originalQuery, model) {
|
|
|
47
47
|
const sources = inferTarget(_.from || _.into || _.entity, {})
|
|
48
48
|
const joinTree = new JoinTree(sources)
|
|
49
49
|
const aliases = Object.keys(sources)
|
|
50
|
+
const target = aliases.length === 1 ? getDefinitionFromSources(sources, aliases[0]) : originalQuery
|
|
50
51
|
Object.defineProperties(inferred, {
|
|
51
52
|
// REVISIT: public, or for local reuse, or in cqn4sql only?
|
|
52
53
|
sources: { value: sources, writable: true },
|
|
53
|
-
target:
|
|
54
|
-
value: aliases.length === 1 ? getDefinitionFromSources(sources, aliases[0]) : originalQuery,
|
|
55
|
-
writable: true,
|
|
56
|
-
}, // REVISIT: legacy?
|
|
54
|
+
_target: { value: target, writable: true, configurable: true }, // REVISIT: legacy?
|
|
57
55
|
})
|
|
58
56
|
// also enrich original query -> writable because it may be inferred again
|
|
59
57
|
Object.defineProperties(originalQuery, {
|
|
60
58
|
sources: { value: sources, writable: true },
|
|
61
|
-
target:
|
|
62
|
-
value: aliases.length === 1 ? getDefinitionFromSources(sources, aliases[0]) : originalQuery,
|
|
63
|
-
writable: true,
|
|
64
|
-
},
|
|
59
|
+
_target: { value: target, writable: true, configurable: true },
|
|
65
60
|
})
|
|
66
61
|
if (originalQuery.SELECT || originalQuery.DELETE || originalQuery.UPDATE) {
|
|
67
62
|
$combinedElements = inferCombinedElements()
|
|
@@ -97,7 +92,7 @@ function infer(originalQuery, model) {
|
|
|
97
92
|
* Each key is a query source alias, and its value is the corresponding CSN Definition.
|
|
98
93
|
* @returns {object} The updated `querySources` object with inferred sources from the `from` clause.
|
|
99
94
|
*/
|
|
100
|
-
function inferTarget(from, querySources) {
|
|
95
|
+
function inferTarget(from, querySources, useTechnicalAlias = true) {
|
|
101
96
|
const { ref } = from
|
|
102
97
|
if (ref) {
|
|
103
98
|
const { id, args } = ref[0]
|
|
@@ -119,14 +114,14 @@ function infer(originalQuery, model) {
|
|
|
119
114
|
from.uniqueSubqueryAlias ||
|
|
120
115
|
from.as ||
|
|
121
116
|
(ref.length === 1
|
|
122
|
-
?
|
|
123
|
-
: (ref.at(-1).id || ref.at(-1)));
|
|
117
|
+
? getImplicitAlias(first, useTechnicalAlias)
|
|
118
|
+
: getImplicitAlias(ref.at(-1).id || ref.at(-1), useTechnicalAlias));
|
|
124
119
|
if (alias in querySources) throw new Error(`Duplicate alias "${alias}"`)
|
|
125
120
|
querySources[alias] = { definition: target, args }
|
|
126
121
|
const last = from.$refLinks.at(-1)
|
|
127
122
|
last.alias = alias
|
|
128
123
|
} else if (from.args) {
|
|
129
|
-
from.args.forEach(a => inferTarget(a, querySources))
|
|
124
|
+
from.args.forEach(a => inferTarget(a, querySources, false))
|
|
130
125
|
} else if (from.SELECT) {
|
|
131
126
|
const subqueryInFrom = infer(from, model) // we need the .elements in the sources
|
|
132
127
|
// if no explicit alias is provided, we make up one
|
|
@@ -136,7 +131,7 @@ function infer(originalQuery, model) {
|
|
|
136
131
|
} else if (typeof from === 'string') {
|
|
137
132
|
// TODO: Create unique alias, what about duplicates?
|
|
138
133
|
const definition = getDefinition(from) || cds.error`"${from}" not found in the definitions of your model`
|
|
139
|
-
querySources[
|
|
134
|
+
querySources[getImplicitAlias(from, useTechnicalAlias)] = { definition }
|
|
140
135
|
} else if (from.SET) {
|
|
141
136
|
infer(from, model)
|
|
142
137
|
}
|
package/lib/utils.js
CHANGED
|
@@ -38,9 +38,34 @@ function isCalculatedElement(def) {
|
|
|
38
38
|
return def?.value
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Calculates the implicit table alias for a given string.
|
|
43
|
+
*
|
|
44
|
+
* Based on the last part of the string, the implicit alias is calculated
|
|
45
|
+
* by taking the first character and prepending it with '$'.
|
|
46
|
+
* A leading '$' is removed if the last part already starts with '$'.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* getImplicitAlias('Books') => '$B'
|
|
50
|
+
* getImplicitAlias('bookshop.Books') => '$B'
|
|
51
|
+
* getImplicitAlias('bookshop.$B') => '$B'
|
|
52
|
+
*
|
|
53
|
+
* @param {string} str - The input string.
|
|
54
|
+
* @returns {string}
|
|
55
|
+
*/
|
|
56
|
+
function getImplicitAlias(str, useTechnicalAlias = true) {
|
|
57
|
+
const index = str.lastIndexOf('.')
|
|
58
|
+
if(useTechnicalAlias) {
|
|
59
|
+
const postfix = (index != -1 ? str.substring(index + 1) : str).replace(/^\$/, '')[0] || /* str === '$' */ '$'
|
|
60
|
+
return '$' + postfix
|
|
61
|
+
}
|
|
62
|
+
return index != -1 ? str.substring(index + 1) : str
|
|
63
|
+
}
|
|
64
|
+
|
|
41
65
|
// export the function to be used in other modules
|
|
42
66
|
module.exports = {
|
|
43
67
|
prettyPrintRef,
|
|
44
68
|
isCalculatedOnRead,
|
|
45
|
-
isCalculatedElement
|
|
69
|
+
isCalculatedElement,
|
|
70
|
+
getImplicitAlias,
|
|
46
71
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js/db-service",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"description": "CDS base database service",
|
|
5
5
|
"homepage": "https://github.com/cap-js/cds-dbs/tree/main/db-service#cds-base-database-service",
|
|
6
6
|
"repository": {
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
],
|
|
17
17
|
"author": "SAP SE (https://www.sap.com)",
|
|
18
18
|
"main": "index.js",
|
|
19
|
-
"types": "./dist/index.d.ts",
|
|
20
19
|
"files": [
|
|
21
20
|
"lib",
|
|
22
21
|
"CHANGELOG.md"
|