Support for using of annotated case classes with arbitrary number of traits as Quill domain models
This documentation assumes you are already familiar with Quill and that you have read its documentation.
The main goal of this library is to allow extending of base domain models using traits. The requirement come from developing a rapid-application-development-framework/content-management-system where core package's domain models should be easily extendable by a a 3rd party libraries.
Sample:
import com.nikolastojiljkovic.annotation.{ Field, Table }
@Table("page")
case class Page(
@Field("id") id: Option[Int],
@Field("parent_id") parentId: Option[Int],
@Field("sorting") sorting: Option[Int],
@Field("title") title: String,
@Field("path") path: String
)
Sample:
@Table("page")
trait SeoSupport {
this: Page =>
@Field("sitemap_change_freq")
def sitemapChangeFrequency: String
@Field("sitemap_priority")
def sitemapPriority: Double
}
In the sample above, usage of Table
annotation is not required.
A trait without a Table
annotation can be used with any case class (as long as the mapped table
has all of the required fields).
Few restrictions for the traits:
- The only abstract methods need to be the ones mapped to a database column,
- Counter-intuitive
def
needs to be used in traits to define columns (instead ofval
) as Scala compiler doesn't expose annotations of trait'sval
members. Internally, when instantiating, thosedef
s will actually becomeval
.
Any Quill context (MySQL, PostgreSQL, Cassandra...) can be used as long as trait
AnnotatedTraitSupport
is included.
import io.getquill._
import com.nikolastojiljkovic.quilltrait._
val ctx = new SqlMirrorContext[MirrorSqlDialect, Literal] with AnnotatedTraitSupport
import ctx._
As table and column names are defined in annotations, it is recommended to use appropriate *Escape
naming strategy designated for the selected Quill context.
Context with trait AnnotatedTraitSupport
can accept annotated case classes and traits the same way
core Quill works with case classes without any limitations.
Select with filtering:
val q = quote {
query[Page with SeoSupport].filter(p => p.sitemapPriority > 0.7)
}
ctx.run(q)
Inserting:
val page = new Page(Some(1), None, Some(0), "Root", "/") with SeoSupport {
val sitemapChangeFrequency = "monthly"
val sitemapPriority = 0.00
}
val pages = quote {
query[Page with SeoSupport]
}
val pageInsert = quote {
(p: Page with SeoSupport) => pages.insert(p)
}
ctx.run(pageInsert(lift(page)))
Updating:
val u = quote {
query[Page with SeoSupport].filter(p => p.id == lift(Option(1))).update(_.sitemapPriority -> lift(0.1))
}
ctx.run(u)
Deleting:
val d = quote {
query[Page with SeoSupport].filter(p => p.id == lift(Option(1))).delete
}
ctx.run(d)
Add quill-trait-core
to sbt dependencies:
libraryDependencies ++= Seq(
"com.github.nstojiljkovic" %% "quill-trait-core" % "0.1.3-SNAPSHOT"
)
Library quill-trait-core
works with any Quill context (MySQL, PostgreSQL, JDBC, Cassandra, even Scala.js).
Quill allows customizing of expansion and execution handling of quotations through implicit
meta instances (schema, insert, update and query meta instances). Internally, core Quill's
contexts have defined low priority implicits for those meta instances which are executed
using macro expansion. Quill-trait context trait AnnotatedTraitSupport
defines higher priority
implicits (higher priority than core's low priority implicits) which define meta instances based
on the annotations.
- Improve documentation
- Write more test cases
- Move annotations to a separate library
- Create macro for using copy with Quill-core annotated traits
See the CONTRIBUTING.md file for details.
See the LICENSE file for details.
- @nstojiljkovic