@sap/cds-compiler 2.4.4 → 2.10.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 (106) hide show
  1. package/CHANGELOG.md +241 -1
  2. package/bin/.eslintrc.json +17 -0
  3. package/bin/cds_update_identifiers.js +8 -7
  4. package/bin/cdsc.js +180 -132
  5. package/bin/cdshi.js +18 -11
  6. package/bin/cdsse.js +38 -32
  7. package/bin/cdsv2m.js +8 -7
  8. package/doc/CHANGELOG_BETA.md +36 -1
  9. package/lib/api/main.js +81 -100
  10. package/lib/api/options.js +17 -11
  11. package/lib/api/validate.js +12 -8
  12. package/lib/backends.js +0 -81
  13. package/lib/base/keywords.js +32 -2
  14. package/lib/base/location.js +2 -2
  15. package/lib/base/message-registry.js +66 -4
  16. package/lib/base/messages.js +84 -27
  17. package/lib/base/model.js +2 -61
  18. package/lib/checks/arrayOfs.js +0 -1
  19. package/lib/checks/defaultValues.js +27 -2
  20. package/lib/checks/elements.js +1 -6
  21. package/lib/checks/enricher.js +8 -2
  22. package/lib/checks/foreignKeys.js +0 -6
  23. package/lib/checks/managedWithoutKeys.js +17 -0
  24. package/lib/checks/nonexpandableStructured.js +38 -0
  25. package/lib/checks/onConditions.js +9 -45
  26. package/lib/checks/queryNoDbArtifacts.js +27 -9
  27. package/lib/checks/selectItems.js +25 -2
  28. package/lib/checks/types.js +26 -2
  29. package/lib/checks/unknownMagic.js +38 -0
  30. package/lib/checks/utils.js +61 -0
  31. package/lib/checks/validator.js +66 -13
  32. package/lib/compiler/assert-consistency.js +24 -12
  33. package/lib/compiler/builtins.js +2 -0
  34. package/lib/compiler/checks.js +6 -4
  35. package/lib/compiler/definer.js +101 -39
  36. package/lib/compiler/index.js +88 -59
  37. package/lib/compiler/resolver.js +455 -209
  38. package/lib/compiler/shared.js +57 -33
  39. package/lib/edm/annotations/genericTranslation.js +183 -187
  40. package/lib/edm/csn2edm.js +128 -99
  41. package/lib/edm/edm.js +18 -21
  42. package/lib/edm/edmPreprocessor.js +361 -127
  43. package/lib/edm/edmUtils.js +103 -33
  44. package/lib/gen/Dictionary.json +74 -28
  45. package/lib/gen/language.checksum +1 -1
  46. package/lib/gen/language.interp +18 -4
  47. package/lib/gen/language.tokens +124 -118
  48. package/lib/gen/languageLexer.interp +13 -1
  49. package/lib/gen/languageLexer.js +870 -839
  50. package/lib/gen/languageLexer.tokens +116 -111
  51. package/lib/gen/languageParser.js +5894 -5614
  52. package/lib/json/from-csn.js +152 -67
  53. package/lib/json/to-csn.js +334 -135
  54. package/lib/language/antlrParser.js +4 -3
  55. package/lib/language/errorStrategy.js +1 -0
  56. package/lib/language/genericAntlrParser.js +24 -14
  57. package/lib/language/language.g4 +188 -128
  58. package/lib/main.d.ts +435 -0
  59. package/lib/main.js +31 -7
  60. package/lib/model/api.js +78 -0
  61. package/lib/model/csnRefs.js +463 -187
  62. package/lib/model/csnUtils.js +280 -136
  63. package/lib/model/enrichCsn.js +75 -4
  64. package/lib/model/revealInternalProperties.js +2 -1
  65. package/lib/modelCompare/compare.js +70 -25
  66. package/lib/optionProcessor.js +13 -10
  67. package/lib/render/.eslintrc.json +4 -1
  68. package/lib/render/DuplicateChecker.js +8 -5
  69. package/lib/render/toCdl.js +123 -40
  70. package/lib/render/toHdbcds.js +156 -65
  71. package/lib/render/toSql.js +87 -11
  72. package/lib/render/utils/common.js +55 -9
  73. package/lib/render/utils/sql.js +3 -3
  74. package/lib/sql-identifier.js +6 -1
  75. package/lib/transform/{sql → db}/.eslintrc.json +0 -0
  76. package/lib/transform/{sql → db}/assertUnique.js +7 -8
  77. package/lib/transform/{sql → db}/constraints.js +35 -20
  78. package/lib/transform/db/draft.js +353 -0
  79. package/lib/transform/db/expansion.js +582 -0
  80. package/lib/transform/db/flattening.js +325 -0
  81. package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
  82. package/lib/transform/{sql → db}/helpers.js +0 -0
  83. package/lib/transform/{sql → db}/transformExists.js +256 -60
  84. package/lib/transform/forHanaNew.js +216 -765
  85. package/lib/transform/forOdataNew.js +60 -56
  86. package/lib/transform/localized.js +48 -26
  87. package/lib/transform/odata/attachPath.js +19 -4
  88. package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
  89. package/lib/transform/odata/generateForeignKeyElements.js +13 -12
  90. package/lib/transform/odata/referenceFlattener.js +60 -36
  91. package/lib/transform/odata/sortByAssociationDependency.js +4 -4
  92. package/lib/transform/odata/structuralPath.js +76 -0
  93. package/lib/transform/odata/structureFlattener.js +21 -22
  94. package/lib/transform/odata/toFinalBaseType.js +5 -5
  95. package/lib/transform/odata/typesExposure.js +27 -17
  96. package/lib/transform/odata/utils.js +2 -2
  97. package/lib/transform/transformUtilsNew.js +141 -77
  98. package/lib/transform/translateAssocsToJoins.js +17 -14
  99. package/lib/transform/universalCsnEnricher.js +67 -0
  100. package/lib/utils/file.js +0 -11
  101. package/lib/utils/moduleResolve.js +6 -8
  102. package/lib/utils/timetrace.js +6 -1
  103. package/package.json +2 -1
  104. package/lib/base/deepCopy.js +0 -66
  105. package/lib/json/walker.js +0 -26
  106. package/lib/utils/string.js +0 -17
