Features strong values that might expire.
Overrides the Persistence methods which accesses the table so the cache is used instead.
Overrides the Persistence methods which accesses the table so the cache is used instead. All instances of the domain model are expected to fit into the cache.
Parse application.conf
and/or reference.conf
for database parameters
Utility class for providing copying of a designated case class with minimal overhead.
Mix this trait into any class that needs to access the H2 synchronous configuration.
Mix this trait into any class that needs to access the H2 synchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
class MyClass extends H2Ctx { import ctx._ }
The H2Configuration object mixes in this trait and provides an alternative mechanism.
Mix this trait into any class that needs to access the MySQL synchronous configuration.
Mix this trait into any class that needs to access the MySQL synchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
class MyClass extends MySqlCtx { import ctx._ }
The MysqlConfiguration object mixes in this trait and provides an alternative mechanism.
Mix this trait into any class that needs to access the MySQL asynchronous configuration.
Mix this trait into any class that needs to access the MySQL asynchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
class MyClass extends MysqlAsyncCtx { import ctx._ }
The MysqlAsyncConfiguration object mixes in this trait and provides an alternative mechanism.
Mix this trait into any class that needs to access the Postgres asynchronous configuration.
Mix this trait into any class that needs to access the Postgres asynchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
class MyClass extends PostgresAsyncCtx { import ctx._ }
The PostgresAsyncConfiguration object mixes in this trait and provides an alternative mechanism.
Mix this trait into any class that needs to access the Postgres synchronous configuration.
Mix this trait into any class that needs to access the Postgres synchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
class MyClass extends PostgresCtx { import ctx._ }
The PostgresConfiguration object mixes in this trait and provides an alternative mechanism.
Extract the Up portion of a Play evolution file and execute SQL statements, including DDL
Features soft values that might expire
SoftCache
contains "soft" values that might expire by timing out or might get bumped if memory fills up.
SoftCache
contains "soft" values that might expire by timing out or might get bumped if memory fills up.
Mix this trait into the DAO to provide this behavior.
DAOs that mix in SoftCache
do not assume that all instances of the case class can fit into memory.
SoftCache
finders that return at most one item from querying the cache will access the database, looking for that item after every cache miss.
Because of this, those SoftCache
finders run more slowly than StrongCache
finders when the cache does not contain the desired value.
SoftCache
finders that return a list of items must always query the database and never look in the cache.
The CachedPersistence
trait implements the default caching strategy.
This trait overrides the default finder implementations.
This trait is experimental, do not use in production.
Mix this trait into any class that needs to access the Sqlite synchronous configuration.
Mix this trait into any class that needs to access the Sqlite synchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
class MyClass extends SqliteCtx { import ctx._ }
The SqliteConfiguration object mixes in this trait and provides an alternative mechanism.
CachePersistence.prefetch
must be called before any finders.
CachePersistence.prefetch
must be called before any finders.
The CachedPersistence
trait implements the default caching strategy.
This trait overrides the default finder implementations.
Ensures that table names are quoted and snake_case but never start with a leading _.
Accesses the table for each query.
Accesses the table for each query.
You can use this abstract class to derive DAOs for case classes that must have direct access to the database so the
case classes are not cached. You don't have to subclass UnCachedPersistence
, but if you do then the DAOs for your
cached domain objects will have the same interface as the DAOs for your uncached domain objects.
From StackOverflow
Object for exposing the H2 synchronous configuration.
Object for exposing the H2 synchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
import H2Configuration.ctx._
Object for exposing the MySQL asynchronous configuration.
Object for exposing the MySQL asynchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
import MysqlAsyncConfiguration.ctx._
Object for exposing the MySQL synchronous configuration.
Object for exposing the MySQL synchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
import MysqlConfiguration.ctx._
Object for exposing the Postgres asynchronous configuration.
Object for exposing the Postgres asynchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
import PostgresAsyncConfiguration.ctx._
Object for exposing the Postgres synchronous configuration.
Object for exposing the Postgres synchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
import PostgresConfiguration.ctx._
Object for exposing the Sqlite synchronous configuration.
Object for exposing the Sqlite synchronous configuration.
Exposes a property called ctx
, which is the Quill context.
To use, simply import the context, like this:
import SqliteConfiguration.ctx._
Features and Benefits
insert
,deleteById
,remove
,update
,upsert
,zap
,findAll
,findById
, plus application-specific finders)Background
Scala uses case classes for modeling domain objects.
quill-cache
optimizes database access for read-mostly domain objects by providing a caching layer overtop Quill. This library depends on has-id, and case classes that need to be cached must extend HasId.HasId
is generic and quite flexible, so you are encouraged to subclass all your domain objects fromHasId
, even if they do not require database caching.The current version of this library has no provision for distributed caches. This could be retrofitted, however the author did not have the need, so the work was not done.
DAOs
The data access object pattern (DAO) is common across all computer languages. DAOs for case classes that require database caching must extend the persistence.CachedPersistence abstract class.
You are free to name DAOs anything you like; this library does not mandate any naming convention. Scala DAOs are often given the same name as the class that they persist, but with a suffix indicating plurality. For example, if a case class named
Point
needs to be persisted, the DAO is usually calledPoints
. Unlike some other persistence libraries for Scala, Quill allows you to define your DAO in the case class's companion object, so you also have that option when using this library.This library provides each DAO with its own cache. DAOs that extend
CachedPersistence
have a method calledpreload()
which your application's initialization must invoke in order to fill that DAO's cache. A cache can be flushed by calling the DAO'sflushCache()
method. Becausepreload()
always flushes the cache before loading it you probably won't ever need to explicitly callflushCache()
.Cache Types
Two types of caches are supported by
CachedPersistence
:SoftCacheLike
do not assume that all instances of the case class can fit into memory.SoftCacheLike
finders query the database after every cache miss. Because of this,SoftCacheLike
finders run more slowly thanStrongCacheLike
finders when the cache does not contain the desired value. This trait is experimental, do not use in production.Caches require an ExecutionContext, and the unit tests provide one:
Consistent APIs for Cached and Uncached DAOs
persistence.CachedPersistence subclasses persistence.UnCachedPersistence, which you can use to derive DAOs for case classes that must have direct access to the database so the case classes are not cached. You don't have to subclass
UnCachedPersistence
to get this behavior, but if you do then the DAOs for your cached domain objects will have the same interface as the DAOs for your uncached domain objects, and your code's structure will be more consistent.Configuration
Your database configuration is specified by a HOCON file called
application.conf
on the classpath. Please seesrc/main/scala/resources/reference.conf
for an example of how to set that up.Here is an excerpt showing configuration for H2 and Postgres databases. Only one of these databases can be active per database context:
The
quill-cache
section of the configuration file specifies parameters for this library:dataSource
sections.See also the Quill test application.conf, Hikari initialization, HikariConfig.java, and Hikari pool sizing
Working with quill-cache
Quill Contexts
Quill-cache provides many flavors of Quill contexts, one for each type of supported database driver. Each context is exposed as an
abstract class
. Import the Quill contextctx
from the appropriate type wherever you need to access the database.Available abstract classes are:
H2Ctx
,MySqlCtx
,PostgresCtx
, andSqliteCtx
. Subclass the appropriateabstract class
for the type of database driver you need, like this:Asynchronous Drivers
Asynchronous drivers are not currently supported by
quill-cache
, but there is an open issue for this enhancement. The database contextsMysqlAsyncCtx
andPostgresAsyncCtx
were written in anticipation of async support.Best Practice
Define a trait called
SelectedCtx
, and mix it into all your DAOs.SelectedCtx
merely extends the database context used in your application. ThePersistenceTest
DAO intest/scala/model/dao
follows this pattern:Now define your application's Quill context as a singleton, and mix in the predefined implicits for Quill-cache defined in
QuillCacheImplicits
.If you have more implicits to mix in, define a trait in the same manner as
QuillCacheImplicits
and mix it in as well:After adding in
MyQuillImplicits
, your revised application Quill contextCtx
is now:Now import the Quill context's internally defined implicits into your DAO's scope. Here are two examples of how to do that, one for cached and one for uncached persistence. Notice that
Users
andTokens
are singletons, which makes them easy to work with. Here isUsers
, a DAO with a strong cache, which means it needs anExecutionContext
likeTestExecutionContext
, which is in scope because it resides in the same package:Here is
Tokens
, a DAO without any cache, which means it does not need anExecutionContext
:Multiple Database Contexts
For circumstances where more than one database contexts need to share the same HikariCP pool, first construct a context, then other contexts can be created from the first context's
dataSource
. In the following example, a context for an H2 database is created usingCtx.dataSource
:Note that the new context need not have the same implicit decoders, encoders or mappers as the original context. See the
ContextTest
unit test for a working example.Here is another variation:
Working with DAOs
Quill-cache
automatically defines a read-only property for each DAO, calledclassName
. This property is derived from the unqualified name of the case class persisted by the DAO. For example, ifmodel.User
is being persisted,className
will beUser
.Each DAO needs the following functions defined:
_findAll
– Quill query foundation - Encapsulates the Quill query that returns all instances of the case class from the database._deleteById
– Encapsulates the Quill query that deletes the instance of the case class with the givenId
from the database._findById
– Encapsulates the Quill query that optionally returns the instance of the case class from the database with the givenId
, orNone
if not found._insert
– Encapsulates the Quill query that inserts the given instance of the case class into the database, and returns the case class as it was stored, including any auto-increment fields._update
– Encapsulates the Quill query that updates the given instance of the case class into the database, and returns the entity. Throws an Exception if the case class was not previously persisted.DAO CRUD
Here is an example of the CRUD-related functions, implemented in the DAO for
model.User
in thequill-cache
unit test suite.With the above defined,
quill-cache
automatically provides the following CRUD-related methods for each DAO. Only finders can take advantage of a cache, if present:See the unit tests for examples of how to use this library.