2025-03-03 00:24:13 +01:00
|
|
|
package lu.foyer
|
|
|
|
|
|
|
|
|
|
import zio.*
|
|
|
|
|
import zio.http.*
|
|
|
|
|
import zio.http.codec.*
|
|
|
|
|
import zio.http.codec.PathCodec.path
|
|
|
|
|
import zio.http.endpoint.*
|
|
|
|
|
import zio.schema.*
|
|
|
|
|
|
2025-10-13 15:46:22 +02:00
|
|
|
trait CommandEngineController[Command, Event: Schema, State: Schema] extends JsonApiController:
|
2025-03-03 00:24:13 +01:00
|
|
|
|
|
|
|
|
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-13 15:46: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-10-13 15:46:22 +02:00
|
|
|
Endpoint(Method.GET / entityName / string("entityId"))
|
2025-03-03 00:24:13 +01:00
|
|
|
.jsonApiOne[State]
|
|
|
|
|
|
2025-10-06 18:30:22 +02:00
|
|
|
private lazy val fetchEventsMany =
|
2025-10-13 15:46:22 +02:00
|
|
|
Endpoint(Method.GET / entityName / string("entityId") / "events")
|
|
|
|
|
.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-10-13 15:46:22 +02:00
|
|
|
Endpoint(Method.GET / entityName / string("entityId") / "events" / string("eventId"))
|
2025-03-03 00:24:13 +01:00
|
|
|
.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
|
2025-10-13 15:46:22 +02:00
|
|
|
(event, _) <- commandEngine
|
|
|
|
|
.handleCommand(command, handler.name, entityId.toString)
|
2025-03-03 00:24:13 +01:00
|
|
|
yield Some(event)
|
|
|
|
|
)
|
|
|
|
|
(endpoint, route)
|
|
|
|
|
|
|
|
|
|
private def generateUpdateCommand(handler: CommandHandler[Command, Event, State]) =
|
|
|
|
|
given Schema[Command] = handler.commandSchema.asInstanceOf[Schema[Command]]
|
2025-10-13 15:46:22 +02:00
|
|
|
val endpoint = Endpoint(
|
|
|
|
|
Method.PUT / entityName / string("entityId") / "commands" / handler.name
|
|
|
|
|
)
|
2025-03-03 00:24:13 +01:00
|
|
|
.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 =
|
2025-10-13 15:46:22 +02:00
|
|
|
fetchMany.implementJsonApiManyEntity(commandEngine.stateRepo.fetchMany)
|
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 =
|
2025-10-13 15:46:22 +02:00
|
|
|
fetchEventsMany.implementJsonApiManyEvent(commandEngine.eventRepo.fetchMany(_, _))
|
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
|