@sap/cds-compiler 3.6.0 → 3.6.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
CHANGED
|
@@ -7,6 +7,15 @@
|
|
|
7
7
|
Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
|
|
10
|
+
## Version 3.6.2 - 2023-02-06
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- to.hdi(.migration): Don't render `-- generated by cds-compiler version` comment at the top of the HDI-based
|
|
15
|
+
artifacts, as this caused HDI to detect the file as `changed`
|
|
16
|
+
and redeploy, causing way longer deployment times. Old behavior can be enabled with option `generatedByComment: true`.
|
|
17
|
+
- to.sql/hdi/hdbcds: Correctly handle variables like `$user` in `exists` filters.
|
|
18
|
+
|
|
10
19
|
## Version 3.6.0 - 2023-01-25
|
|
11
20
|
|
|
12
21
|
### Added
|
package/lib/api/options.js
CHANGED
|
@@ -28,6 +28,7 @@ const publicOptionsNewAPI = [
|
|
|
28
28
|
'magicVars', // deprecated, not removed in v3 as we have specific error messages for it
|
|
29
29
|
'variableReplacements',
|
|
30
30
|
'pre2134ReferentialConstraintNames',
|
|
31
|
+
'generatedByComment',
|
|
31
32
|
// ODATA
|
|
32
33
|
'odataVersion',
|
|
33
34
|
'odataFormat',
|
|
@@ -120,14 +121,14 @@ module.exports = {
|
|
|
120
121
|
cdl: options => translateOptions(options, undefined, undefined, undefined, undefined, 'to.cdl'),
|
|
121
122
|
sql: (options) => {
|
|
122
123
|
const hardOptions = { src: 'sql', toSql: true, forHana: true };
|
|
123
|
-
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'plain' };
|
|
124
|
+
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'plain', generatedByComment: true };
|
|
124
125
|
const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'sql-dialect-and-naming' ], 'to.sql');
|
|
125
126
|
|
|
126
127
|
return Object.assign({}, processed);
|
|
127
128
|
},
|
|
128
129
|
hdi: (options) => {
|
|
129
130
|
const hardOptions = { src: 'hdi', toSql: true, forHana: true };
|
|
130
|
-
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'hana' };
|
|
131
|
+
const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'hana', generatedByComment: false };
|
|
131
132
|
return translateOptions(options, defaultOptions, hardOptions, { sqlDialect: generateStringValidator([ 'hana' ]) }, undefined, 'to.hdi');
|
|
132
133
|
},
|
|
133
134
|
hdbcds: (options) => {
|
package/lib/model/csnRefs.js
CHANGED
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
// const csnPath = ['definitions','P','projection','columns',0];
|
|
75
75
|
// const subElement = inspectRef( csnPath ); // type T is involved
|
|
76
76
|
// csn.definitions.T.type = 'some.other.type';
|
|
77
|
-
// // ({ inspectRef } = csnRefs( csn )); //
|
|
77
|
+
// // ({ inspectRef } = csnRefs( csn )); // drop caches
|
|
78
78
|
// … = inspectRef( csnPath ); // type T - using the cached or the new?
|
|
79
79
|
//
|
|
80
80
|
// On request, we might add a functions for individual cache invalidations or
|
|
@@ -155,6 +155,8 @@
|
|
|
155
155
|
// which contains cached data. Such data can be a link to a CSN node (like
|
|
156
156
|
// `_effectiveType`/`elements`), scalar (like `$queryNumber`) or link to
|
|
157
157
|
// another cache object (like `$next`).
|
|
158
|
+
// - A cache entry must not link to a cache object of another main definition;
|
|
159
|
+
// otherwise, individual cache invalidation does not work.
|
|
158
160
|
// - Usually, each CSN object has an individual cache object.
|
|
159
161
|
// - For CSN queries nodes, cache objects are _shared_: both the CSN nodes
|
|
160
162
|
// `‹query› = { SELECT: ‹select›, … }` and `‹select›` share the same cache
|
|
@@ -260,6 +262,7 @@ function csnRefs( csn, universalReady ) {
|
|
|
260
262
|
getColumn: elem => getCache( elem, '_column' ),
|
|
261
263
|
getElement: col => getCache( col, '_element' ),
|
|
262
264
|
initDefinition,
|
|
265
|
+
dropDefinitionCache,
|
|
263
266
|
targetAspect,
|
|
264
267
|
__getCache_forEnrichCsnDebugging: obj => cache.get( obj ),
|
|
265
268
|
};
|
|
@@ -486,6 +489,31 @@ function csnRefs( csn, universalReady ) {
|
|
|
486
489
|
setCache( art, '$origin$step', (kind === 'element' ? step : { [kind]: step }) );
|
|
487
490
|
}
|
|
488
491
|
|
|
492
|
+
function dropDefinitionCache( main ) {
|
|
493
|
+
const queries = getCache( main, '$queries' );
|
|
494
|
+
if (!queries) // not yet initialized
|
|
495
|
+
return;
|
|
496
|
+
if (!cache.delete( main )) // not yet initialized
|
|
497
|
+
return;
|
|
498
|
+
for (const qcache of queries || []) {
|
|
499
|
+
const { _select } = qcache;
|
|
500
|
+
for (const n of Object.keys( _select.mixin || {} ))
|
|
501
|
+
cache.delete( _select.mixin[n] );
|
|
502
|
+
dropColumnsCache( _select.columns );
|
|
503
|
+
traverseDef( _select, null, null, null, a => cache.delete( a ) ); // elements
|
|
504
|
+
}
|
|
505
|
+
traverseDef( main, null, null, null, a => cache.delete( a ) );
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function dropColumnsCache( select ) {
|
|
509
|
+
if (!select)
|
|
510
|
+
return;
|
|
511
|
+
for (const col of select.columns || select.expand || select.inline || []) {
|
|
512
|
+
dropColumnsCache( col );
|
|
513
|
+
cache.delete( select );
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
489
517
|
/**
|
|
490
518
|
* @param {CSN.Path} csnPath
|
|
491
519
|
*
|
package/lib/optionProcessor.js
CHANGED
|
@@ -293,6 +293,7 @@ optionProcessor.command('Q, toSql')
|
|
|
293
293
|
.option(' --constraints-in-create-table')
|
|
294
294
|
.option(' --pre2134ReferentialConstraintNames')
|
|
295
295
|
.option(' --disable-hana-comments')
|
|
296
|
+
.option(' --generated-by-comment')
|
|
296
297
|
.help(`
|
|
297
298
|
Usage: cdsc toSql [options] <files...>
|
|
298
299
|
|
|
@@ -343,6 +344,8 @@ optionProcessor.command('Q, toSql')
|
|
|
343
344
|
"ALTER TABLE ADD CONSTRAINT" statements
|
|
344
345
|
--pre2134ReferentialConstraintNames Do not prefix the constraint identifier with "c__"
|
|
345
346
|
--disable-hana-comments Disable rendering of doc comments as SAP HANA comments.
|
|
347
|
+
--generated-by-comment Enable rendering of the initial SQL comment for HDI-based artifacts
|
|
348
|
+
|
|
346
349
|
`);
|
|
347
350
|
|
|
348
351
|
optionProcessor.command('toRename')
|
package/lib/render/toSql.js
CHANGED
|
@@ -230,7 +230,7 @@ function toSqlDdl( csn, options ) {
|
|
|
230
230
|
sourceString = sourceString.slice('COLUMN '.length);
|
|
231
231
|
sql[name] = `${options.testMode ? '' : sqlVersionLine}CREATE ${sourceString};`;
|
|
232
232
|
}
|
|
233
|
-
else if (!options.testMode) {
|
|
233
|
+
else if (!options.testMode && options.generatedByComment) {
|
|
234
234
|
mainResultObj[hdbKind][name] = sqlVersionLine + mainResultObj[hdbKind][name];
|
|
235
235
|
}
|
|
236
236
|
}
|
|
@@ -253,7 +253,7 @@ function toSqlDdl( csn, options ) {
|
|
|
253
253
|
mainResultObj.sql = sql;
|
|
254
254
|
|
|
255
255
|
for (const name in deletions)
|
|
256
|
-
deletions[name] = `${options.testMode ? '' : sqlVersionLine}${deletions[name]}`;
|
|
256
|
+
deletions[name] = `${options.testMode || !options.generatedByComment ? '' : sqlVersionLine}${deletions[name]}`;
|
|
257
257
|
|
|
258
258
|
timetrace.stop('SQL rendering');
|
|
259
259
|
return mainResultObj;
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const { forAllQueries, forEachDefinition, walkCsnPath } = require('../../model/csnUtils');
|
|
4
4
|
const { setProp } = require('../../base/model');
|
|
5
5
|
const { getRealName } = require('../../render/utils/common');
|
|
6
|
-
const { csnRefs } = require('../../model/csnRefs');
|
|
7
6
|
const { ModelError } = require('../../base/error');
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -47,9 +46,11 @@ const { ModelError } = require('../../base/error');
|
|
|
47
46
|
* @param {CSN.Model} csn
|
|
48
47
|
* @param {CSN.Options} options
|
|
49
48
|
* @param {Function} error
|
|
49
|
+
* @param {Function} inspectRef
|
|
50
|
+
* @param {Function} initDefinition
|
|
51
|
+
* @param {Function} dropDefinitionCache
|
|
50
52
|
*/
|
|
51
|
-
function handleExists( csn, options, error ) {
|
|
52
|
-
let { inspectRef } = csnRefs(csn);
|
|
53
|
+
function handleExists( csn, options, error, inspectRef, initDefinition, dropDefinitionCache ) {
|
|
53
54
|
const generatedExists = new WeakMap();
|
|
54
55
|
forEachDefinition(csn, (artifact, artifactName) => {
|
|
55
56
|
if (artifact.projection) // do the same hack we do for the other stuff...
|
|
@@ -78,15 +79,19 @@ function handleExists( csn, options, error ) {
|
|
|
78
79
|
|
|
79
80
|
while (toProcess.length > 0) {
|
|
80
81
|
const [ queryPath, exprPath ] = toProcess.pop();
|
|
82
|
+
// Re-init caches for this artifact
|
|
83
|
+
dropDefinitionCache(artifact);
|
|
84
|
+
initDefinition(artifact);
|
|
81
85
|
// leftovers can happen with nested exists - we then need to drill down into the created SELECT
|
|
82
86
|
// to check for further exists
|
|
83
87
|
const { result, leftovers } = processExists(queryPath, exprPath);
|
|
84
88
|
walkCsnPath(csn, exprPath.slice(0, -1))[exprPath[exprPath.length - 1]] = result;
|
|
85
|
-
if (leftovers.length > 0)
|
|
86
|
-
inspectRef = csnRefs(csn).inspectRef; // Refresh caches - we need to resolve stuff in the newly created subquery
|
|
87
89
|
leftovers.reverse();
|
|
88
90
|
toProcess.push(...leftovers); // any leftovers - schedule for further processing
|
|
89
91
|
}
|
|
92
|
+
// Make sure we leave csnRefs usable
|
|
93
|
+
dropDefinitionCache(artifact);
|
|
94
|
+
initDefinition(artifact);
|
|
90
95
|
}
|
|
91
96
|
}, [ 'definitions', artifactName, 'query' ]);
|
|
92
97
|
}
|
|
@@ -764,7 +769,7 @@ function handleExists( csn, options, error ) {
|
|
|
764
769
|
*/
|
|
765
770
|
function remapExistingWhere( target, where ) {
|
|
766
771
|
return where.map((part) => {
|
|
767
|
-
if (part.ref) {
|
|
772
|
+
if (part.ref && part.$scope !== '$magic') {
|
|
768
773
|
part.ref = [ target, ...part.ref ];
|
|
769
774
|
return part;
|
|
770
775
|
}
|
|
@@ -121,6 +121,8 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
121
121
|
let artifactRef,
|
|
122
122
|
inspectRef,
|
|
123
123
|
effectiveType,
|
|
124
|
+
initDefinition,
|
|
125
|
+
dropDefinitionCache,
|
|
124
126
|
get$combined,
|
|
125
127
|
getCsnDef,
|
|
126
128
|
isAssocOrComposition,
|
|
@@ -159,7 +161,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
159
161
|
timetrace.stop('Validate');
|
|
160
162
|
|
|
161
163
|
// Needs to happen before tuple expansion, so the newly generated WHERE-conditions have it applied
|
|
162
|
-
handleExists(csn, options, error);
|
|
164
|
+
handleExists(csn, options, error, inspectRef, initDefinition, dropDefinitionCache);
|
|
163
165
|
|
|
164
166
|
// Check if structured elements and managed associations are compared in an expression
|
|
165
167
|
// and expand these structured elements. This tuple expansion allows all other
|
|
@@ -441,6 +443,8 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
441
443
|
({ artifactRef,
|
|
442
444
|
inspectRef,
|
|
443
445
|
effectiveType,
|
|
446
|
+
initDefinition,
|
|
447
|
+
dropDefinitionCache,
|
|
444
448
|
get$combined,
|
|
445
449
|
getCsnDef,
|
|
446
450
|
isAssocOrComposition,
|
|
@@ -451,7 +455,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
451
455
|
|
|
452
456
|
function bindCsnReferenceOnly(){
|
|
453
457
|
// invalidate caches for CSN ref API
|
|
454
|
-
({ artifactRef, inspectRef, effectiveType } = csnRefs(csn));
|
|
458
|
+
({ artifactRef, inspectRef, effectiveType, initDefinition, dropDefinitionCache } = csnRefs(csn));
|
|
455
459
|
}
|
|
456
460
|
|
|
457
461
|
function handleMixinOnConditions(artifact, artifactName) {
|