Initial commit
This commit is contained in:
commit
1919e4b72c
14 changed files with 640 additions and 0 deletions
10
.envrc
Normal file
10
.envrc
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then
|
||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs="
|
||||
fi
|
||||
|
||||
watch_file flake.nix
|
||||
watch_file flake.lock
|
||||
if ! use flake . --no-pure-eval
|
||||
then
|
||||
echo "devenv could not be built. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2
|
||||
fi
|
||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.devenv
|
||||
.direnv
|
||||
out
|
||||
.bloop
|
||||
.metals
|
||||
24
.scalafmt.conf
Normal file
24
.scalafmt.conf
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
version = "3.8.3"
|
||||
|
||||
preset=defaultWithAlign
|
||||
|
||||
assumeStandardLibraryStripMargin = true
|
||||
maxColumn = 100
|
||||
continuationIndent.callSite = 2
|
||||
continuationIndent.defnSite = 2
|
||||
align.arrowEnumeratorGenerator = true
|
||||
align.openParenDefnSite = false
|
||||
align.stripMargin = true
|
||||
rewrite.rules = [RedundantBraces, Imports, RedundantParens, SortModifiers, PreferCurlyFors]
|
||||
rewrite.redundantBraces.ifElseExpressions = true
|
||||
rewrite.redundantBraces.stringInterpolation = true
|
||||
verticalMultiline.atDefnSite = true
|
||||
verticalMultiline.newlineAfterOpenParen = true
|
||||
optIn.breaksInsideChains = true
|
||||
lineEndings = unix
|
||||
|
||||
runner.dialect = scala3
|
||||
rewrite.scala3.convertToNewSyntax = true
|
||||
rewrite.scala3.removeOptionalBraces = yes
|
||||
rewrite.scala3.insertEndMarkerMinLines = 30
|
||||
rewrite.scala3.removeEndMarkerMaxLines = 29
|
||||
71
api/src/lu/foyer/App.scala
Normal file
71
api/src/lu/foyer/App.scala
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
package lu.foyer
|
||||
|
||||
import lu.foyer.clients.ClientState
|
||||
|
||||
import zio.*
|
||||
import zio.Console.*
|
||||
import zio.http.*
|
||||
import zio.schema.*
|
||||
import zio.http.endpoint.*
|
||||
import zio.http.codec.*
|
||||
import java.net.URI
|
||||
import zio.http.endpoint.openapi.OpenAPIGen
|
||||
import zio.http.endpoint.openapi.SwaggerUI
|
||||
import zio.http.codec.PathCodec.path
|
||||
|
||||
case class JsonApiResponseSingle[T](
|
||||
data: JsonApiResponseEntity[T],
|
||||
links: JsonApiResponseLinks)
|
||||
derives Schema
|
||||
|
||||
case class JsonApiResponseMultiple[T](
|
||||
data: List[JsonApiResponseEntity[T]],
|
||||
links: JsonApiResponseLinks,
|
||||
meta: JsonApiResponseMeta)
|
||||
derives Schema
|
||||
|
||||
case class JsonApiResponseLinks(
|
||||
self: String,
|
||||
first: Option[String] = None,
|
||||
prev: Option[String] = None,
|
||||
next: Option[String] = None,
|
||||
last: Option[String] = None)
|
||||
derives Schema
|
||||
|
||||
case class JsonApiResponseMeta(totalRecords: Int, totalPages: Int) derives Schema
|
||||
|
||||
final case class JsonApiResponseEntity[T](id: String, `type`: String, attributes: T) derives Schema
|
||||
|
||||
case class Page(number: Int, size: Int, totals: Boolean)
|
||||
|
||||
val pageParams =
|
||||
(HttpCodec.query[Option[Int]]("page[number]")
|
||||
& HttpCodec.query[Option[Int]]("page[size]")
|
||||
& HttpCodec.query[Option[Boolean]]("page[totals]"))
|
||||
.transform[Page]((number, size, totals) =>
|
||||
Page(number.getOrElse(0), size.getOrElse(50), totals.getOrElse(false))
|
||||
)(p => (Some(p._1), Some(p._2), Some(p._3)))
|
||||
|
||||
object ClientsController:
|
||||
private val fetchMany =
|
||||
Endpoint(Method.GET / "clients").query(pageParams).out[JsonApiResponseMultiple[ClientState]]
|
||||
|
||||
private val fetchManyRoute =
|
||||
fetchMany.implement(page =>
|
||||
ZIO.succeed(
|
||||
JsonApiResponseMultiple[ClientState](
|
||||
List.empty,
|
||||
JsonApiResponseLinks("https://api.example.org"),
|
||||
meta = JsonApiResponseMeta(0, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val endpoints = List(fetchMany)
|
||||
val routes = Routes(fetchManyRoute)
|
||||
|
||||
object App extends ZIOAppDefault:
|
||||
val openAPI = OpenAPIGen.fromEndpoints(ClientsController.endpoints)
|
||||
val routes = ClientsController.routes ++ SwaggerUI.routes("docs" / "openapi", openAPI)
|
||||
|
||||
override def run = Server.serve(routes).provide(Server.default)
|
||||
37
build.sc
Normal file
37
build.sc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// scalafmt: { runner.dialect = scala213 }
|
||||
package build
|
||||
import mill._, scalalib._
|
||||
|
||||
object Versions {
|
||||
val zio = "2.1.15"
|
||||
val zioJson = "0.7.33"
|
||||
val zioSchema = "1.6.3"
|
||||
val zioHttp = "3.0.1"
|
||||
val zioPrelude = "1.0.0-RC39"
|
||||
}
|
||||
|
||||
trait CommonModule extends ScalaModule {
|
||||
def scalaVersion = "3.6.3"
|
||||
def ivyDeps = Agg(
|
||||
ivy"dev.zio::zio:${Versions.zio}",
|
||||
ivy"dev.zio::zio-schema:${Versions.zioSchema}",
|
||||
ivy"dev.zio::zio-schema-derivation:${Versions.zioSchema}",
|
||||
ivy"dev.zio::zio-prelude:${Versions.zioPrelude}"
|
||||
)
|
||||
}
|
||||
|
||||
object model extends CommonModule
|
||||
|
||||
object core extends CommonModule {
|
||||
def moduleDeps = Seq(model)
|
||||
}
|
||||
|
||||
object api extends CommonModule {
|
||||
def moduleDeps = Seq(core)
|
||||
def ivyDeps = Agg(
|
||||
ivy"dev.zio::zio:${Versions.zio}",
|
||||
ivy"dev.zio::zio-http:${Versions.zioHttp}",
|
||||
ivy"dev.zio::zio-json:${Versions.zioJson}",
|
||||
ivy"dev.zio::zio-schema-json:${Versions.zioSchema}"
|
||||
)
|
||||
}
|
||||
23
core/src/lu/foyer/clients/ClientCommand.scala
Normal file
23
core/src/lu/foyer/clients/ClientCommand.scala
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package lu.foyer
|
||||
package clients
|
||||
|
||||
import zio.schema.*
|
||||
|
||||
import java.time.LocalDate
|
||||
|
||||
enum ClientCommand derives Schema:
|
||||
case Create(
|
||||
lastName: ClientLastName,
|
||||
firstName: ClientFirstName,
|
||||
drivingLicenseDate: Option[ClientDrivingLicenseDate],
|
||||
phoneNumber: Option[PhoneNumberInput],
|
||||
email: Option[Email],
|
||||
address: Option[Address])
|
||||
case Update(
|
||||
lastName: Option[ClientLastName],
|
||||
firstName: Option[ClientFirstName],
|
||||
drivingLicenseDate: Option[ClientDrivingLicenseDate],
|
||||
phoneNumber: Option[PhoneNumberInput],
|
||||
email: Option[Email],
|
||||
address: Option[Address])
|
||||
case Disable(reason: ClientDisabledReason)
|
||||
24
core/src/lu/foyer/clients/ClientEvent.scala
Normal file
24
core/src/lu/foyer/clients/ClientEvent.scala
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package lu.foyer
|
||||
package clients
|
||||
|
||||
import zio.schema.*
|
||||
|
||||
import java.time.LocalDate
|
||||
|
||||
enum ClientEvent derives Schema:
|
||||
case Created(
|
||||
lastName: ClientLastName,
|
||||
firstName: ClientFirstName,
|
||||
birthDate: ClientBirthDate,
|
||||
drivingLicenseDate: Option[ClientDrivingLicenseDate],
|
||||
phoneNumber: Option[PhoneNumberInput],
|
||||
email: Option[Email],
|
||||
address: Option[Address])
|
||||
case Updated(
|
||||
lastName: Option[ClientLastName],
|
||||
firstName: Option[ClientFirstName],
|
||||
birthDate: Option[ClientBirthDate],
|
||||
drivingLicenseDate: Option[ClientDrivingLicenseDate],
|
||||
phoneNumber: Option[PhoneNumberInput],
|
||||
email: Option[Email],
|
||||
address: Option[Address])
|
||||
24
core/src/lu/foyer/clients/ClientState.scala
Normal file
24
core/src/lu/foyer/clients/ClientState.scala
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package lu.foyer
|
||||
package clients
|
||||
|
||||
import zio.schema.*
|
||||
|
||||
import java.time.LocalDate
|
||||
|
||||
enum ClientState derives Schema:
|
||||
case Actif(
|
||||
lastName: ClientLastName,
|
||||
firstName: ClientFirstName,
|
||||
birthDate: ClientBirthDate,
|
||||
drivingLicenseDate: Option[ClientDrivingLicenseDate],
|
||||
phoneNumber: Option[PhoneNumberInput],
|
||||
email: Option[Email],
|
||||
address: Option[Address])
|
||||
case Inactif(
|
||||
lastName: ClientLastName,
|
||||
firstName: ClientFirstName,
|
||||
birthDate: ClientBirthDate,
|
||||
drivingLicenseDate: Option[ClientDrivingLicenseDate],
|
||||
phoneNumber: Option[PhoneNumberInput],
|
||||
email: Option[Email],
|
||||
address: Option[Address])
|
||||
262
flake.lock
generated
Normal file
262
flake.lock
generated
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
{
|
||||
"nodes": {
|
||||
"cachix": {
|
||||
"inputs": {
|
||||
"devenv": [
|
||||
"devenv"
|
||||
],
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"git-hooks": [
|
||||
"devenv"
|
||||
],
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737621947,
|
||||
"narHash": "sha256-8HFvG7fvIFbgtaYAY2628Tb89fA55nPm2jSiNs0/Cws=",
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"rev": "f65a3cd5e339c223471e64c051434616e18cc4f5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "latest",
|
||||
"repo": "cachix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"cachix": "cachix",
|
||||
"flake-compat": "flake-compat",
|
||||
"git-hooks": "git-hooks",
|
||||
"nix": "nix",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1740460834,
|
||||
"narHash": "sha256-RUL1r8zH5wG5L1YipNj1bmt0Oi8L9qwzXsf/ww8WxBc=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "9e4003b2702483bd962dac3d4ff43e8dafb93cda",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1733328505,
|
||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"devenv",
|
||||
"nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712014858,
|
||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"git-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737465171,
|
||||
"narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"git-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"libgit2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1697646580,
|
||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv"
|
||||
],
|
||||
"flake-parts": "flake-parts",
|
||||
"libgit2": "libgit2",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs-23-11": [
|
||||
"devenv"
|
||||
],
|
||||
"nixpkgs-regression": [
|
||||
"devenv"
|
||||
],
|
||||
"pre-commit-hooks": [
|
||||
"devenv"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734114420,
|
||||
"narHash": "sha256-n52PUzub5jZWc8nI/sR7UICOheU8rNA+YZ73YaHeCBg=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "bde6a1a0d1f2af86caa4d20d23eca019f3d57eee",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.24",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1733212471,
|
||||
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1717432640,
|
||||
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1733477122,
|
||||
"narHash": "sha256-qamMCz5mNpQmgBwc8SB5tVMlD5sbwVIToVZtSxMph9s=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "7bd9e84d0452f6d2e63b6e6da29fe73fac951857",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
58
flake.nix
Normal file
58
flake.nix
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling";
|
||||
systems.url = "github:nix-systems/default";
|
||||
devenv.url = "github:cachix/devenv";
|
||||
devenv.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
nixConfig = {
|
||||
extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw=";
|
||||
extra-substituters = "https://devenv.cachix.org";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
devenv,
|
||||
systems,
|
||||
...
|
||||
}@inputs:
|
||||
let
|
||||
forEachSystem = nixpkgs.lib.genAttrs (import systems);
|
||||
in
|
||||
{
|
||||
packages = forEachSystem (system: {
|
||||
devenv-up = self.devShells.${system}.default.config.procfileScript;
|
||||
devenv-test = self.devShells.${system}.default.config.test;
|
||||
});
|
||||
|
||||
devShells = forEachSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
default = devenv.lib.mkShell {
|
||||
inherit inputs pkgs;
|
||||
modules = [
|
||||
{
|
||||
# https://devenv.sh/reference/options/
|
||||
packages = [
|
||||
pkgs.mill
|
||||
pkgs.kafkactl
|
||||
];
|
||||
|
||||
services = {
|
||||
kafka.enable = true;
|
||||
mongodb.enable = true;
|
||||
};
|
||||
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
26
model/src/lu/foyer/RefinedType.scala
Normal file
26
model/src/lu/foyer/RefinedType.scala
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package lu.foyer
|
||||
|
||||
import zio.prelude.*
|
||||
import zio.schema.Schema
|
||||
|
||||
import java.time.LocalDate
|
||||
|
||||
trait RefinedType[Base, New]:
|
||||
inline def assume(value: Base): New = value.asInstanceOf[New]
|
||||
def validation(value: Base): Validation[String, New]
|
||||
|
||||
trait RefinedString[New <: String] extends RefinedType[String, New]:
|
||||
given Schema[New] = Schema[String].transformOrFail(
|
||||
validation(_).toEither.left.map(_.toList.mkString(", ")),
|
||||
Right(_)
|
||||
)
|
||||
|
||||
trait RefinedLocalDate[New <: LocalDate] extends RefinedType[LocalDate, New]:
|
||||
override def validation(value: LocalDate): Validation[String, New] =
|
||||
Validation.succeed(assume(value))
|
||||
given Schema[New] = Schema[LocalDate].transform(assume, identity)
|
||||
|
||||
trait NonBlankString[New <: String] extends RefinedString[New]:
|
||||
override def validation(value: String): Validation[String, New] =
|
||||
if value.isBlank then Validation.fail("Cannot be blank")
|
||||
else Validation.succeed(assume(value))
|
||||
20
model/src/lu/foyer/clients/Address.scala
Normal file
20
model/src/lu/foyer/clients/Address.scala
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package lu.foyer
|
||||
package clients
|
||||
|
||||
import zio.schema.*
|
||||
|
||||
opaque type AddressStreet <: String = String
|
||||
object AddressStreet extends NonBlankString[AddressStreet]
|
||||
|
||||
opaque type AddressPostalCode <: String = String
|
||||
object AddressPostalCode extends NonBlankString[AddressPostalCode]
|
||||
|
||||
opaque type AddressLocality <: String = String
|
||||
object AddressLocality extends NonBlankString[AddressLocality]
|
||||
|
||||
case class Address(
|
||||
street: AddressStreet,
|
||||
postalCode: AddressPostalCode,
|
||||
locality: AddressLocality,
|
||||
country: Country)
|
||||
derives Schema
|
||||
49
model/src/lu/foyer/clients/Client.scala
Normal file
49
model/src/lu/foyer/clients/Client.scala
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package lu.foyer
|
||||
package clients
|
||||
|
||||
import zio.schema.*
|
||||
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
|
||||
opaque type ClientLastName <: String = String
|
||||
object ClientLastName extends NonBlankString[ClientLastName]
|
||||
|
||||
opaque type ClientFirstName <: String = String
|
||||
object ClientFirstName extends NonBlankString[ClientFirstName]
|
||||
|
||||
opaque type ClientBirthDate <: LocalDate = LocalDate
|
||||
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
|
||||
|
||||
// TODO validate using libphonenumber
|
||||
case class PhoneNumber(
|
||||
country: Country,
|
||||
nationalNumber: NationalNumber,
|
||||
lastVerifiedAt: Option[Instant])
|
||||
derives Schema
|
||||
|
||||
case class PhoneNumberInput(
|
||||
country: Country,
|
||||
nationalNumber: String)
|
||||
derives Schema
|
||||
|
||||
enum ClientDisabledReason derives Schema:
|
||||
case GDPR, Death
|
||||
7
model/src/lu/foyer/clients/Country.scala
Normal file
7
model/src/lu/foyer/clients/Country.scala
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package lu.foyer
|
||||
package clients
|
||||
|
||||
import zio.schema.*
|
||||
|
||||
enum Country derives Schema:
|
||||
case LU, FR, BE
|
||||
Loading…
Add table
Add a link
Reference in a new issue