@@ -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' ) ;
@@ -1535,7 +1526,7 @@ function processTraversalWithOnlyRelationSegmentsNoList(
15351526 ) ;
15361527 }
15371528
1538- const innerContext = context . introduceVariable ( node . itemVariable ) ;
1529+ const innerContext = context . bindVariable ( node . itemVariable ) ;
15391530 const itemVar = innerContext . getVariable ( node . itemVariable ) ;
15401531 const forStatementsFrag = getRelationTraversalForStatements ( {
15411532 node,
@@ -1586,7 +1577,7 @@ function processTraversalWithOnlyRelationSegmentsAsList(
15861577 // we could refactor the single usage so it does not use a TraversalQueryNode in the first place
15871578
15881579 const itemVar = aql . variable ( `node` ) ;
1589- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemVar ) ;
1580+ const innerContext = context . bindVariable ( node . itemVariable , itemVar ) ;
15901581
15911582 const forStatementsFrag = getRelationTraversalForStatements ( {
15921583 node,
@@ -1654,7 +1645,7 @@ function processTraversalWithListRelationSegmentsAndNonListFieldSegments(
16541645 segments : node . fieldSegments ,
16551646 sourceFrag : rootVar ,
16561647 } ) ;
1657- const innerContext = context . introduceVariableAlias ( node . itemVariable , fieldTraversalFrag ) ;
1648+ const innerContext = context . bindVariable ( node . itemVariable , fieldTraversalFrag ) ;
16581649
16591650 // note: we don't filter out NULL values even if preserveNullValues is false because that's currently
16601651 // only a flag for performance - actually filtering out NULLs is done by a surrounding AggregationQueryNode
@@ -1721,7 +1712,7 @@ function processTraversalWithNonListRelationSegmentsAndNonListFieldSegments(
17211712 segments : node . fieldSegments ,
17221713 sourceFrag : rootVar ,
17231714 } ) ;
1724- const innerContext = context . introduceVariableAlias ( node . itemVariable , fieldTraversalFrag ) ;
1715+ const innerContext = context . bindVariable ( node . itemVariable , fieldTraversalFrag ) ;
17251716
17261717 return aqlExt . firstOfSubquery (
17271718 forStatementsFrag ,
@@ -1779,7 +1770,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingSubquery(
17791770 ? ( itemFrag : AQLFragment ) => {
17801771 // don't provide rootEntityVariable
17811772 // (if we want to filter on root, it should happen outside already)
1782- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemFrag ) ;
1773+ const innerContext = context . bindVariable ( node . itemVariable , itemFrag ) ;
17831774 return processNode ( filterNode , innerContext ) ;
17841775 }
17851776 : undefined ;
@@ -1792,8 +1783,8 @@ function processTraversalWithRelationAndListFieldSegmentsUsingSubquery(
17921783
17931784 const itemVar = aql . variable ( `item` ) ;
17941785 const innerContext = context
1795- . introduceVariableAlias ( node . itemVariable , itemVar )
1796- . introduceVariableAlias ( node . rootEntityVariable , rootVar ) ;
1786+ . bindVariable ( node . itemVariable , itemVar )
1787+ . bindVariable ( node . rootEntityVariable , rootVar ) ;
17971788
17981789 // The outerMapFrag will produce a list, so a simple RETURN mapFrag would result in nested lists
17991790 // -> we iterate over the items again to flatten the lists (the FOR ${itemVar} ...)
@@ -1885,8 +1876,8 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith
18851876 const innerMapFrag = innerNode
18861877 ? ( itemFrag : AQLFragment ) => {
18871878 const innerContext = context
1888- . introduceVariableAlias ( node . itemVariable , itemFrag )
1889- . introduceVariableAlias ( node . rootEntityVariable , rootVar ) ;
1879+ . bindVariable ( node . itemVariable , itemFrag )
1880+ . bindVariable ( node . rootEntityVariable , rootVar ) ;
18901881 return processNode ( innerNode , innerContext ) ;
18911882 }
18921883 : undefined ;
@@ -1916,7 +1907,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith
19161907 innerFilterFrag = ( itemFrag : AQLFragment ) => {
19171908 // don't map rootEntityVariable
19181909 // (if we want to filter on root, it should happen outside already)
1919- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemFrag ) ;
1910+ const innerContext = context . bindVariable ( node . itemVariable , itemFrag ) ;
19201911 return processNode ( filterNode , innerContext ) ;
19211912 } ;
19221913 }
@@ -2051,8 +2042,8 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith
20512042 // -> we produce items like this: { value: ..., sortValues: [...] }
20522043 const innerMapFrag = ( itemFrag : AQLFragment ) => {
20532044 const innerContext = context
2054- . introduceVariableAlias ( node . itemVariable , itemFrag )
2055- . introduceVariableAlias ( node . rootEntityVariable , rootVar ) ;
2045+ . bindVariable ( node . itemVariable , itemFrag )
2046+ . bindVariable ( node . rootEntityVariable , rootVar ) ;
20562047 const valueFrag = node . innerNode ? processNode ( node . innerNode , innerContext ) : itemFrag ;
20572048
20582049 return aql . lines (
@@ -2079,7 +2070,7 @@ function processTraversalWithRelationAndListFieldSegmentsUsingArrayExpansionWith
20792070 ? ( itemFrag : AQLFragment ) => {
20802071 // don't provide rootEntityVariable
20812072 // (if we want to filter on root, it should happen outside already)
2082- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemFrag ) ;
2073+ const innerContext = context . bindVariable ( node . itemVariable , itemFrag ) ;
20832074 return processNode ( filterNode , innerContext ) ;
20842075 }
20852076 : undefined ;
@@ -2144,13 +2135,13 @@ function processTraversalWithOnlyFieldSegmentsUsingArrayExpansion(
21442135 const innerNode = node . innerNode ;
21452136 const mapFrag = innerNode
21462137 ? ( itemFrag : AQLFragment ) =>
2147- processNode ( innerNode , context . introduceVariableAlias ( node . itemVariable , itemFrag ) )
2138+ processNode ( innerNode , context . bindVariable ( node . itemVariable , itemFrag ) )
21482139 : undefined ;
21492140
21502141 const filterNode = node . filterNode ;
21512142 const filterFrag = filterNode
21522143 ? ( itemFrag : AQLFragment ) =>
2153- processNode ( filterNode , context . introduceVariableAlias ( node . itemVariable , itemFrag ) )
2144+ processNode ( filterNode , context . bindVariable ( node . itemVariable , itemFrag ) )
21542145 : undefined ;
21552146
21562147 // if there are no list segments, this will just be a simple path access
@@ -2220,7 +2211,7 @@ function processTraversalWithOnlyFieldSegmentsUsingSubquery(
22202211
22212212 const itemVar = aql . variable ( 'item' ) ;
22222213
2223- const innerContext = context . introduceVariableAlias ( node . itemVariable , itemVar ) ;
2214+ const innerContext = context . bindVariable ( node . itemVariable , itemVar ) ;
22242215 const returnValueFrag = node . innerNode ? processNode ( node . innerNode , innerContext ) : itemVar ;
22252216
22262217 return aqlExt . subquery (
@@ -2314,10 +2305,7 @@ function getRelationTraversalForStatements({
23142305 if ( ! segment . vertexFilterVariable ) {
23152306 throw new Error ( `vertexFilter is set, but vertexFilterVariable is not` ) ;
23162307 }
2317- const filterContext = context . introduceVariableAlias (
2318- segment . vertexFilterVariable ,
2319- nodeVar ,
2320- ) ;
2308+ const filterContext = context . bindVariable ( segment . vertexFilterVariable , nodeVar ) ;
23212309 // PRUNE to stop on a node that has to be filtered out (only necessary for traversals > 1 path length)
23222310 // however, PRUNE only seems to be a performance feature and is not reliably evaluated
23232311 // (e.g. it's not when using COLLECT with distinct for some reason), so we need to add a path filter
@@ -2331,7 +2319,7 @@ function getRelationTraversalForStatements({
23312319 }
23322320
23332321 const vertexInPathFrag = aql `${ pathVar } .vertices[*]` ;
2334- const pathFilterContext = context . introduceVariableAlias (
2322+ const pathFilterContext = context . bindVariable (
23352323 segment . vertexFilterVariable ,
23362324 vertexInPathFrag ,
23372325 ) ;
@@ -2551,7 +2539,7 @@ register(CreateEntitiesQueryNode, (node, context) => {
25512539} ) ;
25522540
25532541register ( UpdateEntitiesQueryNode , ( node , context ) => {
2554- const newContext = context . introduceVariable ( node . currentEntityVariable ) ;
2542+ const newContext = context . bindVariable ( node . currentEntityVariable ) ;
25552543 const entityVar = newContext . getVariable ( node . currentEntityVariable ) ;
25562544 let entityFrag : AQLFragment ;
25572545 let options : AQLFragment ;
0 commit comments