2023-04-19 12:03:36 +03:00
|
|
|
{-# 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, (.!=), (.:), (.:?))
|
2023-04-26 20:28:48 +03:00
|
|
|
import Data.Aeson qualified as J
|
2023-04-27 10:41:55 +03:00
|
|
|
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
|
2023-04-19 12:03:36 +03:00
|
|
|
import Data.HashMap.Strict.InsOrd.Autodocodec (sortedElemsCodec)
|
|
|
|
import Hasura.LogicalModel.Types
|
|
|
|
import Hasura.Prelude hiding (first)
|
|
|
|
import Hasura.RQL.Types.Backend (Backend (..))
|
2023-04-25 11:59:34 +03:00
|
|
|
import Hasura.RQL.Types.BackendTag (backendPrefix)
|
2023-04-24 21:35:48 +03:00
|
|
|
import Hasura.RQL.Types.BackendType (BackendType)
|
2023-04-19 12:03:36 +03:00
|
|
|
import Hasura.RQL.Types.Common (SourceName, ToAesonPairs (toAesonPairs), defaultSource)
|
|
|
|
import Hasura.RQL.Types.Permission (SelPermDef, _pdRole)
|
2023-04-24 11:50:29 +03:00
|
|
|
import Hasura.RQL.Types.Roles (RoleName)
|
2023-04-19 12:03:36 +03:00
|
|
|
|
|
|
|
-- | Description of a logical model for use in metadata (before schema cache)
|
|
|
|
data LogicalModelMetadata (b :: BackendType) = LogicalModelMetadata
|
|
|
|
{ _lmmName :: LogicalModelName,
|
2023-04-27 10:41:55 +03:00
|
|
|
_lmmFields :: InsOrdHashMap.InsOrdHashMap (Column b) (LogicalModelField b),
|
2023-04-19 12:03:36 +03:00
|
|
|
_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.")
|
2023-04-25 11:59:34 +03:00
|
|
|
$ AC.object (backendPrefix @b <> "LogicalModelMetadata")
|
2023-04-19 12:03:36 +03:00
|
|
|
$ 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
|
2023-04-26 20:28:48 +03:00
|
|
|
parseJSON = J.withObject "LogicalModel" \obj -> do
|
2023-04-19 12:03:36 +03:00
|
|
|
_wlmSource <- obj .:? "source" .!= defaultSource
|
|
|
|
_wlmName <- obj .: "name"
|
2023-04-26 20:28:48 +03:00
|
|
|
_wlmInfo <- parseJSON (J.Object obj)
|
2023-04-19 12:03:36 +03:00
|
|
|
|
|
|
|
pure WithLogicalModel {..}
|
|
|
|
|
|
|
|
instance (ToAesonPairs a) => ToJSON (WithLogicalModel a) where
|
|
|
|
toJSON (WithLogicalModel source name info) =
|
2023-04-26 20:28:48 +03:00
|
|
|
J.object $ ("source", J.toJSON source) : ("name", J.toJSON name) : toAesonPairs info
|