@sap/cds-compiler
Advanced tools
Comparing version 2.10.2 to 2.10.4
@@ -11,2 +11,8 @@ # ChangeLog of Beta Features for cdx compiler and backends | ||
## Version 2.10.4 | ||
### Fixed `nestedProjections` | ||
- to.sql/hdi/hdbcds: Correctly handle a `*` at the not-first place in the query | ||
## Version 2.6.0 | ||
@@ -13,0 +19,0 @@ |
@@ -1110,2 +1110,5 @@ 'use strict'; | ||
function dictionary( node, prop, dict ) { | ||
// Allow skipping dicts like actions in forHanaNew | ||
if(options.skipDict && options.skipDict[prop]) | ||
return; | ||
csnPath.push( prop ); | ||
@@ -1112,0 +1115,0 @@ for (let name of Object.getOwnPropertyNames( dict )) { |
@@ -388,3 +388,3 @@ | ||
return def.old.type === def.new.type && | ||
[ 'length', 'precision', 'scale' ].some(param => def.new[param] < def.old[param]); | ||
[ 'length', 'precision', 'scale' ].some(param => def.new[param] < def.old[param]); | ||
} | ||
@@ -529,3 +529,3 @@ function getEltStr(defVariant, eltName) { | ||
if (renderReferentialConstraintsAsHdbconstraint) { | ||
Object.entries(referentialConstraints).forEach( ([ fileName, constraint ]) => { | ||
Object.entries(referentialConstraints).forEach(([ fileName, constraint ]) => { | ||
resultObj.hdbconstraint[fileName] = constraint; | ||
@@ -535,3 +535,3 @@ }); | ||
else { | ||
Object.values(referentialConstraints).forEach( (constraint) => { | ||
Object.values(referentialConstraints).forEach((constraint) => { | ||
result += `,\n${constraint}`; | ||
@@ -552,4 +552,3 @@ }); | ||
else { | ||
result += `,\n${childEnv.indent}CONSTRAINT ${renderArtifactName(`${artifactName}_${cn}`)} UNIQUE (${ | ||
c.map(cpath => quoteSqlId(cpath.ref[0])).join(', ')})`; | ||
result += `,\n${childEnv.indent}CONSTRAINT ${renderArtifactName(`${artifactName}_${cn}`)} UNIQUE (${c.map(cpath => quoteSqlId(cpath.ref[0])).join(', ')})`; | ||
} | ||
@@ -666,4 +665,3 @@ } | ||
let result = `${env.indent + quotedElementName} ${ | ||
renderTypeReference(artifactName, elementName, elm) | ||
let result = `${env.indent + quotedElementName} ${renderTypeReference(artifactName, elementName, elm) | ||
}${renderNullability(elm, true)}`; | ||
@@ -964,3 +962,3 @@ if (elm.default) | ||
if (ref && ref.params) { | ||
result += `(${renderArgs(path.ref[0].args || {}, '=>', env, syntax)})`; | ||
result += `(${renderArgs(path.ref[0] || {}, '=>', env, syntax)})`; | ||
} | ||
@@ -987,3 +985,3 @@ else if ([ 'udf' ].includes(syntax)) { | ||
* | ||
* @param {Array|object} args Arguments to render | ||
* @param {object} node with `args` to render | ||
* @param {string} sep Separator between args | ||
@@ -995,3 +993,4 @@ * @param {object} env Render environment | ||
*/ | ||
function renderArgs(args, sep, env, syntax) { | ||
function renderArgs(node, sep, env, syntax) { | ||
const args = node.args ? node.args : {}; | ||
// Positional arguments | ||
@@ -1003,3 +1002,4 @@ if (Array.isArray(args)) | ||
else if (typeof args === 'object') | ||
return Object.keys(args).map(key => `${decorateParameter(key, syntax)} ${sep} ${renderExpr(args[key], env)}`).join(', '); | ||
// if this is a function param which is not a reference to the model, we must not quote it | ||
return Object.keys(args).map(key => `${node.func ? key : decorateParameter(key, syntax)} ${sep} ${renderExpr(args[key], env)}`).join(', '); | ||
@@ -1163,8 +1163,7 @@ | ||
// FIXME: We probably also need to consider `excluding` here ? | ||
result += `\n${ | ||
(select.columns || [ '*' ]) | ||
.filter(col => !(select.mixin || Object.create(null))[firstPathStepId(col.ref)]) // No mixin columns | ||
.map(col => renderViewColumn(col, childEnv)) | ||
.filter(s => s !== '') | ||
.join(',\n')}\n`; | ||
result += `\n${(select.columns || [ '*' ]) | ||
.filter(col => !(select.mixin || Object.create(null))[firstPathStepId(col.ref)]) // No mixin columns | ||
.map(col => renderViewColumn(col, childEnv)) | ||
.filter(s => s !== '') | ||
.join(',\n')}\n`; | ||
result += `${env.indent}FROM ${renderViewSource(artifactName, select.from, env)}`; | ||
@@ -1425,6 +1424,6 @@ if (select.where) | ||
case 'null': | ||
// 17.42, NULL, TRUE | ||
// 17.42, NULL, TRUE | ||
return String(x.val).toUpperCase(); | ||
case 'x': | ||
// x'f000' | ||
// x'f000' | ||
return `${x.literal}'${x.val}'`; | ||
@@ -1435,3 +1434,3 @@ case 'date': | ||
if (options.toSql.dialect === 'sqlite') { | ||
// simple string literal '2017-11-02' | ||
// simple string literal '2017-11-02' | ||
return `'${x.val}'`; | ||
@@ -1443,3 +1442,3 @@ } | ||
case 'string': | ||
// 'foo', with proper escaping | ||
// 'foo', with proper escaping | ||
return `'${x.val.replace(/'/g, '\'\'')}'`; | ||
@@ -1609,3 +1608,3 @@ case 'object': | ||
if (s.func) | ||
return `${s.func}(${renderArgs(s.args, '=>', env, null)})`; | ||
return `${s.func}(${renderArgs(s, '=>', env, null)})`; | ||
@@ -1616,3 +1615,3 @@ // Path step, possibly with view parameters and/or filters | ||
// View parameters | ||
result += `(${renderArgs(s.args, '=>', env, null)})`; | ||
result += `(${renderArgs(s, '=>', env, null)})`; | ||
} | ||
@@ -1619,0 +1618,0 @@ if (s.where) { |
@@ -36,3 +36,3 @@ // Common render functions for toCdl.js, toHdbcds.js and toSql.js | ||
return funcName; | ||
return `${funcName}(${renderArgs( node.args )})`; | ||
return `${funcName}(${renderArgs( node )})`; | ||
} | ||
@@ -39,0 +39,0 @@ |
@@ -555,3 +555,3 @@ 'use strict'; | ||
// The thing is shadowed - ignore names present because of .inline, as those "disappear" | ||
if (names[part] && !subs[names[part]].inline) { | ||
if (names[part] !== undefined && !subs[names[part]].inline) { | ||
replaced[part] = true; | ||
@@ -558,0 +558,0 @@ star.push(subs[names[part]]); |
@@ -106,3 +106,3 @@ 'use strict'; | ||
} | ||
} ]); | ||
} ], true, { skipDict: { actions: true } }); | ||
} | ||
@@ -109,0 +109,0 @@ |
@@ -252,2 +252,11 @@ 'use strict'; | ||
} = getFirstAssoc(current, exprPath.concat(i)); | ||
const lastAssoc = getLastAssoc(current, exprPath.concat(i)); | ||
// toE.toF.id -> we must not end on a non-assoc - this will also be caught downstream by | ||
// '“EXISTS” can only be used with associations/compositions, found $(TYPE)' | ||
// But the error might not be clear, since it could be because of our rewritten stuff. The later check | ||
// checks for exists id -> our rewrite turns toE.toF.id into toE[exists toF[exists id]], leading to the same error | ||
if (lastAssoc.tail.length > 0) | ||
error(null, current.$path, { id: lastAssoc.tail[0].id ? lastAssoc.tail[0].id : lastAssoc.tail[0], name: lastAssoc.ref.id ? lastAssoc.ref.id : lastAssoc.ref }, 'Unexpected path step $(ID) after association $(NAME) in "EXISTS"'); | ||
const newThing = [ ...head, nestFilters(head.length + 1, ref, tail, exprPath.concat([ i ])) ]; | ||
@@ -282,11 +291,6 @@ expr[i].ref = newThing; | ||
const base = getBase(queryBase, isPrefixedWithTableAlias, current, exprPath.concat(i)); | ||
const { root, ref, tail } = getFirstAssoc(current, exprPath.concat(i)); | ||
const { root, ref } = getFirstAssoc(current, exprPath.concat(i)); | ||
if (tail.length > 0) { | ||
error(null, current.$path, { id: tail[0].id ? tail[0].id : tail[0], name: ref.id ? ref.id : ref }, 'Unexpected path step $(ID) after association $(NAME) in "EXISTS"'); | ||
continue; | ||
} | ||
if (!root.target) { | ||
error(null, current.$path, { type: root.type }, '“EXISTS” can only be used with associations/compositions, found $(TYPE)'); | ||
error(null, exprPath.concat(i), { type: root.type }, '“EXISTS” can only be used with associations/compositions, found $(TYPE)'); | ||
return { result: [], leftovers: [] }; | ||
@@ -483,2 +487,23 @@ } | ||
/** | ||
* Get the last association from the expression part - similar to getFirstAssoc | ||
* | ||
* @param {object} xprPart | ||
* @param {CSN.Path} path | ||
* @returns {{head: Array, root: CSN.Element, ref: string|object, tail: Array}} The last assoc (root), the corresponding ref (ref), anything before the ref (head) and the rest of the ref (tail). | ||
*/ | ||
function getLastAssoc(xprPart, path) { | ||
const { links, art } = inspectRef(path); | ||
for (let i = xprPart.ref.length - 1; i > -1; i--) { | ||
if (links[i].art && links[i].art.target) { | ||
return { | ||
head: (i === 0 ? [] : xprPart.ref.slice(0, i)), root: links[i].art, ref: xprPart.ref[i], tail: xprPart.ref.slice(i + 1), | ||
}; | ||
} | ||
} | ||
return { | ||
head: (xprPart.ref.length === 1 ? [] : xprPart.ref.slice(0, xprPart.ref.length - 1)), root: art, ref: xprPart.ref[xprPart.ref.length - 1], tail: [], | ||
}; | ||
} | ||
/** | ||
* Check (using inspectRef -> links), wether the first path step is an entity or query source | ||
@@ -485,0 +510,0 @@ * |
@@ -13,3 +13,3 @@ // The module traverses a given CSN using a specific path, collects structural node names and returns them. | ||
keys: traverseArray, | ||
ref: traverseRef, | ||
ref: traverseArray, | ||
query: traverseTyped, | ||
@@ -37,6 +37,2 @@ SELECT: traverseTyped, | ||
function traverseRef(obj, path, index, typeStack) { | ||
return traverseArray(obj, path, index, typeStack); | ||
} | ||
function traverseArray(obj, path, index, typeStack) { | ||
@@ -43,0 +39,0 @@ if(!Array.isArray(obj)) return typeStack; |
{ | ||
"name": "@sap/cds-compiler", | ||
"version": "2.10.2", | ||
"version": "2.10.4", | ||
"description": "CDS (Core Data Services) compiler and backends", | ||
@@ -5,0 +5,0 @@ "homepage": "https://cap.cloud.sap/", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3646338
72546