@@ -576,79 +576,68 @@ def with_usage(in_crsr: str, usage: WithUsage, term: Term, limit: Optional[Limit
576576
577577 def with_clause (in_crsr : str , clause : WithClause , limit : Optional [Limit ]) -> str :
578578 nonlocal query_part
579- # this is the general structure of the with_clause that is created
580- #
581- # FOR cloud in foo FILTER @0 in cloud.kinds
582- # FOR account IN 0..1 OUTBOUND cloud foo_default
583- # OPTIONS { bfs: true, uniqueVertices: 'global' }
584- # FILTER (cloud._key==account._key) or (@1 in account.kinds)
585- # FOR region in 0..1 OUTBOUND account foo_default
586- # OPTIONS { bfs: true, uniqueVertices: 'global' }
587- # FILTER (cloud._key==region._key) or (@2 in region.kinds)
588- # FOR zone in 0..1 OUTBOUND region foo_default
589- # OPTIONS { bfs: true, uniqueVertices: 'global' }
590- # FILTER (cloud._key==zone._key) or (@3 in zone.kinds)
591- # COLLECT l4_cloud = cloud, l4_account=account, l4_region=region WITH COUNT INTO counter3
592- # FILTER (l4_cloud._key==l4_region._key) or (counter3>=0)
593- # COLLECT l3_cloud = l4_cloud, l3_account=l4_account WITH COUNT INTO counter2
594- # FILTER (l3_cloud._key==l3_account._key) or (counter2>=0) // ==2 regions
595- # COLLECT l2_cloud = l3_cloud WITH COUNT INTO counter1
596- # FILTER (counter1>=0) //counter is +1 since the node itself is always bypassed
597- # RETURN ({cloud: l2_cloud._key, count:counter1})
598- current = ctx .next_counter ("with_clause" )
599-
600- def cursor_in (depth : int ) -> str :
601- return f"c{ current } _{ depth } "
602-
603- l0crsr = cursor_in (0 )
579+ # LET incoming = (FOR cloud IN `fix_view` SEARCH cloud.kinds == @b0 RETURN cloud)
580+ # LET clouds = (
581+ # FOR cloud IN incoming
582+ # LET accounts = (
583+ # FOR account IN 1..1 OUTBOUND cloud `fix_test` OPTIONS { bfs: true, uniqueVertices: 'global' }
584+ # FILTER "account" IN account.kinds
585+ # LIMIT 1
586+ # LET regions = (
587+ # FOR region IN 1..1 OUTBOUND account `fix_test` OPTIONS { bfs: true, uniqueVertices: 'global' }
588+ # FILTER "region" IN region.kinds
589+ # LIMIT 1
590+ # LET resources = (
591+ # FOR resource IN 1..1 OUTBOUND region `fix_test` OPTIONS {bfs:true,uniqueVertices:'global'}
592+ # LIMIT 1
593+ # RETURN resource
594+ # )
595+ # FILTER LENGTH(resources)>0
596+ # RETURN region
597+ # )
598+ # FILTER LENGTH(regions)==0
599+ # RETURN account
600+ # )
601+ # FILTER LENGTH(accounts) >0 //any
602+ # RETURN cloud
603+ # )
604+ # FOR cloud IN clouds RETURN cloud
604605
605606 def traversal_filter (cl : WithClause , in_crs : str , depth : int ) -> str :
606607 nav = cl .navigation
607- crsr = cursor_in (depth )
608+ let_crs = ctx .next_crs ()
609+ for_crsr = ctx .next_crs ()
608610 direction = "OUTBOUND" if nav .direction == Direction .outbound else "INBOUND"
609611 unique = "uniqueEdges: 'path'" if with_edges else "uniqueVertices: 'global'"
610- pre , term_string , post = term (crsr , cl .term ) if cl .term else (None , "true" , None )
612+ pre , term_string , post = term (for_crsr , cl .term ) if cl .term else (None , "true" , None )
611613 pre_string = " " + pre if pre else ""
612614 post_string = f" AND ({ post } )" if post else ""
613615 filter_clause = f"({ term_string } )"
614- inner = traversal_filter (cl .with_clause , crsr , depth + 1 ) if cl .with_clause else ""
615- filter_root = f"({ l0crsr } ._key=={ crsr } ._key) or " if depth > 0 else ""
616+ inner = traversal_filter (cl .with_clause , for_crsr , depth + 1 ) if cl .with_clause else ""
616617 edge_type_traversals = f", { direction } " .join (f"`{ db .edge_collection (et )} `" for et in nav .edge_types )
617618 return (
618- f"FOR { crsr } IN 0 ..{ nav .until } { direction } { in_crs } "
619+ f"LET { let_crs } = ( FOR { for_crsr } IN { nav . start } ..{ nav .until } { direction } { in_crs } "
619620 f"{ edge_type_traversals } OPTIONS {{ bfs: true, { unique } }} "
620- f"{ pre_string } FILTER { filter_root } { filter_clause } { post_string } "
621- ) + inner
622-
623- def collect_filter (cl : WithClause , depth : int ) -> str :
624- fltr = cl .with_filter
625- if cl .with_clause :
626- collects = ", " .join (f"l{ depth - 1 } _l{ i } _res=l{ depth } _l{ i } _res" for i in range (0 , depth ))
627- else :
628- collects = ", " .join (f"l{ depth - 1 } _l{ i } _res={ cursor_in (i )} " for i in range (0 , depth ))
629-
630- if depth == 1 :
631- # note: the traversal starts from 0 (only 0 and 1 is allowed)
632- # when we start from 1: increase the count by one to not count the start node
633- # when we start from 0: the start node is expected in the count already
634- filter_term = f"FILTER counter1{ fltr .op } { fltr .num + cl .navigation .start } "
635- else :
636- root_key = f"l{ depth - 1 } _l0_res._key==l{ depth - 1 } _l{ depth - 1 } _res._key"
637- filter_term = f"FILTER ({ root_key } ) or (counter{ depth } { fltr .op } { fltr .num } )"
638-
639- inner = collect_filter (cl .with_clause , depth + 1 ) if cl .with_clause else ""
640- return inner + f"COLLECT { collects } WITH COUNT INTO counter{ depth } { filter_term } "
621+ f"{ pre_string } FILTER { filter_clause } { post_string } "
622+ # for all possible predicates, it is enough to limit the list by num + 1
623+ # empty: if we find one element, it is not empty
624+ # any: if we find one element, it is any
625+ # count op x: if we find x+1 elements, we can always answer the predicate
626+ f"LIMIT { cl .with_filter .num + 1 } "
627+ f"{ inner } RETURN { for_crsr } )"
628+ f"FILTER LENGTH({ let_crs } ){ cl .with_filter .op } { cl .with_filter .num } "
629+ )
641630
642631 out = ctx .next_crs ()
643-
632+ l0crsr = ctx . next_crs ()
644633 limited = f" LIMIT { limit .offset } , { limit .length } " if limit else " "
634+ needs_sort = p .sort and query .aggregate is not None
645635 query_part += (
646636 f"LET { out } =( FOR { l0crsr } in { in_crsr } "
647- + traversal_filter (clause , l0crsr , 1 )
648- + collect_filter (clause , 1 )
649- + (sort ("l0_l0_res" , p .sort ) if p .sort else "" )
637+ + traversal_filter (clause , l0crsr , 0 )
638+ + (sort (l0crsr , p .sort ) if needs_sort else "" )
650639 + limited
651- + "RETURN l0_l0_res ) "
640+ + f "RETURN { l0crsr } ) "
652641 )
653642 return out
654643
0 commit comments