@@ -99,12 +99,12 @@ function infer(originalQuery, model = cds.context?.model || cds.model) {
99
99
if ( ! target ) throw new Error ( `"${ first } " not found in the definitions of your model` )
100
100
if ( ref . length > 1 ) {
101
101
target = from . ref . slice ( 1 ) . reduce ( ( d , r ) => {
102
- const next = d . elements [ r . id || r ] ?. elements ? d . elements [ r . id || r ] : d . elements [ r . id || r ] ?. _target
102
+ const next = d . elements [ r . id || r ] ?. _target || d . elements [ r . id || r ]
103
103
if ( ! next ) throw new Error ( `No association “${ r . id || r } ” in ${ d . kind } “${ d . name } ”` )
104
104
return next
105
105
} , target )
106
106
}
107
- if ( target . kind !== 'entity' && ! target . _isAssociation )
107
+ if ( target . kind !== 'entity' && ! target . isAssociation )
108
108
throw new Error ( 'Query source must be a an entity or an association' )
109
109
110
110
attachRefLinksToArg ( from ) // REVISIT: remove
@@ -165,7 +165,7 @@ function infer(originalQuery, model = cds.context?.model || cds.model) {
165
165
// we need to search for first step in ´model.definitions[infixAlias]`
166
166
if ( $baseLink ) {
167
167
const { definition } = $baseLink
168
- const elements = definition . elements || definition . _target ? .elements
168
+ const elements = definition . _target ?. elements || definition . elements
169
169
const e = elements ?. [ id ] || cds . error `"${ id } " not found in the elements of "${ definition . name } "`
170
170
if ( e . target ) {
171
171
// only fk access in infix filter
@@ -176,7 +176,7 @@ function infer(originalQuery, model = cds.context?.model || cds.model) {
176
176
`"${ e . name } " in path "${ arg . ref . map ( idOnly ) . join ( '.' ) } " must not be an unmanaged association` ,
177
177
)
178
178
// no non-fk traversal in infix filter
179
- if ( ! expandOrExists && nextStep && ! ( nextStep in e . foreignKeys ) )
179
+ if ( ! expandOrExists && nextStep && ! isForeignKeyOf ( nextStep , e ) )
180
180
throw new Error ( `Only foreign keys of "${ e . name } " can be accessed in infix filter` )
181
181
}
182
182
arg . $refLinks . push ( { definition : e , target : definition } )
@@ -495,7 +495,7 @@ function infer(originalQuery, model = cds.context?.model || cds.model) {
495
495
nameSegments . push ( id )
496
496
} else if ( $baseLink ) {
497
497
const { definition, target } = $baseLink
498
- const elements = definition . elements || definition . _target ? .elements
498
+ const elements = definition . _target ?. elements || definition . elements
499
499
if ( elements && id in elements ) {
500
500
const element = elements [ id ]
501
501
rejectNonFkAccess ( element )
@@ -530,7 +530,7 @@ function infer(originalQuery, model = cds.context?.model || cds.model) {
530
530
}
531
531
} else {
532
532
const { definition } = column . $refLinks [ i - 1 ]
533
- const elements = definition . elements || definition . _target ?. elements
533
+ const elements = definition . _target ?. elements || definition . elements //> go for assoc._target first, instead of assoc as struct
534
534
const element = elements ?. [ id ]
535
535
536
536
if ( firstStepIsSelf && element ?. isAssociation ) {
@@ -648,25 +648,25 @@ function infer(originalQuery, model = cds.context?.model || cds.model) {
648
648
}
649
649
650
650
/**
651
- * Check if the next step in the ref is foreign key of `element `
651
+ * Check if the next step in the ref is foreign key of `assoc `
652
652
* if not, an error is thrown.
653
- *
654
- * @param {CSN.Element } element if this is an association, the next step must be a foreign key of the element.
653
+ *
654
+ * @param {CSN.Element } assoc if this is an association, the next step must be a foreign key of the element.
655
655
*/
656
- function rejectNonFkAccess ( element ) {
657
- if ( ! inNestedProjection && ! inCalcElement && element . target ) {
656
+ function rejectNonFkAccess ( assoc ) {
657
+ if ( ! inNestedProjection && ! inCalcElement && assoc . target ) {
658
658
// only fk access in infix filter
659
659
const nextStep = column . ref [ i + 1 ] ?. id || column . ref [ i + 1 ]
660
660
// no unmanaged assoc in infix filter path
661
- if ( ! inExists && element . on )
661
+ if ( ! inExists && assoc . on )
662
662
throw new Error (
663
- `"${ element . name } " in path "${ column . ref
663
+ `"${ assoc . name } " in path "${ column . ref
664
664
. map ( idOnly )
665
665
. join ( '.' ) } " must not be an unmanaged association`
666
666
)
667
- // no non-fk traversal in infix filter
668
- if ( nextStep && element . foreignKeys && ! ( nextStep in element . foreignKeys ) )
669
- throw new Error ( `Only foreign keys of "${ element . name } " can be accessed in infix filter` )
667
+ // no non-fk traversal in infix filter in non-exists path
668
+ if ( nextStep && ! assoc . on && ! isForeignKeyOf ( nextStep , assoc ) )
669
+ throw new Error ( `Only foreign keys of "${ assoc . name } " can be accessed in infix filter` )
670
670
}
671
671
}
672
672
} )
@@ -723,7 +723,7 @@ function infer(originalQuery, model = cds.context?.model || cds.model) {
723
723
if ( inlineCol === '*' ) {
724
724
const wildCardElements = { }
725
725
// either the `.elements´ of the struct or the `.elements` of the assoc target
726
- const leafLinkElements = $leafLink . definition . elements || $leafLink . definition . _target . elements
726
+ const leafLinkElements = $leafLink . definition . _target ?. elements || $leafLink . definition . elements
727
727
Object . entries ( leafLinkElements ) . forEach ( ( [ k , v ] ) => {
728
728
const name = namePrefix ? `${ namePrefix } _${ k } ` : k
729
729
// if overwritten/excluded omit from wildcard elements
@@ -1130,6 +1130,20 @@ function infer(originalQuery, model = cds.context?.model || cds.model) {
1130
1130
} , '' )
1131
1131
}
1132
1132
}
1133
+ /**
1134
+ * Returns true if e is a foreign key of assoc.
1135
+ * this function is also compatible with unfolded csn (UCSN),
1136
+ * where association do not have foreign keys anymore.
1137
+ *
1138
+ * @param {* } e
1139
+ * @param {* } assoc
1140
+ * @returns
1141
+ */
1142
+ function isForeignKeyOf ( e , assoc ) {
1143
+ if ( ! assoc . isAssociation ) return false
1144
+ if ( assoc . foreignKeys ) return e in assoc . foreignKeys
1145
+ return assoc . elements && e in assoc . elements
1146
+ }
1133
1147
const idOnly = ref => ref . id || ref
1134
1148
1135
1149
module . exports = infer
0 commit comments