complex nested predicates

This commit is contained in:
jackfoxy 2024-02-06 10:27:20 -08:00
parent 0b6e79be6d
commit 09e66eac88
4 changed files with 362 additions and 498 deletions

View File

@ -3,6 +3,24 @@
:: a library for parsing urQL tapes
:: (parse:parse(default-database '<db>') "<script>")
|_ default-database=@tas
::
:: parsed list is a predicate leaf
++ pred-leaf
|= parsed=(list raw-pred-cmpnt)
^- predicate:ast
?. ?=(predicate-component:ast -.parsed)
~|("unknown predicate node {<-.parsed>}" !!)
?+ -.parsed ~|("unknown predicate leaf {<-.parsed>}" !!)
qualified-column:ast
[-.parsed ~ ~]
dime
[-.parsed ~ ~]
aggregate:ast
[-.parsed ~ ~]
value-literals:ast
[-.parsed ~ ~]
==
::
:: +parse: parse urQL script, emitting list of high level AST structures
++ parse
@ -2588,8 +2606,7 @@
columns=(list ordered-column:ast)
==
+$ parens ?(%pal %par)
+$ raw-predicate-component ?(parens predicate-component:ast predicate:ast)
+$ raw-predicate-component2 ?(parens predicate-component:ast)
+$ raw-pred-cmpnt ?(parens predicate-component:ast)
+$ group-by-list (list grouping-column:ast)
+$ order-by-list (list ordering-column:ast)
::
@ -3494,28 +3511,37 @@
(cold %lte ;~(pose (jest '<=') (jest '!>')))
(cold %gt (just '>'))
(cold %lt (just '<'))
(cold %and ;~(plug (jester 'and') whitespace))
(cold %or ;~(plug (jester 'or') whitespace))
(cold %in ;~(plug (jester 'in') whitespace))
%: cold %not-in
;~(plug (jester 'not') whitespace (jester 'in') whitespace)
==
(cold %equiv ;~(plug (jester 'equiv') whitespace))
%: cold %not-equiv
;~(plug (jester 'not') whitespace (jester 'equiv') whitespace)
==
==
:: conjunctions
(cold %and ;~(plug (jester 'and') whitespace))
(cold %or ;~(plug (jester 'or') whitespace))
:: ternary operators
(cold %between ;~(plug (jester 'between') whitespace))
%: cold %not-between
;~(plug (jester 'not') whitespace (jester 'between') whitespace)
==
:: unary operators
(cold %not ;~(plug (jester 'not') whitespace))
%: cold %not-exists
;~(plug (jester 'not') whitespace (jester 'exists') whitespace)
==
(cold %exists ;~(plug (jester 'exists') whitespace))
(cold %in ;~(plug (jester 'in') whitespace))
(cold %any ;~(plug (jester 'any') whitespace))
(cold %all ;~(plug (jester 'all') whitespace))
:: ternary operator
(cold %between ;~(plug (jester 'between') whitespace))
:: nesting
(cold %pal pal)
(cold %par par)
==
++ predicate-list ~+
|= a=*
^- (list raw-predicate-component2)
=/ new-list=(list raw-predicate-component2) ~
^- (list raw-pred-cmpnt)
=/ new-list=(list raw-pred-cmpnt) ~
|-
?: =(a ~) (flop new-list)
?: ?=(parens -.a)
@ -3614,338 +3640,151 @@
:: 1=2 3=3
::
++ produce-predicate
|= parsed=(list raw-predicate-component2)
|= parsed=(list raw-pred-cmpnt)
~+
^- predicate:ast
=/ working-tree=predicate:ast ~
=/ tree-stack=(list predicate:ast) ~
|-
?: =((lent parsed) 0)
|-
?~ tree-stack
working-tree
%= $
working-tree
?~ ->-.tree-stack [-<.tree-stack working-tree ~]
[-<.tree-stack ->-.tree-stack working-tree]
tree-stack +.tree-stack
==
?- -.parsed
%pal :: push working predicate onto the stack
?~ working-tree $(parsed +.parsed)
%= $
tree-stack [working-tree tree-stack]
working-tree ~
parsed +.parsed
==
%par :: pop the stack, updating next working tree
?~ tree-stack $(parsed +.parsed)
%= $
tree-stack +.tree-stack
working-tree
?~ ->-.tree-stack [-<.tree-stack working-tree ~]
[-<.tree-stack ->-.tree-stack working-tree]
parsed +.parsed
==
unary-op:ast
?~ working-tree
%= $
working-tree [-.parsed ~ ~]
parsed +.parsed
==
?~ l.working-tree
?: ?&(=(%not -.working-tree) =(%exists -.parsed))
?> ?=(qualified-column:ast +<.parsed)
%= $
working-tree [-.working-tree [-.parsed [+<.parsed ~ ~] ~] ~]
parsed +>.parsed
==
~|
"invalid combination of unary operators {<-.working-tree>} and {<-.parsed>}"
!!
?~ r.working-tree ~|("unary-op, right tree empty {<working-tree>}" !!)
~|("unary-op can't get here {<working-tree>}" !!)
binary-op:ast
?~ working-tree !!
?~ l.working-tree ~|("binary-op, left tree empty {<working-tree>}" !!)
?~ r.working-tree ~|("binary-op, right tree empty {<working-tree>}" !!)
~|("binary-op can't get here {<working-tree>}" !!)
ternary-op:ast
?~ working-tree !!
?~ l.working-tree ~|("ternary-op, left tree empty {<working-tree>}" !!)
?~ r.working-tree
~|("ternary-op, right tree empty {<working-tree>}" !!)
~|("ternary-op can't get here {<working-tree>}" !!)
conjunction:ast
?~ working-tree
%= $
working-tree [-.parsed ~ ~]
parsed +.parsed
==
?~ l.working-tree
~|("conjunction, left tree empty {<working-tree>}" !!)
?~ r.working-tree
~|("conjunction, right tree empty {<working-tree>}" !!)
%= $
working-tree [-.parsed working-tree ~]
parsed +.parsed
==
all-any-op:ast
?~ working-tree
~|
"operator {<-.parsed>} can only follow equality or inequality operator"
!!
?~ r.working-tree
?: ?&(?=(binary-op:ast n.working-tree) ?!(=(%in n.working-tree)))
?: ?=(value-literals:ast +<.parsed)
%= $
working-tree
[-.working-tree +<.working-tree [-.parsed [+<.parsed ~ ~] ~]]
parsed +>.parsed
==
?: ?=(qualified-column:ast +<.parsed)
%= $
working-tree
[-.working-tree +<.working-tree [-.parsed [+<.parsed ~ ~] ~]]
parsed +>.parsed
==
~|
"all-any-op {<-.parsed>} must target CTE or literal list {<+<.parsed>}"
!!
~|
"all-any-op {<-.parsed>} can only follow equality or inequality operator"
!!
~|
"all-any-op {<-.parsed>} can't get here, working-tree {<working-tree>}"
!!
qualified-column:ast
?~ working-tree
?: ?=(binary-op:ast +<.parsed)
%= $
working-tree [+<.parsed [-.parsed ~ ~] ~]
parsed +>.parsed
==
?: ?=(unary-op:ast +<.parsed)
?: ?&(=(%not +<.parsed) =(%between +>-.parsed))
?: =(%and +>+>-.parsed)
%= $
working-tree
:+ %not
:+ %between
(produce-predicate ~[-.parsed %gte +>+<.parsed])
(produce-predicate ~[-.parsed %lte +>+>+<.parsed])
~
parsed +>+>+>.parsed
==
%= $
working-tree
:+ %not
:+ %between
(produce-predicate ~[-.parsed %gte +>+<.parsed])
(produce-predicate ~[-.parsed %lte +>+>-.parsed])
~
parsed +>+>+.parsed
==
?: =(%in +>-.parsed)
%= $
working-tree
:+ %not
(produce-predicate ~[-.parsed %in +>+<.parsed])
~
parsed +>+>.parsed
==
~|
"unary-op {<+<.parsed>} after qualified-column, working-tree {<working-tree>}"
!!
?: =(%between +<.parsed)
?: =(%and +>+<.parsed)
%= $
working-tree
:+ %between
(produce-predicate ~[-.parsed %gte +>-.parsed])
(produce-predicate ~[-.parsed %lte +>+>-.parsed])
parsed +>+>+.parsed
==
%= $
working-tree
:+ %between
(produce-predicate ~[-.parsed %gte +>-.parsed])
(produce-predicate ~[-.parsed %lte +>+<.parsed])
parsed +>+>.parsed
==
~|
"qualified-column after {<+<.parsed>} , working-tree {<working-tree>}"
!!
?~ l.working-tree
%= $
working-tree [-.working-tree [-.parsed ~ ~] ~]
parsed +.parsed
==
?~ r.working-tree
?: ?=(conjunction:ast -.working-tree)
%= $
working-tree ~
tree-stack [working-tree tree-stack]
==
%= $
working-tree [-.working-tree +<.working-tree [-.parsed ~ ~]]
parsed +.parsed
==
~|("qualified-column can't get here" !!)
dime
?~ working-tree
?: ?=(binary-op:ast +<.parsed)
%= $
working-tree [+<.parsed [-.parsed ~ ~] ~]
parsed +>.parsed
==
?: ?=(unary-op:ast +<.parsed)
?: ?&(=(%not +<.parsed) =(%between +>-.parsed))
?: =(%and +>+>-.parsed)
%= $
working-tree
:+ %not
:+ %between
(produce-predicate ~[-.parsed %gte +>+<.parsed])
(produce-predicate ~[-.parsed %lte +>+>+<.parsed])
~
parsed +>+>+>.parsed
==
%= $
working-tree
:+ %not
:+ %between
(produce-predicate ~[-.parsed %gte +>+<.parsed])
(produce-predicate ~[-.parsed %lte +>+>-.parsed])
~
parsed +>+>+.parsed
==
?: =(%in +>-.parsed)
%= $
working-tree
[%not (produce-predicate ~[-.parsed %in +>+<.parsed]) ~]
parsed +>+>.parsed
==
~|
"unary-op {<+<.parsed>} after value-literal, working-tree {<working-tree>}"
!!
?: =(%between +<.parsed)
?: =(%and +>+<.parsed)
%= $
working-tree
:+ %between
(produce-predicate ~[-.parsed %gte +>-.parsed])
(produce-predicate ~[-.parsed %lte +>+>-.parsed])
parsed +>+>+.parsed
==
%= $
working-tree
:+ %between
(produce-predicate ~[-.parsed %gte +>-.parsed])
(produce-predicate ~[-.parsed %lte +>+<.parsed])
parsed +>+>.parsed
==
~| "value-literal after {<+<.parsed>} , working-tree {<working-tree>}"
!!
?~ l.working-tree
%= $
working-tree [-.working-tree [-.parsed ~ ~] ~]
parsed +.parsed
==
?~ r.working-tree
?: ?=(conjunction:ast -.working-tree)
%= $
working-tree ~
tree-stack [working-tree tree-stack]
==
%= $
working-tree [-.working-tree +<.working-tree [-.parsed ~ ~]]
parsed +.parsed
==
~|("value-literal can't get here" !!)
aggregate:ast
?~ working-tree
?: ?=(binary-op:ast +<.parsed)
%= $
working-tree [+<.parsed [-.parsed ~ ~] ~]
parsed +>.parsed
==
?: ?=(unary-op:ast +<.parsed)
?: ?&(=(%not +<.parsed) =(%between +>-.parsed))
?: =(%and +>+>-.parsed)
%= $
working-tree
:+ %not
:+ %between
(produce-predicate ~[-.parsed %gte +>+<.parsed])
(produce-predicate ~[-.parsed %lte +>+>+<.parsed])
~
parsed +>+>+>.parsed
==
%= $
working-tree
:+ %not
:+ %between
(produce-predicate ~[-.parsed %gte +>+<.parsed])
(produce-predicate ~[-.parsed %lte +>+>-.parsed])
~
parsed +>+>+.parsed
==
?: =(%in +>-.parsed)
%= $
working-tree
[%not (produce-predicate ~[-.parsed %in +>+<.parsed]) ~]
parsed +>+>.parsed
==
~|
"unary-op {<+<.parsed>} after aggregate, working-tree {<working-tree>}"
!!
?: =(%between +<.parsed)
?: =(%and +>+<.parsed)
%= $
working-tree
:+ %between
(produce-predicate ~[-.parsed %gte +>-.parsed])
(produce-predicate ~[-.parsed %lte +>+>-.parsed])
parsed +>+>+.parsed
==
%= $
working-tree
:+ %between
(produce-predicate ~[-.parsed %gte +>-.parsed])
(produce-predicate ~[-.parsed %lte +>+<.parsed])
parsed +>+>.parsed
==
~| "aggregate after {<+<.parsed>} , working-tree {<working-tree>}"
!!
?~ l.working-tree
%= $
working-tree [-.working-tree [-.parsed ~ ~] ~]
parsed +.parsed
==
?~ r.working-tree
?: ?=(conjunction:ast -.working-tree)
%= $
working-tree ~
tree-stack [working-tree tree-stack]
==
%= $
working-tree [-.working-tree +<.working-tree [-.parsed ~ ~]]
parsed +.parsed
==
~|("selected-aggregate can't get here" !!)
value-literals:ast
?~ working-tree
~|("Literal list in a predicate can only follow the IN operator" !!)
?~ l.working-tree !!
?~ r.working-tree
%= $
working-tree [-.working-tree +<.working-tree [-.parsed ~ ~]]
parsed +.parsed
==
~|("value-literal-list can't get here" !!)
=/ length (lent parsed)
=/ state (fold (flop parsed) [length 0 ~ 0 parsed] pred-folder)
?~ cmpnt.state
?: =(%pal -.parsed)
(produce-predicate (scag (sub length 2) `(list raw-pred-cmpnt)`+.parsed))
(pred-leaf parsed)
=/ r=(pair (list raw-pred-cmpnt) (list raw-pred-cmpnt))
(split-at parsed cmpnt-displ.state)
?+ -.q.r ~|("unknown predicate node {<-.q.r>}" !!)
unary-op:ast :: ?(%not-exists %exists)
[-.q.r (produce-predicate `(list raw-pred-cmpnt)`+.q.r) ~]
binary-op:ast :: ?(%eq inequality-op %equiv %not-equiv %in)
[-.q.r (produce-predicate p.r) (produce-predicate +.q.r)]
ternary-op:ast :: %between
?: =(%and +>-.q.r)
:+ -.q.r
[%gte (pred-leaf p.r) (pred-leaf (limo ~[+<.q.r]))]
[%lte (pred-leaf p.r) (pred-leaf (limo +>+.q.r))]
:+ -.q.r
[%gte (pred-leaf p.r) (pred-leaf (limo ~[+<.q.r]))]
[%lte (pred-leaf p.r) (pred-leaf (limo +>.q.r))]
conjunction:ast :: ?(%and %or)
[-.q.r (produce-predicate p.r) (produce-predicate +.q.r)]
all-any-op:ast :: ?(%all %any)
[-.q.r (produce-predicate `(list raw-pred-cmpnt)`+.q.r) ~]
==
::
:: +pred-folder [raw-pred-cmpnt pred-folder-state] -> pred-folder-state
++ pred-folder
|= [pred-comp=raw-pred-cmpnt state=pred-folder-state]
^- pred-folder-state
?+ pred-comp (advance-pred-folder-state state)
::
:: parens alter the level
%pal
:* (dec displ.state)
(dec level.state)
cmpnt.state
cmpnt-displ.state
the-list.state
==
%par
:* (dec displ.state)
+(level.state)
cmpnt.state
cmpnt-displ.state
the-list.state
==
::
:: these operators have equivalent precendence, choose first in lowest level
unary-op:ast :: ?(%not %exists)
?: &(=(level.state 0) =(cmpnt.state ~))
(update-pred-folder-state pred-comp state)
(advance-pred-folder-state state)
binary-op:ast :: ?(%eq inequality-op %equiv %not-equiv %in)
?: &(=(level.state 0) =(cmpnt.state ~))
(update-pred-folder-state pred-comp state)
:: binary-op takes precedence over all-any-op
?: ?& =(level.state 0)
!=(cmpnt.state `%and)
!=(cmpnt.state `%or)
?| =((snag displ.state the-list.state) %all)
=((snag displ.state the-list.state) %any)
==
==
(update-pred-folder-state pred-comp state)
(advance-pred-folder-state state)
ternary-op:ast :: ?(%between %not-between)
?: &(=(level.state 0) =(cmpnt.state ~))
(update-pred-folder-state pred-comp state)
(advance-pred-folder-state state)
all-any-op:ast :: ?(%all %any)
?: &(=(level.state 0) =(cmpnt.state ~))
(update-pred-folder-state pred-comp state)
(advance-pred-folder-state state)
::
:: 2nd highest precedence
%and :: skip if the %and is of a ternary-op
?: ?& =(level.state 0)
(gth displ.state 3)
?| =((snag (sub displ.state 3) the-list.state) %between)
=((snag (sub displ.state 3) the-list.state) %not-between)
==
==
(advance-pred-folder-state state)
?: &(=(level.state 0) =(cmpnt.state ~))
(update-pred-folder-state pred-comp state)
?: ?|(=(`%and cmpnt.state) =(`%or cmpnt.state))
(advance-pred-folder-state state)
?: =(level.state 0)
(update-pred-folder-state pred-comp state)
(advance-pred-folder-state state)
::
:: highest precedence
%or
?: &(=(level.state 0) =(cmpnt.state ~))
(update-pred-folder-state pred-comp state)
?: =(`%or cmpnt.state)
(advance-pred-folder-state state)
?: =(level.state 0)
(update-pred-folder-state pred-comp state)
(advance-pred-folder-state state)
==
+$ pred-folder-state
$:
displ=@
level=@
cmpnt=(unit raw-pred-cmpnt)
cmpnt-displ=@
the-list=(list raw-pred-cmpnt)
==
::
:: +split-at: [(list T) index:@] -> [(list T) (list T)]
++ split-at
|* [p=(list) i=@]
[(scag i p) (slag i p)]
::
:: +fold: [(list T1) state:T2 folder:$-([T1 T2] T2)] -> T2
++ fold
|= [a=(list raw-pred-cmpnt) b=pred-folder-state c=_pred-folder]
|- ^+ b
?~ a b
$(a t.a, b (c i.a b))
++ update-pred-folder-state
|= [pred-comp=raw-pred-cmpnt state=pred-folder-state]
^- pred-folder-state
:* (dec displ.state)
level.state
`pred-comp
(dec displ.state)
the-list.state
==
++ advance-pred-folder-state
|= state=pred-folder-state
^- pred-folder-state
:* (dec displ.state)
level.state
cmpnt.state
cmpnt-displ.state
the-list.state
==
::
:: parse scalar
::
++ get-datum ~+

View File

@ -85,16 +85,16 @@
::
:: { = | <> | != | > | >= | !> | < | <= | !< | BETWEEN...AND...
:: | IS DISTINCT FROM | IS NOT DISTINCT FROM }
+$ ternary-op %between
+$ ternary-op ?(%between %not-between)
+$ inequality-op ?(%neq %gt %gte %lt %lte)
+$ all-any-op ?(%all %any)
+$ binary-op ?(%eq inequality-op %equiv %not-equiv %in)
+$ unary-op ?(%not %exists)
+$ binary-op ?(%eq inequality-op %equiv %not-equiv %in %not-in)
+$ unary-op ?(%exists %not-exists)
+$ conjunction ?(%and %or)
+$ ops-and-conjs
?(ternary-op binary-op unary-op all-any-op conjunction)
?(ternary-op binary-op unary-op all-any-op conjunction)
+$ predicate-component
?(ops-and-conjs qualified-column dime value-literals aggregate)
?(ops-and-conjs qualified-column dime value-literals aggregate)
+$ predicate (tree predicate-component)
+$ datum $%(qualified-column dime)
+$ datum-or-scalar $@(datum scalar-function)

View File

@ -69,7 +69,14 @@
++ and-fb-gte-f--fb-lte-b [%and foobar-gte-foo foobar-lte-bar]
++ and-fb-gte-f--t1f2-eq-z [%and foobar-gte-foo t1-foo2-eq-zod]
++ and-f-eq-1--t1f3-lt-any [%and foo-eq-1 t1-foo3-lt-any-list]
++ and-and [%and and-fb-gte-f--fb-lte-b t1-foo2-eq-zod]
++ and-and
:+ %and
:+ %and
foobar-gte-foo
foobar-lte-bar
:+ %eq
t1-foo2
[[%p 0] ~ ~]
++ and-and-or [%or and-and t2-bar-in-list]
++ and-and-or-and [%or and-and and-fb-gte-f--t1f2-eq-z]
++ and-and-or-and-or-and [%or and-and-or-and and-f-eq-1--t1f3-lt-any]
@ -90,20 +97,27 @@
++ king-and [%and [second-and] last-or]
::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
::
:: expected/actual match
++ test-predicate-26
::
:: complext predicate, bug test
++ test-predicate-36
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE foobar >=foo And foobar<=bar ".
" and T1.foo2 = ~zod ".
" WHERE A1.adoption-email = A2.adoption-email ".
" AND A1.adoption-date = A2.adoption-date ".
" AND foo = bar ".
" AND ((A1.name = A2.name AND A1.species > A2.species) ".
" OR ".
" (A1.name > A2.name AND A1.species = A2.species) ".
" OR ".
" (A1.name > A2.name AND A1.species > A2.species) ".
" ) ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) and-and
=/ pred=(tree predicate-component:ast)
[%and [%and [%and [%eq a1-adoption-email a2-adoption-email] [%eq a1-adoption-date a2-adoption-date]] [%eq foo bar]] [%or [%or [%and [%eq a1-name a2-name] [%gt a1-species a2-species]] [%and [%gt a1-name a2-name] [%eq a1-species a2-species]]] [%and [%gt a1-name a2-name] [%gt a1-species a2-species]]]]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
--

View File

@ -2223,7 +2223,7 @@
" WHERE foobar Not Between foo And bar ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) [%not [%between foobar-gte-foo foobar-lte-bar] ~]
=/ pred=(tree predicate-component:ast) [%not-between foobar-gte-foo foobar-lte-bar]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
@ -2234,7 +2234,7 @@
" WHERE foobar Not Between foo bar ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) [%not [%between foobar-gte-foo foobar-lte-bar] ~]
=/ pred=(tree predicate-component:ast) [%not-between foobar-gte-foo foobar-lte-bar]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
@ -2278,7 +2278,7 @@
" WHERE T1.foo nOt In bar ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) [%not [%in t1-foo bar] ~]
=/ pred=(tree predicate-component:ast) [%not-in t1-foo bar]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
@ -2289,7 +2289,7 @@
" WHERE T1.foo not in (1,2,3) ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) [%not [%in t1-foo value-literals] ~]
=/ pred=(tree predicate-component:ast) [%not-in t1-foo value-literals]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
@ -2322,7 +2322,7 @@
" WHERE NOT EXISTS T1.foo ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) [%not [%exists t1-foo ~] ~]
=/ pred=(tree predicate-component:ast) [%not-exists t1-foo ~]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
@ -2333,7 +2333,7 @@
" WHERE NOT exists foo ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) [%not [%exists foo ~] ~]
=/ pred=(tree predicate-component:ast) [%not-exists foo ~]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
@ -2374,131 +2374,143 @@
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
:: expected/actual match
::++ test-predicate-26
:: =/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
:: " WHERE foobar >=foo And foobar<=bar ".
:: " and T1.foo2 = ~zod ".
:: " SELECT *"
:: =/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
:: =/ pred=(tree predicate-component:ast) and-and
:: =/ expected
:: [%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
:: %+ expect-eq
:: !> ~[expected]
:: !> (parse:parse(default-database 'db1') query)
:: expected/actual match
::++ test-predicate-27
:: =/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
:: " WHERE foobar >=foo And foobar<=bar ".
:: " and T1.foo2 = ~zod ".
:: " or T2.bar in (1,2,3)".
:: " SELECT *"
:: =/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
:: =/ pred=(tree predicate-component:ast) and-and-or
:: =/ expected
:: [%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
:: %+ expect-eq
:: !> ~[expected]
:: !> (parse:parse(default-database 'db1') query)
:: expected/actual match
::++ test-predicate-28
:: =/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
:: " WHERE foobar >=foo And foobar<=bar ".
:: " and T1.foo2 = ~zod ".
:: " or ".
:: " foobar>=foo ".
:: " AND T1.foo2=~zod ".
:: " SELECT *"
:: =/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
:: =/ pred=(tree predicate-component:ast) and-and-or-and
:: =/ expected
:: [%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
:: %+ expect-eq
:: !> ~[expected]
:: !> (parse:parse(default-database 'db1') query)
:: expected/actual match
::++ test-predicate-29
:: =/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
:: " WHERE foobar >=foo And foobar<=bar ".
:: " and T1.foo2 = ~zod ".
:: " or ".
:: " foobar>=foo ".
:: " AND T1.foo2=~zod ".
:: " OR ".
:: " foo = 1 ".
:: " AND T1.foo3 < any (1,2,3) ".
:: " SELECT *"
:: =/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
:: =/ pred=(tree predicate-component:ast) and-and-or-and-or-and
:: =/ expected
:: [%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
:: %+ expect-eq
:: !> ~[expected]
:: !> (parse:parse(default-database 'db1') query)
::
:: simple nesting
:: expected/actual match
::++ test-predicate-30
:: =/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
:: " WHERE (foobar > foo OR foobar < bar) ".
:: " AND T1.foo>foo2 ".
:: " AND T2.bar IN (1,2,3) ".
:: " AND (T1.foo3< any (1,2,3) OR T1.foo2=~zod AND foo=1 ) ".
:: " SELECT *"
:: =/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
:: =/ pred=(tree predicate-component:ast) king-and
:: =/ expected
:: [%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
:: %+ expect-eq
:: !> ~[expected]
:: !> (parse:parse(default-database 'db1') query)
++ test-predicate-26
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE foobar >=foo And foobar<=bar ".
" and T1.foo2 = ~zod ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast)
:+ %and
:+ %and
[%gte foobar foo]
[%lte foobar bar]
:+ %eq
t1-foo2
[[%p 0] ~ ~]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
::
:: expected/actual match
++ test-predicate-27
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE foobar >=foo And foobar<=bar ".
" and T1.foo2 = ~zod ".
" or T2.bar in (1,2,3)".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) and-and-or
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
::
:: expected/actual match
++ test-predicate-28
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE foobar >=foo And foobar<=bar ".
" and T1.foo2 = ~zod ".
" or ".
" foobar>=foo ".
" AND T1.foo2=~zod ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) and-and-or-and
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
::
:: expected/actual match
++ test-predicate-29
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE foobar >=foo And foobar<=bar ".
" and T1.foo2 = ~zod ".
" or ".
" foobar>=foo ".
" AND T1.foo2=~zod ".
" OR ".
" foo = 1 ".
" AND T1.foo3 < any (1,2,3) ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) and-and-or-and-or-and
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
::
:: simple nesting
++ test-predicate-30
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE (foobar > foo OR foobar < bar) ".
" AND T1.foo>foo2 ".
" AND T2.bar IN (1,2,3) ".
" AND (T1.foo3< any (1,2,3) OR T1.foo2=~zod AND foo=1 ) ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast)
:+ %and
:+ %and
:+ %and
first-or
t1-foo-gt-foo2
:+ %in
t2-bar
value-literals
:+ %or
t1-foo3-lt-any-list
:+ %and
t1-foo2-eq-zod
foo-eq-1
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
::
:: nesting
:: expected/actual match
::++ test-predicate-31
:: =/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
:: " WHERE foobar > foo AND foobar < bar ".
:: " AND ( T1.foo>foo2 AND T2.bar IN (1,2,3) ".
:: " OR (T1.foo3< any (1,2,3) AND T1.foo2=~zod AND foo=1 ) ".
:: " OR (foo3=foo4 AND foo5=foo6) ".
:: " OR foo4=foo5 ".
:: " ) ".
:: " AND foo6=foo7".
:: " SELECT *"
:: =/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
:: =/ pred=(tree predicate-component:ast) a-a-l-a-o-l-a-a-r-o-r-a-l-o-r-a
:: =/ expected
:: [%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
:: %+ expect-eq
:: !> ~[expected]
:: !> (parse:parse(default-database 'db1') query)
++ test-predicate-31
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE foobar > foo AND foobar < bar ".
" AND ( T1.foo>foo2 AND T2.bar IN (1,2,3) ".
" OR (T1.foo3< any (1,2,3) AND T1.foo2=~zod AND foo=1 ) ".
" OR (foo3=foo4 AND foo5=foo6) ".
" OR foo4=foo5 ".
" ) ".
" AND foo6=foo7".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) a-a-l-a-o-l-a-a-r-o-r-a-l-o-r-a
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
::
:: simple nesting, superfluous () around entire predicate
:: expected/actual match
::++ test-predicate-32
:: =/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
:: " WHERE ((foobar > foo OR foobar < bar) ".
:: " AND T1.foo>foo2 ".
:: " AND T2.bar IN (1,2,3) ".
:: " AND (T1.foo3< any (1,2,3) OR T1.foo2=~zod AND foo=1 )) ".
:: " SELECT *"
:: =/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
:: =/ pred=(tree predicate-component:ast) king-and
:: =/ expected
:: [%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
:: %+ expect-eq
:: !> ~[expected]
:: !> (parse:parse(default-database 'db1') query)
++ test-predicate-32
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE ((foobar > foo OR foobar < bar) ".
" AND T1.foo>foo2 ".
" AND T2.bar IN (1,2,3) ".
" AND (T1.foo3< any (1,2,3) OR T1.foo2=~zod AND foo=1 )) ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast) king-and
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
::
:: aggregate inequality
++ test-predicate-33
@ -2525,27 +2537,26 @@
!> (parse:parse(default-database 'db1') select)
::
:: complext predicate, bug test
:: expected/actual match
::++ test-predicate-36
:: =/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
:: " WHERE A1.adoption-email = A2.adoption-email ".
:: " AND A1.adoption-date = A2.adoption-date ".
:: " AND foo = bar ".
:: " AND ((A1.name = A2.name AND A1.species > A2.species) ".
:: " OR ".
:: " (A1.name > A2.name AND A1.species = A2.species) ".
:: " OR ".
:: " (A1.name > A2.name AND A1.species > A2.species) ".
:: " ) ".
:: " SELECT *"
:: =/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
:: =/ pred=(tree predicate-component:ast)
:: [%and [%and [%and [%eq a1-adoption-email a2-adoption-email] [%eq a1-adoption-date a2-adoption-date]] [%eq foo bar]] [%or [%or [%and [%eq a1-name a2-name] [%gt a1-species a2-species]] [%and [%gt a1-name a2-name] [%eq a1-species a2-species]]] [%and [%gt a1-name a2-name] [%gt a1-species a2-species]]]]
:: =/ expected
:: [%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
:: %+ expect-eq
:: !> ~[expected]
:: !> (parse:parse(default-database 'db1') query)
++ test-predicate-36
=/ query "FROM adoptions AS T1 JOIN adoptions AS T2 ON T1.foo = T2.bar ".
" WHERE A1.adoption-email = A2.adoption-email ".
" AND A1.adoption-date = A2.adoption-date ".
" AND foo = bar ".
" AND ((A1.name = A2.name AND A1.species > A2.species) ".
" OR ".
" (A1.name > A2.name AND A1.species = A2.species) ".
" OR ".
" (A1.name > A2.name AND A1.species > A2.species) ".
" ) ".
" SELECT *"
=/ joinpred=(tree predicate-component:ast) [%eq t1-foo t2-bar]
=/ pred=(tree predicate-component:ast)
[%and [%and [%and [%eq a1-adoption-email a2-adoption-email] [%eq a1-adoption-date a2-adoption-date]] [%eq foo bar]] [%or [%or [%and [%eq a1-name a2-name] [%gt a1-species a2-species]] [%and [%gt a1-name a2-name] [%eq a1-species a2-species]]] [%and [%gt a1-name a2-name] [%gt a1-species a2-species]]]]
=/ expected
[%transform ctes=~ [[%query [~ [%from object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T1']] joins=~[[%joined-object join=%join object=[%table-set object=[%qualified-object ship=~ database='db1' namespace='dbo' name='adoptions'] alias=[~ 'T2']] predicate=`joinpred]]]] scalars=~ `pred group-by=~ having=~ select-all-columns ~] ~ ~]]
%+ expect-eq
!> ~[expected]
!> (parse:parse(default-database 'db1') query)
::
:: outer parens
++ test-predicate-37