Created
June 19, 2021 11:29
-
-
Save programaker/ff634ef17a9aeff880dfb4863dca5e59 to your computer and use it in GitHub Desktop.
Custom refinements for domain types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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