io.getquill.context

Type members

Classlikes

trait Context[+Dialect <: Idiom, +Naming <: NamingStrategy] extends ProtoContextSecundus[Dialect, Naming] with EncodingDsl with Closeable
trait ContextEffect[F[_]]

In order to be able to reuse methods in the Jdbc Context as well as others, there must be a way to encapsulate the effects of these contexts. This simple interface provides them in a fairly generic manner.

In order to be able to reuse methods in the Jdbc Context as well as others, there must be a way to encapsulate the effects of these contexts. This simple interface provides them in a fairly generic manner.

trait ContextStandard[+Idiom <: Idiom, +Naming <: NamingStrategy] extends Context[Idiom, Naming] with ContextVerbPrepareLambda[Idiom, Naming]
trait ContextTranslateMacro[+Dialect <: Idiom, +Naming <: NamingStrategy] extends ContextTranslateProto[Dialect, Naming]
trait ContextTranslateProto[+Dialect <: Idiom, +Naming <: NamingStrategy]
trait ContextVerbPrepare[+Dialect <: Idiom, +Naming <: NamingStrategy]
trait ContextVerbPrepareLambda[+Dialect <: Idiom, +Naming <: NamingStrategy] extends ContextVerbPrepare[Dialect, Naming]
trait ContextVerbStream[+Dialect <: Idiom, +Naming <: NamingStrategy] extends ProtoStreamContext[Dialect, Naming]
trait ContextVerbTranslate[+Dialect <: Idiom, +Naming <: NamingStrategy] extends ContextTranslateMacro[Dialect, Naming]
object Execution

Enums and helper methods for QueryExecution and QueryExecutionBatch

Enums and helper methods for QueryExecution and QueryExecutionBatch

class ExecutionInfo(val executionType: ExecutionType, queryAst: => Ast, queryTopLevelQuat: => Quat)

Metadata related to query execution. Note that AST should be lazy so as not to be evaluated at runtime (which would happen with a by-value property since { ExecutionInfo(stuff, ast) } is spliced into a query-execution site). Additionally, there are performance overheads even splicing the finalized version of the AST into call sites of therun` functions. For this reason, this functionality is being used only in ProtoQuill and only when a trait extends the trait AstSplicing. In the future it might potentially be controlled by a compiler argument.

Metadata related to query execution. Note that AST should be lazy so as not to be evaluated at runtime (which would happen with a by-value property since { ExecutionInfo(stuff, ast) } is spliced into a query-execution site). Additionally, there are performance overheads even splicing the finalized version of the AST into call sites of therun` functions. For this reason, this functionality is being used only in ProtoQuill and only when a trait extends the trait AstSplicing. In the future it might potentially be controlled by a compiler argument.

Companion:
object
Companion:
class
sealed trait ExecutionType
Companion:
object
Companion:
class
sealed trait Extraction[-ResultRow, -Session, +T]
Companion:
object
object Extraction
Companion:
class

TODO Right now this is just insert but we can easily extend to update and delete

TODO Right now this is just insert but we can easily extend to update and delete

The function call that regularly drives query insertion is {code} query[T].insert(_.field1 -> value, _.field2 -> value, etc...) {code} Let's call this the field-insertion api.

This macro essentially takes an insert of the form query[T].insert(T(...)) and converts into the former form.

Once we've parsed an insert e.g. query[Person]insertValue(Person("Joe", "Bloggs")) we then need to synthesize the insertions that this would represent e.g. query[Person].insert(_.firstName -> "Joe", _.lastName -> "Bloggs")

Each function of field-insertion API basically takes the form {code} (v) => vAssignmentProperty -> assignmentValue (on the AST) {code}

Let's take a look at a slighly more complex example Given: {code} case class Person(name: String, age: Option[Age]); Age(value: Int) quote { query[Person].insert(Person("Joe", Age(345))) } {code}

This expands out into a series of statements which will be parsed to AST assignments This: (v: Person) => v.name -> (v:Person).name Will be parsed into this: {code} Assignment(Id(v), Prop(Id(v), name), Constant("Joe")) {code}

This: (v: Person) => v.age.map(v => v.value) -> Option(v:Age).map(v => v.value) Will be parsed into this: {code} Assignment(Id(v), OptionTableMap(Prop(Id(v), age), Id(v), Prop(Id(v), value)) OptionTableMap(OptionApply(CaseClass(value=345)), Id(v), Prop(Id(v), value)) ) {code}

The end result of this synthesis is a series of assignments for an insert for the given entity.

Another possiblity is that the entity is lifted: {code} case class Person(name: String, age: Option[Age]); Age(value: Int) quote { query[Person].insertValue(lift(Person("Joe", Age(345)))) } {code} TODO Finish doc

Note that as a result of the way this is implemented, if either the InsertMeta or the SchemaMeta is not inline, the entire resulting query will not be inline since they both will be summoned and used in the resulting expressions. It might be useful to introduce a configuration parameter to ignore non-inline InsertMetas or non-inline SchemaMetas. Or maybe this could even be an annotation.

object LiftMacro
object MetaMacro

For a query that has a filter(p => liftQuery(List("Joe","Jack")).contains(p.name)) we need to turn the "WHERE p.name in (?)" into WHERE p.name in (?, ?) i.e. to "Particularize" the query to the number of elements in the query lift. In Scala2-Quill we could just access the values of the liftQuery list directly since the lift was an 'Any' value directly in the AST. In Scala 3 however, we need to treat the lifted list as an Expr and create an Expr[String] that represents the Query that is to be during runtime based on the content of the list which has to be manipulated inside of a '{ ... } block.

