{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Metadata representation of a stored procedure in the metadata,
--   as well as a parser and prettyprinter for the query code.
module Hasura.StoredProcedure.Metadata
  ( StoredProcedureMetadata (..),
    spmStoredProcedure,
    spmConfig,
    spmArguments,
    spmDescription,
    spmReturns,
    ArgumentName (..),
    module Hasura.StoredProcedure.Types,
  )
where

import Autodocodec
import Autodocodec qualified as AC
import Control.Lens (makeLenses)
import Data.Aeson (FromJSON, ToJSON)
import Hasura.LogicalModel.Types
import Hasura.LogicalModelResolver.Types (ArgumentName (..))
import Hasura.Prelude hiding (first)
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.BackendTag (backendPrefix)
import Hasura.RQL.Types.BackendType
import Hasura.StoredProcedure.Types (NullableScalarType (..), StoredProcedureConfig (..), nullableScalarTypeMapCodec)

---------------------------------------

-- | The representation of stored procedures within the metadata structure.
data StoredProcedureMetadata (b :: BackendType) = StoredProcedureMetadata
  { forall (b :: BackendType).
StoredProcedureMetadata b -> FunctionName b
_spmStoredProcedure :: FunctionName b,
    forall (b :: BackendType).
StoredProcedureMetadata b -> StoredProcedureConfig
_spmConfig :: StoredProcedureConfig,
    forall (b :: BackendType).
StoredProcedureMetadata b -> LogicalModelName
_spmReturns :: LogicalModelName,
    forall (b :: BackendType).
StoredProcedureMetadata b
-> HashMap ArgumentName (NullableScalarType b)
_spmArguments :: HashMap ArgumentName (NullableScalarType b),
    forall (b :: BackendType). StoredProcedureMetadata b -> Maybe Text
_spmDescription :: Maybe Text
  }
  deriving ((forall x.
 StoredProcedureMetadata b -> Rep (StoredProcedureMetadata b) x)
-> (forall x.
    Rep (StoredProcedureMetadata b) x -> StoredProcedureMetadata b)
-> Generic (StoredProcedureMetadata b)
forall x.
Rep (StoredProcedureMetadata b) x -> StoredProcedureMetadata b
forall x.
StoredProcedureMetadata b -> Rep (StoredProcedureMetadata b) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (b :: BackendType) x.
Rep (StoredProcedureMetadata b) x -> StoredProcedureMetadata b
forall (b :: BackendType) x.
StoredProcedureMetadata b -> Rep (StoredProcedureMetadata b) x
$cfrom :: forall (b :: BackendType) x.
StoredProcedureMetadata b -> Rep (StoredProcedureMetadata b) x
from :: forall x.
StoredProcedureMetadata b -> Rep (StoredProcedureMetadata b) x
$cto :: forall (b :: BackendType) x.
Rep (StoredProcedureMetadata b) x -> StoredProcedureMetadata b
to :: forall x.
Rep (StoredProcedureMetadata b) x -> StoredProcedureMetadata b
Generic)

deriving instance (Backend b) => Eq (StoredProcedureMetadata b)

deriving instance (Backend b) => Show (StoredProcedureMetadata b)

instance (Backend b) => HasCodec (StoredProcedureMetadata b) where
  codec :: JSONCodec (StoredProcedureMetadata b)
codec =
    Text
-> JSONCodec (StoredProcedureMetadata b)
-> JSONCodec (StoredProcedureMetadata b)
forall input output.
Text -> ValueCodec input output -> ValueCodec input output
CommentCodec
      (Text
"A stored procedure as represented in metadata.")
      (JSONCodec (StoredProcedureMetadata b)
 -> JSONCodec (StoredProcedureMetadata b))
-> JSONCodec (StoredProcedureMetadata b)
-> JSONCodec (StoredProcedureMetadata b)
forall a b. (a -> b) -> a -> b
$ Text
-> ObjectCodec
     (StoredProcedureMetadata b) (StoredProcedureMetadata b)
-> JSONCodec (StoredProcedureMetadata b)
forall input output.
Text -> ObjectCodec input output -> ValueCodec input output
AC.object (forall (b :: BackendType). HasTag b => Text
backendPrefix @b Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"StoredProcedureMetadata")
      (ObjectCodec
   (StoredProcedureMetadata b) (StoredProcedureMetadata b)
 -> JSONCodec (StoredProcedureMetadata b))
-> ObjectCodec
     (StoredProcedureMetadata b) (StoredProcedureMetadata b)
-> JSONCodec (StoredProcedureMetadata b)
forall a b. (a -> b) -> a -> b
$ FunctionName b
-> StoredProcedureConfig
-> LogicalModelName
-> HashMap ArgumentName (NullableScalarType b)
-> Maybe Text
-> StoredProcedureMetadata b
forall (b :: BackendType).
FunctionName b
-> StoredProcedureConfig
-> LogicalModelName
-> HashMap ArgumentName (NullableScalarType b)
-> Maybe Text
-> StoredProcedureMetadata b
StoredProcedureMetadata
      (FunctionName b
 -> StoredProcedureConfig
 -> LogicalModelName
 -> HashMap ArgumentName (NullableScalarType b)
 -> Maybe Text
 -> StoredProcedureMetadata b)
-> Codec Object (StoredProcedureMetadata b) (FunctionName b)
-> Codec
     Object
     (StoredProcedureMetadata b)
     (StoredProcedureConfig
      -> LogicalModelName
      -> HashMap ArgumentName (NullableScalarType b)
      -> Maybe Text
      -> StoredProcedureMetadata b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Text -> ObjectCodec (FunctionName b) (FunctionName b)
forall output.
HasCodec output =>
Text -> Text -> ObjectCodec output output
AC.requiredField Text
"stored_procedure" Text
spDoc
      ObjectCodec (FunctionName b) (FunctionName b)
-> (StoredProcedureMetadata b -> FunctionName b)
-> Codec Object (StoredProcedureMetadata b) (FunctionName b)
forall oldInput output newInput.
ObjectCodec oldInput output
-> (newInput -> oldInput) -> ObjectCodec newInput output
AC..= StoredProcedureMetadata b -> FunctionName b
forall (b :: BackendType).
StoredProcedureMetadata b -> FunctionName b
_spmStoredProcedure
        Codec
  Object
  (StoredProcedureMetadata b)
  (StoredProcedureConfig
   -> LogicalModelName
   -> HashMap ArgumentName (NullableScalarType b)
   -> Maybe Text
   -> StoredProcedureMetadata b)
-> Codec Object (StoredProcedureMetadata b) StoredProcedureConfig
-> Codec
     Object
     (StoredProcedureMetadata b)
     (LogicalModelName
      -> HashMap ArgumentName (NullableScalarType b)
      -> Maybe Text
      -> StoredProcedureMetadata b)
forall a b.
Codec Object (StoredProcedureMetadata b) (a -> b)
-> Codec Object (StoredProcedureMetadata b) a
-> Codec Object (StoredProcedureMetadata b) b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Text
-> Text -> ObjectCodec StoredProcedureConfig StoredProcedureConfig
forall output.
HasCodec output =>
Text -> Text -> ObjectCodec output output
requiredField Text
"configuration" Text
configDoc
      ObjectCodec StoredProcedureConfig StoredProcedureConfig
-> (StoredProcedureMetadata b -> StoredProcedureConfig)
-> Codec Object (StoredProcedureMetadata b) StoredProcedureConfig
forall oldInput output newInput.
ObjectCodec oldInput output
-> (newInput -> oldInput) -> ObjectCodec newInput output
AC..= StoredProcedureMetadata b -> StoredProcedureConfig
forall (b :: BackendType).
StoredProcedureMetadata b -> StoredProcedureConfig
_spmConfig
        Codec
  Object
  (StoredProcedureMetadata b)
  (LogicalModelName
   -> HashMap ArgumentName (NullableScalarType b)
   -> Maybe Text
   -> StoredProcedureMetadata b)
-> Codec Object (StoredProcedureMetadata b) LogicalModelName
-> Codec
     Object
     (StoredProcedureMetadata b)
     (HashMap ArgumentName (NullableScalarType b)
      -> Maybe Text -> StoredProcedureMetadata b)
forall a b.
Codec Object (StoredProcedureMetadata b) (a -> b)
-> Codec Object (StoredProcedureMetadata b) a
-> Codec Object (StoredProcedureMetadata b) b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Text -> Text -> ObjectCodec LogicalModelName LogicalModelName
forall output.
HasCodec output =>
Text -> Text -> ObjectCodec output output
requiredField Text
"returns" Text
returnsDoc
      ObjectCodec LogicalModelName LogicalModelName
-> (StoredProcedureMetadata b -> LogicalModelName)
-> Codec Object (StoredProcedureMetadata b) LogicalModelName
forall oldInput output newInput.
ObjectCodec oldInput output
-> (newInput -> oldInput) -> ObjectCodec newInput output
AC..= StoredProcedureMetadata b -> LogicalModelName
forall (b :: BackendType).
StoredProcedureMetadata b -> LogicalModelName
_spmReturns
        Codec
  Object
  (StoredProcedureMetadata b)
  (HashMap ArgumentName (NullableScalarType b)
   -> Maybe Text -> StoredProcedureMetadata b)
-> Codec
     Object
     (StoredProcedureMetadata b)
     (HashMap ArgumentName (NullableScalarType b))
-> Codec
     Object
     (StoredProcedureMetadata b)
     (Maybe Text -> StoredProcedureMetadata b)
forall a b.
Codec Object (StoredProcedureMetadata b) (a -> b)
-> Codec Object (StoredProcedureMetadata b) a
-> Codec Object (StoredProcedureMetadata b) b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Text
-> HashMap ArgumentName (NullableScalarType b)
-> Text
-> ObjectCodec
     (HashMap ArgumentName (NullableScalarType b))
     (HashMap ArgumentName (NullableScalarType b))
forall output.
HasCodec output =>
Text -> output -> Text -> ObjectCodec output output
optionalFieldWithDefault Text
"arguments" HashMap ArgumentName (NullableScalarType b)
forall a. Monoid a => a
mempty Text
argumentDoc
      ObjectCodec
  (HashMap ArgumentName (NullableScalarType b))
  (HashMap ArgumentName (NullableScalarType b))
-> (StoredProcedureMetadata b
    -> HashMap ArgumentName (NullableScalarType b))
-> Codec
     Object
     (StoredProcedureMetadata b)
     (HashMap ArgumentName (NullableScalarType b))
forall oldInput output newInput.
ObjectCodec oldInput output
-> (newInput -> oldInput) -> ObjectCodec newInput output
AC..= StoredProcedureMetadata b
-> HashMap ArgumentName (NullableScalarType b)
forall (b :: BackendType).
StoredProcedureMetadata b
-> HashMap ArgumentName (NullableScalarType b)
_spmArguments
        Codec
  Object
  (StoredProcedureMetadata b)
  (Maybe Text -> StoredProcedureMetadata b)
-> Codec Object (StoredProcedureMetadata b) (Maybe Text)
-> ObjectCodec
     (StoredProcedureMetadata b) (StoredProcedureMetadata b)
forall a b.
Codec Object (StoredProcedureMetadata b) (a -> b)
-> Codec Object (StoredProcedureMetadata b) a
-> Codec Object (StoredProcedureMetadata b) b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Text -> Text -> ObjectCodec (Maybe Text) (Maybe Text)
forall output.
HasCodec output =>
Text -> Text -> ObjectCodec (Maybe output) (Maybe output)
optionalField Text
"description" Text
descriptionDoc
      ObjectCodec (Maybe Text) (Maybe Text)
-> (StoredProcedureMetadata b -> Maybe Text)
-> Codec Object (StoredProcedureMetadata b) (Maybe Text)
forall oldInput output newInput.
ObjectCodec oldInput output
-> (newInput -> oldInput) -> ObjectCodec newInput output
AC..= StoredProcedureMetadata b -> Maybe Text
forall (b :: BackendType). StoredProcedureMetadata b -> Maybe Text
_spmDescription
    where
      spDoc :: Text
spDoc = Text
"The name of the SQL stored procedure"
      configDoc :: Text
configDoc = Text
"The configuration for the SQL stored procedure"
      argumentDoc :: Text
argumentDoc = Text
"Free variables in the expression and their types"
      returnsDoc :: Text
returnsDoc = Text
"Return type (table) of the expression"
      descriptionDoc :: Text
descriptionDoc = Text
"A description of the stored procedure which appears in the graphql schema"

deriving via
  (Autodocodec (StoredProcedureMetadata b))
  instance
    (Backend b) => (FromJSON (StoredProcedureMetadata b))

deriving via
  (Autodocodec (StoredProcedureMetadata b))
  instance
    (Backend b) => (ToJSON (StoredProcedureMetadata b))

makeLenses ''StoredProcedureMetadata