2025-03-03 00:24:13 +01:00
|
|
|
package lu.foyer
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
import lu.foyer.JsonApiResponse.One
|
2025-03-03 00:24:13 +01:00
|
|
|
import zio.*
|
|
|
|
|
import zio.Console.*
|
|
|
|
|
import zio.http.*
|
|
|
|
|
import zio.http.codec.*
|
|
|
|
|
import zio.http.codec.PathCodec.path
|
|
|
|
|
import zio.http.endpoint.*
|
|
|
|
|
import zio.schema.*
|
|
|
|
|
|
|
|
|
|
import java.net.URI
|
|
|
|
|
import java.time.LocalDate
|
|
|
|
|
import java.util.UUID
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
trait CommandEngineController[Command: Schema, Event: Schema, State: Schema]
|
2025-03-03 00:24:13 +01:00
|
|
|
extends JsonApiController:
|
|
|
|
|
|
|
|
|
|
def commandEngine: CommandEngine[Command, Event, State]
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchMany =
|
2025-03-03 00:24:13 +01:00
|
|
|
Endpoint(Method.GET / entityName)
|
2025-10-06 18:30:22 +02:00
|
|
|
// .query(HttpCodec.query[Page])
|
2025-03-03 00:24:13 +01:00
|
|
|
.jsonApiMany[State]
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchOne =
|
2025-03-03 00:24:13 +01:00
|
|
|
Endpoint(Method.GET / entityName / uuid("entityId"))
|
|
|
|
|
.jsonApiOne[State]
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchEventsMany =
|
2025-03-03 00:24:13 +01:00
|
|
|
Endpoint(Method.GET / entityName / uuid("entityId") / "events")
|
2025-10-06 18:30:22 +02:00
|
|
|
// .query(HttpCodec.query[Page])
|
2025-03-03 00:24:13 +01:00
|
|
|
.jsonApiMany[Event]
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchEventsOne =
|
2025-03-03 00:24:13 +01:00
|
|
|
Endpoint(Method.GET / entityName / uuid("entityId") / "events" / uuid("eventId"))
|
|
|
|
|
.jsonApiOne[Event]
|
|
|
|
|
|
|
|
|
|
private def generateCommands = commandEngine.handlers.map(handler =>
|
|
|
|
|
if handler.isCreate then generateCreateCommand(handler)
|
|
|
|
|
else generateUpdateCommand(handler)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
private def generateCreateCommand(handler: CommandHandler[Command, Event, State]) =
|
|
|
|
|
given Schema[Command] = handler.commandSchema.asInstanceOf[Schema[Command]]
|
|
|
|
|
val endpoint = Endpoint(Method.POST / entityName / "commands" / handler.name)
|
|
|
|
|
.in[Command]
|
2025-10-06 18:30:22 +02:00
|
|
|
.jsonApiOneWithStatus[Event](Status.Created)
|
2025-03-03 00:24:13 +01:00
|
|
|
val route = endpoint.implementJsonApiOneEvent(command =>
|
|
|
|
|
for
|
|
|
|
|
entityId <- Random.nextUUID
|
|
|
|
|
(event, state) <- commandEngine
|
|
|
|
|
.handleCommand(command, handler.name, entityId)
|
|
|
|
|
yield Some(event)
|
|
|
|
|
)
|
|
|
|
|
(endpoint, route)
|
|
|
|
|
|
|
|
|
|
private def generateUpdateCommand(handler: CommandHandler[Command, Event, State]) =
|
|
|
|
|
given Schema[Command] = handler.commandSchema.asInstanceOf[Schema[Command]]
|
|
|
|
|
val endpoint = Endpoint(Method.PUT / entityName / uuid("entityId") / "commands" / handler.name)
|
|
|
|
|
.in[Command]
|
|
|
|
|
.jsonApiOne[Event]
|
|
|
|
|
val route = endpoint.implementJsonApiOneEvent((entityId, command) =>
|
|
|
|
|
for (event, _) <- commandEngine
|
|
|
|
|
.handleCommand(command, handler.name, entityId)
|
|
|
|
|
yield Some(event)
|
|
|
|
|
)
|
|
|
|
|
(endpoint, route)
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val (commands, commandsRoutes) = generateCommands.unzip
|
2025-03-03 00:24:13 +01:00
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchManyRoute =
|
|
|
|
|
fetchMany.implementJsonApiManyEntity(_ =>
|
|
|
|
|
commandEngine.stateRepo.fetchMany(Page(None, None, totals = Some(true)))
|
|
|
|
|
)
|
2025-03-03 00:24:13 +01:00
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchOneRoute =
|
2025-03-03 00:24:13 +01:00
|
|
|
fetchOne.implementJsonApiOneEntity(commandEngine.stateRepo.fetchOne)
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchEventsManyRoute =
|
|
|
|
|
fetchEventsMany.implementJsonApiManyEvent(entityId =>
|
|
|
|
|
commandEngine.eventRepo.fetchMany(entityId, Page(None, None, totals = Some(true)))
|
|
|
|
|
)
|
2025-03-03 00:24:13 +01:00
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchEventsOneRoute =
|
2025-03-03 00:24:13 +01:00
|
|
|
fetchEventsOne.implementJsonApiOneEvent(commandEngine.eventRepo.fetchOne(_, _))
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
lazy val endpoints = List(
|
2025-03-03 00:24:13 +01:00
|
|
|
fetchMany,
|
|
|
|
|
fetchOne,
|
|
|
|
|
fetchEventsMany,
|
|
|
|
|
fetchEventsOne
|
|
|
|
|
) ++ commands
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
lazy val routes = (Routes(
|
2025-03-03 00:24:13 +01:00
|
|
|
fetchManyRoute,
|
|
|
|
|
fetchOneRoute,
|
|
|
|
|
fetchEventsManyRoute,
|
|
|
|
|
fetchEventsOneRoute
|
2025-10-06 18:30:22 +02:00
|
|
|
) ++ Routes.fromIterable(commandsRoutes)) @@ proxyHeadersAspect
|
2025-03-03 00:24:13 +01:00
|
|
|
|
|
|
|
|
end CommandEngineController
|