Skip to content

Instantly share code, notes, and snippets.

@programaker
Created June 19, 2021 11:29
Show Gist options
  • Save programaker/ff634ef17a9aeff880dfb4863dca5e59 to your computer and use it in GitHub Desktop.
Save programaker/ff634ef17a9aeff880dfb4863dca5e59 to your computer and use it in GitHub Desktop.
Custom refinements for domain types
import eu.timepit.refined.api.{Refined, Validate}
import eu.timepit.refined.boolean.{And, Not}
import eu.timepit.refined.refineV
/* Domain types */
final case class Customer(id: Long, name: String, age: Int)
final case class Order(description: String)
//===
/* Predicates */
final case class ValidCustomer()
object ValidCustomer {
implicit val validateCustomer: Validate.Plain[Customer, ValidCustomer] =
Validate.fromPredicate(
customer => customer.id >= 0L && !customer.name.isBlank && customer.age > 0,
customer => s"$customer is valid",
ValidCustomer()
)
}
final case class Minor()
object Minor {
implicit val validateMinor: Validate.Plain[Customer, Minor] =
Validate.fromPredicate(
customer => customer.age < 18,
customer => s"$customer is minor",
Minor()
)
}
//===
/* Services */
object CandyShop {
final case class Candy(name: String)
type CandyShopCustomerP = ValidCustomer
type CandyShopCustomer = Customer Refined CandyShopCustomerP
def serve(candy: Candy, customer: CandyShopCustomer): Order =
Order(s"1 ${candy.name} for ${customer.value.name}")
}
object Bar {
final case class Drink(name: String)
type BarCustomerP = ValidCustomer And Not[Minor]
type BarCustomer = Customer Refined BarCustomerP
def serve(drink: Drink, customer: BarCustomer): Order =
Order(s"1 ${drink.name} for ${customer.value.name}")
}
//===
import CandyShop._
import Bar._
val nobody = Customer(id = 0L, name = "", age = 0)
val mrSmith = Customer(id = 1L, name = "Mr Smith", age = 40)
val smithJr = Customer(id = 2L, name = "Smith Jr", age = 5)
val nobodyValid = refineV[ValidCustomer](nobody)
val mrSmithValid = refineV[ValidCustomer](mrSmith)
val smithJrValid = refineV[ValidCustomer](smithJr)
println(">>> Basic validation")
println(nobodyValid)
println(mrSmithValid)
println(smithJrValid)
val candy = Candy("Chocolate")
val nobodyBuyingCandy = refineV[CandyShopCustomerP](nobody).map(CandyShop.serve(candy, _))
val mrSmithBuyingCandy = refineV[CandyShopCustomerP](mrSmith).map(CandyShop.serve(candy, _))
val smithJrBuyingCandy = refineV[CandyShopCustomerP](smithJr).map(CandyShop.serve(candy, _))
println(">>> At the candy shop")
println(nobodyBuyingCandy)
println(mrSmithBuyingCandy)
println(smithJrBuyingCandy)
val drink = Drink("Beer")
val nobodyBuyingDrink = refineV[BarCustomerP](nobody).map(Bar.serve(drink, _))
val mrSmithBuyingDrink = refineV[BarCustomerP](mrSmith).map(Bar.serve(drink, _))
val smithJrBuyingDrink = refineV[BarCustomerP](smithJr).map(Bar.serve(drink, _))
println(">>> At the bar")
println(nobodyBuyingDrink)
println(mrSmithBuyingDrink)
println(smithJrBuyingDrink)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment