@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
@@ -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) => {
@@ -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 )); // invalidate caches
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
  *
@@ -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')
@@ -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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "3.6.0",
3
+ "version": "3.6.2",
4
4
  "description": "CDS (Core Data Services) compiler and backends",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "author": "SAP SE (https://www.sap.com)",