For a query that has a filter(p => liftQuery(List("Joe","Jack")).contains(p.name)) we need to turn the "WHERE p.name in (?)" into WHERE p.name in (?, ?) i.e. to "Particularize" the query to the number of elements in the query lift. In Scala2-Quill we could just access the values of the liftQuery list directly since the lift was an 'Any' value directly in the AST. In Scala 3 however, we need to treat the lifted list as an Expr and create an Expr[String] that represents the Query that is to be during runtime based on the content of the list which has to be manipulated inside of a '{ ... } block.

In some cases the action that goes inside the batch needs an infix. For example, for SQL server to be able to do batch inserts of rows with IDs you need to do something like: {{ liftQuery(products).foreach(p => sql"SET IDENTITY_INSERT Product ON; ${query[Product].insertValue(p)}".as[Insert[Int]]) }} In order to yield something like this: {{ SET IDENTITY_INSERT Product ON; INSERT INTO Product (id,description,sku) VALUES (?, ?, ?) }} Otherwise SQLServer will not let you insert the row because IDENTITY_INSERT will be off.

In some cases the action that goes inside the batch needs an infix. For example, for SQL server to be able to do batch inserts of rows with IDs you need to do something like: {{ liftQuery(products).foreach(p => sql"SET IDENTITY_INSERT Product ON; ${query[Product].insertValue(p)}".as[Insert[Int]]) }} In order to yield something like this: {{ SET IDENTITY_INSERT Product ON; INSERT INTO Product (id,description,sku) VALUES (?, ?, ?) }} Otherwise SQLServer will not let you insert the row because IDENTITY_INSERT will be off.

trait ProtoContextSecundus[+Dialect <: Idiom, +Naming <: NamingStrategy] extends RowContext

A common context used between Quill and ProtoQuill. This is more like a pre-context because the actual run methods cannot be contained here since they use macros. Right now not all Scala2-Quill context extend this context but hopefully they will all in the future. This will establish a common general-api that Quill contexts can use. In ProtoQuill, this context is used for the base of all other context and allows the Scala 3 macros to call the execute___ methods. In Scala2-Quill wherein macros are less strict about signatures, this cannot be used for Context (in Context.scala) but various higher-level context extend it as a guard-rail against API drift i.e. so that the Scala2-Quill and ProtoQuill internal-context APIs remain largely the same.

A common context used between Quill and ProtoQuill. This is more like a pre-context because the actual run methods cannot be contained here since they use macros. Right now not all Scala2-Quill context extend this context but hopefully they will all in the future. This will establish a common general-api that Quill contexts can use. In ProtoQuill, this context is used for the base of all other context and allows the Scala 3 macros to call the execute___ methods. In Scala2-Quill wherein macros are less strict about signatures, this cannot be used for Context (in Context.scala) but various higher-level context extend it as a guard-rail against API drift i.e. so that the Scala2-Quill and ProtoQuill internal-context APIs remain largely the same.

trait ProtoStreamContext[+Dialect <: Idiom, +Naming <: NamingStrategy] extends RowContext

Drives execution of Quoted blocks i.e. Queries etc... from the context.

Drives execution of Quoted blocks i.e. Queries etc... from the context.

object QueryMacro

A QueryMeta allows contra-mapping some Query[T] to a combination of a Query[R] and then an extractor R => T. That is to say a function Query[T] => Query[R] and R => T function is automatically swapped in for a Query[T].

A QueryMeta allows contra-mapping some Query[T] to a combination of a Query[R] and then an extractor R => T. That is to say a function Query[T] => Query[R] and R => T function is automatically swapped in for a Query[T].

Internally, we use the term 'quip' (i.e. query + flip) to mean the QueryMeta construct, The Query[T] => Query[R] function itself is called the Quipper. Since a QueryMeta comes with an R=>M contramap function to apply to an extractor we call that the 'baq' since it mapps the inner query back from R to T.

Once the quip is summoned, it is applied to the original user-created query and then called a requip (i.e. re-applied quip). That it to say the requip is: FunctionApply(Query[T] => Query[R], Query[R])

Note that since internally, a QueryMeta carries a Quoted instance, the QueryMeta itself is a QuotationLot. For that reason, we call the whole QueryMeta structure a quip-lot. (Metaphorically speaking, a 'lot' meta real-estate containing a quip)

Given a PersonName(name: String) we can define a QueryMeta like this: {{ inline given QueryMeta[PersonName, String] = queryMeta( quote { (q: Query[PersonName]) => q.map(p => p.name) } // The Quipper )((name: String) => PersonName(name)) // The Baq }} When we do something like: {{ inline def people = quote { query[PersonName] } val result = ctx.run(people) }} The Query-Lot AST becomes EntityQuery("Person")

object QuoteMacro

Drives dynamic execution from the Context Note that AST is already elaborated by the time it comes into here

Drives dynamic execution from the Context Note that AST is already elaborated by the time it comes into here

Companion:
object
sealed trait SplicingBehavior
Companion:
object
Companion:
class
case class StaticState(query: Query, rawLifts: List[PlanterExpr[_, _, _]], returnAction: Option[ReturnAction], idiom: Idiom, secondaryLifts: List[PlanterExpr[_, _, _]])(queryAst: => Ast)