1
1
package tyqu
2
2
3
+ import scala .annotation .targetName
4
+
5
+ import utils .IsTupleOf
6
+ import Tuple .Fold
7
+
3
8
4
9
type Numeric = Int | Long | Float | Double
5
10
type Primitive = Numeric | String | Char | Boolean
6
11
12
+ type LogicalAnd [A , B ] <: Boolean = (A , B ) match
13
+ case (true , true ) => true
14
+ case _ => false
15
+
16
+ type ForAll [T <: Tuple , Pred [X ] <: Boolean ] <: Boolean = T match
17
+ case EmptyTuple => true
18
+ case h *: t => LogicalAnd [Pred [h], ForAll [t, Pred ]]
19
+
20
+ type CanSelectExpr [T ] <: Boolean = T match
21
+ case Expression [? , true ] => true
22
+ case Expression [? , false ] => false
23
+ case _ => Nothing
24
+
25
+ type ArgsCanSelect [T ] <: Boolean = T match
26
+ case Tuple => ForAll [T , CanSelectExpr ]
27
+ case _ => CanSelectExpr [T ]
28
+
7
29
8
30
sealed abstract class Relation :
9
31
def underlyingName : String
@@ -17,113 +39,169 @@ abstract class TableRelation[T <: Table](val table: T) extends Relation:
17
39
def underlyingName : String = table.tableName
18
40
def getColumnName (property : String ) = table.getColumnName(property)
19
41
def colToExpr (col : Column [? ]) = table.colToExpr(col)(this .asInstanceOf [TableRelation [table.type ]])
20
- def pk : NamedExpression [? , ? ] = colToExpr(table.pk)
42
+ def pk : NamedExpression [? , ? , ? ] = colToExpr(table.pk)
21
43
22
44
enum JoinType :
23
45
case Inner , Left , Right , FullOuter
24
46
25
47
case class FromRelation [T <: Table ](t : T ) extends TableRelation (t)
26
48
27
- case class JoinRelation [T <: Table ](t : T , joinType : JoinType , on : JoinRelation [T ] => Expression [Boolean ]) extends TableRelation (t)
49
+ case class JoinRelation [T <: Table ](t : T , joinType : JoinType , on : JoinRelation [T ] => Expression [Boolean , ? ]) extends TableRelation (t)
28
50
29
51
case class SubqueryRelation (qb : QueryBuilder [? ]) extends Relation :
30
52
def underlyingName : String = qb.from.underlyingName
31
53
def getColumnName (property : String ) = qb.from.getColumnName(property)
32
54
33
55
34
- abstract sealed class Expression [T ]:
35
-
36
- def as (n : String ) = Alias [T , n.type ](n, this )
56
+ abstract sealed class Expression [T , CanSelect <: Boolean ]:
37
57
38
- def asc = Asc (this )
39
- def desc = Desc (this )
58
+ def as (n : String ) = Alias [T , CanSelect , n.type ](n, this )
40
59
41
- infix def === [T2 <: T | Null ]( rhs : Expression [T2 ] ) = Function [Boolean ](" =" , List (this , rhs))
42
- infix def =!= [T2 <: T | Null ]( rhs : Expression [T2 ] ) = Function [Boolean ](" !=" , List (this , rhs))
60
+ infix def === [T2 <: T | Null , E < : Expression [T2 , ? ]]( rhs : E ) = Function [Boolean ](" =" , (this , rhs))
61
+ infix def =!= [T2 <: T | Null , E < : Expression [T2 , ? ]]( rhs : E ) = Function [Boolean ](" !=" , (this , rhs))
43
62
44
- def concat (rhs : Expression [? ]) =
45
- Function [String ](" CONCAT" , List (this , rhs).flatMap{
46
- case Function (" CONCAT" , exprs) => exprs
47
- case expr => List (expr)
48
- })
63
+ def concat [E <: Expression [? , ? ]](rhs : E ) =
64
+ Concat (this , rhs)
49
65
50
- def count = Function [Int ](" COUNT" , List ( this ) )
66
+ def count = Aggregation [Int ](" COUNT" , this )
51
67
52
68
end Expression
53
69
70
+ type AnyExpression = Expression [? , ? ]
54
71
55
- abstract sealed class NamedExpression [T , N <: String & Singleton ](val alias : N ) extends Expression [T ]
72
+ abstract sealed class NamedExpression [T , CanSelect <: Boolean , N <: String & Singleton ](val alias : N ) extends Expression [T , CanSelect ]
56
73
57
- case class Alias [T , N <: String & Singleton ](name : N , expression : Expression [T ]) extends NamedExpression [T , N ](name)
74
+ case class Alias [T , CanSelect <: Boolean , N <: String & Singleton ](name : N , expression : Expression [T , CanSelect ]) extends NamedExpression [T , CanSelect , N ](name)
58
75
59
- case class ColumnValue [T , N <: String & Singleton ](name : N , relation : Relation ) extends NamedExpression [T , N ](name)
76
+ case class ColumnValue [T , CanSelect <: Boolean , N <: String & Singleton ](name : N , relation : Relation ) extends NamedExpression [T , CanSelect , N ](name)
60
77
61
78
// E because the type in QueryBuilder is invariant
62
- case class SubqueryExpression [T , E <: Expression [T ]](qb : QueryBuilder [E ]) extends Expression [T ]
79
+ case class SubqueryExpression [T , E <: Expression [T , true ]](qb : QueryBuilder [E ]) extends Expression [T , true ]
80
+
81
+ case class LiteralExpression [T ](value : T , static : Boolean = false ) extends Expression [T , true ]
82
+
83
+ abstract class ProductExpression [T , Arguments <: Tuple | Expression [? , ? ]] extends Expression [T , ArgsCanSelect [Arguments ]]
84
+
85
+ case class Function [T , Arguments <: Tuple ](name : String , arguments : Arguments )(using IsTupleOf [Arguments , Expression [? , ? ]] =:= true ) extends ProductExpression [T , Arguments ]
86
+
87
+ object Function :
88
+ final class ApplyHelper [T ]:
89
+ def apply [Arguments <: Tuple ](name : String , arguments : Arguments )(using IsTupleOf [Arguments , Expression [? , ? ]] =:= true ) = new Function [T , Arguments ](name, arguments)
90
+
91
+ def apply [E <: Expression [? , ? ]](name : String , argument : E ) = new Function [T , Tuple1 [E ]](name, Tuple1 (argument))
92
+
93
+ def apply [T ] = ApplyHelper [T ]()
63
94
64
- case class LiteralExpression [ T ]( value : T , static : Boolean = false ) extends Expression [T ]
95
+ case class Aggregation [ T , Arguments <: Tuple ]( name : String , arguments : Arguments )( using IsTupleOf [ Arguments , Expression [ ? , ? ]] =:= true ) extends Expression [T | Null , true ]
65
96
66
- case class Function [T ](name : String , arguments : List [Expression [? ]]) extends Expression [T ]
97
+ object Aggregation :
98
+ final class ApplyHelper [T ]:
99
+ def apply [Arguments <: Tuple ](name : String , arguments : Arguments )(using IsTupleOf [Arguments , Expression [? , ? ]] =:= true ) = new Aggregation [T , Arguments ](name, arguments)
100
+
101
+ def apply [E <: Expression [? , ? ]](name : String , argument : E ) = new Aggregation [T , Tuple1 [E ]](name, Tuple1 (argument))
102
+
103
+ def apply [T ] = ApplyHelper [T ]()
104
+ end Aggregation
105
+
106
+ abstract class UnaryNumericAggregation (name : String ):
107
+ def apply [T <: Numeric | Null ](e : Expression [T , ? ]) = Aggregation [T | Null ](name, Tuple (e))
108
+ def unapply (a : Aggregation [? , ? ]): Option [AnyExpression ] =
109
+ if a.name == name then Some (a)
110
+ else None
111
+ end UnaryNumericAggregation
112
+
113
+ object Sum extends UnaryNumericAggregation (" SUM" )
114
+ object Avg extends UnaryNumericAggregation (" AVG" )
115
+ object Min extends UnaryNumericAggregation (" MIN" )
116
+ object Max extends UnaryNumericAggregation (" MAX" )
67
117
68
118
def lit [T ](value : T ) = LiteralExpression (value)
69
119
120
+ abstract class BinaryFunction [T ](name : String ):
121
+ def apply [E1 <: Expression [? , ? ], E2 <: Expression [? , ? ]](a : E1 , b : E2 ) =
122
+ Function [T ](name, (a, b))
123
+
124
+ def unapply (f : Function [? , ? ]): Option [(AnyExpression , AnyExpression )] =
125
+ if f.name == name then Some (f.arguments.asInstanceOf [(AnyExpression , AnyExpression )])
126
+ else None
127
+
128
+ object Concat extends BinaryFunction [String ](" CONCAT" )
70
129
71
- case class And ( lhs : Expression [Boolean ], rhs : Expression [Boolean ] ) extends Expression [Boolean ]
72
- case class Or ( lhs : Expression [Boolean ], rhs : Expression [Boolean ] ) extends Expression [Boolean ]
73
- case class Not ( expression : Expression [Boolean ] ) extends Expression [Boolean ]
74
- case class IsNull [T ]( expression : Expression [T | Null ] ) extends Expression [Boolean ]
75
- case class IsNotNull [T ]( expression : Expression [T | Null ] ) extends Expression [Boolean ]
76
- case class Exists (subquery : SubqueryExpression [? , ? ]) extends Expression [Boolean ]
77
- case class StartsWith (needle : String , haystack : Expression [String ]) extends Expression [Boolean ]
78
- case class EndsWith (needle : String , haystack : Expression [String ]) extends Expression [Boolean ]
79
- case class Contains (needle : String , haystack : Expression [String ]) extends Expression [Boolean ]
130
+ case class And [ L < : Expression [Boolean , ? ], R < : Expression [Boolean , ? ]]( lhs : L , rhs : R ) extends ProductExpression [Boolean , ( L , R ) ]
131
+ case class Or [ L < : Expression [Boolean , ? ], R < : Expression [Boolean , ? ]]( lhs : L , rhs : R ) extends ProductExpression [Boolean , ( L , R ) ]
132
+ case class Not [ E < : Expression [Boolean , ? ]]( expression : E ) extends ProductExpression [Boolean , Tuple1 [ E ] ]
133
+ case class IsNull [T , S <: Boolean , E <: Expression [T | Null , S ]]( expression : E ) extends ProductExpression [Boolean , Tuple1 [ E ] ]
134
+ case class IsNotNull [T , E < : Expression [T | Null , ? ]]( expression : E ) extends ProductExpression [Boolean , E ]
135
+ case class Exists (subquery : SubqueryExpression [? , ? ]) extends Expression [Boolean , true ]
136
+ case class StartsWith [ S <: Boolean ] (needle : String , haystack : Expression [String , S ]) extends Expression [Boolean , S ]
137
+ case class EndsWith [ S <: Boolean ] (needle : String , haystack : Expression [String , S ]) extends Expression [Boolean , S ]
138
+ case class Contains [ S <: Boolean ] (needle : String , haystack : Expression [String , S ]) extends Expression [Boolean , S ]
80
139
81
- case class CountAll () extends Expression [Int ]
140
+ case class CountAll () extends Expression [Int , true ]
82
141
83
- case class Plus [T1 <: Numeric | Null , T2 <: Numeric | Null ]( lhs : Expression [T1 ], rhs : Expression [T2 ] ) extends Expression [T1 | T2 ]
84
- case class Minus [T1 <: Numeric | Null , T2 <: Numeric | Null ]( lhs : Expression [T1 ], rhs : Expression [T2 ] ) extends Expression [T1 | T2 ]
85
- case class Multiply [T1 <: Numeric | Null , T2 <: Numeric | Null ]( lhs : Expression [T1 ], rhs : Expression [T2 ] ) extends Expression [T1 | T2 ]
86
- case class Divide [T1 <: Numeric | Null , T2 <: Numeric | Null ]( lhs : Expression [T1 ], rhs : Expression [T2 ] ) extends Expression [T1 | T2 ]
142
+ case class Plus [T1 <: Numeric | Null , T2 <: Numeric | Null , E1 < : Expression [T1 , ? ], E2 < : Expression [T2 , ? ]]( lhs : E1 , rhs : E2 ) extends ProductExpression [T1 | T2 , ( E1 , E2 ) ]
143
+ case class Minus [T1 <: Numeric | Null , T2 <: Numeric | Null , E1 < : Expression [T1 , ? ], E2 < : Expression [T2 , ? ]]( lhs : E1 , rhs : E2 ) extends ProductExpression [T1 | T2 , ( E1 , E2 ) ]
144
+ case class Multiply [T1 <: Numeric | Null , T2 <: Numeric | Null , E1 < : Expression [T1 , ? ], E2 < : Expression [T2 , ? ]]( lhs : E1 , rhs : E2 ) extends ProductExpression [T1 | T2 , ( E1 , E2 ) ]
145
+ case class Divide [T1 <: Numeric | Null , T2 <: Numeric | Null , E1 < : Expression [T1 , ? ], E2 < : Expression [T2 , ? ]]( lhs : E1 , rhs : E2 ) extends ProductExpression [T1 | T2 , ( E1 , E2 ) ]
87
146
88
147
89
- extension (lhs : Expression [Boolean ])
90
- infix def && (rhs : Expression [Boolean ]) =
148
+ extension [ S <: Boolean ] (lhs : Expression [Boolean , S ])
149
+ infix def && [ S2 <: Boolean ] (rhs : Expression [Boolean , S2 ]) =
91
150
if (lhs == NoFilterExpression ) rhs
92
151
else And (lhs, rhs)
93
- infix def || (rhs : Expression [Boolean ]) = Or (lhs, rhs)
152
+ infix def || [ S2 <: Boolean ] (rhs : Expression [Boolean , S2 ]) = Or (lhs, rhs)
94
153
infix def unary_! = Not (lhs)
95
154
96
155
97
- extension [T <: Numeric | Null ] (lhs : Expression [T ])
98
- infix def < [T2 <: Numeric | Null ](rhs : Expression [T2 ]) = Function [Boolean ](" <" , List (lhs, rhs))
99
- infix def <= [T2 <: Numeric | Null ](rhs : Expression [T2 ]) = Function [Boolean ](" <=" , List (lhs, rhs))
100
- infix def > [T2 <: Numeric | Null ](rhs : Expression [T2 ]) = Function [Boolean ] (" >" , List (lhs, rhs))
101
- infix def >= [T2 <: Numeric | Null ](rhs : Expression [T2 ]) = Function [Boolean ](" >=" , List (lhs, rhs))
102
- infix def + [T2 <: Numeric | Null ](rhs : Expression [T2 ]) = Plus (lhs, rhs)
103
- infix def - [T2 <: Numeric | Null ](rhs : Expression [T2 ]) = Minus (lhs, rhs)
104
- infix def * [T2 <: Numeric | Null ](rhs : Expression [T2 ]) = Multiply (lhs, rhs)
105
- infix def / [T2 <: Numeric | Null ](rhs : Expression [T2 ]) = Divide (lhs, rhs)
156
+ extension [T <: Numeric | Null , S <: Boolean ] (lhs : Expression [T , S ])
157
+ infix def < [T2 <: Numeric | Null , S2 <: Boolean ](rhs : Expression [T2 , S2 ]) = Function [Boolean ](" <" , (lhs, rhs))
158
+ infix def <= [T2 <: Numeric | Null , S2 <: Boolean ](rhs : Expression [T2 , S2 ]) = Function [Boolean ](" <=" , (lhs, rhs))
159
+ infix def > [T2 <: Numeric | Null , S2 <: Boolean ](rhs : Expression [T2 , S2 ]) = Function [Boolean , ( Expression [ T , S ], Expression [ T2 , S2 ])] (" >" , (lhs, rhs))
160
+ infix def >= [T2 <: Numeric | Null , S2 <: Boolean ](rhs : Expression [T2 , S2 ]) = Function [Boolean ](" >=" , (lhs, rhs))
161
+ infix def + [T2 <: Numeric | Null , S2 <: Boolean ](rhs : Expression [T2 , S2 ]) = Plus (lhs, rhs)
162
+ infix def - [T2 <: Numeric | Null , S2 <: Boolean ](rhs : Expression [T2 , S2 ]) = Minus (lhs, rhs)
163
+ infix def * [T2 <: Numeric | Null , S2 <: Boolean ](rhs : Expression [T2 , S2 ]) = Multiply (lhs, rhs)
164
+ infix def / [T2 <: Numeric | Null , S2 <: Boolean ](rhs : Expression [T2 , S2 ]) = Divide (lhs, rhs)
106
165
107
166
108
- extension [T ] (lhs : Expression [T | Null ])
167
+ extension [T , S <: Boolean ] (lhs : Expression [T | Null , S ])
109
168
def isNull = IsNull (lhs)
110
169
def isNotNull = IsNotNull (lhs)
111
- def getOrElse [T2 ](fallback : Expression [T2 ]) = Function [T | T2 ](" COALESCE" , List (lhs, fallback))
170
+ def getOrElse [T2 , S2 <: Boolean ](fallback : Expression [T2 , S2 ]) = Function [T | T2 ](" COALESCE" , (lhs, fallback))
112
171
113
172
114
- extension (lhs : Expression [? ])
115
- infix def + (rhs : Expression [? ]) = lhs.concat(rhs)
173
+ extension (lhs : Expression [? , ? ])
174
+ infix def + [ T , S <: Boolean ] (rhs : Expression [T , S ]) = lhs.concat(rhs)
116
175
117
176
118
- extension (lhs : Expression [String ])
177
+ extension (lhs : Expression [String , ? ])
119
178
def startsWith (rhs : String ) = StartsWith (needle = rhs, haystack = lhs)
120
179
def endsWith (rhs : String ) = EndsWith (needle = rhs, haystack = lhs)
121
180
def contains (rhs : String ) = Contains (needle = rhs, haystack = lhs)
122
181
123
182
124
- given Conversion [String , Expression [String ]] = LiteralExpression (_)
125
- given Conversion [Int , Expression [Int ]] = LiteralExpression (_)
126
- given [T , E <: Expression [T ]]: Conversion [QueryBuilder [E ], Expression [T ]] = SubqueryExpression (_)
183
+ extension (e : Expression [? , true ])
184
+ def asc = Asc (e)
185
+ def desc = Desc (e)
186
+
187
+
188
+ extension [T <: Numeric | Null , E <: Expression [T , true ]] (qb : QueryBuilder [E ])
189
+ def sum = qb.copy(scope = Sum (qb.scope))
190
+ def min = qb.copy(scope = Min (qb.scope))
191
+ def max = qb.copy(scope = Max (qb.scope))
192
+ def avg = qb.copy(scope = Avg (qb.scope))
193
+
194
+
195
+ extension [T <: Numeric | Null ] (e : Expression [T , false ])
196
+ def sum = Sum (e)
197
+ def min = Min (e)
198
+ def max = Max (e)
199
+ def avg = Avg (e)
200
+
201
+
202
+ given Conversion [String , Expression [String , true ]] = LiteralExpression (_)
203
+ given Conversion [Int , Expression [Int , true ]] = LiteralExpression (_)
204
+ given [T , E <: Expression [T , true ]]: Conversion [QueryBuilder [E ], Expression [T , true ]] = SubqueryExpression (_)
127
205
128
206
129
207
object NoFilterExpression extends LiteralExpression (true )
0 commit comments