{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Arbiter.Core.QueueRegistry
(
JobPayloadRegistry
, TableForPayload
, AllQueuesUnique
, RegistryTables (..)
) where
import Data.Kind (Constraint, Type)
import Data.Proxy (Proxy (..))
import Data.Text (Text)
import Data.Text qualified as T
import GHC.TypeLits (ErrorMessage (..), KnownSymbol, Symbol, TypeError, symbolVal)
type JobPayloadRegistry = [(Symbol, Type)]
type family TableForPayload (payload :: Type) (registry :: JobPayloadRegistry) :: Symbol where
TableForPayload payload ('(table, payload) ': _) = table
TableForPayload payload ('(_, _) ': rest) =
TableForPayload payload rest
TableForPayload payload '[] =
TypeError ('Text "Payload type " ':<>: 'ShowType payload ':<>: 'Text " not found in registry")
type family AllQueuesUnique (registry :: JobPayloadRegistry) :: Constraint where
AllQueuesUnique '[] = ()
AllQueuesUnique ('(table, _) ': rest) =
(NotInTables table rest, AllQueuesUnique rest)
type family NotInTables (table :: Symbol) (registry :: JobPayloadRegistry) :: Constraint where
NotInTables _ '[] = ()
NotInTables table ('(table, _) ': _) =
TypeError
( 'Text "Duplicate table name: "
':<>: 'ShowType table
':<>: 'Text ""
':$$: 'Text "Each table can only be used once in the registry."
':$$: 'Text "Hint: Multiple payload types cannot share the same table."
)
NotInTables table ('(_, _) ': rest) = NotInTables table rest
class RegistryTables (registry :: JobPayloadRegistry) where
registryTableNames :: Proxy registry -> [Text]
instance RegistryTables '[] where
registryTableNames :: Proxy '[] -> [Text]
registryTableNames Proxy '[]
_ = []
instance (KnownSymbol table, RegistryTables rest) => RegistryTables ('(table, payload) ': rest) where
registryTableNames :: Proxy ('(table, payload) : rest) -> [Text]
registryTableNames Proxy ('(table, payload) : rest)
_ =
String -> Text
T.pack (Proxy table -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (forall {k} (t :: k). Proxy t
forall (t :: Symbol). Proxy t
Proxy @table)) Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: Proxy rest -> [Text]
forall (registry :: JobPayloadRegistry).
RegistryTables registry =>
Proxy registry -> [Text]
registryTableNames (forall (t :: JobPayloadRegistry). Proxy t
forall {k} (t :: k). Proxy t
Proxy @rest)