polymorphic persistents
We can use polymorphism with our persistent objects as well. For
example, let’s say our blogging system has two kinds of users: members and commenters. Only members
can have a user profile. Here, we use annotations @polyPersistent and @derivedPersistent in
place of @persistent:
import longevity.model.annotations.component
import longevity.model.annotations.derivedPersistent
import longevity.model.annotations.polyPersistent
@component[DomainModel]
case class UserProfile(
tagline: String,
imageUri: Uri,
description: Markdown)
@polyPersistent[DomainModel]
sealed trait User {
val username: Username
val email: Email
}
@derivedPersistent[DomainModel, User]
case class Member(
username: Username,
email: Email,
profile: UserProfile)
extends User
@derivedPersistent[DomainModel, User]
case class Commenter(
username: Username,
email: Email)
extends User
As with polymorphic components, we must remember to seal the trait to form a proper abstract data type.
The non-annotation equivalent is as follows:
import longevity.model.CType
import longevity.model.DerivedPType
import longevity.model.PolyPType
case class UserProfile(
tagline: String,
imageUri: Uri,
description: Markdown)
object UserProfile extends CType[DomainModel, UserProfile]
sealed trait User {
val username: Username
val email: Email
}
object User extends PolyPType[DomainModel, User] {
object props {
// ...
}
}
case class Member(
username: Username,
email: Email,
profile: UserProfile)
extends User
object Member extends DerivedPType[DomainModel, Member, User] {
object props {
// ...
}
}
case class Commenter(
username: Username,
email: Email)
extends User
object Commenter extends DerivedPType[DomainModel, Commenter, User] {
object props {
// ...
}
}
Notice how User, Member, and Commenter all have their own
properties, keys, and indexes. We could, for example, put in a
key on User.username, and
indexes on User.email and
Member.profile.tagline, like so:
import longevity.model.annotations.derivedPersistent
import longevity.model.annotations.polyPersistent
@polyPersistent[DomainModel]
trait User {
val username: Username
val email: Email
}
object User {
implicit val usernameKey = key(props.username)
override val indexSet = Set(index(props.email))
}
@derivedPersistent[DomainModel, User]
case class Member(
username: Username,
email: Email,
profile: UserProfile)
extends User
object Member {
override val indexSet = Set(index(props.profile.tagline))
}
When you construct your longevity context, you will be able to use
repository for for each of your @derivedPersistents, along with one for the
parent @polyPersistent. These persistent classes will share the same backing store, so a Member
persisted as a User will be retrievable as a Member, and vice-versa. Keys and indexes declared
in object User will apply to all types of Users, whereas keys and indexes declared in object
Member will only apply to members. For more information, see the section on persisting
polymorphism.