graphql-engine/server/src-lib/Hasura/LogicalModel/Metadata.hs
Tom Harding e0c0043e76 Upgrade Ormolu to 0.7.0.0
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9284
GitOrigin-RevId: 2f2cf2ad01900a54e4bdb970205ac0ef313c7e00
2023-05-24 13:53:53 +00:00

101 lines
3.6 KiB
Haskell

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
module Hasura.LogicalModel.Metadata
( LogicalModelMetadata (..),
LogicalModelName (..),
WithLogicalModel (..),
lmmName,
lmmFields,
lmmDescription,
lmmSelectPermissions,
)
where
import Autodocodec (Autodocodec (Autodocodec), HasCodec)
import Autodocodec qualified as AC
import Control.Lens (makeLenses)
import Data.Aeson (FromJSON (parseJSON), ToJSON, (.!=), (.:), (.:?))
import Data.Aeson qualified as J
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
import Data.HashMap.Strict.InsOrd.Autodocodec (sortedElemsCodec)
import Hasura.LogicalModel.Types
import Hasura.Prelude hiding (first)
import Hasura.RQL.Types.Backend (Backend (..))
import Hasura.RQL.Types.BackendTag (backendPrefix)
import Hasura.RQL.Types.BackendType (BackendType)
import Hasura.RQL.Types.Common (SourceName, ToAesonPairs (toAesonPairs), defaultSource)
import Hasura.RQL.Types.Permission (SelPermDef, _pdRole)
import Hasura.RQL.Types.Roles (RoleName)
-- | Description of a logical model for use in metadata (before schema cache)
data LogicalModelMetadata (b :: BackendType) = LogicalModelMetadata
{ _lmmName :: LogicalModelName,
_lmmFields :: InsOrdHashMap.InsOrdHashMap (Column b) (LogicalModelField b),
_lmmDescription :: Maybe Text,
_lmmSelectPermissions :: InsOrdHashMap RoleName (SelPermDef b)
}
deriving (Generic)
makeLenses ''LogicalModelMetadata
instance (Backend b) => HasCodec (LogicalModelMetadata b) where
codec =
AC.CommentCodec
("A return type.")
$ AC.object (backendPrefix @b <> "LogicalModelMetadata")
$ LogicalModelMetadata
<$> AC.requiredField "name" nameDoc
AC..= _lmmName
<*> AC.requiredFieldWith "fields" logicalModelFieldMapCodec fieldsDoc
AC..= _lmmFields
<*> AC.optionalField "description" descriptionDoc
AC..= _lmmDescription
<*> optSortedList "select_permissions" _pdRole
AC..= _lmmSelectPermissions
where
nameDoc = "A name for a logical model"
fieldsDoc = "Return types for the logical model"
descriptionDoc = "Optional description text which appears in the GraphQL Schema."
optSortedList name keyForElem =
AC.optionalFieldWithOmittedDefaultWith' name (sortedElemsCodec keyForElem) mempty
deriving via
(Autodocodec (LogicalModelMetadata b))
instance
(Backend b) => FromJSON (LogicalModelMetadata b)
deriving via
(Autodocodec (LogicalModelMetadata b))
instance
(Backend b) => ToJSON (LogicalModelMetadata b)
deriving stock instance (Backend b) => Eq (LogicalModelMetadata b)
deriving stock instance (Backend b) => Show (LogicalModelMetadata b)
-- | A wrapper to tie something to a particular native query. Specifically, it
-- assumes the underlying '_wlmInfo' is represented as an object, and adds two
-- keys to that object: @source@ and @root_field_name@.
data WithLogicalModel a = WithLogicalModel
{ _wlmSource :: SourceName,
_wlmName :: LogicalModelName,
_wlmInfo :: a
}
deriving stock (Eq, Show)
-- | something to note here: if the `a` contains a `name` or `source` key then
-- this won't work anymore.
instance (FromJSON a) => FromJSON (WithLogicalModel a) where
parseJSON = J.withObject "LogicalModel" \obj -> do
_wlmSource <- obj .:? "source" .!= defaultSource
_wlmName <- obj .: "name"
_wlmInfo <- parseJSON (J.Object obj)
pure WithLogicalModel {..}
instance (ToAesonPairs a) => ToJSON (WithLogicalModel a) where
toJSON (WithLogicalModel source name info) =
J.object $ ("source", J.toJSON source) : ("name", J.toJSON name) : toAesonPairs info