High Level API
The high level API relies on two mechanisms to provide type safety and reduce boilerplate code:
- Automatic ZIO Schema derivation for case classes
- Semi automatic generation of
ProjectionExpression
's for case classes and sealed traits
ZIO Schema derivation​
The High Level API methods rely on a ZIO Schema for a particular type being in implicit scope. This is achieved using the DeriveSchema.gen
macro. Internally codecs are automatically generated for the case classes based on the meta data provided by the Schema
's.
final case class Person(id: String, name: String)
object Person {
implicit val schema: Schema.CaseClass2[String, String, Person] = DeriveSchema.gen[Person]
}
Projection Expression generation​
The automated generation of ProjectionExpression
's is achieved using the ProjectionExpression.accessors
method. For classes this method generates a ProjectionExpression
for each field. For sealed traits it generates a ProjectionExpression
for each child.
final case class Person(id: String, name: String)
object Person {
implicit val schema // ...
val (id, name) = ProjectionExpression.accessors[Person]
}
Using a ProjectionExpression
as a springboard to creating further expressions​
In the above example Person.id
and Person.name
are ProjectionExpression
s automatically generated by the ProjectionExpression.accessors
method.
They are used as a springboard for creating further type safe APIs eg
Person.id === "1"
creates aConditionExpression
Person.name.set("Smith")
creates anUpdateExpression
Person.id.partitionKey === "1"
creates a primary key expression
DynamoDBQuery
CRUD methods​
There are also type safe query creation methods in the DynamoDBQuery
companion object such as get
, put
, update
, deleteFrom
, queryAll
and all these take expressions as arguments. So taking our example further we can see how all these APIs can be used together to create a type safe CRUD queries:
final case class Person(id: String, name: String)
object Person {
implicit val schema: Schema.CaseClass2[String, String, Person] = DeriveSchema.gen[Person]
val (id, name) = ProjectionExpression.accessors[Person]
}
val table = "person-table"
val person = Person("1", "John")
for {
_ <- DynamoDBQuery.put(table, person).where(!Person.id.exists).execute
found <- DynamoDBQuery.get(table)(Person.id.partitionKey === "1").execute.absolve
_ <- DynamoDBQuery.update(table)(Person.id.partitionKey === "1")(
Person.name.set("Smith")
).execute
_ <- ZIO.debug(found == person) // true
} yield ()