@sap/cds-compiler 4.7.6 → 4.9.0
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 +63 -3
- package/bin/cds_remove_invalid_whitespace.js +135 -0
- package/bin/cds_update_annotations.js +180 -0
- package/bin/cds_update_identifiers.js +3 -4
- package/bin/cdsc.js +28 -1
- package/bin/cdshi.js +13 -3
- package/doc/CHANGELOG_BETA.md +24 -1
- package/lib/api/main.js +119 -46
- package/lib/api/options.js +51 -0
- package/lib/api/validate.js +1 -5
- package/lib/base/builtins.js +116 -0
- package/lib/base/keywords.js +5 -1
- package/lib/base/location.js +91 -14
- package/lib/base/message-registry.js +76 -46
- package/lib/base/messages.js +121 -35
- package/lib/base/model.js +4 -7
- package/lib/checks/actionsFunctions.js +3 -3
- package/lib/checks/annotationsOData.js +3 -0
- package/lib/checks/defaultValues.js +5 -2
- package/lib/checks/elements.js +2 -1
- package/lib/checks/enricher.js +2 -2
- package/lib/checks/queryNoDbArtifacts.js +5 -3
- package/lib/checks/utils.js +1 -1
- package/lib/checks/validator.js +8 -56
- package/lib/compiler/assert-consistency.js +11 -7
- package/lib/compiler/builtins.js +0 -74
- package/lib/compiler/checks.js +105 -29
- package/lib/compiler/define.js +37 -25
- package/lib/compiler/extend.js +35 -12
- package/lib/compiler/index.js +9 -10
- package/lib/compiler/lsp-api.js +5 -0
- package/lib/compiler/populate.js +13 -5
- package/lib/compiler/propagator.js +24 -18
- package/lib/compiler/resolve.js +47 -45
- package/lib/compiler/shared.js +61 -21
- package/lib/compiler/tweak-assocs.js +15 -90
- package/lib/compiler/utils.js +3 -3
- package/lib/compiler/xpr-rewrite.js +689 -0
- package/lib/compiler/{classes.js → xsn-model.js} +0 -16
- package/lib/edm/annotations/edmJson.js +7 -5
- package/lib/edm/annotations/genericTranslation.js +149 -71
- package/lib/edm/csn2edm.js +25 -9
- package/lib/edm/edm.js +7 -7
- package/lib/edm/edmInboundChecks.js +57 -5
- package/lib/edm/edmPreprocessor.js +54 -25
- package/lib/edm/edmUtils.js +3 -16
- package/lib/gen/Dictionary.json +138 -14
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +2085 -1989
- package/lib/json/csnVersion.js +7 -4
- package/lib/json/from-csn.js +21 -11
- package/lib/json/to-csn.js +8 -4
- package/lib/language/antlrParser.js +1 -1
- package/lib/language/genericAntlrParser.js +23 -16
- package/lib/language/multiLineStringParser.js +2 -2
- package/lib/language/textUtils.js +1 -1
- package/lib/main.d.ts +90 -14
- package/lib/main.js +9 -1
- package/lib/model/cloneCsn.js +21 -9
- package/lib/model/csnRefs.js +153 -42
- package/lib/model/csnUtils.js +14 -11
- package/lib/model/enrichCsn.js +4 -2
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/model/sortViews.js +14 -6
- package/lib/modelCompare/compare.js +135 -122
- package/lib/optionProcessor.js +49 -2
- package/lib/render/DuplicateChecker.js +6 -6
- package/lib/render/manageConstraints.js +1 -0
- package/lib/render/toCdl.js +6 -3
- package/lib/render/toHdbcds.js +4 -48
- package/lib/render/toSql.js +6 -3
- package/lib/transform/addTenantFields.js +58 -35
- package/lib/transform/db/applyTransformations.js +34 -1
- package/lib/transform/db/constraints.js +1 -1
- package/lib/transform/db/expansion.js +11 -3
- package/lib/transform/db/flattening.js +71 -46
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/temporal.js +6 -3
- package/lib/transform/db/transformExists.js +2 -2
- package/lib/transform/db/views.js +1 -4
- package/lib/transform/effective/annotations.js +194 -0
- package/lib/transform/effective/main.js +11 -10
- package/lib/transform/effective/misc.js +45 -14
- package/lib/transform/effective/types.js +4 -3
- package/lib/transform/forOdata.js +29 -12
- package/lib/transform/forRelationalDB.js +104 -113
- package/lib/transform/localized.js +7 -6
- package/lib/transform/odata/flattening.js +228 -107
- package/lib/transform/odata/toFinalBaseType.js +10 -26
- package/lib/transform/odata/typesExposure.js +41 -25
- package/lib/transform/parseExpr.js +4 -7
- package/lib/transform/transformUtils.js +50 -43
- package/lib/transform/translateAssocsToJoins.js +48 -48
- package/lib/transform/universalCsn/coreComputed.js +2 -1
- package/lib/transform/universalCsn/universalCsnEnricher.js +12 -16
- package/package.json +2 -2
- package/share/messages/README.md +4 -0
- package/share/messages/anno-duplicate-unrelated-layer.md +1 -1
- package/share/messages/anno-missing-rewrite.md +45 -0
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/def-duplicate-autoexposed.md +1 -1
- package/share/messages/extend-repeated-intralayer.md +3 -16
- package/share/messages/extend-unrelated-layer.md +1 -1
- package/share/messages/message-explanations.json +2 -0
- package/share/messages/redirected-to-ambiguous.md +1 -1
- package/share/messages/redirected-to-complex.md +1 -1
- package/share/messages/redirected-to-unrelated.md +1 -1
- package/share/messages/rewrite-not-supported.md +1 -1
- package/share/messages/syntax-expecting-unsigned-int.md +2 -2
- package/share/messages/type-missing-enum-value.md +59 -0
- package/share/messages/wildcard-excluding-one.md +1 -1
- package/bin/.eslintrc.json +0 -17
- package/lib/api/.eslintrc.json +0 -37
- package/lib/checks/.eslintrc.json +0 -31
- package/lib/compiler/.eslintrc.json +0 -8
- package/lib/edm/.eslintrc.json +0 -46
- package/lib/inspect/.eslintrc.json +0 -4
- package/lib/json/.eslintrc.json +0 -4
- package/lib/language/.eslintrc.json +0 -4
- package/lib/model/.eslintrc.json +0 -13
- package/lib/modelCompare/utils/.eslintrc.json +0 -22
- package/lib/render/.eslintrc.json +0 -22
- package/lib/transform/.eslintrc.json +0 -13
- package/lib/transform/db/.eslintrc.json +0 -41
- package/lib/transform/draft/.eslintrc.json +0 -4
- package/lib/transform/effective/.eslintrc.json +0 -4
- package/lib/transform/universalCsn/.eslintrc.json +0 -37
- package/lib/utils/.eslintrc.json +0 -7
package/lib/model/csnRefs.js
CHANGED
|
@@ -171,15 +171,14 @@
|
|
|
171
171
|
// hierarchy, query number, table aliases and links from a column to its
|
|
172
172
|
// respective inferred element.
|
|
173
173
|
|
|
174
|
-
// TODO: some `name` property would be useful (also set with `initDefinition`)
|
|
175
|
-
|
|
176
174
|
// Properties in cache:
|
|
177
175
|
//
|
|
178
176
|
// - _effectiveType on def/member/items: cached result of effectiveType()
|
|
179
177
|
// - _origin on def/member/items: the "prototype"
|
|
180
178
|
// - $origin on def/member/items: whether implicit _origin refs have been set for direct members
|
|
181
179
|
// - _parent: currently just use to allow ref to `up_` in anonymous aspect
|
|
182
|
-
// for managed compositions
|
|
180
|
+
// for managed compositions;
|
|
181
|
+
// in queries always the main artifact (see `$next` for name resolution)
|
|
183
182
|
// - _env on non-string path item: environment provided by the ref so far,
|
|
184
183
|
// next path item is element in it
|
|
185
184
|
// - _ref on non-string `type` or `from` ref, or on alias: the referred def/elem
|
|
@@ -193,10 +192,11 @@
|
|
|
193
192
|
|
|
194
193
|
'use strict';
|
|
195
194
|
|
|
195
|
+
|
|
196
196
|
const BUILTIN_TYPE = {};
|
|
197
|
-
const { locationString } = require('../base/location');
|
|
197
|
+
const { SemanticLocation, locationString } = require('../base/location');
|
|
198
198
|
const { ModelError, CompilerAssertion } = require('../base/error');
|
|
199
|
-
const { isAnnotationExpression } = require('../
|
|
199
|
+
const { isAnnotationExpression } = require('../base/builtins');
|
|
200
200
|
|
|
201
201
|
// Properties in which artifact or members are defined - next property in the
|
|
202
202
|
// "csnPath" is the name or index of that property; 'args' (its value can be a
|
|
@@ -230,7 +230,8 @@ const referenceSemantics = {
|
|
|
230
230
|
orderBy_ref: { lexical: query => query, dynamic: 'query' },
|
|
231
231
|
orderBy_expr: { lexical: query => query, dynamic: 'source' }, // ref in ORDER BY expression
|
|
232
232
|
orderBy_set_ref: { lexical: query => query.$next, dynamic: 'query' }, // to outer SELECT (from UNION)
|
|
233
|
-
// refs in ORDER BY expr in UNION not really allowed
|
|
233
|
+
// refs in ORDER BY expr in UNION not really allowed
|
|
234
|
+
// only with table alias (of outer queries) or $self
|
|
234
235
|
orderBy_set_expr: { lexical: query => query.$next, dynamic: false },
|
|
235
236
|
// default: { lexical: query => query, dynamic: 'source' }
|
|
236
237
|
};
|
|
@@ -244,11 +245,13 @@ function justDollar() {
|
|
|
244
245
|
* @param {boolean|string} [universalReady]
|
|
245
246
|
*/
|
|
246
247
|
function csnRefs( csn, universalReady ) {
|
|
248
|
+
// some users exchange the dict while using csn-refs !?! see test/testDraft.js
|
|
249
|
+
// const { definitions } = csn;
|
|
247
250
|
const cache = new WeakMap();
|
|
248
251
|
setCache( BUILTIN_TYPE, '_origin', null );
|
|
249
252
|
if (universalReady === 'init-all') {
|
|
250
|
-
for (const
|
|
251
|
-
initDefinition(
|
|
253
|
+
for (const name of Object.keys( csn.definitions || {}))
|
|
254
|
+
initDefinition( name );
|
|
252
255
|
}
|
|
253
256
|
// Functions which set the new `baseEnv`:
|
|
254
257
|
resolveRef.expandInline = function resolveExpandInline( ref, ...args ) {
|
|
@@ -275,6 +278,7 @@ function csnRefs( csn, universalReady ) {
|
|
|
275
278
|
initDefinition,
|
|
276
279
|
dropDefinitionCache,
|
|
277
280
|
targetAspect,
|
|
281
|
+
msgLocations,
|
|
278
282
|
__getCache_forEnrichCsnDebugging: obj => cache.get( obj ),
|
|
279
283
|
};
|
|
280
284
|
|
|
@@ -324,9 +328,7 @@ function csnRefs( csn, universalReady ) {
|
|
|
324
328
|
const target = (staticAssoc ? targetAspect( env ) : env.target || env.targetAspect);
|
|
325
329
|
if (typeof target !== 'string')
|
|
326
330
|
return target || env;
|
|
327
|
-
|
|
328
|
-
initDefinition( def );
|
|
329
|
-
return def;
|
|
331
|
+
return initDefinition( target );
|
|
330
332
|
}
|
|
331
333
|
|
|
332
334
|
/**
|
|
@@ -342,18 +344,19 @@ function csnRefs( csn, universalReady ) {
|
|
|
342
344
|
if (typeof ref === 'string') {
|
|
343
345
|
const main = csn.definitions[ref];
|
|
344
346
|
if (main)
|
|
345
|
-
return initDefinition(
|
|
347
|
+
return initDefinition( ref );
|
|
348
|
+
// notFound only meant for builtins and $self
|
|
349
|
+
if (notFound !== undefined)
|
|
350
|
+
return notFound;
|
|
346
351
|
}
|
|
347
352
|
else {
|
|
348
353
|
const art = cached( ref, '_ref', artifactPathRef );
|
|
349
354
|
if (art)
|
|
350
355
|
return art;
|
|
356
|
+
// Backend bug workaround, TODO: delete next 2 lines
|
|
357
|
+
if (notFound !== undefined)
|
|
358
|
+
return notFound;
|
|
351
359
|
}
|
|
352
|
-
if (notFound !== undefined && typeof ref === 'string')
|
|
353
|
-
return notFound; // is only meant for builtins and $self
|
|
354
|
-
// Backend bug workaround, TODO: delete next 2 lines
|
|
355
|
-
if (notFound !== undefined)
|
|
356
|
-
return notFound;
|
|
357
360
|
throw new ModelError( `Unknown artifact reference: ${ typeof ref !== 'string' ? JSON.stringify(ref.ref) : ref }` );
|
|
358
361
|
}
|
|
359
362
|
|
|
@@ -367,8 +370,7 @@ function csnRefs( csn, universalReady ) {
|
|
|
367
370
|
|
|
368
371
|
function artifactPathRef( ref ) {
|
|
369
372
|
const [ head, ...tail ] = ref.ref;
|
|
370
|
-
let art =
|
|
371
|
-
initDefinition( art );
|
|
373
|
+
let art = initDefinition( pathId( head ) );
|
|
372
374
|
for (const elem of tail) {
|
|
373
375
|
const env = navigationEnv( art );
|
|
374
376
|
art = env.elements[pathId( elem )];
|
|
@@ -378,8 +380,7 @@ function csnRefs( csn, universalReady ) {
|
|
|
378
380
|
|
|
379
381
|
function artifactFromRef( ref, noLast ) {
|
|
380
382
|
const [ head, ...tail ] = ref.ref;
|
|
381
|
-
let art =
|
|
382
|
-
initDefinition( art );
|
|
383
|
+
let art = initDefinition( pathId( head ) );
|
|
383
384
|
for (const elem of tail) {
|
|
384
385
|
const env = navigationEnv( art );
|
|
385
386
|
art = env.elements[pathId( elem )];
|
|
@@ -401,9 +402,7 @@ function csnRefs( csn, universalReady ) {
|
|
|
401
402
|
const targetName = refCtx !== 'keys_origin' && art.target ||
|
|
402
403
|
art.$origin && art.$origin.target ||
|
|
403
404
|
art.cast.target;
|
|
404
|
-
|
|
405
|
-
initDefinition( target );
|
|
406
|
-
return target;
|
|
405
|
+
return initDefinition( targetName );
|
|
407
406
|
}
|
|
408
407
|
|
|
409
408
|
function getOrigin( art ) {
|
|
@@ -411,8 +410,11 @@ function csnRefs( csn, universalReady ) {
|
|
|
411
410
|
}
|
|
412
411
|
|
|
413
412
|
function getOriginRaw( art ) {
|
|
414
|
-
if (art.type) // TODO: make robust against "linked" = only direct
|
|
415
|
-
return
|
|
413
|
+
if (art.type) { // TODO: make robust against "linked" = only direct
|
|
414
|
+
return (art.type !== '$self' || csn.definitions.$self)
|
|
415
|
+
? artifactRef( art.type, BUILTIN_TYPE )
|
|
416
|
+
: getCache( boundActionOrMain( art ), '_parent' );
|
|
417
|
+
}
|
|
416
418
|
if (typeof art.$origin === 'object') // null, […], {…}
|
|
417
419
|
return getOriginExplicit( art.$origin );
|
|
418
420
|
|
|
@@ -437,9 +439,8 @@ function csnRefs( csn, universalReady ) {
|
|
|
437
439
|
if (!Array.isArray( $origin )) // anonymous prototype in $origin
|
|
438
440
|
return getOriginExplicit( $origin.$origin );
|
|
439
441
|
const [ head, ...tail ] = $origin;
|
|
440
|
-
const main = csn.definitions[head];
|
|
441
442
|
// if (!main) throw Error(JSON.stringify({$origin,csn}))
|
|
442
|
-
initDefinition(
|
|
443
|
+
const main = initDefinition( head );
|
|
443
444
|
return tail.reduce( originNavigation, main );
|
|
444
445
|
}
|
|
445
446
|
|
|
@@ -483,8 +484,13 @@ function csnRefs( csn, universalReady ) {
|
|
|
483
484
|
}
|
|
484
485
|
|
|
485
486
|
function initDefinition( main ) {
|
|
487
|
+
const name = typeof main === 'string' && main;
|
|
488
|
+
if (name) {
|
|
489
|
+
main = csn.definitions[name];
|
|
490
|
+
setCache( main, '$name', name );
|
|
491
|
+
}
|
|
486
492
|
// TODO: some --test-mode check that the argument is in ‹csn›.definitions ?
|
|
487
|
-
if (getCache( main, '$queries' ) !== undefined) // already computed
|
|
493
|
+
if (!main || getCache( main, '$queries' ) !== undefined) // already computed
|
|
488
494
|
return main;
|
|
489
495
|
traverseDef( main, null, null, null, initNode );
|
|
490
496
|
const queries = cached( main, '$queries', allQueries );
|
|
@@ -650,7 +656,7 @@ function csnRefs( csn, universalReady ) {
|
|
|
650
656
|
const up = getCache( parent, '_parent' );
|
|
651
657
|
const target = up && typeof up.target === 'string' && csn.definitions[up.target];
|
|
652
658
|
if (target && target.elements) {
|
|
653
|
-
initDefinition( target );
|
|
659
|
+
initDefinition( up.target );
|
|
654
660
|
art = target.elements.up_;
|
|
655
661
|
}
|
|
656
662
|
}
|
|
@@ -696,7 +702,8 @@ function csnRefs( csn, universalReady ) {
|
|
|
696
702
|
const links = path.map( (_v, idx) => ({ idx }) );
|
|
697
703
|
// TODO: backends should be changed to enable uncommenting:
|
|
698
704
|
// if (!art) // does not work with test3/Associations/KeylessManagedAssociation/
|
|
699
|
-
// throw new ModelError( `Path item 0=${ pathId( path[0] )
|
|
705
|
+
// throw new ModelError( `Path item 0=${ pathId( path[0] )
|
|
706
|
+
// } refers to nothing, scope: ${ scope }`);
|
|
700
707
|
links[0].art = art;
|
|
701
708
|
for (let i = 1; i < links.length; ++i) { // yes, starting at 1, links[0] is set above
|
|
702
709
|
parent = navigationEnv( art, staticAssoc );
|
|
@@ -734,6 +741,110 @@ function csnRefs( csn, universalReady ) {
|
|
|
734
741
|
};
|
|
735
742
|
}
|
|
736
743
|
|
|
744
|
+
/**
|
|
745
|
+
* Return [ Location, SemanticLocation ] from `csnPath`.
|
|
746
|
+
*/
|
|
747
|
+
function msgLocations( csnPath ) {
|
|
748
|
+
let location = csn?.$location;
|
|
749
|
+
const artifact = new SemanticLocation();
|
|
750
|
+
let obj = csn;
|
|
751
|
+
let index = 0;
|
|
752
|
+
let inlinePathIndex = null;
|
|
753
|
+
if (typeof csnPath[0] === 'object')
|
|
754
|
+
startPath( csnPath[0] );
|
|
755
|
+
|
|
756
|
+
/* eslint-disable no-return-assign */
|
|
757
|
+
const pathFunctions = {
|
|
758
|
+
definitions: name => absolute( name, 'type' ),
|
|
759
|
+
vocabularies: name => absolute( name, 'annotation' ),
|
|
760
|
+
extensions,
|
|
761
|
+
projection,
|
|
762
|
+
SELECT: projection,
|
|
763
|
+
// TODO: alias
|
|
764
|
+
mixin: name => nameInProp( name, 'mixin' ),
|
|
765
|
+
actions: name => nameInProp( name, 'action' ),
|
|
766
|
+
params: name => nameInProp( name, 'param' ),
|
|
767
|
+
returns: () => (artifact.param = ''),
|
|
768
|
+
elements: name => elements( name, artifact.select == null ? null : 'element' ),
|
|
769
|
+
columns: elements,
|
|
770
|
+
expand: elements,
|
|
771
|
+
inline: elements,
|
|
772
|
+
keys: pos => elements( pos, 'key' ),
|
|
773
|
+
enum: name => elements( name, 'enum' ),
|
|
774
|
+
item: () => (artifact.innerKind = 'item'),
|
|
775
|
+
// targetAspect: () => (artifact.innerKind = 'aspect')
|
|
776
|
+
'@': suffix,
|
|
777
|
+
}; /* eslint-enable no-return-assign */
|
|
778
|
+
|
|
779
|
+
while (obj && index < csnPath.length) {
|
|
780
|
+
const step = csnPath[index++];
|
|
781
|
+
obj = obj[step];
|
|
782
|
+
const fn = pathFunctions[step] || pathFunctions[step.charAt( 0 )];
|
|
783
|
+
if (fn)
|
|
784
|
+
fn( csnPath[index] );
|
|
785
|
+
if (obj?.$location)
|
|
786
|
+
location = obj.$location;
|
|
787
|
+
}
|
|
788
|
+
return [ location, artifact ];
|
|
789
|
+
|
|
790
|
+
function startPath( art ) {
|
|
791
|
+
const parent = getCache( art, '_parent' );
|
|
792
|
+
if (parent) {
|
|
793
|
+
if (!art.SELECT && !art.projection)
|
|
794
|
+
throw new CompilerAssertion( 'CSN path starts with object other than def or query' );
|
|
795
|
+
}
|
|
796
|
+
obj = csn.definitions;
|
|
797
|
+
absolute( getCache( parent || art, '$name' ), 'type' );
|
|
798
|
+
obj = art;
|
|
799
|
+
location = art.$location || parent?.$location || csn.$location;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function absolute( name, defaultKind ) {
|
|
803
|
+
obj = obj[name];
|
|
804
|
+
artifact.mainKind = obj.kind || defaultKind;
|
|
805
|
+
artifact.absolute = name;
|
|
806
|
+
++index;
|
|
807
|
+
}
|
|
808
|
+
function extensions( pos ) {
|
|
809
|
+
obj = obj[pos];
|
|
810
|
+
artifact.mainKind = obj.annotate ? 'annotate' : 'extend';
|
|
811
|
+
artifact.absolute = obj.annotate || obj.extend;
|
|
812
|
+
++index;
|
|
813
|
+
}
|
|
814
|
+
function projection() {
|
|
815
|
+
let select = getCache( obj, '$queryNumber' );
|
|
816
|
+
if (select === 1) {
|
|
817
|
+
const parent = getCache( obj, '_parent' );
|
|
818
|
+
if (parent && getCache( parent, '$queries' )?.length === 1)
|
|
819
|
+
select = 0;
|
|
820
|
+
}
|
|
821
|
+
artifact.select = select;
|
|
822
|
+
}
|
|
823
|
+
function nameInProp( name, prop ) {
|
|
824
|
+
obj = obj[name];
|
|
825
|
+
artifact[prop] = name;
|
|
826
|
+
++index;
|
|
827
|
+
}
|
|
828
|
+
function elements( name, kind ) {
|
|
829
|
+
obj = obj[name];
|
|
830
|
+
const elem = (typeof name === 'string') ? name : !obj.inline && columnAlias( obj );
|
|
831
|
+
if (obj.inline) { // inline
|
|
832
|
+
inlinePathIndex ??= artifact.element.length;
|
|
833
|
+
}
|
|
834
|
+
else if (inlinePathIndex != null) { // inline before: remove inline col indexes
|
|
835
|
+
if (elem)
|
|
836
|
+
artifact.element.length = inlinePathIndex;
|
|
837
|
+
inlinePathIndex = null;
|
|
838
|
+
}
|
|
839
|
+
artifact.element.push( elem || name + 1);
|
|
840
|
+
artifact.innerKind = kind || undefined;
|
|
841
|
+
++index;
|
|
842
|
+
}
|
|
843
|
+
function suffix( prop ) {
|
|
844
|
+
artifact.suffix = prop;
|
|
845
|
+
obj = null; // stop
|
|
846
|
+
}
|
|
847
|
+
}
|
|
737
848
|
/**
|
|
738
849
|
* Get the array of all (sub-)queries (value of the `SELECT`/`projection`
|
|
739
850
|
* property) inside the given `main` artifact (of `main.query`).
|
|
@@ -904,8 +1015,8 @@ function queryOrMain( query, main ) {
|
|
|
904
1015
|
* - NOT on a `join` node inside `from`.
|
|
905
1016
|
*
|
|
906
1017
|
* @param {CSN.Query} query
|
|
907
|
-
* @param {CSN.QuerySelect} fromSelect
|
|
908
|
-
* @param {CSN.Query} parentQuery
|
|
1018
|
+
* @param {CSN.QuerySelect} fromSelect for query in `from`
|
|
1019
|
+
* @param {CSN.Query} parentQuery for a sub query (ex those in `from`)
|
|
909
1020
|
* @param {(query: CSN.Query&CSN.QueryFrom, select: CSN.QuerySelectEnriched, parentQuery: CSN.Query) => void} callback
|
|
910
1021
|
*/
|
|
911
1022
|
function traverseQuery( query, fromSelect, parentQuery, callback ) {
|
|
@@ -1021,16 +1132,18 @@ function implicitAs( ref ) {
|
|
|
1021
1132
|
function startCsnPath( csnPath, csn ) {
|
|
1022
1133
|
const head = csnPath[0];
|
|
1023
1134
|
if (typeof head !== 'string') {
|
|
1024
|
-
const {
|
|
1135
|
+
const {
|
|
1136
|
+
main, parent, art, query,
|
|
1137
|
+
} = head;
|
|
1025
1138
|
return {
|
|
1026
|
-
index: 1, main, parent, art,
|
|
1139
|
+
index: 1, main, parent, art, query,
|
|
1027
1140
|
};
|
|
1028
1141
|
}
|
|
1029
|
-
if (csnPath.length < 2 ||
|
|
1030
|
-
throw new CompilerAssertion( 'References outside definitions and vocabularies not supported yet');
|
|
1031
|
-
const art = csn[
|
|
1142
|
+
if (csnPath.length < 2 || head !== 'definitions' && head !== 'vocabularies')
|
|
1143
|
+
throw new CompilerAssertion( 'References outside definitions and vocabularies not supported yet' );
|
|
1144
|
+
const art = csn[head][csnPath[1]];
|
|
1032
1145
|
return {
|
|
1033
|
-
index: 2, main: art, parent: art, art,
|
|
1146
|
+
index: 2, main: art, parent: art, art, query: null,
|
|
1034
1147
|
};
|
|
1035
1148
|
}
|
|
1036
1149
|
|
|
@@ -1041,8 +1154,6 @@ function startCsnPath( csnPath, csn ) {
|
|
|
1041
1154
|
* @param {any} resolve
|
|
1042
1155
|
*/
|
|
1043
1156
|
function analyseCsnPath( csnPath, csn, resolve ) {
|
|
1044
|
-
/** @type {object} */
|
|
1045
|
-
let query = null;
|
|
1046
1157
|
/** @type {any} */
|
|
1047
1158
|
let refCtx = null;
|
|
1048
1159
|
/** @type {boolean|string|number} */
|
|
@@ -1051,7 +1162,7 @@ function analyseCsnPath( csnPath, csn, resolve ) {
|
|
|
1051
1162
|
let baseCtx = null;
|
|
1052
1163
|
let baseEnv = null;
|
|
1053
1164
|
let {
|
|
1054
|
-
index, main, parent, art,
|
|
1165
|
+
index, main, parent, art, query,
|
|
1055
1166
|
} = startCsnPath( csnPath, csn );
|
|
1056
1167
|
let obj = art;
|
|
1057
1168
|
|
package/lib/model/csnUtils.js
CHANGED
|
@@ -6,8 +6,9 @@ const {
|
|
|
6
6
|
applyTransformations,
|
|
7
7
|
applyTransformationsOnNonDictionary,
|
|
8
8
|
applyTransformationsOnDictionary,
|
|
9
|
+
mergeTransformers,
|
|
9
10
|
} = require('../transform/db/applyTransformations');
|
|
10
|
-
const { isBuiltinType,
|
|
11
|
+
const { isBuiltinType, isAnnotationExpression } = require('../base/builtins');
|
|
11
12
|
const { ModelError, CompilerAssertion } = require('../base/error');
|
|
12
13
|
const { typeParameters } = require('../compiler/builtins');
|
|
13
14
|
const { forEach } = require('../utils/objectUtils');
|
|
@@ -134,7 +135,8 @@ function getUtils( model, universalReady ) {
|
|
|
134
135
|
}
|
|
135
136
|
else if (arg.ref) {
|
|
136
137
|
const art = artifactRef.from(arg);
|
|
137
|
-
elements = mergeElementsIntoMap(elements, art.elements, art.$location,
|
|
138
|
+
elements = mergeElementsIntoMap(elements, art.elements, art.$location,
|
|
139
|
+
arg.as || implicitAs(arg.ref), implicitAs(arg.ref) || arg.as);
|
|
138
140
|
}
|
|
139
141
|
else if (arg.SELECT || arg.SET) {
|
|
140
142
|
elements = mergeElementMaps(elements, getSources(arg, true));
|
|
@@ -670,11 +672,13 @@ function isEdmPropertyRendered( elementCsn, options ) {
|
|
|
670
672
|
// V4 struct: on/off
|
|
671
673
|
if (elementCsn == null)
|
|
672
674
|
return false;
|
|
673
|
-
const renderForeignKey = (options.odataVersion === 'v4' && options.odataFormat === 'structured')
|
|
675
|
+
const renderForeignKey = (options.odataVersion === 'v4' && options.odataFormat === 'structured')
|
|
676
|
+
? !!options.odataForeignKeys : true;
|
|
674
677
|
const isNotIgnored = !elementCsn.target ? !elementCsn['@cds.api.ignore'] : true;
|
|
675
678
|
const isNavigable = elementCsn.target
|
|
676
679
|
? (elementCsn['@odata.navigable'] === undefined ||
|
|
677
|
-
elementCsn['@odata.navigable'] !== undefined &&
|
|
680
|
+
elementCsn['@odata.navigable'] !== undefined &&
|
|
681
|
+
(elementCsn['@odata.navigable'] === null || elementCsn['@odata.navigable'] === true)) : true;
|
|
678
682
|
// Foreign Keys can be ignored
|
|
679
683
|
if (elementCsn['@odata.foreignKey4'])
|
|
680
684
|
return isNotIgnored && renderForeignKey;
|
|
@@ -1124,7 +1128,7 @@ function moveAnnotationsAndDoc( sourceNode, targetNode, overwrite = false ) {
|
|
|
1124
1128
|
* override: Whether to ignore existing annotations.
|
|
1125
1129
|
* filter: Positive filter. If it returns true, annotations for the referenced artifact
|
|
1126
1130
|
* will be applied.
|
|
1127
|
-
* applyToElements:
|
|
1131
|
+
* applyToElements: Whether to apply annotations to elements or only to artifacts
|
|
1128
1132
|
*/
|
|
1129
1133
|
function applyAnnotationsFromExtensions( csn, config ) {
|
|
1130
1134
|
if (!csn.extensions)
|
|
@@ -1189,7 +1193,8 @@ function isAspect( node ) {
|
|
|
1189
1193
|
*/
|
|
1190
1194
|
function hasValidSkipOrExists( artifact ) {
|
|
1191
1195
|
return artifact.kind === 'entity' &&
|
|
1192
|
-
(hasAnnotationValue(artifact, '@cds.persistence.exists', true) ||
|
|
1196
|
+
(hasAnnotationValue(artifact, '@cds.persistence.exists', true) ||
|
|
1197
|
+
hasAnnotationValue(artifact, '@cds.persistence.skip', true));
|
|
1193
1198
|
}
|
|
1194
1199
|
|
|
1195
1200
|
/**
|
|
@@ -1368,7 +1373,8 @@ function functionList( functions, thisArg ) {
|
|
|
1368
1373
|
* @returns {boolean}
|
|
1369
1374
|
*/
|
|
1370
1375
|
function isDollarSelfOrProjectionOperand( arg ) {
|
|
1371
|
-
return arg.ref && arg.ref.length === 1 &&
|
|
1376
|
+
return arg.ref && arg.ref.length === 1 &&
|
|
1377
|
+
(arg.ref[0] === '$self' || arg.ref[0] === '$projection');
|
|
1372
1378
|
}
|
|
1373
1379
|
|
|
1374
1380
|
/**
|
|
@@ -1408,15 +1414,11 @@ function findAnnotationExpression( node, prop ) {
|
|
|
1408
1414
|
},
|
|
1409
1415
|
});
|
|
1410
1416
|
}
|
|
1411
|
-
|
|
1412
1417
|
return isExpr;
|
|
1413
1418
|
}
|
|
1414
1419
|
|
|
1415
1420
|
module.exports = {
|
|
1416
1421
|
getUtils,
|
|
1417
|
-
isBuiltinType,
|
|
1418
|
-
isMagicVariable,
|
|
1419
|
-
isAnnotationExpression,
|
|
1420
1422
|
applyAnnotationsFromExtensions,
|
|
1421
1423
|
forEachGeneric,
|
|
1422
1424
|
forEachDefinition,
|
|
@@ -1433,6 +1435,7 @@ module.exports = {
|
|
|
1433
1435
|
applyTransformations,
|
|
1434
1436
|
applyTransformationsOnNonDictionary,
|
|
1435
1437
|
applyTransformationsOnDictionary,
|
|
1438
|
+
mergeTransformers,
|
|
1436
1439
|
setDependencies,
|
|
1437
1440
|
isPersistedOnDatabase,
|
|
1438
1441
|
isPersistedAsView,
|
package/lib/model/enrichCsn.js
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
const { csnRefs, artifactProperties } = require('./csnRefs');
|
|
43
43
|
const { locationString } = require('../base/location');
|
|
44
44
|
const { CompilerAssertion } = require('../base/error');
|
|
45
|
-
const { isAnnotationExpression } = require('../
|
|
45
|
+
const { isAnnotationExpression } = require('../base/builtins');
|
|
46
46
|
const shuffleGen = require('../base/shuffle');
|
|
47
47
|
|
|
48
48
|
function enrichCsn( csn, options = {} ) {
|
|
@@ -207,7 +207,9 @@ function enrichCsn( csn, options = {} ) {
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
function pathRef( parent, prop, path, inspectionPath = csnPath ) {
|
|
210
|
-
const inspection = handleError( err => ((err)
|
|
210
|
+
const inspection = handleError( err => ((err)
|
|
211
|
+
? { scope: err.toString() }
|
|
212
|
+
: inspectRef( inspectionPath )));
|
|
211
213
|
const {
|
|
212
214
|
links, art, scope, $env,
|
|
213
215
|
} = inspection;
|
|
@@ -38,7 +38,8 @@ const kindsRepresentedAsLinks = {
|
|
|
38
38
|
// represent table alias in from / join-args property as link:
|
|
39
39
|
$tableAlias: tableAliasAsLink,
|
|
40
40
|
// represent "navigation elements" in _combined as links:
|
|
41
|
-
$navElement: (art, parent) => art._parent && parent !== art._parent.elements &&
|
|
41
|
+
$navElement: (art, parent) => art._parent && parent !== art._parent.elements &&
|
|
42
|
+
art._parent.kind !== 'aspect',
|
|
42
43
|
// represent mixin in $tableAliases as link:
|
|
43
44
|
mixin: tableAliasAsLink,
|
|
44
45
|
// represent $projection as link, as it is just another search name for $self:
|
package/lib/model/sortViews.js
CHANGED
|
@@ -5,8 +5,11 @@ const { ModelError } = require('../base/error');
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @typedef {Object} Layers
|
|
8
|
-
* @property {Array[]} layers
|
|
9
|
-
*
|
|
8
|
+
* @property {Array[]} layers
|
|
9
|
+
* An array of arrays, each subarray encompassing one Layer - L0 being layers[0].
|
|
10
|
+
* @property {CSN.Artifact[]} leftover
|
|
11
|
+
* Any artifacts not sorted into a layer due to unmet dependencies.
|
|
12
|
+
* Points to there being some error.
|
|
10
13
|
*/
|
|
11
14
|
|
|
12
15
|
/**
|
|
@@ -22,7 +25,8 @@ const { ModelError } = require('../base/error');
|
|
|
22
25
|
*/
|
|
23
26
|
function sortTopologically( csn, _dependents, _dependencies ) {
|
|
24
27
|
const layers = [];
|
|
25
|
-
let { zero, nonZero } = _calculateDepth(Object.entries(csn.definitions),
|
|
28
|
+
let { zero, nonZero } = _calculateDepth(Object.entries(csn.definitions),
|
|
29
|
+
_dependents, _dependencies);
|
|
26
30
|
while (zero.length !== 0) {
|
|
27
31
|
const currentLayer = [];
|
|
28
32
|
zero.forEach(([ artifactName, artifact ]) => {
|
|
@@ -87,8 +91,10 @@ function _findWithXPointers( definitionsArray, x, _dependents, _dependencies ) {
|
|
|
87
91
|
* For ordering, only the FROM clause of views is checked - this requires A2J to
|
|
88
92
|
* be run beforehand to resolve association usages.
|
|
89
93
|
*
|
|
90
|
-
* @param {{sql: string, csn: CSN.Model}} arg
|
|
91
|
-
*
|
|
94
|
+
* @param {{sql: string, csn: CSN.Model}} arg
|
|
95
|
+
* sql: Map of <object name>: "CREATE STATEMENT", csn: Model
|
|
96
|
+
* @returns {{name: string, sql: string}[]}
|
|
97
|
+
* Sorted array of artifact name / "CREATE STATEMENTS" pairs
|
|
92
98
|
*/
|
|
93
99
|
module.exports = function sortViews({ sql, csn }) {
|
|
94
100
|
const { cleanup, _dependents, _dependencies } = setDependencies(csn);
|
|
@@ -98,7 +104,9 @@ module.exports = function sortViews({ sql, csn }) {
|
|
|
98
104
|
|
|
99
105
|
const result = [];
|
|
100
106
|
// keep the "artifact name" - needed for to.hdi sorting
|
|
101
|
-
layers.forEach(layer => layer.forEach(objName => result.push({
|
|
107
|
+
layers.forEach(layer => layer.forEach(objName => result.push({
|
|
108
|
+
name: objName, sql: sql[objName], dependents: csn.definitions[objName][_dependents],
|
|
109
|
+
})));
|
|
102
110
|
// attach sql artifacts which are not considered during the view sorting algorithm
|
|
103
111
|
// --> this is the case for "ALTER TABLE ADD CONSTRAINT" statements,
|
|
104
112
|
// because their identifiers are not part of the csn.definitions
|