@sap/cds-compiler 6.6.2 → 6.7.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +37 -1
  2. package/bin/cdsc.js +2 -0
  3. package/bin/cdsse.js +1 -1
  4. package/lib/base/message-registry.js +13 -7
  5. package/lib/base/model.js +0 -72
  6. package/lib/checks/elements.js +1 -1
  7. package/lib/checks/featureFlags.js +2 -2
  8. package/lib/checks/manyExpand.js +28 -0
  9. package/lib/checks/validator.js +2 -0
  10. package/lib/compiler/assert-consistency.js +3 -4
  11. package/lib/compiler/base.js +8 -0
  12. package/lib/compiler/builtins.js +8 -9
  13. package/lib/compiler/checks.js +27 -6
  14. package/lib/compiler/cycle-detector.js +4 -4
  15. package/lib/compiler/define.js +65 -83
  16. package/lib/compiler/extend.js +357 -325
  17. package/lib/compiler/finalize-parse-cdl.js +3 -4
  18. package/lib/compiler/generate.js +205 -203
  19. package/lib/compiler/kick-start.js +34 -49
  20. package/lib/compiler/populate.js +95 -28
  21. package/lib/compiler/propagator.js +3 -5
  22. package/lib/compiler/resolve.js +17 -13
  23. package/lib/compiler/shared.js +52 -20
  24. package/lib/compiler/tweak-assocs.js +2 -4
  25. package/lib/compiler/utils.js +84 -31
  26. package/lib/edm/edmAnnoPreprocessor.js +2 -2
  27. package/lib/gen/BaseParser.js +924 -1055
  28. package/lib/gen/CdlGrammar.checksum +1 -1
  29. package/lib/gen/CdlParser.js +5 -2
  30. package/lib/json/from-csn.js +25 -16
  31. package/lib/main.d.ts +13 -0
  32. package/lib/model/revealInternalProperties.js +18 -0
  33. package/lib/parsers/AstBuildingParser.js +22 -5
  34. package/lib/render/toHdbcds.js +2 -2
  35. package/lib/render/toSql.js +1 -1
  36. package/lib/render/utils/sql.js +2 -2
  37. package/lib/render/utils/standardDatabaseFunctions.js +2 -2
  38. package/lib/transform/db/constraints.js +3 -4
  39. package/lib/transform/db/expansion.js +2 -44
  40. package/lib/transform/db/killAnnotations.js +1 -1
  41. package/lib/transform/db/processSqlServices.js +10 -11
  42. package/lib/transform/effective/main.js +2 -1
  43. package/lib/transform/featureFlags.js +6 -1
  44. package/lib/transform/forOdata.js +7 -124
  45. package/lib/transform/forRelationalDB.js +2 -1
  46. package/lib/transform/odata/fioriTreeViews.js +173 -0
  47. package/lib/transform/odata/flattening.js +2 -2
  48. package/lib/transform/translateAssocsToJoins.js +7 -4
  49. package/package.json +1 -1
  50. package/share/messages/message-explanations.json +0 -2
  51. package/share/messages/type-unexpected-foreign-keys.md +0 -52
  52. package/share/messages/type-unexpected-on-condition.md +0 -52
@@ -1 +1 @@
1
- 2af41f8c84ca1fa40a50b8c58903dadc
1
+ f0320d5264a6107c245a82427b4f6338
@@ -1,6 +1,7 @@
1
- // Parser generated by redepage v0.3.1
1
+ // Parser generated by redepage v0.3.2
2
2
  'use strict;'
3
3
  const { XsnSource, XsnArtifact, XsnName } = require( '../compiler/xsn-model' )
4
+ const { isValidEnumValue } = require( '../compiler/base' )
4
5
  const AstBuildingParser = require('../parsers/AstBuildingParser')
5
6
  const keywords={
6
7
  abstract:0,
@@ -2717,7 +2718,9 @@ case'@':this.annoAssignStd({art},336);continue
2717
2718
  default:this.s=337;continue
2718
2719
  }
