Compare commits
2 commits
cf6aa999ae
...
2d30969ec5
Author | SHA1 | Date | |
---|---|---|---|
2d30969ec5 | |||
1878d59821 |
25 changed files with 121 additions and 107 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
target/
|
target/
|
||||||
.bsp/
|
.bsp/
|
||||||
.metals/
|
.metals/
|
||||||
|
.bloop/
|
||||||
|
project/metals.sbt
|
|
@ -1,4 +1,4 @@
|
||||||
version = "3.8.1"
|
version = "3.8.3"
|
||||||
style = defaultWithAlign
|
style = defaultWithAlign
|
||||||
runner.dialect=scala3
|
runner.dialect=scala3
|
||||||
maxColumn = 80
|
maxColumn = 80
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
name := "minisql"
|
name := "minisql"
|
||||||
|
|
||||||
scalaVersion := "3.5.0-RC4"
|
scalaVersion := "3.5.2"
|
||||||
|
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
scalacOptions ++= Seq("-experimental")
|
scalacOptions ++= Seq("-experimental", "-language:experimental.namedTuples")
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
sbt.version=1.10.0
|
sbt.version=1.10.5
|
||||||
|
|
8
project/project/metals.sbt
Normal file
8
project/project/metals.sbt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// format: off
|
||||||
|
// DO NOT EDIT! This file is auto-generated.
|
||||||
|
|
||||||
|
// This file enables sbt-bloop to create bloop config files.
|
||||||
|
|
||||||
|
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.6.0")
|
||||||
|
|
||||||
|
// format: on
|
|
@ -1 +0,0 @@
|
||||||
jilen@jilendeiMac.2465
|
|
|
@ -1,28 +0,0 @@
|
||||||
package minisql
|
|
||||||
|
|
||||||
import scala.collection.immutable.{Map => IMap}
|
|
||||||
import scala.quoted.*
|
|
||||||
import minisql.ast.{*, given}
|
|
||||||
import scala.deriving.*
|
|
||||||
import scala.compiletime.*
|
|
||||||
|
|
||||||
sealed trait Query[T] {
|
|
||||||
def ast: Ast
|
|
||||||
}
|
|
||||||
|
|
||||||
case class Column
|
|
||||||
|
|
||||||
case class EntityQuery[A](ast: Entity) extends Query
|
|
||||||
|
|
||||||
inline def compile(inline e: Ast): Unit = ${ compileImpl('e) }
|
|
||||||
|
|
||||||
private def compileImpl(e: Expr[Ast])(using Quotes) = {
|
|
||||||
import quotes.reflect.*
|
|
||||||
e.value match {
|
|
||||||
case Some(v) =>
|
|
||||||
report.info("Static:" + v.toString())
|
|
||||||
case None =>
|
|
||||||
report.info("Dynamic")
|
|
||||||
}
|
|
||||||
'{ () }
|
|
||||||
}
|
|
|
@ -81,16 +81,16 @@ case class ConcatMap(query: Ast, alias: Ident, body: Ast) extends Query
|
||||||
case class SortBy(query: Ast, alias: Ident, criterias: Ast, ordering: Ordering)
|
case class SortBy(query: Ast, alias: Ident, criterias: Ast, ordering: Ordering)
|
||||||
extends Query
|
extends Query
|
||||||
|
|
||||||
sealed trait Ordering extends Ast
|
sealed trait Ordering extends Ast
|
||||||
case class TupleOrdering(elems: List[Ordering]) extends Ordering
|
case class TupleOrdering(elems: List[Ordering]) extends Ordering
|
||||||
|
|
||||||
sealed trait PropertyOrdering extends Ordering
|
sealed trait PropertyOrdering extends Ordering
|
||||||
case object Asc extends PropertyOrdering
|
case object Asc extends PropertyOrdering
|
||||||
case object Desc extends PropertyOrdering
|
case object Desc extends PropertyOrdering
|
||||||
case object AscNullsFirst extends PropertyOrdering
|
case object AscNullsFirst extends PropertyOrdering
|
||||||
case object DescNullsFirst extends PropertyOrdering
|
case object DescNullsFirst extends PropertyOrdering
|
||||||
case object AscNullsLast extends PropertyOrdering
|
case object AscNullsLast extends PropertyOrdering
|
||||||
case object DescNullsLast extends PropertyOrdering
|
case object DescNullsLast extends PropertyOrdering
|
||||||
|
|
||||||
case class GroupBy(query: Ast, alias: Ident, body: Ast) extends Query
|
case class GroupBy(query: Ast, alias: Ident, body: Ast) extends Query
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ case class Ident(name: String, visibility: Visibility) extends Ast {
|
||||||
*/
|
*/
|
||||||
object Ident {
|
object Ident {
|
||||||
def apply(name: String): Ident = Ident(name, Visibility.neutral)
|
def apply(name: String): Ident = Ident(name, Visibility.neutral)
|
||||||
def unapply(p: Ident) = Some((p.name))
|
def unapply(p: Ident) = Some((p.name))
|
||||||
|
|
||||||
object Opinionated {
|
object Opinionated {
|
||||||
def apply(name: String, visibilityNew: Visibility): Ident =
|
def apply(name: String, visibilityNew: Visibility): Ident =
|
||||||
|
@ -188,7 +188,7 @@ sealed trait OpinionValues[T <: Opinion[T]] {
|
||||||
sealed trait Visibility extends Opinion[Visibility]
|
sealed trait Visibility extends Opinion[Visibility]
|
||||||
object Visibility extends OpinionValues[Visibility] {
|
object Visibility extends OpinionValues[Visibility] {
|
||||||
case object Visible extends Visibility with Opinion[Visibility]
|
case object Visible extends Visibility with Opinion[Visibility]
|
||||||
case object Hidden extends Visibility with Opinion[Visibility]
|
case object Hidden extends Visibility with Opinion[Visibility]
|
||||||
|
|
||||||
inline override def neutral: Visibility = Visible
|
inline override def neutral: Visibility = Visible
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ sealed trait Renameable extends Opinion[Renameable] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
object Renameable extends OpinionValues[Renameable] {
|
object Renameable extends OpinionValues[Renameable] {
|
||||||
case object Fixed extends Renameable with Opinion[Renameable]
|
case object Fixed extends Renameable with Opinion[Renameable]
|
||||||
case object ByStrategy extends Renameable with Opinion[Renameable]
|
case object ByStrategy extends Renameable with Opinion[Renameable]
|
||||||
|
|
||||||
inline override def neutral: Renameable = ByStrategy
|
inline override def neutral: Renameable = ByStrategy
|
||||||
|
@ -248,8 +248,8 @@ object Property {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait OptionOperation extends Ast
|
sealed trait OptionOperation extends Ast
|
||||||
case class OptionFlatten(ast: Ast) extends OptionOperation
|
case class OptionFlatten(ast: Ast) extends OptionOperation
|
||||||
case class OptionGetOrElse(ast: Ast, body: Ast) extends OptionOperation
|
case class OptionGetOrElse(ast: Ast, body: Ast) extends OptionOperation
|
||||||
case class OptionFlatMap(ast: Ast, alias: Ident, body: Ast)
|
case class OptionFlatMap(ast: Ast, alias: Ident, body: Ast)
|
||||||
extends OptionOperation
|
extends OptionOperation
|
||||||
|
@ -259,9 +259,9 @@ case class OptionForall(ast: Ast, alias: Ident, body: Ast)
|
||||||
case class OptionExists(ast: Ast, alias: Ident, body: Ast)
|
case class OptionExists(ast: Ast, alias: Ident, body: Ast)
|
||||||
extends OptionOperation
|
extends OptionOperation
|
||||||
case class OptionContains(ast: Ast, body: Ast) extends OptionOperation
|
case class OptionContains(ast: Ast, body: Ast) extends OptionOperation
|
||||||
case class OptionIsEmpty(ast: Ast) extends OptionOperation
|
case class OptionIsEmpty(ast: Ast) extends OptionOperation
|
||||||
case class OptionNonEmpty(ast: Ast) extends OptionOperation
|
case class OptionNonEmpty(ast: Ast) extends OptionOperation
|
||||||
case class OptionIsDefined(ast: Ast) extends OptionOperation
|
case class OptionIsDefined(ast: Ast) extends OptionOperation
|
||||||
case class OptionTableFlatMap(ast: Ast, alias: Ident, body: Ast)
|
case class OptionTableFlatMap(ast: Ast, alias: Ident, body: Ast)
|
||||||
extends OptionOperation
|
extends OptionOperation
|
||||||
case class OptionTableMap(ast: Ast, alias: Ident, body: Ast)
|
case class OptionTableMap(ast: Ast, alias: Ident, body: Ast)
|
||||||
|
@ -270,15 +270,15 @@ case class OptionTableExists(ast: Ast, alias: Ident, body: Ast)
|
||||||
extends OptionOperation
|
extends OptionOperation
|
||||||
case class OptionTableForall(ast: Ast, alias: Ident, body: Ast)
|
case class OptionTableForall(ast: Ast, alias: Ident, body: Ast)
|
||||||
extends OptionOperation
|
extends OptionOperation
|
||||||
object OptionNone extends OptionOperation
|
object OptionNone extends OptionOperation
|
||||||
case class OptionSome(ast: Ast) extends OptionOperation
|
case class OptionSome(ast: Ast) extends OptionOperation
|
||||||
case class OptionApply(ast: Ast) extends OptionOperation
|
case class OptionApply(ast: Ast) extends OptionOperation
|
||||||
case class OptionOrNull(ast: Ast) extends OptionOperation
|
case class OptionOrNull(ast: Ast) extends OptionOperation
|
||||||
case class OptionGetOrNull(ast: Ast) extends OptionOperation
|
case class OptionGetOrNull(ast: Ast) extends OptionOperation
|
||||||
|
|
||||||
sealed trait IterableOperation extends Ast
|
sealed trait IterableOperation extends Ast
|
||||||
case class MapContains(ast: Ast, body: Ast) extends IterableOperation
|
case class MapContains(ast: Ast, body: Ast) extends IterableOperation
|
||||||
case class SetContains(ast: Ast, body: Ast) extends IterableOperation
|
case class SetContains(ast: Ast, body: Ast) extends IterableOperation
|
||||||
case class ListContains(ast: Ast, body: Ast) extends IterableOperation
|
case class ListContains(ast: Ast, body: Ast) extends IterableOperation
|
||||||
|
|
||||||
case class If(condition: Ast, `then`: Ast, `else`: Ast) extends Ast
|
case class If(condition: Ast, `then`: Ast, `else`: Ast) extends Ast
|
||||||
|
@ -318,7 +318,7 @@ sealed trait Action extends Ast
|
||||||
|
|
||||||
case class Update(query: Ast, assignments: List[Assignment]) extends Action
|
case class Update(query: Ast, assignments: List[Assignment]) extends Action
|
||||||
case class Insert(query: Ast, assignments: List[Assignment]) extends Action
|
case class Insert(query: Ast, assignments: List[Assignment]) extends Action
|
||||||
case class Delete(query: Ast) extends Action
|
case class Delete(query: Ast) extends Action
|
||||||
|
|
||||||
sealed trait ReturningAction extends Action {
|
sealed trait ReturningAction extends Action {
|
||||||
def action: Ast
|
def action: Ast
|
||||||
|
@ -358,11 +358,11 @@ object OnConflict {
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait Target
|
sealed trait Target
|
||||||
case object NoTarget extends Target
|
case object NoTarget extends Target
|
||||||
case class Properties(props: List[Property]) extends Target
|
case class Properties(props: List[Property]) extends Target
|
||||||
|
|
||||||
sealed trait Action
|
sealed trait Action
|
||||||
case object Ignore extends Action
|
case object Ignore extends Action
|
||||||
case class Update(assignments: List[Assignment]) extends Action
|
case class Update(assignments: List[Assignment]) extends Action
|
||||||
}
|
}
|
||||||
//************************************************************
|
//************************************************************
|
||||||
|
@ -386,34 +386,15 @@ sealed trait ScalarLift extends Lift
|
||||||
case class ScalarValueLift(
|
case class ScalarValueLift(
|
||||||
name: String,
|
name: String,
|
||||||
liftId: String
|
liftId: String
|
||||||
) extends ScalarLift {
|
) extends ScalarLift
|
||||||
|
|
||||||
def expandedLiftId: Option[(String, Int)] = {
|
|
||||||
val idxStart = liftId.indexOf('[')
|
|
||||||
val idxEnd = liftId.indexOf(']')
|
|
||||||
if (idxStart != -1 && idxEnd != -1) {
|
|
||||||
val idx = liftId.substring(idxStart + 1, idxEnd).toIntOption
|
|
||||||
idx.map(i => liftId.substring(0, idxStart) -> i)
|
|
||||||
} else None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case class ScalarQueryLift(name: String, liftId: String) extends ScalarLift {
|
|
||||||
def at(idx: Int): ScalarValueLift =
|
|
||||||
ScalarValueLift(s"${name}[$idx]", s"${liftId}[${idx}]")
|
|
||||||
}
|
|
||||||
|
|
||||||
object ScalarLift {
|
object ScalarLift {
|
||||||
given ToExpr[ScalarLift] with {
|
given ToExpr[ScalarLift] with {
|
||||||
def apply(l: ScalarLift)(using Quotes) = l match {
|
def apply(l: ScalarLift)(using Quotes) = l match {
|
||||||
case ScalarValueLift(n, id) =>
|
case ScalarValueLift(n, id) =>
|
||||||
'{ ScalarValueLift(${ Expr(n) }, ${ Expr(id) }) }
|
'{ ScalarValueLift(${ Expr(n) }, ${ Expr(id) }) }
|
||||||
case ScalarQueryLift(n, id) =>
|
|
||||||
'{ ScalarQueryLift(${ Expr(n) }, ${ Expr(id) }) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait CaseClassLift extends Lift
|
sealed trait CaseClassLift extends Lift
|
||||||
case class CaseClassQueryLift(name: String, liftId: String)
|
|
||||||
extends CaseClassLift
|
|
|
@ -68,6 +68,9 @@ private given FromExpr[Property] with {
|
||||||
)
|
)
|
||||||
} =>
|
} =>
|
||||||
Some(Property(a, n, r, v))
|
Some(Property(a, n, r, v))
|
||||||
|
case o =>
|
||||||
|
println(s"Canot extrat ${o.show}:${x}")
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +106,9 @@ 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 o =>
|
||||||
|
println(s"Cannot extract ${o.show}")
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,17 +226,37 @@ private given FromExpr[If] with {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private[minisql] given astFromExpr: FromExpr[Ast] = new FromExpr[Ast] {
|
private def extractTerm(using Quotes)(x: quotes.reflect.Term) = {
|
||||||
|
import quotes.reflect.*
|
||||||
private def isAstType[t](using Quotes, Type[t]) = {
|
def unwrapTerm(t: Term): Term = t match {
|
||||||
import quotes.reflect.*
|
case Inlined(_, _, o) => unwrapTerm(o)
|
||||||
val t1 = TypeRepr.of[t].dealias.simplified
|
case Block(Nil, last) => last
|
||||||
println(s"isAstType ${TypeRepr.of[t]} ===> ${t1}")
|
case Typed(t, _) =>
|
||||||
t1 <:< TypeRepr.of[Ast]
|
unwrapTerm(t)
|
||||||
|
case Select(t, "$asInstanceOf$") =>
|
||||||
|
unwrapTerm(t)
|
||||||
|
case TypeApply(t, _) =>
|
||||||
|
unwrapTerm(t)
|
||||||
|
case o => o
|
||||||
}
|
}
|
||||||
|
val o = unwrapTerm(x)
|
||||||
|
println(s"From ========== ${x.show}")
|
||||||
|
println(s"To ========== ${o.show}")
|
||||||
|
o
|
||||||
|
}
|
||||||
|
|
||||||
|
extension (e: Expr[Any]) {
|
||||||
|
def toTerm(using Quotes) = {
|
||||||
|
import quotes.reflect.*
|
||||||
|
e.asTerm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
given astFromExpr: FromExpr[Ast] = new FromExpr[Ast] {
|
||||||
|
|
||||||
def unapply(e: Expr[Ast])(using Quotes): Option[Ast] = {
|
def unapply(e: Expr[Ast])(using Quotes): Option[Ast] = {
|
||||||
e match {
|
|
||||||
|
extractTerm(e.toTerm).asExpr match {
|
||||||
case '{ $x: Query } => x.value
|
case '{ $x: Query } => x.value
|
||||||
case '{ $x: ScalarValueLift } => x.value
|
case '{ $x: ScalarValueLift } => x.value
|
||||||
case '{ $x: Property } => x.value
|
case '{ $x: Property } => x.value
|
||||||
|
@ -242,26 +268,7 @@ private[minisql] given astFromExpr: FromExpr[Ast] = new FromExpr[Ast] {
|
||||||
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: Ast).asInstanceOf } =>
|
case o => None
|
||||||
unapply(x.asInstanceOf)
|
|
||||||
case '{ (${ x }: t1).asInstanceOf[t2] } if isAstType[t2] =>
|
|
||||||
unapply(x.asInstanceOf)
|
|
||||||
case o =>
|
|
||||||
import quotes.reflect.*
|
|
||||||
def unwrapInline(x: Term): Unit = x match {
|
|
||||||
case Inlined(_, bs, t) =>
|
|
||||||
unwrapInline(t)
|
|
||||||
case Typed(t, _) =>
|
|
||||||
unwrapInline(t)
|
|
||||||
case TypeApply(t, _) =>
|
|
||||||
unwrapInline(t)
|
|
||||||
// case Select(x, "$asInstanceOf$") =>
|
|
||||||
// unwrapInline(x)
|
|
||||||
case o =>
|
|
||||||
println(s"unwrapped term(${o.getClass}): ${o.show}")
|
|
||||||
}
|
|
||||||
unwrapInline(o.asTerm)
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
46
src/main/scala/minisql/dsl.scala
Normal file
46
src/main/scala/minisql/dsl.scala
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package minisql.dsl
|
||||||
|
|
||||||
|
import minisql.ast.{Ast, Entity, given}
|
||||||
|
import scala.quoted.*
|
||||||
|
import scala.compiletime.*
|
||||||
|
import scala.compiletime.ops.string.*
|
||||||
|
|
||||||
|
sealed trait Dsl {
|
||||||
|
def ast: Ast
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Query[E] extends Dsl
|
||||||
|
|
||||||
|
class EntityQuery[E](val ast: Ast) extends Query
|
||||||
|
|
||||||
|
given FromExpr[EntityQuery[?]] with {
|
||||||
|
def unapply(x: Expr[EntityQuery[?]])(using Quotes): Option[EntityQuery[?]] = {
|
||||||
|
x match {
|
||||||
|
case '{ EntityQuery(${ Expr(ast) }) } =>
|
||||||
|
Some(EntityQuery(ast))
|
||||||
|
case _ =>
|
||||||
|
import quotes.reflect.*
|
||||||
|
println(s"cannot unlift ${x.asTerm}")
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
given FromExpr[Dsl] with {
|
||||||
|
def unapply(d: Expr[Dsl])(using Quotes): Option[Dsl] = d match {
|
||||||
|
case '{ ($x: EntityQuery[?]) } => x.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline def query[E](inline table: String) =
|
||||||
|
EntityQuery[E](Entity(table, Nil))
|
||||||
|
|
||||||
|
inline def compile(inline x: Dsl): Option[String] = ${ compileImpl('x) }
|
||||||
|
|
||||||
|
private def compileImpl(x: Expr[Dsl])(using Quotes): Expr[Option[String]] = {
|
||||||
|
import quotes.reflect.*
|
||||||
|
x.value match {
|
||||||
|
case Some(xv) => '{ Some(${ Expr(xv.ast.toString()) }) }
|
||||||
|
case None => '{ None }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue