Persistent Entities in Lagom hold state of individual entities. In other words, they cannot be used to serve queries that span more than single entity. This requires us to create another view of the data that is tailored to serve rather optimized queries that span over multiple entities, which brings us to the most talked about separation of the write-side and the read-side of the persistent data, also known as CQRS (Command Query Responsibility Segregation) pattern.
In this blog post I would like to demonstrate how read side persistence is implemented in Lagom using Slick which is a modern database query and access library for Scala that allows us to write database queries in Scala thus profiting from static checks, compile-time safety and compositionality of Scala.
Lagom's Slick support is build on top of it’s support for storing persistent entities in a relational database. This requires us to add
lagomScaladslPersistenceJdbc as our dependency. We would also require to add a JDBC database connector driver of our choice. We will be using mysql connector for this demo.
Notice that we don't require
Slick dependency, for it being natively supported by the framework itself.
Lagom uses Play’s JDBC support to configure and create a connection pool, which requires us to provide details, such as, JDBC driver, database URL, etc in the
application.conf to help Lagom with the same. We also need to configure a correct Slick profile, which is
slick.jdbc.MySQLProfile$ in our case. These profiles abstract relevant SQL dialect, data type encodings, or other idiosyncracies.
Next we need our application loader to load relevant read-side persistence components which includes
Note: Please be informed that the order in which the traits
WriteSideCassandraPersistenceComponents are extended to create EmployeeApplication is of grave importance due to a bug in Lagom which requires trait
ReadSideJdbcPersistenceComponents to be mixed in before the trait
Let's now model our employee entity as Slick table definition as shown below.
Lagom makes use of the database configurations from our
application.conf to create and inject an instance of Slick
Database required as a dependency in our repository.
Unlike get queries,
updateEmployee queries return Slick
DBIOAction as required by
ReadSideProcessor.ReadSideHandler that handles events generated by Persistent Entities, which I'll introduce later. It is the Slick’s
Database which facilitates the execution of these
Database also manages the execution of blocking JDBC calls in a thread pool designed to handle them, which is why
db.run() API returns a
Every state change in a Persistent Entity is persisted in Cassandra as logs of historical events, which is how Lagom implements what's called as Event Sourcing. It is in response of the persistence of these events that the read-side is required to update the read-side data model. Lagom has a built in support for populating the read-side view out of the box. This is achieved by implementing a
ReadSideProcessor with assistance from the
SlickReadSide support component.
ReadSideProcessor implementation must implement a
buildHandler that returns a
ReadSideHandler, which is used by Lagom to prepare read-side processing and eventually handle the events returned by
aggregateTags method definition. All events with a particular tag are consumed as a sequential, ordered stream of events. You can refer Lagom documentation to learn how tags are implemented.
Now the Lagom's built in support comes into play when you extend
ReadSideSlickPersistenceComponents trait in your application loader.
As you can see, besides bringing in Slick
JdbcProfile right from our
application.conf as we discussed above, the
ReadSideSlickPersistenceComponents trait also brings in an implementation of
It is this
SlickReadSide implementation that implements a
ReadSideHandler builder out of the box for us. We can now implement our
ReadSideProcessor as shown below.
The event handlers
processEmployeeUpdated eventually ask our repository implementations to return
DBIOAction in response to respective events that these handlers are registered against.
And this is how we implement read-side persistence in Lagom using Slick. You can find the complete working implementation here on github.