mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 08:02:15 +03:00
Moving kriti function references into a single module for coordination of availability
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5095 GitOrigin-RevId: 8394c33f0182baad53306c6efc3ab720957b7339
This commit is contained in:
parent
b326fd978a
commit
6821b90910
@ -199,7 +199,7 @@ Please submit any feedback you may have for this feature at https://github.com/h
|
||||
### Bug fixes and improvements
|
||||
|
||||
- server: fix bug where hasura SQL trigger was not dropped when MSSQL source is dropped
|
||||
- server: Kriti `basicFunctions` now available for REST Connectors
|
||||
- server: Kriti `basicFunctions` now available for REST Connectors and Webhook Transforms
|
||||
- server: use `root_field_namespace` as prefix for remote schema (fixes #8438)
|
||||
- server: allow all argument types for BigQuery routines
|
||||
- server: fix prefix/suffix behaviour for `graphql-default` naming convention (fixes #8544)
|
||||
|
@ -395,6 +395,7 @@ library
|
||||
, Control.Monad.Unique
|
||||
, Data.Aeson.Extended
|
||||
, Data.Aeson.KeyMap.Extended
|
||||
, Data.Aeson.Kriti.Functions
|
||||
, Data.Environment
|
||||
, Data.HashMap.Strict.Extended
|
||||
, Data.HashMap.Strict.Multi
|
||||
|
65
server/src-lib/Data/Aeson/Kriti/Functions.hs
Normal file
65
server/src-lib/Data/Aeson/Kriti/Functions.hs
Normal file
@ -0,0 +1,65 @@
|
||||
-- | Module of reusable functions for Kriti transforms.
|
||||
--
|
||||
-- NOTE: This defines an alternative `runKritiWith` that includes the basicFunctions by default.
|
||||
-- You should probably invoke Kriti through this module rather than directly in order to
|
||||
-- make updating the functions available only require touching this module.
|
||||
--
|
||||
-- TODO: This should be added to the documentation and referenced in (for-example) REST Connectors once
|
||||
-- the documentation refactor project is complete.
|
||||
module Data.Aeson.Kriti.Functions (runKriti, runKritiWith, basicFunctions, environmentFunctions, sessionFunctions) where
|
||||
|
||||
import Control.Arrow (left)
|
||||
import Data.Aeson qualified as J
|
||||
import Data.Environment qualified as Env
|
||||
import Data.HashMap.Strict qualified as M
|
||||
import Data.Text qualified as T
|
||||
import Hasura.Prelude
|
||||
import Hasura.Session (SessionVariables, getSessionVariableValue, mkSessionVariable)
|
||||
import Kriti qualified
|
||||
import Kriti.CustomFunctions qualified as Kriti
|
||||
import Kriti.Error (SerializeError (serialize), SerializedError)
|
||||
import Kriti.Error qualified as Kriti
|
||||
|
||||
type KritiFunc = J.Value -> Either Kriti.CustomFunctionError J.Value
|
||||
|
||||
-- | `Data.Aeson.Kriti.Functions.runKriti` attaches the basicFunctions by default
|
||||
-- NOTE: The error type is SerializedError due to KritiError not currently being exported
|
||||
runKriti :: Text -> [(Text, J.Value)] -> Either SerializedError J.Value
|
||||
runKriti t m = left serialize $ Kriti.runKritiWith t m basicFunctions
|
||||
|
||||
-- | `Data.Aeson.Kriti.Functions.runKritiWith` attaches the basicFunctions by default.
|
||||
runKritiWith :: Text -> [(Text, J.Value)] -> HashMap Text KritiFunc -> Either SerializedError J.Value
|
||||
runKritiWith t m f = left serialize $ Kriti.runKritiWith t m (basicFunctions <> f)
|
||||
|
||||
-- | Re-Export of the Kriti 'stdlib'
|
||||
basicFunctions :: M.HashMap Text KritiFunc
|
||||
basicFunctions = Kriti.basicFuncMap
|
||||
|
||||
-- | Functions that interact with environment variables
|
||||
environmentFunctions :: Env.Environment -> M.HashMap Text KritiFunc
|
||||
environmentFunctions env =
|
||||
M.fromList
|
||||
[ ("getEnvironmentVariable", getEnvVar)
|
||||
]
|
||||
where
|
||||
getEnvVar :: J.Value -> Either Kriti.CustomFunctionError J.Value
|
||||
getEnvVar = \case
|
||||
J.Null -> Right $ J.Null
|
||||
J.String k -> Right $ J.toJSON $ Env.lookupEnv env (T.unpack k)
|
||||
_ -> Left $ Kriti.CustomFunctionError "Environment variable name should be a string"
|
||||
|
||||
-- | Functions that interact with HGE session during requests
|
||||
sessionFunctions :: Maybe SessionVariables -> M.HashMap Text KritiFunc
|
||||
sessionFunctions sessionVars = M.singleton "getSessionVariable" getSessionVar
|
||||
where
|
||||
-- Returns Null if session-variables aren't passed in
|
||||
-- Throws an error if session variable isn't found. Perhaps a version that returns null would also be useful.
|
||||
-- Lookups are case-insensitive
|
||||
getSessionVar :: J.Value -> Either Kriti.CustomFunctionError J.Value
|
||||
getSessionVar = \case
|
||||
J.Null -> Right $ J.Null
|
||||
J.String txt ->
|
||||
case sessionVars >>= getSessionVariableValue (mkSessionVariable txt) of
|
||||
Just x -> Right $ J.String x
|
||||
Nothing -> Left . Kriti.CustomFunctionError $ "Session variable \"" <> txt <> "\" not found"
|
||||
_ -> Left $ Kriti.CustomFunctionError "Session variable name should be a string"
|
@ -7,6 +7,7 @@ where
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
import Data.Aeson qualified as J
|
||||
import Data.Aeson.Kriti.Functions qualified as KFunc
|
||||
import Data.Environment qualified as Env
|
||||
import Data.HashMap.Strict qualified as M
|
||||
import Data.Text qualified as T
|
||||
@ -14,8 +15,6 @@ import Hasura.Backends.DataConnector.API qualified as API
|
||||
import Hasura.Backends.DataConnector.Adapter.Types (ConnSourceConfig (ConnSourceConfig, template, value), SourceConfig (..))
|
||||
import Hasura.Base.Error (Code (NotSupported), QErr, throw400)
|
||||
import Hasura.Prelude
|
||||
import Kriti qualified
|
||||
import Kriti.CustomFunctions qualified as Kriti
|
||||
import Kriti.Error qualified as Kriti
|
||||
|
||||
transformConfig :: (MonadError QErr m) => API.Config -> Maybe Text -> [(T.Text, J.Value)] -> Env.Environment -> m API.Config
|
||||
@ -23,8 +22,8 @@ transformConfig config maybeTemplate scope env = do
|
||||
case maybeTemplate of
|
||||
Nothing -> pure config
|
||||
(Just t) ->
|
||||
case Kriti.runKritiWith t (("$config", J.toJSON config) : scope) (additionalFunctions env) of
|
||||
Left e -> throw400 NotSupported $ "transformConfig: Kriti template transform failed - " <> tshow (Kriti.serialize e)
|
||||
case KFunc.runKritiWith t (("$config", J.toJSON config) : scope) (additionalFunctions env) of
|
||||
Left e -> throw400 NotSupported $ "transformConfig: Kriti template transform failed - " <> tshow e
|
||||
Right (J.Object r) -> pure $ API.Config r
|
||||
Right o -> throw400 NotSupported $ "transformConfig: Kriti did not decode into Object - " <> tshow o
|
||||
|
||||
@ -37,10 +36,4 @@ transformConnSourceConfig :: (MonadError QErr m) => ConnSourceConfig -> [(T.Text
|
||||
transformConnSourceConfig ConnSourceConfig {value, template} scope env = transformConfig value template scope env
|
||||
|
||||
additionalFunctions :: Env.Environment -> M.HashMap T.Text (J.Value -> Either Kriti.CustomFunctionError J.Value)
|
||||
additionalFunctions env = M.singleton "env" getEnv <> Kriti.basicFuncMap
|
||||
where
|
||||
getEnv :: J.Value -> Either Kriti.CustomFunctionError J.Value
|
||||
getEnv x = case x of
|
||||
J.Null -> Right $ J.Null
|
||||
J.String k -> Right $ J.toJSON $ Env.lookupEnv env (T.unpack k)
|
||||
_ -> Left $ Kriti.CustomFunctionError "Environment variable name should be a string"
|
||||
additionalFunctions env = KFunc.environmentFunctions env
|
||||
|
@ -55,13 +55,13 @@ where
|
||||
import Control.Lens (Lens', lens, set, traverseOf, view)
|
||||
import Data.Aeson (FromJSON, ToJSON)
|
||||
import Data.Aeson.Extended qualified as J
|
||||
import Data.Aeson.Kriti.Functions qualified as KFunc
|
||||
import Data.Bifunctor (first)
|
||||
import Data.ByteString.Lazy qualified as BL
|
||||
import Data.CaseInsensitive qualified as CI
|
||||
import Data.Coerce (Coercible)
|
||||
import Data.Functor.Barbie (AllBF, ApplicativeB, ConstraintsB, FunctorB, TraversableB)
|
||||
import Data.Functor.Barbie qualified as B
|
||||
import Data.HashMap.Strict qualified as M
|
||||
import Data.Text.Encoding qualified as TE
|
||||
import Data.Validation qualified as V
|
||||
import Hasura.Incremental (Cacheable)
|
||||
@ -73,9 +73,7 @@ import Hasura.RQL.DDL.Webhook.Transform.Headers (Headers (..), HeadersTransformF
|
||||
import Hasura.RQL.DDL.Webhook.Transform.Method
|
||||
import Hasura.RQL.DDL.Webhook.Transform.QueryParams
|
||||
import Hasura.RQL.DDL.Webhook.Transform.Url
|
||||
import Hasura.Session (SessionVariables, getSessionVariableValue, mkSessionVariable)
|
||||
import Kriti qualified (runKriti)
|
||||
import Kriti.Error qualified as Kriti (CustomFunctionError (CustomFunctionError), serialize)
|
||||
import Hasura.Session (SessionVariables)
|
||||
import Network.HTTP.Client.Transformable qualified as HTTP
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
@ -376,18 +374,8 @@ buildRespTransformCtx reqCtx sessionVars engine respBody =
|
||||
{ responseTransformBody = fromMaybe J.Null $ J.decode @J.Value respBody,
|
||||
responseTransformReqCtx = J.toJSON reqCtx,
|
||||
responseTransformEngine = engine,
|
||||
responseTransformFunctions = M.singleton "getSessionVariable" getSessionVar
|
||||
responseTransformFunctions = KFunc.sessionFunctions sessionVars
|
||||
}
|
||||
where
|
||||
getSessionVar :: J.Value -> Either Kriti.CustomFunctionError J.Value
|
||||
getSessionVar inp = case inp of
|
||||
J.String txt ->
|
||||
case sessionVarValue of
|
||||
Just x -> Right $ J.String x
|
||||
Nothing -> Left . Kriti.CustomFunctionError $ "Session variable \"" <> txt <> "\" not found"
|
||||
where
|
||||
sessionVarValue = sessionVars >>= getSessionVariableValue (mkSessionVariable txt)
|
||||
_ -> Left $ Kriti.CustomFunctionError "Session variable name should be a string"
|
||||
|
||||
-- | Construct a Template Transformation function for Responses
|
||||
--
|
||||
@ -403,7 +391,7 @@ mkRespTemplateTransform _ Body.Remove _ = pure J.Null
|
||||
mkRespTemplateTransform engine (Body.ModifyAsJSON (Template template)) ResponseTransformCtx {..} =
|
||||
let context = [("$body", responseTransformBody), ("$request", responseTransformReqCtx)]
|
||||
in case engine of
|
||||
Kriti -> first (TransformErrorBundle . pure . J.toJSON . Kriti.serialize) $ Kriti.runKriti template context
|
||||
Kriti -> first (TransformErrorBundle . pure . J.toJSON) $ KFunc.runKriti template context
|
||||
mkRespTemplateTransform engine (Body.ModifyAsFormURLEncoded formTemplates) context =
|
||||
case engine of
|
||||
Kriti -> do
|
||||
|
@ -43,6 +43,7 @@ import Control.Arrow (left)
|
||||
import Control.Lens (bimap, view)
|
||||
import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey)
|
||||
import Data.Aeson qualified as J
|
||||
import Data.Aeson.Kriti.Functions as KFunc
|
||||
import Data.Binary.Builder (toLazyByteString)
|
||||
import Data.ByteString (ByteString)
|
||||
import Data.ByteString.Builder.Scientific (scientificBuilder)
|
||||
@ -54,9 +55,7 @@ import Data.Text.Encoding qualified as TE
|
||||
import Data.Validation (Validation, fromEither)
|
||||
import Hasura.Incremental (Cacheable)
|
||||
import Hasura.Prelude
|
||||
import Hasura.Session (SessionVariables, getSessionVariableValue, mkSessionVariable)
|
||||
import Kriti (runKritiWith)
|
||||
import Kriti.CustomFunctions qualified as Kriti (basicFuncMap)
|
||||
import Hasura.Session (SessionVariables)
|
||||
import Kriti.Error qualified as Kriti (CustomFunctionError (..), serialize)
|
||||
import Kriti.Parser qualified as Kriti (parser)
|
||||
import Network.HTTP.Client.Transformable qualified as HTTP
|
||||
@ -166,25 +165,14 @@ mkReqTransformCtx url sessionVars rtcEngine reqData =
|
||||
view HTTP.queryParams reqData & fmap \(key, val) ->
|
||||
(TE.decodeUtf8 key, fmap TE.decodeUtf8 val)
|
||||
in Just $ J.toJSON queryParams
|
||||
rtcFunctions = M.singleton "getSessionVariable" getSessionVar
|
||||
in RequestTransformCtx
|
||||
{ rtcBaseUrl,
|
||||
rtcBody,
|
||||
rtcSessionVariables,
|
||||
rtcQueryParams,
|
||||
rtcEngine,
|
||||
rtcFunctions = rtcFunctions <> Kriti.basicFuncMap
|
||||
rtcFunctions = KFunc.sessionFunctions sessionVars
|
||||
}
|
||||
where
|
||||
getSessionVar :: J.Value -> Either Kriti.CustomFunctionError J.Value
|
||||
getSessionVar inp = case inp of
|
||||
J.String txt ->
|
||||
case sessionVarValue of
|
||||
Just x -> Right $ J.String x
|
||||
Nothing -> Left . Kriti.CustomFunctionError $ "Session variable \"" <> txt <> "\" not found"
|
||||
where
|
||||
sessionVarValue = sessionVars >>= getSessionVariableValue (mkSessionVariable txt)
|
||||
_ -> Left $ Kriti.CustomFunctionError "Session variable name should be a string"
|
||||
|
||||
-- | Common context that is made available to all response transformations.
|
||||
data ResponseTransformCtx = ResponseTransformCtx
|
||||
@ -257,9 +245,9 @@ runRequestTemplateTransform template RequestTransformCtx {rtcEngine = Kriti, ..}
|
||||
[ ("$query_params",) <$> rtcQueryParams,
|
||||
("$base_url",) <$> rtcBaseUrl
|
||||
]
|
||||
eResult = runKritiWith (unTemplate $ template) context rtcFunctions
|
||||
eResult = KFunc.runKritiWith (unTemplate $ template) context rtcFunctions
|
||||
in eResult & left \kritiErr ->
|
||||
let renderedErr = J.toJSON $ Kriti.serialize kritiErr
|
||||
let renderedErr = J.toJSON kritiErr
|
||||
in TransformErrorBundle [renderedErr]
|
||||
|
||||
-- TODO: Should this live in 'Hasura.RQL.DDL.Webhook.Transform.Validation'?
|
||||
@ -291,9 +279,9 @@ runResponseTemplateTransform ::
|
||||
Either TransformErrorBundle J.Value
|
||||
runResponseTemplateTransform template ResponseTransformCtx {responseTransformEngine = Kriti, ..} =
|
||||
let context = [("$body", responseTransformBody), ("$request", responseTransformReqCtx)]
|
||||
eResult = runKritiWith (unTemplate $ template) context responseTransformFunctions
|
||||
eResult = KFunc.runKritiWith (unTemplate $ template) context responseTransformFunctions
|
||||
in eResult & left \kritiErr ->
|
||||
let renderedErr = J.toJSON $ Kriti.serialize kritiErr
|
||||
let renderedErr = J.toJSON kritiErr
|
||||
in TransformErrorBundle [renderedErr]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user