Efflorescence is an experimental library for working with cloud-based data stores. It currently provides an ORM layer for the Google Cloud Platform Datastore.
An early release of Efflorescence is available on Maven Central, and can be included in an sbt project by including,
"com.propensive" %% "efflorescence" % "0.2.0"
To use Efflorescence, you should first set up a GCP
account, and grant appropriate access rights to a
service account, as described
here. Efflorescence uses
the Java API provided by Google to handle the underlying communication to the
GCP. This library expects to read the environment variable
GOOGLE_APPLICATION_CREDENTIALS, pointing to a local file containing those
credentials, as a JSON file (which is downloadable through the GCP user
Currently if any issues relating to credentials occur, an exception will be thrown by the Google API.
If that has been completed succesfully, that is the most difficult part of the instructions completed, and everything from now on is trivial.
To get started, first import the
and create a case class you would like to store, for example,
case class Person(email: String, name: String, age: Int)
and use an implicit
Id typeclass instance to choose a primary key for this
data type. Picking a unique field should be adequate, for example,
implicit val personId: Id[Person] = _.email
Note that the above concise syntax is only possible using SAM types in Scala 2.12.
You are now ready to save a value, which is as simple as calling
.save() on a
case class instance, like so,
Person("firstname.lastname@example.org", "Jon Pretty", 35).save()
If the save was successful, the value should now be in the GCP Datastore, with
the "kind" (in GCP terminology, though this is really a "type")
We can fetch all
Persons from the Datastore by calling,
which returns an
Serialization and Deserialization
Saving a case class value will use Magnolia to try to
Encoder for that type. This will be possible only if all of its
parameters can be serialized. All Java primitive types and strings are
Additionally, any nested case class instances can also be serialized, provided they meet the same conditions.
It will make most sense sometimes to compose datatypes directly inside others.
But other times, it will be most useful to refer to values stored elsewhere.
This can be done with
Refs, which can also be included in a case class
structure, and are serializable.
Ref can only exist for a value which has already been saved into the
Datastore, and it is indeed the return type of the
Ref is not the datatype itself; it is merely a reference to it, and can be
easily dereferenced by calling its'
Here is an example using two case classes,
case class Company(id: String, name: String) case class Person(id: String, name: String, company: Ref[Company])
where we may want to have several
Persons all referring to the same
Company. As usual, we need to ensure both types have IDs,
implicit val companyId: Id[Company] = _.id implicit val personId: Id[Person] = _.id
We can now create and link some data, like so,
val company: Company = Company("propensive", "Propensive Ltd") val companyRef: Ref[Company] = company.save() val person: Person = Person("jonpretty", "Jon Pretty", companyRef) person.save()
and to access the
Company value, via the
Person, we would just call
As this is currently just an early and incomplete release, certain obvious features are missing, for example,
Options and other collections are not supported
- GCP Datastore namespaces are not supported
- the only data query currently available gets all records
This is very experimental software, and should not be considered production-ready.
There is currently no website for Efflorescence.
Efflorescence is made available under the Apache 2.0 license.