foyer-dsi-assure-2035/api/src/lu/foyer/CommandEngineController.scala

94 lines
3 KiB
Scala
Raw Normal View History

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