@@ -160,7 +160,7 @@ class QueryContext {
160160 * @param variableNode the variable token as it is referenced in the query tree
161161 * @param aqlVariable the variable token as it will be available within the AQL fragment
162162 */
163- private newNestedContextWithVariableMapping (
163+ private newNestedContextWithVariableBinding (
164164 variableNode : VariableQueryNode ,
165165 aqlVariable : AQLFragment ,
166166 ) : QueryContext {
@@ -177,31 +177,24 @@ class QueryContext {
177177 /**
178178 * Creates a new QueryContext that is identical to this one but has one additional variable binding
179179 *
180- * The AQLFragment for the variable will be available via getVariable() .
180+ * If aqlFrag is omitted, a new AQLVariable will be created using the name of the variableNode .
181181 *
182- * @param {VariableQueryNode } variableNode the variable as referenced in the query tree
183- * @returns {QueryContext } the nested context
184- */
185- introduceVariable ( variableNode : VariableQueryNode ) : QueryContext {
186- if ( this . variableMap . has ( variableNode ) ) {
187- throw new Error ( `Variable ${ variableNode } is introduced twice` ) ;
188- }
189- const variable = new AQLVariable ( variableNode . label ) ;
190- return this . newNestedContextWithVariableMapping ( variableNode , variable ) ;
191- }
192-
193- /**
194- * Creates a new QueryContext that is identical to this one but has one additional variable binding
182+ * For aqlFrag, you can specify an AQLVariable or a different AQLFragment (e.g. a field access).
183+ * Do not specify complex AQL expressions because they would be repeated for every use of the
184+ * variable.
195185 *
196186 * @param variableNode the variable as referenced in the query tree
197- * @param existingVariable a variable that has been previously introduced with introduceVariable() and fetched by getVariable
198- * @returns { QueryContext } the nested context
187+ * @param aqlFrag the fragment representing the variable in AQL
188+ * @returns the new context
199189 */
200- introduceVariableAlias (
190+ bindVariable (
201191 variableNode : VariableQueryNode ,
202- existingVariable : AQLFragment ,
192+ aqlFrag : AQLFragment = new AQLVariable ( variableNode . label ) ,
203193 ) : QueryContext {
204- return this . newNestedContextWithVariableMapping ( variableNode , existingVariable ) ;
194+ if ( this . variableMap . has ( variableNode ) ) {
195+ throw new Error ( `Variable ${ variableNode } is introduced twice` ) ;
196+ }
197+ return this . newNestedContextWithVariableBinding ( variableNode , aqlFrag ) ;
205198 }
206199
207200 /**
@@ -224,7 +217,7 @@ class QueryContext {
224217 let newContext : QueryContext ;
225218 if ( resultVariable ) {
226219 resultVar = new AQLQueryResultVariable ( resultVariable . label ) ;
227- newContext = this . newNestedContextWithVariableMapping ( resultVariable , resultVar ) ;
220+ newContext = this . newNestedContextWithVariableBinding ( resultVariable , resultVar ) ;
228221 } else {
229222 resultVar = undefined ;
230223 newContext = this ;
@@ -287,7 +280,7 @@ class QueryContext {
287280 throw new Error ( `Variable ${ variableNode . toString ( ) } is used but not introduced` ) ;
288281 }
289282 // we're returning an AQLFragment as AQLVariable
290- // it can be a non-variable fragment (e.g. a simple field access) if we used introduceVariableAlias
283+ // it can be a non-variable fragment (e.g. a simple field access) if we used bindVariable
291284 // typescript only allows it because there are no private fields in AQLVariable
292285 // TODO introduce a better way to introduce a VariableQueryNode as AQLVariable, then make this here return AQLFragment
293286 return variable ;
@@ -337,7 +330,7 @@ function createAQLCompoundQuery(
337330 const variableAssignmentNodes : VariableAssignmentQueryNode [ ] = [ ] ;
338331 node = extractVariableAssignments ( node , variableAssignmentNodes ) ;
339332 for ( const assignmentNode of variableAssignmentNodes ) {
340- context = context . introduceVariable ( assignmentNode . variableNode ) ;
333+ context = context . bindVariable ( assignmentNode . variableNode ) ;
341334 const tmpVar = context . getVariable ( assignmentNode . variableNode ) ;
342335 variableAssignments . push (
343336 aql `LET ${ tmpVar } = ${ processNode ( assignmentNode . variableValueNode , context ) } ` ,
@@ -472,7 +465,7 @@ register(VariableQueryNode, (node, context) => {
472465} ) ;
473466
474467register ( VariableAssignmentQueryNode , ( node , context ) => {
475- const newContext = context . introduceVariable ( node . variableNode ) ;
468+ const newContext = context . bindVariable ( node . variableNode ) ;
476469 const tmpVar = newContext . getVariable ( node . variableNode ) ;
477470
478471 // note that we have to know statically if the context var is a list or an object
@@ -551,7 +544,7 @@ register(RevisionQueryNode, (node, context) => {
551544
552545register ( FlexSearchQueryNode , ( node , context ) => {
553546 let itemContext = context
554- . introduceVariable ( node . itemVariable )
547+ . bindVariable ( node . itemVariable )
555548 . withExtension ( inFlexSearchFilterSymbol , true ) ;
556549 const viewName = getFlexSearchViewNameForRootEntity ( node . rootEntityType ! ) ;
557550 context . addCollectionAccess ( viewName , AccessType . EXPLICIT_READ ) ;
@@ -565,7 +558,7 @@ register(FlexSearchQueryNode, (node, context) => {
565558} ) ;
566559
567560register ( TransformListQueryNode , ( node , context ) => {
568- let itemContext = context . introduceVariable ( node . itemVariable ) ;
561+ let itemContext = context . bindVariable ( node . itemVariable ) ;
569562 const itemVar = itemContext . getVariable ( node . itemVariable ) ;
570563 let itemProjectionContext = itemContext ;
571564
@@ -577,9 +570,7 @@ register(TransformListQueryNode, (node, context) => {
577570 const variableAssignmentNodes : VariableAssignmentQueryNode [ ] = [ ] ;
578571 innerNode = extractVariableAssignments ( innerNode , variableAssignmentNodes ) ;
579572 for ( const assignmentNode of variableAssignmentNodes ) {
580- itemProjectionContext = itemProjectionContext . introduceVariable (
581- assignmentNode . variableNode ,
582- ) ;
573+ itemProjectionContext = itemProjectionContext . bindVariable ( assignmentNode . variableNode ) ;
583574 const tmpVar = itemProjectionContext . getVariable ( assignmentNode . variableNode ) ;
584575 variableAssignments . push (
585576 aql `LET ${ tmpVar } = ${ processNode (
@@ -665,7 +656,7 @@ function generateLimitClause({ skip = 0, maxCount }: LimitClauseArgs): AQLFragme
665656 */
666657function generateInClause ( node : QueryNode , context : QueryContext , entityVar : AQLFragment ) {
667658 if ( node instanceof TransformListQueryNode && node . innerNode === node . itemVariable ) {
668- const itemContext = context . introduceVariableAlias ( node . itemVariable , entityVar ) ;
659+ const itemContext = context . bindVariable ( node . itemVariable , entityVar ) ;
669660 return generateInClauseWithFilterAndOrderAndLimit ( {
670661 node,
671662 itemContext,
@@ -846,7 +837,7 @@ register(AggregationQueryNode, (node, context) => {
846837register ( UpdateChildEntitiesQueryNode , ( node , context ) => {
847838 const itemsVar = aql . variable ( 'items' ) ;
848839 const itemsWithIndexVar = aql . variable ( 'itemsWithIndex' ) ;
849- const childContext = context . introduceVariable ( node . dictionaryVar ) ;
840+ const childContext = context . bindVariable ( node . dictionaryVar ) ;
850841 const dictVar = childContext . getVariable ( node . dictionaryVar ) ;
851842 const updatedDictVar = aql . variable ( 'updatedDict' ) ;
852843 const itemVar = aql . variable ( 'item' ) ;
@@ -1529,7 +1520,7 @@ function processTraversalWithOnlyRelationSegmentsNoList(
15291520 ) ;
15301521 }
15311522
1532- const innerContext = context . introduceVariable ( node . itemVariable ) ;
1523+ const innerContext = context . bindVariable ( node . itemVariable ) ;
15331524 const itemVar = innerContext . getVariable ( node . itemVariable ) ;
15341525 const forStatementsFrag = getRelationTraversalForStatements ( {
15351526 node,
@@ -1580,7 +1571,7 @@ function processTraversalWithOnlyRelationSegmentsAsList(
15801571 // we could refactor the single usage so it does not use a TraversalQueryNode in the first place
15811572
15821573 const itemVar = aql . variable ( `node` ) ;
1583- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemVar ) ;
1574+ const innerContext = context . bindVariable ( node . itemVariable , itemVar ) ;
15841575
15851576 const forStatementsFrag = getRelationTraversalForStatements ( {
15861577 node,
@@ -1648,7 +1639,7 @@ function processTraversalWithListRelationSegmentsAndNonListFieldSegments(
16481639 segments : node . fieldSegments ,
16491640 sourceFrag : rootVar ,
16501641 } ) ;
1651- const innerContext = context . introduceVariableAlias ( node . itemVariable , fieldTraversalFrag ) ;
1642+ const innerContext = context . bindVariable ( node . itemVariable , fieldTraversalFrag ) ;
16521643
16531644 // note: we don't filter out NULL values even if preserveNullValues is false because that's currently
16541645 // only a flag for performance - actually filtering out NULLs is done by a surrounding AggregationQueryNode
@@ -1715,7 +1706,7 @@ function processTraversalWithNonListRelationSegmentsAndNonListFieldSegments(
17151706 segments : node . fieldSegments ,
17161707 sourceFrag : rootVar ,
17171708 } ) ;
1718- const innerContext = context . introduceVariableAlias ( node . itemVariable , fieldTraversalFrag ) ;
1709+ const innerContext = context . bindVariable ( node . itemVariable , fieldTraversalFrag ) ;
17191710
17201711 return aqlExt . firstOfSubquery (
17211712 forStatementsFrag ,
@@ -1773,7 +1764,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingSubquery(
17731764 ? ( itemFrag : AQLFragment ) => {
17741765 // don't provide rootEntityVariable
17751766 // (if we want to filter on root, it should happen outside already)
1776- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemFrag ) ;
1767+ const innerContext = context . bindVariable ( node . itemVariable , itemFrag ) ;
17771768 return processNode ( filterNode , innerContext ) ;
17781769 }
17791770 : undefined ;
@@ -1786,8 +1777,8 @@ function processTraversalWithRelationAndListFieldSegmentsUsingSubquery(
17861777
17871778 const itemVar = aql . variable ( `item` ) ;
17881779 const innerContext = context
1789- . introduceVariableAlias ( node . itemVariable , itemVar )
1790- . introduceVariableAlias ( node . rootEntityVariable , rootVar ) ;
1780+ . bindVariable ( node . itemVariable , itemVar )
1781+ . bindVariable ( node . rootEntityVariable , rootVar ) ;
17911782
17921783 // The outerMapFrag will produce a list, so a simple RETURN mapFrag would result in nested lists
17931784 // -> we iterate over the items again to flatten the lists (the FOR ${itemVar} ...)
@@ -1851,8 +1842,8 @@ function processTraversalWithRelationAndListFieldSegmentsWithoutSort(
18511842 const innerMapFrag = innerNode
18521843 ? ( itemFrag : AQLFragment ) => {
18531844 const innerContext = context
1854- . introduceVariableAlias ( node . itemVariable , itemFrag )
1855- . introduceVariableAlias ( node . rootEntityVariable , rootVar ) ;
1845+ . bindVariable ( node . itemVariable , itemFrag )
1846+ . bindVariable ( node . rootEntityVariable , rootVar ) ;
18561847 return processNode ( innerNode , innerContext ) ;
18571848 }
18581849 : undefined ;
@@ -1882,7 +1873,7 @@ function processTraversalWithRelationAndListFieldSegmentsWithoutSort(
18821873 innerFilterFrag = ( itemFrag : AQLFragment ) => {
18831874 // don't map rootEntityVariable
18841875 // (if we want to filter on root, it should happen outside already)
1885- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemFrag ) ;
1876+ const innerContext = context . bindVariable ( node . itemVariable , itemFrag ) ;
18861877 return processNode ( filterNode , innerContext ) ;
18871878 } ;
18881879 }
@@ -2014,8 +2005,8 @@ function processTraversalWithRelationAndListFieldSegmentsWithSort(
20142005 // -> we produce items like this: { value: ..., sortValues: [...] }
20152006 const innerMapFrag = ( itemFrag : AQLFragment ) => {
20162007 const innerContext = context
2017- . introduceVariableAlias ( node . itemVariable , itemFrag )
2018- . introduceVariableAlias ( node . rootEntityVariable , rootVar ) ;
2008+ . bindVariable ( node . itemVariable , itemFrag )
2009+ . bindVariable ( node . rootEntityVariable , rootVar ) ;
20192010 const valueFrag = node . innerNode ? processNode ( node . innerNode , innerContext ) : itemFrag ;
20202011
20212012 return aql . lines (
@@ -2042,7 +2033,7 @@ function processTraversalWithRelationAndListFieldSegmentsWithSort(
20422033 ? ( itemFrag : AQLFragment ) => {
20432034 // don't provide rootEntityVariable
20442035 // (if we want to filter on root, it should happen outside already)
2045- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemFrag ) ;
2036+ const innerContext = context . bindVariable ( node . itemVariable , itemFrag ) ;
20462037 return processNode ( filterNode , innerContext ) ;
20472038 }
20482039 : undefined ;
@@ -2107,13 +2098,13 @@ function processTraversalWithOnlyFieldSegmentsUsingArrayExpansion(
21072098 const innerNode = node . innerNode ;
21082099 const mapFrag = innerNode
21092100 ? ( itemFrag : AQLFragment ) =>
2110- processNode ( innerNode , context . introduceVariableAlias ( node . itemVariable , itemFrag ) )
2101+ processNode ( innerNode , context . bindVariable ( node . itemVariable , itemFrag ) )
21112102 : undefined ;
21122103
21132104 const filterNode = node . filterNode ;
21142105 const filterFrag = filterNode
21152106 ? ( itemFrag : AQLFragment ) =>
2116- processNode ( filterNode , context . introduceVariableAlias ( node . itemVariable , itemFrag ) )
2107+ processNode ( filterNode , context . bindVariable ( node . itemVariable , itemFrag ) )
21172108 : undefined ;
21182109
21192110 // if there are no list segments, this will just be a simple path access
@@ -2175,7 +2166,7 @@ function processTraversalWithOnlyFieldSegmentsUsingSubquery(
21752166
21762167 const itemVar = aql . variable ( 'item' ) ;
21772168
2178- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemVar ) ;
2169+ const innerContext = context . bindVariable ( node . itemVariable , itemVar ) ;
21792170 const returnValueFrag = node . innerNode ? processNode ( node . innerNode , innerContext ) : itemVar ;
21802171
21812172 // we could also do the filter in getFieldTraversalFragment(), but if we have a subquery anyway, this is simpler
@@ -2275,10 +2266,7 @@ function getRelationTraversalForStatements({
22752266 if ( ! segment . vertexFilterVariable ) {
22762267 throw new Error ( `vertexFilter is set, but vertexFilterVariable is not` ) ;
22772268 }
2278- const filterContext = context . introduceVariableAlias (
2279- segment . vertexFilterVariable ,
2280- nodeVar ,
2281- ) ;
2269+ const filterContext = context . bindVariable ( segment . vertexFilterVariable , nodeVar ) ;
22822270 // PRUNE to stop on a node that has to be filtered out (only necessary for traversals > 1 path length)
22832271 // however, PRUNE only seems to be a performance feature and is not reliably evaluated
22842272 // (e.g. it's not when using COLLECT with distinct for some reason), so we need to add a path filter
@@ -2292,7 +2280,7 @@ function getRelationTraversalForStatements({
22922280 }
22932281
22942282 const vertexInPathFrag = aql `${ pathVar } .vertices[*]` ;
2295- const pathFilterContext = context . introduceVariableAlias (
2283+ const pathFilterContext = context . bindVariable (
22962284 segment . vertexFilterVariable ,
22972285 vertexInPathFrag ,
22982286 ) ;
@@ -2511,7 +2499,7 @@ register(CreateEntitiesQueryNode, (node, context) => {
25112499} ) ;
25122500
25132501register ( UpdateEntitiesQueryNode , ( node , context ) => {
2514- const newContext = context . introduceVariable ( node . currentEntityVariable ) ;
2502+ const newContext = context . bindVariable ( node . currentEntityVariable ) ;
25152503 const entityVar = newContext . getVariable ( node . currentEntityVariable ) ;
25162504 let entityFrag : AQLFragment ;
25172505 let options : AQLFragment ;
0 commit comments