{-# language DataKinds #-} {-# language GADTs #-} {-# language PolyKinds #-} {-# language TypeFamilies #-} {-# language TypeOperators #-} {-# language UndecidableInstances #-} {-| Description : Protocol-defined annotations. Libraries can define custom annotations to indicate additional information not found in the 'Package' itself. For example, GraphQL has optional default values for arguments. -} module Mu.Rpc.Annotations ( RpcAnnotation (..) , AnnotatedPackage , GetPackageAnnotation , GetPackageAnnotationMay , GetServiceAnnotation , GetServiceAnnotationMay , GetMethodAnnotation , GetMethodAnnotationMay , GetArgAnnotation , GetArgAnnotationMay ) where import GHC.TypeLits import Mu.Rpc -- | Annotations proper. data RpcAnnotation domain serviceName methodName argName where -- | Annotation over the whole package. AnnPackage :: domain -> RpcAnnotation domain serviceName methodName argName -- | Annotation over a service. AnnService :: serviceName -> domain -> RpcAnnotation domain serviceName methodName argName -- | Annotation over a method. AnnMethod :: serviceName -> methodName -> domain -> RpcAnnotation domain serviceName methodName argName -- | Annotation over an argument. AnnArg :: serviceName -> methodName -> argName -> domain -> RpcAnnotation domain serviceName methodName argName -- |  This type family links each schema to -- its corresponding annotations from one domain. type family AnnotatedPackage domain (sch :: Package serviceName methodName argName tyRef) :: [RpcAnnotation domain serviceName methodName argName] -- | Find the annotation over the package in the given set. -- If the annotation cannot be found, raise a 'TypeError'. type family GetPackageAnnotation (anns :: [RpcAnnotation domain s m a]) :: domain where GetPackageAnnotation '[] = TypeError ('Text "cannot find package annotation") GetPackageAnnotation ('AnnPackage d ': rs) = d GetPackageAnnotation (r ': rs) = GetPackageAnnotation rs -- | Find the annotation over the package in the given set. -- If the annotation cannot be found, return Nothing type family GetPackageAnnotationMay (anns :: [RpcAnnotation domain s m a]) :: Maybe domain where GetPackageAnnotationMay '[] = 'Nothing GetPackageAnnotationMay ('AnnPackage d ': rs) = 'Just d GetPackageAnnotationMay (r ': rs) = GetPackageAnnotationMay rs -- | Find the annotation over the given service in the given set. -- If the annotation cannot be found, raise a 'TypeError'. type family GetServiceAnnotation (anns :: [RpcAnnotation domain s m a]) (snm :: s) :: domain where GetServiceAnnotation '[] snm = TypeError ('Text "cannot find service annotation for " ':<>: 'ShowType snm) GetServiceAnnotation ('AnnService snm d ': rs) snm = d GetServiceAnnotation (r ': rs) snm = GetServiceAnnotation rs snm -- | Find the annotation over the given service in the given set. -- If the annotation cannot be found, return Nothing type family GetServiceAnnotationMay (anns :: [RpcAnnotation domain s m a]) (snm :: s) :: Maybe domain where GetServiceAnnotationMay '[] snm = 'Nothing GetServiceAnnotationMay ('AnnService snm d ': rs) snm = 'Just d GetServiceAnnotationMay (r ': rs) snm = GetServiceAnnotationMay rs snm -- | Find the annotation over the given method in the given service. -- If the annotation cannot be found, raise a 'TypeError'. type family GetMethodAnnotation (anns :: [RpcAnnotation domain s m a]) (snm :: s) (mnm :: m) :: domain where GetMethodAnnotation '[] snm mnm = TypeError ('Text "cannot find method annotation for " ':<>: 'ShowType snm ':<>: 'Text "/" ':<>: 'ShowType mnm) GetMethodAnnotation ('AnnMethod snm mnm d ': rs) snm mnm = d GetMethodAnnotation (r ': rs) snm mnm = GetMethodAnnotation rs snm mnm -- | Find the annotation over the given method in the given service. -- If the annotation cannot be found, return Nothing type family GetMethodAnnotationMay (anns :: [RpcAnnotation domain s m a]) (snm :: s) (mnm :: m) :: Maybe domain where GetMethodAnnotationMay '[] snm mnm = 'Nothing GetMethodAnnotationMay ('AnnMethod snm mnm d ': rs) snm mnm = 'Just d GetMethodAnnotationMay (r ': rs) snm mnm = GetMethodAnnotationMay rs snm mnm -- | Find the annotation over the given argument in the given method in the given service. -- If the annotation cannot be found, raise a 'TypeError'. type family GetArgAnnotation (anns :: [RpcAnnotation domain s m a]) (snm :: s) (mnm :: m) (anm :: a) :: domain where GetArgAnnotation '[] snm mnm anm = TypeError ('Text "cannot find argument annotation for " ':<>: 'ShowType snm ':<>: 'Text "/" ':<>: 'ShowType mnm ':<>: 'Text "/" ':<>: 'ShowType anm) GetArgAnnotation ('AnnArg snm mnm anm d ': rs) snm mnm anm = d GetArgAnnotation (r ': rs) snm mnm anm = GetArgAnnotation rs snm mnm anm -- | Find the annotation over the given argument in the given method in the given service. -- If the annotation cannot be found, return Nothing type family GetArgAnnotationMay (anns :: [RpcAnnotation domain s m a]) (snm :: s) (mnm :: m) (anm :: a) :: Maybe domain where GetArgAnnotationMay '[] snm mnm anm = 'Nothing GetArgAnnotationMay ('AnnArg snm mnm anm d ': rs) snm mnm anm = 'Just d GetArgAnnotationMay (r ': rs) snm mnm anm = GetArgAnnotationMay rs snm mnm anm