Implement contracts

This commit is contained in:
Paul-Henri Froidmont 2025-10-06 18:30:22 +02:00
parent 31014d1a0c
commit efdc50eb1d
Signed by: phfroidmont
GPG key ID: BE948AFD7E7873BE
33 changed files with 879 additions and 173 deletions

View file

@ -0,0 +1,7 @@
package lu.foyer
import zio.schema.*
enum AppError(description: String) extends Throwable:
case NotFound(desc: String) extends AppError(desc)
case Unexpected(desc: String) extends AppError(desc)

View file

@ -0,0 +1,10 @@
package lu.foyer
import zio.schema.*
import java.util.UUID
opaque type ClientEntityId <: UUID = UUID
object ClientEntityId extends RefinedUUID[ClientEntityId]
opaque type Email <: String = String
object Email extends NonBlankString[Email]

View file

@ -4,6 +4,7 @@ import zio.prelude.*
import zio.schema.Schema
import java.time.LocalDate
import java.util.UUID
trait RefinedType[Base, New]:
inline def assume(value: Base): New = value.asInstanceOf[New]
@ -15,6 +16,15 @@ trait RefinedString[New <: String] extends RefinedType[String, New]:
Right(_)
)
trait RefinedUUID[New <: UUID] extends RefinedType[UUID, New]:
def apply(value: UUID): New = assume(value)
override def validation(value: UUID): Validation[String, New] =
Validation.succeed(assume(value))
given Schema[New] = Schema[UUID].transformOrFail(
validation(_).toEither.left.map(_.toList.mkString(", ")),
Right(_)
)
trait RefinedLocalDate[New <: LocalDate] extends RefinedType[LocalDate, New]:
def apply(value: LocalDate): New = assume(value)
override def validation(value: LocalDate): Validation[String, New] =

View file

@ -18,21 +18,9 @@ object ClientBirthDate extends RefinedLocalDate[ClientBirthDate]
opaque type ClientDrivingLicenseDate <: LocalDate = LocalDate
object ClientDrivingLicenseDate extends RefinedLocalDate[ClientDrivingLicenseDate]
opaque type Email <: String = String
object Email extends NonBlankString[Email]
opaque type NationalNumber <: String = String
object NationalNumber extends NonBlankString[NationalNumber]
case class Client(
lastName: ClientFirstName,
firstName: ClientLastName,
drivingLicenseDate: ClientDrivingLicenseDate,
phoneNumber: PhoneNumber,
email: Email,
address: Address)
derives Schema
case class PhoneNumber(
country: Country,
nationalNumber: NationalNumber,
@ -45,4 +33,4 @@ case class PhoneNumberInput(
derives Schema
enum ClientDisabledReason derives Schema:
case GDPR, Death
case gdpr, death

View file

@ -4,4 +4,4 @@ package clients
import zio.schema.*
enum Country derives Schema:
case LU, FR, BE
case LU, FR, BE, CH

View file

@ -0,0 +1,11 @@
package lu.foyer
package contracts
import zio.schema.*
import java.util.Currency
opaque type EmployeeDisplayName <: String = String
object EmployeeDisplayName extends NonBlankString[EmployeeDisplayName]
final case class Employee(uid: String, displayName: EmployeeDisplayName, email: Email)
derives Schema

View file

@ -0,0 +1,27 @@
package lu.foyer
package contracts
import zio.schema.*
enum FormulaType(val maxCoverage: Long, val basePremium: BigDecimal):
case Bronze extends FormulaType(10_000, 600)
case Silver extends FormulaType(25_000, 900)
case Gold extends FormulaType(250_000, 1500)
object FormulaType:
enum Json:
case bronze, silver, gold
given Schema[FormulaType] = DeriveSchema
.gen[Json].transform(
{
case Json.bronze => FormulaType.Bronze
case Json.silver => FormulaType.Silver
case Json.gold => FormulaType.Gold
},
{
case FormulaType.Bronze => Json.bronze
case FormulaType.Silver => Json.silver
case FormulaType.Gold => Json.gold
}
)

View file

@ -0,0 +1,8 @@
package lu.foyer
package contracts
import zio.schema.*
import zio.schema.annotation.caseName
enum ProductType derives Schema:
@caseName("car") case Car

View file

@ -0,0 +1,7 @@
package lu.foyer
package contracts
import zio.schema.*
enum TerminationReasonType derives Schema:
case Rejected, HolderDeceased, TerminatedByClient

View file

@ -0,0 +1,16 @@
package lu.foyer
package contracts
import zio.schema.*
import java.util.Currency
opaque type VehiclePlate <: String = String
object VehiclePlate extends NonBlankString[VehiclePlate]
opaque type VehicleBrand <: String = String
object VehicleBrand extends NonBlankString[VehicleBrand]
final case class Amount(value: BigDecimal, currency: Currency) derives Schema
final case class Vehicle(plate: VehiclePlate, brand: VehicleBrand, insuredValue: Amount)
derives Schema