@@ -1,4 +1,5 @@
1
1
  'use strict';
2
+ const { setProp } = require('../base/model');
2
3
  const { isBuiltinType, isEdmPropertyRendered } = require('../model/csnUtils');
3
4
 
4
5
  /* eslint max-statements-per-line:off */
@@ -114,6 +115,12 @@ function isToMany(assoc) {
114
115
  return targetMax === '*' || Number(targetMax) > 1;
115
116
  }
116
117
 
118
+ function isSingleton(entityCsn, v) {
119
+ const singleton = entityCsn['@odata.singleton'];
120
+ const hasNullable = entityCsn['@odata.singleton.nullable'] !== undefined && entityCsn['@odata.singleton.nullable'] !== null;
121
+ return v && singleton || ((singleton === undefined || singleton === null) && hasNullable);
122
+ }
123
+
117
124
  function isEntity(artifact)
118
125
  {
119
126
  return ['entity'].includes(artifact.kind);
@@ -142,7 +149,7 @@ function isActionOrFunction(artifact) {
142
149
  return ['action', 'function'].includes(artifact.kind);
143
150
  }
144
151
 
145
- function resolveOnConditionAndPrepareConstraints(assocCsn, messageFunctions) {
152
+ function resolveOnConditionAndPrepareConstraints(csn, assocCsn, messageFunctions) {
146
153
  if(!assocCsn._constraints)
147
154
  throw Error('Please debug me: need _constraints');
148
155
 
@@ -154,7 +161,7 @@ function resolveOnConditionAndPrepareConstraints(assocCsn, messageFunctions) {
154
161
  getExpressionArguments(assocCsn.on);
155
162
 
156
163
  // for all $self conditions, fill constraints of partner (if any)
157
- let isBacklink = assocCsn._constraints.selfs.length == 1 && assocCsn._constraints.termCount == 1;
164
+ let isBacklink = assocCsn._constraints.selfs.length === 1 && assocCsn._constraints.termCount === 1;
158
165
 
159
166
  /* example for _originalTarget:
160
167
  entity E (with parameters) {
@@ -167,14 +174,19 @@ function resolveOnConditionAndPrepareConstraints(assocCsn, messageFunctions) {
167
174
  ON Condition back.toE => parter=toE cannot be resolved in EParameters, _originalTarget 'E' is
168
175
  required for that
169
176
  */
170
- assocCsn._constraints.selfs.filter(p => p).forEach(partner => {
171
- const originAssocCsn = (assocCsn._originalTarget || assocCsn._target).elements[partner];
172
- const parentArtifactName = assocCsn._parent.name;
177
+ assocCsn._constraints.selfs.filter(p => p).forEach(partnerPath => {
178
+ // resolve partner path in target
179
+ const originAssocCsn = resolveOriginAssoc(csn, (assocCsn._originalTarget || assocCsn._target), partnerPath);
180
+ const parentName = assocCsn.$abspath[0];
181
+ const parent = csn.definitions[parentName];
173
182
  if(originAssocCsn) {
174
- if(originAssocCsn._originalTarget !== assocCsn._parent && originAssocCsn._target !== assocCsn._parent) {
183
+ const originParentName = originAssocCsn.$abspath[0];
184
+ if(originAssocCsn._originalTarget !== parent && originAssocCsn._target !== parent) {
175
185
  isBacklink = false;
176
- info(null, ['definitions', parentArtifactName, 'elements', assocCsn.name],
177
- `"${originAssocCsn._parent.name}:${partner}" with target "${originAssocCsn._target.name}" is compared with $self which represents "${parentArtifactName}"`);
186
+ // Partnership is ambiguous
187
+ setProp(originAssocCsn, '$noPartner', true);
188
+ info(null, ['definitions', parentName, 'elements', assocCsn.name],
189
+ `"${originParentName}:${partnerPath.join('.')}" with target "${originAssocCsn._target.name}" is compared with $self which represents "${parentName}"`);
178
190
  }
179
191
  if(isAssociationOrComposition(originAssocCsn)) {
180
192
  // Mark this association as backlink if $self appears exactly once
@@ -187,7 +199,10 @@ function resolveOnConditionAndPrepareConstraints(assocCsn, messageFunctions) {
187
199
  else {
188
200
  isBacklink = false;
189
201
  }
190
- // collect all backlinks at forward association
202
+ }
203
+ // store all backlinks at forward, required to calculate rendering of foreign keys
204
+ // if the termCount != 1 or more than one $self compare this is not a backlink
205
+ if(assocCsn._constraints.selfs.length === 1 && assocCsn._constraints.termCount === 1) {
191
206
  originAssocCsn._selfReferences.push(assocCsn);
192
207
  }
193
208
  assocCsn._constraints._origins.push(originAssocCsn);
@@ -203,8 +218,8 @@ function resolveOnConditionAndPrepareConstraints(assocCsn, messageFunctions) {
203
218
  }
204
219
  else
205
220
  {
206
- warning(null, ['definitions', parentArtifactName],
207
- { partner: `${assocCsn._target.name}/${partner}`, name: `${parentArtifactName}/${assocCsn.name}` },
221
+ warning(null, ['definitions', parentName],
222
+ { partner: `${assocCsn._target.name}/${partnerPath}`, name: `${parentName}/${assocCsn.name}` },
208
223
  'Can\'t resolve backlink to $(PARTNER) from $(NAME)');
209
224
  }
210
225
  });
@@ -268,7 +283,7 @@ function resolveOnConditionAndPrepareConstraints(assocCsn, messageFunctions) {
268
283
  // do we have a $self id?
269
284
  // if so, store partner in selfs array
270
285
  if(c[0][0] === '$self' && c[0].length === 1) {
271
- assocCsn._constraints.selfs.push(c[1][0]);
286
+ assocCsn._constraints.selfs.push(c[1]);
272
287
  } else {
273
288
  const key = c.join(',');
274
289
  assocCsn._constraints.constraints[key] = c;
@@ -281,7 +296,7 @@ function resolveOnConditionAndPrepareConstraints(assocCsn, messageFunctions) {
281
296
  }
282
297
  }
283
298
 
284
- function finalizeReferentialConstraints(assocCsn, options, warning)
299
+ function finalizeReferentialConstraints(csn, assocCsn, options, info)
285
300
  {
286
301
  if(!assocCsn._constraints)
287
302
  throw Error('Please debug me: need _constraints');
@@ -317,11 +332,16 @@ function finalizeReferentialConstraints(assocCsn, options, warning)
317
332
  });
318
333
 
319
334
  if(!assocCsn._target.$isParamEntity) {
320
- // Header is composed of Items => Cds.Composition: Header is principal => use header's primary keys
321
- let dependentEntity = assocCsn._parent;
335
+ // Use $path to identify main artifact in case assocs parent was a nested type and deanonymized
336
+ // Some (draft) associations don't have a $path, use _parent as last resort
337
+ let dependentEntity = assocCsn.$path ? csn.definitions[assocCsn.$path[1]] : assocCsn._parent;
338
+ let localDepEntity = assocCsn._parent;
339
+ // _target must always be a main artifact
322
340
  let principalEntity = assocCsn._target;
323
341
  if(assocCsn.type === 'cds.Composition') {
324
- principalEntity = assocCsn._parent;
342
+ // Header is composed of Items => Cds.Composition: Header is principal => use header's primary keys
343
+ principalEntity = dependentEntity;
344
+ localDepEntity = undefined;
325
345
  dependentEntity = assocCsn._target;
326
346
  // Swap the constraint elements to be correct on Composition [principal, dependent] => [dependent, principal]
327
347
  Object.keys(assocCsn._constraints.constraints).forEach(cn => {
@@ -332,14 +352,44 @@ function finalizeReferentialConstraints(assocCsn, options, warning)
332
352
  const remainingPrincipalRefs = [];
333
353
  foreach(assocCsn._constraints.constraints,
334
354
  c => {
355
+ // rc === true will remove the constraint (positive filter expression)
356
+ let rc = true;
335
357
  // concatenate all paths in flat mode to identify the correct element
336
358
  // in structured mode only resolve top level element (path rewriting is done elsewhere)
337
- const fk = dependentEntity.elements[ ( options.isFlatFormat ? c[0].join('_') : c[0][0] )];
338
- const principalEltRef = ( options.isFlatFormat ? c[1].join('_') : c[1][0] );
339
- const pk = principalEntity.$keys && principalEntity.$keys[ principalEltRef ];
340
- if(isConstraintCandidate(fk) && isConstraintCandidate(pk))
341
- remainingPrincipalRefs.push(principalEltRef);
342
- return !(isConstraintCandidate(fk) && isConstraintCandidate(pk));
359
+ const depEltName = ( options.isFlatFormat ? c[0].join('_') : c[0][0] );
360
+ const principalEltName = ( options.isFlatFormat ? c[1].join('_') : c[1][0] );
361
+ const fk = (isEntity(dependentEntity) && dependentEntity.elements[ depEltName ]) ||
362
+ (localDepEntity && localDepEntity.elements && localDepEntity.elements[ depEltName ]);
363
+ const pk = principalEntity.$keys && principalEntity.$keys[ principalEltName ];
364
+ if(isConstraintCandidate(fk) && isConstraintCandidate(pk)) {
365
+ if(options.isStructFormat) {
366
+ // In structured mode it might be the association has a new _parent due to
367
+ // type de-anonymization.
368
+ // There are three cases for dependent ON condition paths:
369
+ // 1) path is relative to assoc in same sub structure
370
+ // 2) path is absolute and ends up in a different environment
371
+ // 3) path is absolute and touches in assoc's environment
372
+
373
+ // => 1) if _parents are equal, fk path is relative to assoc
374
+ if(fk._parent === assocCsn._parent) {
375
+ rc = false;
376
+ }
377
+ // => 2) & 3) if path is not relative to assoc, remove main entity (pos=0) and assoc (pos=n-1)
378
+ // and check path identity: If absolute path touches assoc's _parent, add it
379
+ else if(!assocCsn.$abspath.slice(1, assocCsn.$abspath.length-1).some((p,i) => c[0][i] !== p)) {
380
+ // this was an absolute addressed path, remove environment prefix
381
+ c[0].splice(0, assocCsn.$abspath.length-2);
382
+ rc = false;
383
+ }
384
+ }
385
+ else {
386
+ // for flat mode isConstraintCandidate(fk) && isConstraintCandidate(pk) is sufficient
387
+ rc = false;
388
+ }
389
+ }
390
+ if(!rc)
391
+ remainingPrincipalRefs.push(principalEltName);
392
+ return rc;
343
393
  },
344
394
  (c, cn) => { delete assocCsn._constraints.constraints[cn]; }
345
395
  );
@@ -349,8 +399,8 @@ function finalizeReferentialConstraints(assocCsn, options, warning)
349
399
  const renderedKeys = Object.values(principalEntity.$keys).filter(isConstraintCandidate).map(v=>v.name);
350
400
  if(options.isV2() && intersect(renderedKeys, remainingPrincipalRefs).length !== renderedKeys.length)
351
401
  if(options.odataV2PartialConstr) {
352
- warning('odata-spec-violation-constraints', ['definitions', assocCsn._parent.name, 'elements', assocCsn.name],
353
- 'Partial referential constraints (not spec compliant) produced based on user setting');
402
+ info('odata-spec-violation-constraints',
403
+ ['definitions', assocCsn._parent.name, 'elements', assocCsn.name], { api: 'OData V2' });
354
404
  }
355
405
  else {
356
406
  assocCsn._constraints.constraints = {};
@@ -387,8 +437,8 @@ function finalizeReferentialConstraints(assocCsn, options, warning)
387
437
  const renderedKeys = Object.values(assocCsn._target.$keys).filter(isConstraintCandidate).map(v=>v.name);
388
438
  if(options.isV2() && intersect(renderedKeys, remainingPrincipalRefs).length !== renderedKeys.length) {
389
439
  if(options.odataV2PartialConstr) {
390
- warning('odata-spec-violation-constraints', ['definitions', assocCsn._parent.name, 'elements', assocCsn.name],
391
- 'Partial referential constraints (not spec compliant) produced based on user setting');
440
+ info('odata-spec-violation-constraints',
441
+ ['definitions', assocCsn._parent.name, 'elements', assocCsn.name], { api: 'OData V2' } );
392
442
  }
393
443
  else {
394
444
  assocCsn._constraints.constraints = {};
@@ -474,7 +524,7 @@ function determineMultiplicity(csn)
474
524
 
475
525
  function mapCdsToEdmType(csn, messageFunctions, isV2=false, isMediaType=false)
476
526
  {
477
- const { warning, error } = messageFunctions;
527
+ const { error } = messageFunctions || { error: ()=>true };
478
528
  let cdsType = csn.type;
479
529
  if(cdsType === undefined) {
480
530
  error(null, csn.$location, `no type found`);
@@ -543,8 +593,6 @@ function mapCdsToEdmType(csn, messageFunctions, isV2=false, isMediaType=false)
543
593
  if(['cds.hana.ST_POINT', 'cds.hana.ST_GEOMETRY'].includes(cdsType)) {
544
594
  error(null, csn.$path, { type: cdsType }, `OData V2 does not support Geometry data types, $(TYPE) can't be mapped`);
545
595
  }
546
- if(cdsType === 'cds.DecimalFloat' || cdsType === 'cds.hana.SMALLDECIMAL')
547
- warning(null, csn.$path, { type: cdsType }, `OData V2 does not support $(TYPE)`);
548
596
  }
549
597
  else // isV4
550
598
  {
@@ -571,13 +619,21 @@ function addTypeFacets(node, csn)
571
619
  // node.Precision = 16;
572
620
  else if (csn.type === 'cds.Timestamp' && node.Type === 'Edm.DateTimeOffset')
573
621
  node.Precision = 7;
574
- else if([ 'cds.Decimal', 'cds.DecimalFloat', 'cds.hana.SMALLDECIMAL' ].includes(csn.type) && !csn.precision && !csn.scale) {
622
+ if([ 'cds.Decimal', 'cds.DecimalFloat', 'cds.hana.SMALLDECIMAL' ].includes(csn.type)) {
575
623
  if(isV2) {
576
- node.setXml( { 'sap:variable-scale': true } );
624
+ // no prec/scale or scale is 'floating'/'variable'
625
+ if(!(csn.precision || csn.scale) || ['floating', 'variable'].includes(csn.scale)) {
626
+ node.setXml( { 'sap:variable-scale': true } );
627
+ delete node.Scale;
628
+ }
577
629
  }
578
630
  else {
579
- // if Decimal has no p, s set scale 'variable'
580
- node.setXml( { Scale: 'variable' } ); // floating is V4.01
631
+ // map both floating and variable to => variable
632
+ if(node.Scale === 'floating')
633
+ node.Scale = 'variable';
634
+ if(!csn.precision && !csn.scale)
635
+ // if Decimal has no p, s set scale 'variable'
636
+ node.setXml( { Scale: 'variable' } ); // floating is V4.01
581
637
  }
582
638
  }
583
639
  // Unicode unused today
@@ -636,6 +692,19 @@ function getBaseName(name) {
636
692
  return (lastDotIdx > 0 ) ? name.substring(lastDotIdx+1, name.length) : name;
637
693
  }
638
694
 
695
+ // This is a poor mans path resolver for $self partner paths only
696
+ function resolveOriginAssoc(csn, env, path) {
697
+ for(let i = 0; i < path.length; i++) {
698
+ let elements = (env.items && env.items.elements || env.elements);
699
+ if(elements)
700
+ env = env.elements[path[i]];
701
+ let type = (env.items && env.items.type || env.type);
702
+ if(type && !isBuiltinType(type) && !(env.items && env.items.elements || env.elements))
703
+ env = csn.definitions[env.type];
704
+ }
705
+ return env;
706
+ }
707
+
639
708
  module.exports = {
640
709
  validateOptions,
641
710
  intersect,
@@ -647,6 +716,7 @@ module.exports = {
647
716
  isComposition,
648
717
  isAssociationOrComposition,
649
718
  isToMany,
719
+ isSingleton,
650
720
  isEntity,
651
721
  isStructuredType,
652
722
  isStructuredArtifact,
@@ -4,7 +4,12 @@
4
4
  "Type": "Aggregation.ApplySupportedType",
5
5
  "AppliesTo": [
6
6
  "EntitySet",
7
- "Collection",
7
+ "Collection"
8
+ ]
9
+ },
10
+ "Aggregation.ApplySupportedDefaults": {
11
+ "Type": "Aggregation.ApplySupportedBase",
12
+ "AppliesTo": [
8
13
  "EntityContainer"
9
14
  ]
10
15
  },
@@ -420,8 +425,7 @@
420
425
  "Type": "Edm.Boolean",
421
426
  "AppliesTo": [
422
427
  "Property"
423
- ],
424
- "$experimental": true
428
+ ]
425
429
  },
426
430
  "Common.Experimental": {
427
431
  "Type": "Edm.String"
@@ -718,10 +722,24 @@
718
722
  "EntityType"
719
723
  ]
720
724
  },
721
- "Common.WeakReferentialConstraint": {
722
- "Type": "Common.WeakReferentialConstraintType",
725
+ "Common.SAPObjectNodeType": {
726
+ "Type": "Common.SAPObjectNodeTypeType",
723
727
  "AppliesTo": [
724
- "EntitySet"
728
+ "EntityType"
729
+ ],
730
+ "$experimental": true
731
+ },
732
+ "Common.Composition": {
733
+ "Type": "Core.Tag",
734
+ "AppliesTo": [
735
+ "NavigationProperty"
736
+ ],
737
+ "$experimental": true
738
+ },
739
+ "Common.SAPObjectNodeTypeReference": {
740
+ "Type": "Edm.String",
741
+ "AppliesTo": [
742
+ "Property"
725
743
  ],
726
744
  "$experimental": true
727
745
  },
@@ -1233,14 +1251,20 @@
1233
1251
  "AppliesTo": [
1234
1252
  "EntityType",
1235
1253
  "Property",
1236
- "Term"
1254
+ "Term",
1255
+ "TypeDefinition",
1256
+ "Parameter",
1257
+ "ReturnType"
1237
1258
  ]
1238
1259
  },
1239
1260
  "Core.MediaType": {
1240
1261
  "Type": "Edm.String",
1241
1262
  "AppliesTo": [
1242
1263
  "Property",
1243
- "Term"
1264
+ "Term",
1265
+ "TypeDefinition",
1266
+ "Parameter",
1267
+ "ReturnType"
1244
1268
  ]
1245
1269
  },
1246
1270
  "Core.IsMediaType": {
@@ -1328,6 +1352,9 @@
1328
1352
  "Core.SymbolicName": {
1329
1353
  "Type": "Core.SimpleIdentifier"
1330
1354
  },
1355
+ "Core.GeometryFeature": {
1356
+ "Type": "Core.GeometryFeatureType"
1357
+ },
1331
1358
  "Graph.links": {
1332
1359
  "Type": "Collection(Graph.link)",
1333
1360
  "AppliesTo": [
@@ -1339,8 +1366,7 @@
1339
1366
  "Type": "HTML5.CssDefaultsType",
1340
1367
  "AppliesTo": [
1341
1368
  "Record"
1342
- ],
1343
- "$experimental": true
1369
+ ]
1344
1370
  },
1345
1371
  "Measures.ISOCurrency": {
1346
1372
  "Type": "Edm.String",
@@ -1779,6 +1805,13 @@
1779
1805
  "Property"
1780
1806
  ]
1781
1807
  },
1808
+ "UI.DoNotCheckScaleOfMeasuredQuantity": {
1809
+ "Type": "Edm.Boolean",
1810
+ "AppliesTo": [
1811
+ "Property"
1812
+ ],
1813
+ "$experimental": true
1814
+ },
1782
1815
  "Validation.Pattern": {
1783
1816
  "Type": "Edm.String",
1784
1817
  "AppliesTo": [
@@ -1884,15 +1917,24 @@
1884
1917
  }
1885
1918
  },
1886
1919
  "types": {
1887
- "Aggregation.ApplySupportedType": {
1920
+ "Aggregation.ApplySupportedBase": {
1888
1921
  "$kind": "ComplexType",
1889
1922
  "Properties": {
1890
1923
  "Transformations": "Collection(Edm.String)",
1891
1924
  "CustomAggregationMethods": "Collection(Edm.String)",
1892
- "Rollup": "Aggregation.RollupType",
1925
+ "Rollup": "Aggregation.RollupType"
1926
+ }
1927
+ },
1928
+ "Aggregation.ApplySupportedType": {
1929
+ "$kind": "ComplexType",
1930
+ "BaseType": "Aggregation.ApplySupportedBase",
1931
+ "Properties": {
1893
1932
  "PropertyRestrictions": "Edm.Boolean",
1894
1933
  "GroupableProperties": "Collection(Edm.PropertyPath)",
1895
- "AggregatableProperties": "Collection(Aggregation.AggregatablePropertyType)"
1934
+ "AggregatableProperties": "Collection(Aggregation.AggregatablePropertyType)",
1935
+ "Transformations": "Collection(Edm.String)",
1936
+ "CustomAggregationMethods": "Collection(Edm.String)",
1937
+ "Rollup": "Aggregation.RollupType"
1896
1938
  }
1897
1939
  },
1898
1940
  "Aggregation.AggregatablePropertyType": {
@@ -2536,20 +2578,10 @@
2536
2578
  "UpperBoundaryIncluded": "Edm.Boolean"
2537
2579
  }
2538
2580
  },
2539
- "Common.WeakReferentialConstraintType": {
2581
+ "Common.SAPObjectNodeTypeType": {
2540
2582
  "$kind": "ComplexType",
2541
2583
  "Properties": {
2542
- "ReferenceRoot": "Edm.String",
2543
- "ReferencePath": "Edm.String",
2544
- "ForeignKeys": "Collection(Common.ForeignKeyType)"
2545
- },
2546
- "$experimental": true
2547
- },
2548
- "Common.ForeignKeyType": {
2549
- "$kind": "ComplexType",
2550
- "Properties": {
2551
- "Property": "Edm.PropertyPath",
2552
- "ReferencedProperty": "Edm.String"
2584
+ "Name": "Edm.String"
2553
2585
  },
2554
2586
  "$experimental": true
2555
2587
  },
@@ -2559,6 +2591,7 @@
2559
2591
  "Label": "Edm.String",
2560
2592
  "CollectionPath": "Edm.String",
2561
2593
  "CollectionRoot": "Edm.String",
2594
+ "DistinctValuesSupported": "Edm.Boolean",
2562
2595
  "SearchSupported": "Edm.Boolean",
2563
2596
  "FetchValues": "Common.FetchValuesType",
2564
2597
  "PresentationVariantQualifier": "Common.SimpleIdentifier",
@@ -2571,6 +2604,7 @@
2571
2604
  "Properties": {
2572
2605
  "Label": "Edm.String",
2573
2606
  "CollectionPath": "Edm.String",
2607
+ "DistinctValuesSupported": "Edm.Boolean",
2574
2608
  "FetchValues": "Common.FetchValuesType",
2575
2609
  "PresentationVariantQualifier": "Common.SimpleIdentifier",
2576
2610
  "SelectionVariantQualifier": "Common.SimpleIdentifier",
@@ -2664,7 +2698,8 @@
2664
2698
  "TargetEntities": "Collection(Edm.NavigationPropertyPath)",
2665
2699
  "EffectTypes": "Common.EffectType",
2666
2700
  "TriggerAction": "Common.QualifiedName",
2667
- "TriggeredIndicator": "Edm.Boolean"
2701
+ "TriggeredIndicator": "Edm.Boolean",
2702
+ "Discretionary": "Edm.Boolean"
2668
2703
  }
2669
2704
  },
2670
2705
  "Common.SortOrderType": {
@@ -2993,6 +3028,14 @@
2993
3028
  "DefaultValue": "Edm.String"
2994
3029
  }
2995
3030
  },
3031
+ "Core.GeometryFeatureType": {
3032
+ "$kind": "ComplexType",
3033
+ "Properties": {
3034
+ "geometry": "Edm.Geometry",
3035
+ "properties": "Core.Dictionary",
3036
+ "id": "Edm.String"
3037
+ }
3038
+ },
2996
3039
  "Core.RevisionKind": {
2997
3040
  "$kind": "EnumType",
2998
3041
  "Members": [
@@ -3041,6 +3084,10 @@
3041
3084
  "$kind": "TypeDefinition",
3042
3085
  "UnderlyingType": "Edm.String"
3043
3086
  },
3087
+ "Core.QualifiedActionName": {
3088
+ "$kind": "TypeDefinition",
3089
+ "UnderlyingType": "Edm.String"
3090
+ },
3044
3091
  "Core.LocalDateTime": {
3045
3092
  "$kind": "TypeDefinition",
3046
3093
  "UnderlyingType": "Edm.String"
@@ -3073,8 +3120,7 @@
3073
3120
  "$kind": "ComplexType",
3074
3121
  "Properties": {
3075
3122
  "width": "Edm.String"
3076
- },
3077
- "$experimental": true
3123
+ }
3078
3124
  },
3079
3125
  "Measures.DurationGranularityType": {
3080
3126
  "$kind": "TypeDefinition",
@@ -1 +1 @@
1
- fbf6b49a533d366eef716d236739c5cf
1
+ 1bb596306f100150c345f169744f5170