{-# LANGUAGE NamedFieldPuns #-} module PostgREST.Plan.CallPlan ( CallPlan(..) , CallParams(..) , CallArgs(..) , RpcParamValue(..) , toRpcParams ) where import qualified Data.Aeson as JSON import qualified Data.ByteString.Lazy as LBS import qualified Data.HashMap.Strict as HM import PostgREST.SchemaCache.Identifiers (FieldName, QualifiedIdentifier) import PostgREST.SchemaCache.Routine (Routine (..), RoutineParam (..)) import Protolude data CallPlan = FunctionCall { funCQi :: QualifiedIdentifier , funCParams :: CallParams , funCArgs :: CallArgs , funCScalar :: Bool , funCSetOfScalar :: Bool , funCRetCompositeAlias :: Bool , funCFilterFields :: Set FieldName , funCReturning :: Set FieldName } data CallParams = KeyParams [RoutineParam] -- ^ Call with key params: func(a := val1, b:= val2) | OnePosParam RoutineParam -- ^ Call with positional params(only one supported): func(val) data CallArgs = DirectArgs (HM.HashMap Text RpcParamValue) | JsonArgs (Maybe LBS.ByteString) -- | RPC query param value `/rpc/func?v=`, used for VARIADIC functions on form-urlencoded POST and GETs -- | It can be fixed `?v=1` or repeated `?v=1&v=2&v=3. data RpcParamValue = Fixed Text | Variadic [Text] instance JSON.ToJSON RpcParamValue where toJSON (Fixed v) = JSON.toJSON v -- Not possible to get here anymore. Variadic arguments are only supported for -- true variadic arguments, but the toJSON instance is only used for the "single unnamed json argument" case. toJSON (Variadic v) = JSON.toJSON v -- | Convert rpc params `/rpc/func?a=val1&b=val2` to json `{"a": "val1", "b": "val2"} toRpcParams :: Routine -> [(Text, Text)] -> HM.HashMap Text RpcParamValue toRpcParams proc prms = if not $ pdHasVariadic proc then -- if proc has no variadic param, save steps and directly convert to map HM.fromList $ second Fixed <$> prms else HM.fromListWith mergeParams $ toRpcParamValue proc <$> prms where mergeParams :: RpcParamValue -> RpcParamValue -> RpcParamValue mergeParams (Variadic a) (Variadic b) = Variadic $ b ++ a mergeParams v _ = v -- repeated params for non-variadic parameters are not merged toRpcParamValue :: Routine -> (Text, Text) -> (Text, RpcParamValue) toRpcParamValue proc (k, v) | prmIsVariadic k = (k, Variadic [v]) | otherwise = (k, Fixed v) where prmIsVariadic prm = isJust $ find (\RoutineParam{ppName, ppVar} -> ppName == prm && ppVar) $ pdParams proc