longevity

A Persistence Framework for Scala and NoSQL

View project on GitHub

polymorphic components

Let’s say that on our blogging site, we want to be able to verify the identity of our users, and we have a few different approaches for doing so. We can use email verification, where we send the user an email, with a link that they can click to verify the email address. We can also use SMS verification, where we send the user an SMS message with a temporary code in it, and ask the user to enter it into the webpage. Or we can use a third-party account verification system such as Google Sign-In.

An idealized representation of this portion of our domain might look like so:

import org.joda.time.DateTime

trait UserVerification {
  val verificationDate: DateTime
}

case class EmailVerification(
  email: Email,
  verificationDate: DateTime)
extends UserVerification

case class SmsVerification(
  phoneNumber: PhoneNumber,
  verificationDate: DateTime)
extends UserVerification

case class GoogleSignIn(
  email: Email,
  idToken: String,
  verificationDate: DateTime)
extends UserVerification

In our User object, we want to keep track of all the user’s successful verification attempts:

case class User(
  username: String,
  email: Email,
  verifications: List[UserVerification])

For this to work, all we need to do is to make longevity aware of our polymorphic component UserVerification, and its children. We do this using annotations @polyComponent and @derivedComponent:

import longevity.model.annotations.polyComponent
import longevity.model.annotations.derivedComponent
import longevity.model.annotations.persistent
import org.joda.time.DateTime

@polyComponent[DomainModel]
trait UserVerification {
  val verificationDate: DateTime
}

@derivedComponent[DomainModel, UserVerification]
case class EmailVerification(
  email: Email,
  verificationDate: DateTime)
extends UserVerification

@derivedComponent[DomainModel, UserVerification]
case class SmsVerification(
  phoneNumber: PhoneNumber,
  verificationDate: DateTime)
extends UserVerification

@derivedComponent[DomainModel, UserVerification]
case class GoogleSignIn(
  email: Email,
  idToken: String,
  verificationDate: DateTime)
extends UserVerification

@persistent[DomainModel]
case class User(
  username: String,
  email: Email,
  verifications: List[UserVerification])

The non-annotation equivalent is as follows:

import longevity.model.DerivedCType
import longevity.model.PType
import longevity.model.PolyCType
import org.joda.time.DateTime

trait UserVerification {
  val verificationDate: DateTime
}

object UserVerification extends PolyCType[DomainModel, UserVerification]

case class EmailVerification(
  email: Email,
  verificationDate: DateTime)
extends UserVerification

object EmailVerification extends DerivedCType[DomainModel, EmailVerification, UserVerification]

case class SmsVerification(
  phoneNumber: PhoneNumber,
  verificationDate: DateTime)
extends UserVerification

object SmsVerification extends DerivedCType[DomainModel, SmsVerification, UserVerification]

case class GoogleSignIn(
  email: Email,
  idToken: String,
  verificationDate: DateTime)
extends UserVerification

object GoogleSignIn extends DerivedCType[DomainModel, GoogleSignIn, UserVerification]

case class User(
  username: String,
  email: Email,
  verifications: List[UserVerification])

object User extends PType[DomainModel, User] {
  object props {
    // ...
  }
}
prev: subtype polymorphism
up: subtype polymorphism
next: polymorphic persistents