2719
2720
  case 337:switch(this.lk()){
2720
- case'Id':case'@':case'key':this.elementDef({outer:$.outer,art},0);continue
2721
+ case'Id':case'@':case'key':if(this.elementDef({outer:$.outer,art},0)){ if (![ 'virtual', 'key', 'masked', '$syntax', 'elements', 'type', 'items' ]
2722
+ .some( p => art[p] ) && isValidEnumValue( art.value ))
2723
+ art.$syntax = 'or-enum'; }continue
2721
2724
  case'extend':this.ckP(338,['Id']);continue
2722
2725
  default:this.ei();continue
2723
2726
  }
@@ -121,6 +121,7 @@ const { isAnnotationExpression } = require('../base/builtins');
121
121
  const { CompilerAssertion } = require('../base/error');
122
122
  const { Location } = require('../base/location');
123
123
  const { XsnSource } = require('../compiler/xsn-model');
124
+ const { isValidEnumValue } = require( '../compiler/base' );
124
125
  const { xsnAsTree, splitClauses } = require('../parsers/XprTree');
125
126
 
126
127
  const $location = Symbol.for('cds.$location');
@@ -734,7 +735,7 @@ const schema = compileSchema( {
734
735
  class: 'expression', // calculated elements
735
736
  vZeroFor: 'val', // CSN v0.1.0 property for `val` in enum def
736
737
  // type: annoValue,
737
- inKind: [ 'element', 'enum' ], // TODO: Remove "enum" again; currently for extensions
738
+ inKind: [ 'element' ],
738
739
  optional: exprProperties.concat([ 'stored' ]),
739
740
  },
740
741
  stored: {
@@ -993,21 +994,15 @@ function definition( def, spec, xsn, csn, name ) {
993
994
  }
994
995
  pushLocation( def );
995
996
  const savedInExtensions = inExtensions;
996
- let kind = calculateKind( def, spec ); // might set inExtensions
997
- const r = (kind === '$column') ? { location: location() } : { location: location(), kind };
997
+ const r = { location: location(), kind: undefined };
998
+ const kind = calculateKind( def, spec, r ); // might set inExtensions
999
+ if (kind !== '$column')
1000
+ r.kind ??= kind;
998
1001
  const xor = {};
999
1002
  const { prop } = spec;
1000
1003
  const kind0 = (spec.validKinds.length || spec.prop === 'extensions') && kind;
1001
1004
  const csnProps = Object.keys( def );
1002
1005
 
1003
- // For compatibility, extension property `elements` could actually be an `enum`:
1004
- if (savedInExtensions === '' && prop === 'elements' && // in extend property `elements`
1005
- !Object.keys( def ).some( couldNotBeEnumProperty )) {
1006
- r.$syntax = 'enum'; // could be an enum
1007
- if (def.val !== undefined || def['#'] !== undefined)
1008
- kind = 'enum'; // for function expected(), i.e. allow property `val`/`#`
1009
- }
1010
-
1011
1006
  if (csnProps.length) {
1012
1007
  const valueName = (prop === 'keys' || prop === 'foreignKeys' ? 'targetElement' : 'value');
1013
1008
  // the next is basically object() + the inValue handling
@@ -1057,17 +1052,19 @@ function namespace( ref, spec ) {
1057
1052
  return ns ? { kind: 'namespace', name: ns } : null;
1058
1053
  }
1059
1054
 
1060
- function couldNotBeEnumProperty( prop ) {
1061
- // returns true for `value` (which we allow with warning when extending an enum with `elements`)
1055
+ function couldBeEnumProperty( prop ) {
1062
1056
  const inKind = schema[prop]?.inKind; // undefined for annotations, $location, …
1063
1057
  // inKind for annotation assignments is function -> can be for enum
1064
- return Array.isArray( inKind ) && inKind.includes( 'element' );
1058
+ return inKind && // `value` handled extra
1059
+ (!Array.isArray( inKind ) || prop === 'value' || inKind.includes( 'enum' ));
1065
1060
  }
1066
1061
 
1067
1062
  function actions( def, spec, xsn, csn, name ) {
1068
1063
  if (def.kind === 'extend' && (def.elements || def.enum)) {
1069
1064
  // TODO: Handle this case in extend.js; already done for `returns`
1070
1065
  // See message ext-expecting-returns
1066
+ // TODO: the location would also bad here
1067
+ // (should be at the property, not containing object - but we remove this anyway)
1071
1068
  error( 'syntax-unexpected-property', location(true), {
1072
1069
  '#': def.kind,
1073
1070
  prop: def.enum ? 'enum' : 'elements',
@@ -1873,7 +1870,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
1873
1870
  return { type: ignore };
1874
1871
  }
1875
1872
 
1876
- function calculateKind( def, spec ) {
1873
+ function calculateKind( def, spec, xsn ) {
1877
1874
  if (inExtensions) {
1878
1875
  inExtensions = spec.defaultKind;
1879
1876
  return 'annotate';
@@ -1883,9 +1880,21 @@ function calculateKind( def, spec ) {
1883
1880
  return (def.extend) ? 'extend' : 'annotate';
1884
1881
  }
1885
1882
  const kind = (def.kind === 'view') ? 'entity' : def.kind; // 'view' is CSN v0.1.0
1886
- if (kind === 'extend' && inExtensions === '') // valid extend -> keep inExtensions
1883
+ const inExtend = inExtensions === '';
1884
+ if (inExtend && kind === 'extend') // extend in extend -> keep inExtensions
1887
1885
  return 'extend';
1888
1886
  inExtensions = null;
1887
+ // Compatibilitity: object rendered in `elements` of extend might be enum:
1888
+ if (inExtend && !def.kind && spec.defaultKind === 'element' &&
1889
+ Object.keys( def ).every( couldBeEnumProperty )) {
1890
+ if (isValidEnumValue( def.value ))
1891
+ xsn.$syntax = 'or-enum'; // could be an enum
1892
+ xsn.kind = 'element';
1893
+ // We also allow a `val` which is not embedded in a `value` also on an element
1894
+ // def inside extensions, because that is how compiler v3 has written it:
1895
+ if (def.val && !def.value)
1896
+ return 'enum'; // use schema of enum (for `val`)
1897
+ }
1889
1898
  if (!spec.validKinds.includes( kind ))
1890
1899
  return spec.defaultKind;
1891
1900
  return (def.abstract || def.$syntax === 'aspect')
package/lib/main.d.ts CHANGED
@@ -313,6 +313,19 @@ declare namespace compiler {
313
313
  * @private
314
314
  */
315
315
  edm4OpenAPI?: boolean
316
+ /**
317
+ * Enable the draft-generated artifacts to handle state messages.
318
+ *
319
+ * @since v6.1.0
320
+ */
321
+ draftMessages?: boolean
322
+ /**
323
+ * Add `CreatedByUserDescription`, `LastChangedByUserDescription` and
324
+ * `InProcessByUserDescription` fields to the `DraftAdministrativeData` entity.
325
+ *
326
+ * @since v6.6.0
327
+ */
328
+ draftUserDescription?: boolean
316
329
  }
317
330
 
318
331
  /**
@@ -8,6 +8,8 @@
8
8
  // This function should return a meaningful result in all circumstances:
9
9
  // * with --parse-only, with both CDL and CSN input,
10
10
  // * for the core compiler output and all transformations working on the XSN.
11
+ //
12
+ // TODO: make sure that all extend statements are listed)
11
13
 
12
14
  'use strict';
13
15
 
@@ -95,6 +97,7 @@ function revealInternalProperties( model, nameOrPath ) {
95
97
  _layerExtends: layerExtends,
96
98
  _origin: origin,
97
99
  $compositionTargets: d => d, // dictionary( boolean )
100
+ _extensions: revealExtensions,
98
101
  _extend: reveal,
99
102
  _annotate: reveal,
100
103
  _annotateS: artifactIdentifier,
@@ -270,6 +273,21 @@ function revealInternalProperties( model, nameOrPath ) {
270
273
  return artifactDictionary( node, parent );
271
274
  }
272
275
 
276
+ function revealExtensions( node ) {
277
+ if (Array.isArray( node ))
278
+ return array( node, revealSingleExtension );
279
+ const r = {};
280
+ for (const prop in node)
281
+ r[prop] = revealExtensions( node[prop] );
282
+ return r;
283
+ }
284
+
285
+ function revealSingleExtension( node, parent ) {
286
+ return (node.kind && node.__unique_id__ == null && node.$effectiveSeqNo == null && !node.builtin)
287
+ ? reveal( node, parent )
288
+ : artifactIdentifier( node, parent );
289
+ }
290
+
273
291
  function reveal( node, parent, name ) {
274
292
  if (node == null || typeof node !== 'object' )
275
293
  return node;
@@ -39,6 +39,17 @@ const valueTokens = {
39
39
  true: true,
40
40
  };
41
41
  const valueTokensLength = Object.values( valueTokens ).length;
42
+ // likewise, if expectedArray contains all the following tokens, replace them by 'Literal'
43
+ const literalTokens = {
44
+ Number: true,
45
+ QuotedLiteral: true,
46
+ String: true,
47
+ '#': true,
48
+ true: true,
49
+ false: true,
50
+ null: true,
51
+ };
52
+ const literalTokensLength = Object.values( literalTokens ).length;
42
53
 
43
54
  const extensionDicts = {
44
55
  elements: true, enum: true, params: true, returns: true,
@@ -107,9 +118,15 @@ class AstBuildingParser extends BaseParser {
107
118
  let array = this.expectingArray_();
108
119
  this.s = savedState;
109
120
  // Avoid clutter in messages: replace all value tokens by ‹Value› if all are there:
110
- const reduced = raw ? array : array.filter( tok => valueTokens[tok] !== true );
111
- if (reduced.length + valueTokensLength === array.length)
112
- array = [ 'Value', ...reduced ];
121
+ const withoutValueTokens = raw ? array : array.filter( tok => valueTokens[tok] !== true );
122
+ if (withoutValueTokens.length + valueTokensLength === array.length) {
123
+ array = [ 'Value', ...withoutValueTokens ];
124
+ }
125
+ else {
126
+ const withoutLiteralTokens = raw ? array : array.filter( tok => literalTokens[tok] !== true );
127
+ if (withoutLiteralTokens.length + literalTokensLength === array.length)
128
+ array = [ 'Literal', ...withoutLiteralTokens ];
129
+ }
113
130
  return array.map( tok => this.antlrName( tok ) )
114
131
  .sort( (a, b) => (tokenPrecedence(a) < tokenPrecedence(b) ? -1 : 1) );
115
132
  }
@@ -153,7 +170,7 @@ class AstBuildingParser extends BaseParser {
153
170
  this.conditionStackLength == null) // after error recovery
154
171
  return false;
155
172
  if (this.constructor.tracingParser)
156
- this._traceSubPush( 'queryOnLeft' );
173
+ this._traceSubPush?.( 'queryOnLeft' );
157
174
  return this.queryOnLeft( 'table', mode );
158
175
  }
159
176
 
@@ -175,7 +192,7 @@ class AstBuildingParser extends BaseParser {
175
192
  if (this.inSameRule_( this.s, this.stack.at( -1 ).followState ))
176
193
  return false;
177
194
  this.dynamic_.parenthesesCtx = [ null ];
178
- this._tracePush( 'Parentheses()' );
195
+ this._tracePush?.( 'Parentheses()' );
179
196
  }
180
197
  const { parenthesesCtx } = this.dynamic_;
181
198
  const noQuery = parenthesesCtx?.[0];
@@ -4,7 +4,7 @@ const {
4
4
  getLastPartOf, getLastPartOfRef,
5
5
  hasValidSkipOrExists, getNormalizedQuery,
6
6
  getRootArtifactName, getResultingName, getNamespace, forEachMember, getVariableReplacement,
7
- pathName, hasPersistenceSkipAnnotation, implicitAs,
7
+ pathName, hasPersistenceSkipAnnotation, implicitAs, forEachDefinition,
8
8
  } = require('../model/csnUtils');
9
9
  const { isBuiltinType, isMagicVariable } = require('../base/builtins');
10
10
  const keywords = require('../base/keywords');
@@ -18,7 +18,7 @@ const {
18
18
  renderReferentialConstraint,
19
19
  } = require('./utils/sql');
20
20
  const DuplicateChecker = require('./DuplicateChecker');
21
- const { forEachDefinition, isDeprecatedEnabled } = require('../base/model');
21
+ const { isDeprecatedEnabled } = require('../base/model');
22
22
  const { checkCSNVersion } = require('../json/csnVersion');
23
23
  const { timetrace } = require('../utils/timetrace');
24
24
 
@@ -104,7 +104,7 @@ class SqlRenderEnvironment {
104
104
  * }
105
105
  * }
106
106
  *
107
- * @param {CSN.Model} csn HANA transformed CSN
107
+ * @param {CSN.Model} csn for SQL transformed CSN
108
108
  * @param {CSN.Options} options Transformation options
109
109
  * @param {object} messageFunctions Message functions such as `error()`, `info()`, …
110
110
  * @returns {object} Dictionary of artifact-type:artifacts, where artifacts is a dictionary of name:content
@@ -5,7 +5,7 @@
5
5
  const { getResultingName } = require('../../model/csnUtils');
6
6
  const { smartId, delimitedId } = require('../../sql-identifier');
7
7
  const { ModelError } = require('../../base/error');
8
- const { isBetaEnabled, setProp } = require('../../base/model');
8
+ const { setProp } = require('../../base/model');
9
9
 
10
10
  /**
11
11
  * Render a given referential constraint as part of a SQL CREATE TABLE statement, or as .hdbconstraint artefact.
@@ -161,7 +161,7 @@ const allowedHdbProjectionViewProperties = {
161
161
  * @returns {boolean} `true` if the artifact is a projection view, otherwise `false`.
162
162
  */
163
163
  function isProjectionView( csn, artifact, options ) {
164
- if (!isBetaEnabled(options, 'projectionViews') || !artifact.projection || options.sqlDialect !== 'hana' || artifact.params || !artifact.$dataProductService)
164
+ if (!artifact.projection || options.sqlDialect !== 'hana' || artifact.params || !artifact.$dataProductService)
165
165
  return false;
166
166
 
167
167
  if (artifact.$isProjectionView !== undefined)
@@ -666,7 +666,7 @@ const hanaFunctions = {
666
666
  const x = this.renderArgs({ ...signature, args: [ args[0] ] });
667
667
  const y = this.renderArgs({ ...signature, args: [ args[1] ] });
668
668
  // make sure to cast NUMERIC to BIGINT (corresponds to cds.Int64)
669
- return `(EXTRACT(EPOCH FROM (${ y }) - (${ x })) * 10000000)::BIGINT`;
669
+ return `(EXTRACT(EPOCH FROM (${ y })::TIMESTAMP - (${ x })::TIMESTAMP) * 10000000)::BIGINT`;
670
670
  },
671
671
  seconds_between(signature) {
672
672
  const { args } = signature;
@@ -674,7 +674,7 @@ const hanaFunctions = {
674
674
  const x = this.renderArgs({ ...signature, args: [ args[0] ] });
675
675
  const y = this.renderArgs({ ...signature, args: [ args[1] ] });
676
676
 
677
- return `EXTRACT(EPOCH FROM (${ y }) - (${ x }))::BIGINT`;
677
+ return `EXTRACT(EPOCH FROM (${ y })::TIMESTAMP - (${ x })::TIMESTAMP)::BIGINT`;
678
678
  },
679
679
  days_between(signature) {
680
680
  const { args } = signature;
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const { forEachDefinition } = require('../../base/model');
4
3
  const { applyTransformations, getResultingName, hasPersistenceSkipAnnotation } = require('../../model/csnUtils');
5
4
  const { forEach, forEachKey } = require('../../utils/objectUtils');
6
5
  const { CompilerAssertion } = require('../../base/error');
@@ -92,7 +91,7 @@ function createReferentialConstraints( csn, options ) {
92
91
  associations.forEach(association => association.fn());
93
92
 
94
93
  // Step III: Create the final referential constraints from all dependent key <-> parent key pairs stemming from the same $sourceAssociation
95
- forEachDefinition(csn, collectAndAttachReferentialConstraints);
94
+ forEach(csn.definitions, collectAndAttachReferentialConstraints);
96
95
 
97
96
  /**
98
97
  * Retrieve the <up_> link of an `cds.Composition` used in an on-condition like `$self = <comp>.<up_>`
@@ -501,10 +500,10 @@ function createReferentialConstraints( csn, options ) {
501
500
  * - Find all other elements in artifact with the same sourceAssociation
502
501
  * - Create constraints with the information supplied by $parentKey, $parentTable and $onDelete
503
502
  *
504
- * @param {CSN.Artifact} artifact
505
503
  * @param {string} artifactName
504
+ * @param {CSN.Artifact} artifact
506
505
  */
507
- function collectAndAttachReferentialConstraints( artifact, artifactName ) {
506
+ function collectAndAttachReferentialConstraints( artifactName, artifact ) {
508
507
  const referentialConstraints = Object.create(null);
509
508
 
510
509
  // tenant foreign keys may have multiple parent keys
@@ -2,14 +2,12 @@
2
2
 
3
3
  const {
4
4
  applyTransformations,
5
- setDependencies,
6
5
  walkCsnPath,
7
6
  getUtils,
8
7
  forEachDefinition,
9
8
  } = require('../../model/csnUtils');
10
9
  const { implicitAs, columnAlias, pathId } = require('../../model/csnRefs');
11
10
  const { setProp } = require('../../base/model');
12
- const { forEach } = require('../../utils/objectUtils');
13
11
  const { killNonrequiredAnno } = require('./killAnnotations');
14
12
  const { featureFlags } = require('../featureFlags');
15
13
  const { applyTransformationsOnNonDictionary } = require('./applyTransformations');
@@ -128,15 +126,11 @@ function expandStructureReferences( csn, options, pathDelimiter, messageFunction
128
126
  * For such skipped things, error for usage of assoc pointing to them and ignore publishing of assoc pointing to them.
129
127
  */
130
128
  function rewriteExpandInline() {
131
- let cleanup = [];
132
- let _dependents;
133
-
134
129
  const entity = findAnEntity();
135
130
  const toDummify = [];
136
131
 
137
132
  applyTransformations(csn, {
138
- columns: (parent, name, columns, path) => {
139
- const artifact = csn.definitions[path[1]];
133
+ columns: (parent) => {
140
134
  // get$combined expects a SET/SELECT - so we wrap the parent
141
135
  // (which is the thing inside SET/SELECT)
142
136
  // We can directly use SELECT here, as only projections and SELECT can have .columns
@@ -146,18 +140,7 @@ function expandStructureReferences( csn, options, pathDelimiter, messageFunction
146
140
  root[key] = root[key][0].element;
147
141
  });
148
142
  const rewritten = rewrite(root, parent.columns, parent.excluding);
149
- /*
150
- * Do not remove unexpandable many columns in OData
151
- */
152
- if (rewritten.toMany.length > 0 && !options.toOdata) {
153
- markAsToDummify(artifact, path[1]);
154
- rewritten.toMany.forEach(({ art }) => {
155
- error( null, art.$path || [ 'definitions', path[1] ], { name: `${ art.$env || path[1] }:${ art.ref.map(r => r.id || r) }` }, 'Unexpected .expand with to-many association $(NAME)');
156
- });
157
- }
158
- else {
159
- parent.columns = rewritten.columns;
160
- }
143
+ parent.columns = rewritten.columns;
161
144
  },
162
145
  });
163
146
 
@@ -166,8 +149,6 @@ function expandStructureReferences( csn, options, pathDelimiter, messageFunction
166
149
  if (!options.toOdata)
167
150
  dummyfy();
168
151
 
169
- cleanup.forEach(fn => fn());
170
-
171
152
  csnUtils = getUtils(csn);
172
153
 
173
154
  const publishing = [];
@@ -267,29 +248,6 @@ function expandStructureReferences( csn, options, pathDelimiter, messageFunction
267
248
  info(null, path, { name: last, target }, 'Ignoring association $(NAME) with target $(TARGET), because it was skipped because of .expand in conjunction with to-many');
268
249
  }
269
250
 
270
- /**
271
- * Mark the given artifact and all (transitively) dependent artifacts as `toDummify`.
272
- * This means that they will be replaced with simple dummy views in `@dummify`
273
- *
274
- * @param {CSN.Artifact} artifact
275
- * @param {string} name
276
- */
277
- function markAsToDummify( artifact, name ) {
278
- if (!_dependents && cleanup.length === 0)
279
- ({ cleanup, _dependents } = setDependencies(csn, csnUtils));
280
-
281
- const stack = [ [ artifact, name ] ];
282
- while (stack.length > 0) {
283
- const [ a, n ] = stack.pop();
284
- if (a[_dependents]) {
285
- forEach(a[_dependents], (dependentName, dependent) => {
286
- stack.push([ dependent, dependentName ]);
287
- });
288
- }
289
- toDummify.push(n);
290
- }
291
- }
292
-
293
251
  /**
294
252
  * Replace the artifacts in `toDummify` with simple dummy views as produced by createDummyView.
295
253
  */
@@ -26,7 +26,7 @@ const requiredAnnos = {
26
26
  '@Core.Computed': true,
27
27
  [sqlServiceAnnotation]: true,
28
28
  '@cds.external': true, // for external ABAP SQL services and data products for now
29
- '@DataIntegration.dataproduct.type': true, // for data product production
29
+ '@data.product': true, // for data product production
30
30
  };
31
31
 
32
32
  /**
@@ -18,13 +18,13 @@ function processSqlServices(csn, options) {
18
18
  setProp(csn, '$dummyServiceEntities', Object.create(null));
19
19
  setProp(csn, '$dataProductEntities', Object.create(null));
20
20
  return function findAndMarkSqlServiceArtifacts(artifact, artifactName) {
21
- const { sqlServiceName, dummyServiceName, dataProductServiceName } = isEntityInSqlService(artifact, artifactName, csn, options);
21
+ const { sqlServiceName, dummyServiceName, dataProductProductionServiceName } = isEntityInSqlService(artifact, artifactName, csn, options);
22
22
  if (sqlServiceName?.length > 0)
23
23
  setProp(artifact, '$sqlService', sqlServiceName);
24
24
  if (dummyServiceName?.length > 0)
25
25
  setProp(artifact, '$dummyService', dummyServiceName);
26
- if (dataProductServiceName?.length > 0)
27
- setProp(artifact, '$dataProductService', dataProductServiceName);
26
+ if (dataProductProductionServiceName?.length > 0)
27
+ setProp(artifact, '$dataProductService', dataProductProductionServiceName);
28
28
  };
29
29
  }
30
30
 
@@ -58,7 +58,7 @@ function isDummyService(artifact, options) {
58
58
  * @returns {object} An object containing the names of the SQL service and external ABAP SQL service, if found.
59
59
  */
60
60
  function isEntityInSqlService(artifact, artifactName, csn, options) {
61
- const result = { sqlServiceName: undefined, dummyServiceName: undefined, dataProductServiceName: undefined };
61
+ const result = { sqlServiceName: undefined, dummyServiceName: undefined, dataProductProductionServiceName: undefined };
62
62
  if (artifact.kind !== 'entity' || !artifactName.includes('.') || hasPersistenceSkipAnnotation(artifact))
63
63
  return result;
64
64
 
@@ -75,8 +75,8 @@ function isEntityInSqlService(artifact, artifactName, csn, options) {
75
75
  if (isDummyService(definition, options))
76
76
  result.dummyServiceName = possibleServiceName;
77
77
 
78
- if (isDataProductService(definition, options))
79
- result.dataProductServiceName = possibleServiceName;
78
+ if (isDataProductProductionService(definition))
79
+ result.dataProductProductionServiceName = possibleServiceName;
80
80
 
81
81
  // We don't allow nested services/contexts - if we find one, we don't need to keep searching
82
82
  if (definition.kind === 'service' || definition.kind === 'context')
@@ -115,21 +115,20 @@ function createServiceDummy(artifact, artifactName, csn, { error }) {
115
115
  }
116
116
 
117
117
  /**
118
- * Determines if the given artifact is a data product service.
118
+ * Determines if the given artifact is a data product production service.
119
119
  *
120
120
  * @param {object} artifact - The artifact to evaluate.
121
- * @param {object} options - The options object containing feature flags.
122
121
  * @returns {boolean} - Returns `true` if the artifact is a data product service, otherwise `false`.
123
122
  */
124
- function isDataProductService(artifact, options) {
125
- return isBetaEnabled(options, 'projectionViews') && artifact.kind === 'service' && artifact['@DataIntegration.dataproduct.type'] === 'primary';
123
+ function isDataProductProductionService(artifact) {
124
+ return artifact.kind === 'service' && artifact['@data.product'] && !artifact['@cds.external'];
126
125
  }
127
126
 
128
127
  module.exports = {
129
128
  processSqlServices,
130
129
  isSqlService,
131
130
  isDummyService,
132
- isDataProductService,
131
+ isDataProductProductionService,
133
132
  sqlServiceAnnotation,
134
133
  createServiceDummy,
135
134
  };
@@ -17,7 +17,7 @@ const misc = require('./misc');
17
17
  const annotations = require('./annotations');
18
18
  const { rewriteCalculatedElementsInViews, processCalculatedElementsInEntities } = require('../db/rewriteCalculatedElements');
19
19
  const { cloneFullCsn } = require('../../model/cloneCsn');
20
- const { featureFlags } = require('../featureFlags');
20
+ const { featureFlags, removeFeatureFlags } = require('../featureFlags');
21
21
  const getServiceFilterFunction = require('./service');
22
22
  const { traverseQuery } = require('../../model/csnRefs');
23
23
  const { expandWildcard } = require('../db/expansion');
@@ -136,6 +136,7 @@ function effectiveCsn( model, options, messageFunctions ) {
136
136
  }
137
137
 
138
138
  messageFunctions.throwWithError();
139
+ removeFeatureFlags(csn);
139
140
 
140
141
  return csn;
141
142
  }
@@ -2,4 +2,9 @@
2
2
 
3
3
  const featureFlags = Symbol.for('Feature flags');
4
4
 
5
- module.exports = { featureFlags };
5
+ function removeFeatureFlags(csn) {
6
+ if (csn.meta)
7
+ delete csn.meta[featureFlags];
8
+ }
9
+
10
+ module.exports = { featureFlags, removeFeatureFlags };