packages feed

keiro-dsl-0.2.0.0: test/conformance-v2/HospitalCapacity/Reservation/Holes.hs

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE TypeApplications #-}

-- HAND-OWNED hole module, filled by hand for the v2 (evolved) conformance
-- aggregate. The transducer body matches the v1 reference; the v2 event carries
-- a new `triageNote` field sourced as a literal here, and the upcaster defaults
-- `triageNote` on v1-on-disk payloads that lack it.
module HospitalCapacity.Reservation.Holes (
    reservationTransducer,
    applyTransfer_decisions,
    upcastTransferReservationCreatedV1,
) where

import Data.Aeson (Value (..))
import Data.Aeson.KeyMap qualified as KM
import Data.Text (Text)
import Generated.HospitalCapacity.Reservation.Domain
import Keiki.Builder ((=:))
import Keiki.Builder qualified as B
import Keiki.Core (HsPred, SymTransducer, lit, (./=), (.==), (.||))

reservationTransducer ::
    SymTransducer
        (HsPred ReservationRegs ReservationCommand)
        ReservationRegs
        ReservationVertex
        ReservationCommand
        ReservationEvent
reservationTransducer =
    B.buildTransducer ReservationUnrequested initialReservationRegs isTerminal do
        B.from ReservationUnrequested do
            B.onCmd inCtorRequestTransferReservation $ \d -> B.do
                B.requireGuard (d.divertStatus ./= lit TotalDivert .|| d.lifeCriticalOverride .== lit True)
                B.slot @"reservationState" =: lit ReservationHeld
                B.emit
                    wireTransferReservationCreated
                    TransferReservationCreatedTermFields
                        { reservationId = d.reservationId
                        , hospitalId = d.hospitalId
                        , commandId = d.commandId
                        , patientAcuity = d.patientAcuity
                        , divertStatus = d.divertStatus
                        , lifeCriticalOverride = d.lifeCriticalOverride
                        , triageNote = lit ""
                        }
                B.goto ReservationHeld
        B.from ReservationHeld do
            B.onCmd inCtorConfirmReservation $ \d -> B.do
                B.slot @"reservationState" =: lit ReservationConfirmed
                B.emit
                    wireTransferReservationConfirmed
                    TransferReservationConfirmedTermFields
                        { reservationId = d.reservationId
                        , hospitalId = d.hospitalId
                        , commandId = d.commandId
                        }
                B.goto ReservationConfirmed
  where
    isTerminal = \case
        ReservationExpired -> True
        ReservationAdmitted -> True
        ReservationReleased -> True
        _ -> False

applyTransfer_decisions :: ReservationEvent -> recorded -> txn ()
applyTransfer_decisions _event _recorded = error "HOLE: fill transfer_decisions projection apply"

-- Bring a v1 TransferReservationCreated payload up to v2 by defaulting the new
-- `triageNote` field when it is absent (a v1-on-disk payload lacks it).
upcastTransferReservationCreatedV1 :: Value -> Either Text Value
upcastTransferReservationCreatedV1 v = case v of
    Object o -> Right (Object (KM.insertWith (\_new old -> old) "triageNote" (String "") o))
    _ -> Left "upcastTransferReservationCreatedV1: expected a JSON object"