More instance
This commit is contained in:
parent
a1201a67aa
commit
23c0484609
5 changed files with 190 additions and 25 deletions
|
@ -70,7 +70,7 @@ private given FromExpr[Property] with {
|
||||||
} =>
|
} =>
|
||||||
Some(Property(a, n, r, v))
|
Some(Property(a, n, r, v))
|
||||||
case o =>
|
case o =>
|
||||||
println(s"Cannot extrat ${o.show}")
|
println(s"Cannot extract ${o.show}")
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,8 @@ private given FromExpr[Ordering] with {
|
||||||
case '{ Desc } => Some(Desc)
|
case '{ Desc } => Some(Desc)
|
||||||
case '{ AscNullsFirst } => Some(AscNullsFirst)
|
case '{ AscNullsFirst } => Some(AscNullsFirst)
|
||||||
case '{ AscNullsLast } => Some(AscNullsLast)
|
case '{ AscNullsLast } => Some(AscNullsLast)
|
||||||
|
case '{ DescNullsFirst } => Some(DescNullsFirst)
|
||||||
|
case '{ DescNullsLast } => Some(DescNullsLast)
|
||||||
case '{ TupleOrdering($xs) } => xs.value.map(TupleOrdering(_))
|
case '{ TupleOrdering($xs) } => xs.value.map(TupleOrdering(_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,6 +137,35 @@ private given FromExpr[Query] with {
|
||||||
Some(Take(b, n))
|
Some(Take(b, n))
|
||||||
case '{ SortBy(${ Expr(b) }, ${ Expr(p) }, ${ Expr(s) }, ${ Expr(o) }) } =>
|
case '{ SortBy(${ Expr(b) }, ${ Expr(p) }, ${ Expr(s) }, ${ Expr(o) }) } =>
|
||||||
Some(SortBy(b, p, s, o))
|
Some(SortBy(b, p, s, o))
|
||||||
|
case '{ GroupBy(${ Expr(b) }, ${ Expr(p) }, ${ Expr(body) }) } =>
|
||||||
|
Some(GroupBy(b, p, body))
|
||||||
|
case '{ Distinct(${ Expr(a) }) } =>
|
||||||
|
Some(Distinct(a))
|
||||||
|
case '{ DistinctOn(${ Expr(q) }, ${ Expr(a) }, ${ Expr(body) }) } =>
|
||||||
|
Some(DistinctOn(q, a, body))
|
||||||
|
case '{ Aggregation(${ Expr(op) }, ${ Expr(a) }) } =>
|
||||||
|
Some(Aggregation(op, a))
|
||||||
|
case '{ Union(${ Expr(a) }, ${ Expr(b) }) } =>
|
||||||
|
Some(Union(a, b))
|
||||||
|
case '{ UnionAll(${ Expr(a) }, ${ Expr(b) }) } =>
|
||||||
|
Some(UnionAll(a, b))
|
||||||
|
case '{
|
||||||
|
Join(
|
||||||
|
${ Expr(t) },
|
||||||
|
${ Expr(a) },
|
||||||
|
${ Expr(b) },
|
||||||
|
${ Expr(ia) },
|
||||||
|
${ Expr(ib) },
|
||||||
|
${ Expr(on) }
|
||||||
|
)
|
||||||
|
} =>
|
||||||
|
Some(Join(t, a, b, ia, ib, on))
|
||||||
|
case '{
|
||||||
|
FlatJoin(${ Expr(t) }, ${ Expr(a) }, ${ Expr(ia) }, ${ Expr(on) })
|
||||||
|
} =>
|
||||||
|
Some(FlatJoin(t, a, ia, on))
|
||||||
|
case '{ Nested(${ Expr(a) }) } =>
|
||||||
|
Some(Nested(a))
|
||||||
case o =>
|
case o =>
|
||||||
println(s"Cannot extract ${o.show}")
|
println(s"Cannot extract ${o.show}")
|
||||||
None
|
None
|
||||||
|
@ -153,17 +184,21 @@ private given FromExpr[BinaryOperator] with {
|
||||||
case '{ NumericOperator.* } => Some(NumericOperator.*)
|
case '{ NumericOperator.* } => Some(NumericOperator.*)
|
||||||
case '{ NumericOperator./ } => Some(NumericOperator./)
|
case '{ NumericOperator./ } => Some(NumericOperator./)
|
||||||
case '{ NumericOperator.> } => Some(NumericOperator.>)
|
case '{ NumericOperator.> } => Some(NumericOperator.>)
|
||||||
|
case '{ NumericOperator.>= } => Some(NumericOperator.>=)
|
||||||
|
case '{ NumericOperator.< } => Some(NumericOperator.<)
|
||||||
|
case '{ NumericOperator.<= } => Some(NumericOperator.<=)
|
||||||
|
case '{ NumericOperator.% } => Some(NumericOperator.%)
|
||||||
case '{ StringOperator.split } => Some(StringOperator.split)
|
case '{ StringOperator.split } => Some(StringOperator.split)
|
||||||
case '{ StringOperator.startsWith } => Some(StringOperator.startsWith)
|
case '{ StringOperator.startsWith } => Some(StringOperator.startsWith)
|
||||||
case '{ StringOperator.concat } => Some(StringOperator.concat)
|
case '{ StringOperator.concat } => Some(StringOperator.concat)
|
||||||
case '{ BooleanOperator.&& } => Some(BooleanOperator.&&)
|
case '{ BooleanOperator.&& } => Some(BooleanOperator.&&)
|
||||||
case '{ BooleanOperator.|| } => Some(BooleanOperator.||)
|
case '{ BooleanOperator.|| } => Some(BooleanOperator.||)
|
||||||
|
case '{ SetOperator.contains } => Some(SetOperator.contains)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private given FromExpr[UnaryOperator] with {
|
private given FromExpr[UnaryOperator] with {
|
||||||
|
|
||||||
def unapply(x: Expr[UnaryOperator])(using Quotes): Option[UnaryOperator] = {
|
def unapply(x: Expr[UnaryOperator])(using Quotes): Option[UnaryOperator] = {
|
||||||
x match {
|
x match {
|
||||||
case '{ BooleanOperator.! } => Some(BooleanOperator.!)
|
case '{ BooleanOperator.! } => Some(BooleanOperator.!)
|
||||||
|
@ -171,6 +206,33 @@ private given FromExpr[UnaryOperator] with {
|
||||||
case '{ StringOperator.toLowerCase } => Some(StringOperator.toLowerCase)
|
case '{ StringOperator.toLowerCase } => Some(StringOperator.toLowerCase)
|
||||||
case '{ StringOperator.toLong } => Some(StringOperator.toLong)
|
case '{ StringOperator.toLong } => Some(StringOperator.toLong)
|
||||||
case '{ StringOperator.toInt } => Some(StringOperator.toInt)
|
case '{ StringOperator.toInt } => Some(StringOperator.toInt)
|
||||||
|
case '{ NumericOperator.- } => Some(NumericOperator.-)
|
||||||
|
case '{ SetOperator.nonEmpty } => Some(SetOperator.nonEmpty)
|
||||||
|
case '{ SetOperator.isEmpty } => Some(SetOperator.isEmpty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private given FromExpr[AggregationOperator] with {
|
||||||
|
def unapply(
|
||||||
|
x: Expr[AggregationOperator]
|
||||||
|
)(using Quotes): Option[AggregationOperator] = {
|
||||||
|
x match {
|
||||||
|
case '{ AggregationOperator.min } => Some(AggregationOperator.min)
|
||||||
|
case '{ AggregationOperator.max } => Some(AggregationOperator.max)
|
||||||
|
case '{ AggregationOperator.avg } => Some(AggregationOperator.avg)
|
||||||
|
case '{ AggregationOperator.sum } => Some(AggregationOperator.sum)
|
||||||
|
case '{ AggregationOperator.size } => Some(AggregationOperator.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private given FromExpr[Operator] with {
|
||||||
|
def unapply(x: Expr[Operator])(using Quotes): Option[Operator] = {
|
||||||
|
x match {
|
||||||
|
case '{ $x: BinaryOperator } => x.value
|
||||||
|
case '{ $x: UnaryOperator } => x.value
|
||||||
|
case '{ $x: AggregationOperator } => x.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,18 +287,21 @@ private given FromExpr[Action] with {
|
||||||
|
|
||||||
extension [A](xs: Seq[Expr[A]]) {
|
extension [A](xs: Seq[Expr[A]]) {
|
||||||
private def sequence(using FromExpr[A], Quotes): Option[List[A]] = {
|
private def sequence(using FromExpr[A], Quotes): Option[List[A]] = {
|
||||||
val acc = xs.foldLeft(Option(List.newBuilder[A])) { (r, x) =>
|
if (xs.isEmpty) Some(Nil)
|
||||||
for {
|
else {
|
||||||
_r <- r
|
val acc = xs.foldLeft(Option(List.newBuilder[A])) { (r, x) =>
|
||||||
_x <- x.value
|
for {
|
||||||
} yield _r += _x
|
_r <- r
|
||||||
|
_x <- x.value
|
||||||
|
} yield _r += _x
|
||||||
|
}
|
||||||
|
acc.map(_.result())
|
||||||
}
|
}
|
||||||
acc.map(b => b.result())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private given FromExpr[Constant] with {
|
private given FromExpr[Value] with {
|
||||||
def unapply(x: Expr[Constant])(using Quotes): Option[Constant] = {
|
def unapply(x: Expr[Value])(using Quotes): Option[Value] = {
|
||||||
import quotes.reflect.{Constant => *, *}
|
import quotes.reflect.{Constant => *, *}
|
||||||
x match {
|
x match {
|
||||||
case '{ Constant($ce) } =>
|
case '{ Constant($ce) } =>
|
||||||
|
@ -244,8 +309,92 @@ private given FromExpr[Constant] with {
|
||||||
case Literal(v) =>
|
case Literal(v) =>
|
||||||
Some(Constant(v.value))
|
Some(Constant(v.value))
|
||||||
}
|
}
|
||||||
|
case '{ NullValue } =>
|
||||||
|
Some(NullValue)
|
||||||
|
case '{ $x: CaseClass } => x.value
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private given FromExpr[OptionOperation] with {
|
||||||
|
def unapply(
|
||||||
|
x: Expr[OptionOperation]
|
||||||
|
)(using Quotes): Option[OptionOperation] = {
|
||||||
|
x match {
|
||||||
|
case '{ OptionFlatten(${ Expr(ast) }) } =>
|
||||||
|
Some(OptionFlatten(ast))
|
||||||
|
case '{ OptionGetOrElse(${ Expr(ast) }, ${ Expr(body) }) } =>
|
||||||
|
Some(OptionGetOrElse(ast, body))
|
||||||
|
case '{
|
||||||
|
OptionFlatMap(${ Expr(ast) }, ${ Expr(alias) }, ${ Expr(body) })
|
||||||
|
} =>
|
||||||
|
Some(OptionFlatMap(ast, alias, body))
|
||||||
|
case '{ OptionMap(${ Expr(ast) }, ${ Expr(alias) }, ${ Expr(body) }) } =>
|
||||||
|
Some(OptionMap(ast, alias, body))
|
||||||
|
case '{
|
||||||
|
OptionForall(${ Expr(ast) }, ${ Expr(alias) }, ${ Expr(body) })
|
||||||
|
} =>
|
||||||
|
Some(OptionForall(ast, alias, body))
|
||||||
|
case '{
|
||||||
|
OptionExists(${ Expr(ast) }, ${ Expr(alias) }, ${ Expr(body) })
|
||||||
|
} =>
|
||||||
|
Some(OptionExists(ast, alias, body))
|
||||||
|
case '{ OptionContains(${ Expr(ast) }, ${ Expr(body) }) } =>
|
||||||
|
Some(OptionContains(ast, body))
|
||||||
|
case '{ OptionIsEmpty(${ Expr(ast) }) } =>
|
||||||
|
Some(OptionIsEmpty(ast))
|
||||||
|
case '{ OptionNonEmpty(${ Expr(ast) }) } =>
|
||||||
|
Some(OptionNonEmpty(ast))
|
||||||
|
case '{ OptionIsDefined(${ Expr(ast) }) } =>
|
||||||
|
Some(OptionIsDefined(ast))
|
||||||
|
case '{
|
||||||
|
OptionTableFlatMap(
|
||||||
|
${ Expr(ast) },
|
||||||
|
${ Expr(alias) },
|
||||||
|
${ Expr(body) }
|
||||||
|
)
|
||||||
|
} =>
|
||||||
|
Some(OptionTableFlatMap(ast, alias, body))
|
||||||
|
case '{
|
||||||
|
OptionTableMap(${ Expr(ast) }, ${ Expr(alias) }, ${ Expr(body) })
|
||||||
|
} =>
|
||||||
|
Some(OptionTableMap(ast, alias, body))
|
||||||
|
case '{
|
||||||
|
OptionTableExists(${ Expr(ast) }, ${ Expr(alias) }, ${ Expr(body) })
|
||||||
|
} =>
|
||||||
|
Some(OptionTableExists(ast, alias, body))
|
||||||
|
case '{
|
||||||
|
OptionTableForall(${ Expr(ast) }, ${ Expr(alias) }, ${ Expr(body) })
|
||||||
|
} =>
|
||||||
|
Some(OptionTableForall(ast, alias, body))
|
||||||
|
case '{ OptionNone } => Some(OptionNone)
|
||||||
|
case '{ OptionSome(${ Expr(ast) }) } => Some(OptionSome(ast))
|
||||||
|
case '{ OptionApply(${ Expr(ast) }) } => Some(OptionApply(ast))
|
||||||
|
case '{ OptionOrNull(${ Expr(ast) }) } => Some(OptionOrNull(ast))
|
||||||
|
case '{ OptionGetOrNull(${ Expr(ast) }) } => Some(OptionGetOrNull(ast))
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private given FromExpr[CaseClass] with {
|
||||||
|
def unapply(x: Expr[CaseClass])(using Quotes): Option[CaseClass] = {
|
||||||
|
import quotes.reflect.*
|
||||||
|
x match {
|
||||||
|
case '{ CaseClass(${ Expr(values) }) } =>
|
||||||
|
// Verify the values are properly structured as List[(String, Ast)]
|
||||||
|
try {
|
||||||
|
Some(CaseClass(values))
|
||||||
|
} catch {
|
||||||
|
case e: Exception =>
|
||||||
|
report.warning(
|
||||||
|
s"Failed to extract CaseClass values: ${e.getMessage}",
|
||||||
|
x.asTerm.pos
|
||||||
|
)
|
||||||
|
None
|
||||||
|
}
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,12 +465,14 @@ given astFromExpr: FromExpr[Ast] = new FromExpr[Ast] {
|
||||||
case '{ $x: Property } => x.value
|
case '{ $x: Property } => x.value
|
||||||
case '{ $x: Ident } => x.value
|
case '{ $x: Ident } => x.value
|
||||||
case '{ $x: Tuple } => x.value
|
case '{ $x: Tuple } => x.value
|
||||||
case '{ $x: Constant } => x.value
|
case '{ $x: Value } => x.value
|
||||||
case '{ $x: Operation } => x.value
|
case '{ $x: Operation } => x.value
|
||||||
case '{ $x: Ordering } => x.value
|
case '{ $x: Ordering } => x.value
|
||||||
case '{ $x: Action } => x.value
|
case '{ $x: Action } => x.value
|
||||||
case '{ $x: If } => x.value
|
case '{ $x: If } => x.value
|
||||||
case '{ $x: Infix } => x.value
|
case '{ $x: Infix } => x.value
|
||||||
|
case '{ $x: CaseClass } => x.value
|
||||||
|
case '{ $x: OptionOperation } => x.value
|
||||||
case o =>
|
case o =>
|
||||||
import quotes.reflect.*
|
import quotes.reflect.*
|
||||||
report.warning(s"Cannot get value from ${o.show}", o.asTerm.pos)
|
report.warning(s"Cannot get value from ${o.show}", o.asTerm.pos)
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
package minisql.ast
|
package minisql.ast
|
||||||
|
|
||||||
sealed trait JoinType
|
import scala.quoted.*
|
||||||
|
|
||||||
case object InnerJoin extends JoinType
|
enum JoinType {
|
||||||
case object LeftJoin extends JoinType
|
case InnerJoin
|
||||||
case object RightJoin extends JoinType
|
case LeftJoin
|
||||||
case object FullJoin extends JoinType
|
case RightJoin
|
||||||
|
case FullJoin
|
||||||
|
}
|
||||||
|
|
||||||
|
object JoinType {
|
||||||
|
given FromExpr[JoinType] with {
|
||||||
|
|
||||||
|
def unapply(x: Expr[JoinType])(using Quotes): Option[JoinType] = x match {
|
||||||
|
case '{ JoinType.InnerJoin } => Some(JoinType.InnerJoin)
|
||||||
|
case '{ JoinType.LeftJoin } => Some(JoinType.LeftJoin)
|
||||||
|
case '{ JoinType.RightJoin } => Some(JoinType.RightJoin)
|
||||||
|
case '{ JoinType.FullJoin } => Some(JoinType.FullJoin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -346,10 +346,10 @@ trait SqlIdiom extends Idiom {
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val joinTypeTokenizer: Tokenizer[JoinType] = Tokenizer[JoinType] {
|
implicit val joinTypeTokenizer: Tokenizer[JoinType] = Tokenizer[JoinType] {
|
||||||
case InnerJoin => stmt"INNER JOIN"
|
case JoinType.InnerJoin => stmt"INNER JOIN"
|
||||||
case LeftJoin => stmt"LEFT JOIN"
|
case JoinType.LeftJoin => stmt"LEFT JOIN"
|
||||||
case RightJoin => stmt"RIGHT JOIN"
|
case JoinType.RightJoin => stmt"RIGHT JOIN"
|
||||||
case FullJoin => stmt"FULL JOIN"
|
case JoinType.FullJoin => stmt"FULL JOIN"
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit def orderByCriteriaTokenizer(implicit
|
implicit def orderByCriteriaTokenizer(implicit
|
||||||
|
|
|
@ -192,10 +192,10 @@ trait MirrorIdiomBase extends Idiom {
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val joinTypeTokenizer: Tokenizer[JoinType] = Tokenizer[JoinType] {
|
implicit val joinTypeTokenizer: Tokenizer[JoinType] = Tokenizer[JoinType] {
|
||||||
case InnerJoin => stmt"join"
|
case JoinType.InnerJoin => stmt"join"
|
||||||
case LeftJoin => stmt"leftJoin"
|
case JoinType.LeftJoin => stmt"leftJoin"
|
||||||
case RightJoin => stmt"rightJoin"
|
case JoinType.RightJoin => stmt"rightJoin"
|
||||||
case FullJoin => stmt"fullJoin"
|
case JoinType.FullJoin => stmt"fullJoin"
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit def functionTokenizer(implicit
|
implicit def functionTokenizer(implicit
|
||||||
|
|
|
@ -100,7 +100,7 @@ class FromExprsSuite extends FunSuite {
|
||||||
|
|
||||||
testFor("Join") {
|
testFor("Join") {
|
||||||
Join(
|
Join(
|
||||||
InnerJoin,
|
JoinType.InnerJoin,
|
||||||
Ident("a"),
|
Ident("a"),
|
||||||
Ident("b"),
|
Ident("b"),
|
||||||
Ident("a1"),
|
Ident("a1"),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue