graphql-engine/server/src-lib/Hasura/GraphQL/Utils.hs

106 lines
3.0 KiB
Haskell
Raw Normal View History

2018-06-27 16:11:32 +03:00
module Hasura.GraphQL.Utils
( showName
2018-06-27 16:11:32 +03:00
, showNamedTy
, throwVE
, getBaseTy
, groupTuples
, groupListWith
, mkMapWith
, showNames
, unwrapTy
, simpleGraphQLQuery
, jsonValueToGValue
, getBaseTyWithNestedLevelsCount
2018-06-27 16:11:32 +03:00
) where
import Hasura.Prelude
import Hasura.RQL.Types.Error
2018-06-27 16:11:32 +03:00
import Data.Scientific (floatingOrInteger)
import qualified Data.Aeson as A
2018-06-27 16:11:32 +03:00
import qualified Data.HashMap.Strict as Map
import qualified Data.List.NonEmpty as NE
import qualified Data.Text as T
import qualified Language.GraphQL.Draft.Syntax as G
showName :: G.Name -> Text
showName name = "\"" <> G.unName name <> "\""
throwVE :: (MonadError QErr m) => Text -> m a
throwVE = throw400 ValidationFailed
showNamedTy :: G.NamedType -> Text
showNamedTy nt =
"'" <> G.showNT nt <> "'"
getBaseTy :: G.GType -> G.NamedType
getBaseTy = \case
G.TypeNamed _ n -> n
G.TypeList _ lt -> getBaseTyL lt
2018-06-27 16:11:32 +03:00
where
getBaseTyL = getBaseTy . G.unListType
getBaseTyWithNestedLevelsCount :: G.GType -> (G.NamedType, Int)
getBaseTyWithNestedLevelsCount ty = go ty 0
where
go :: G.GType -> Int -> (G.NamedType, Int)
go gType ctr =
case gType of
G.TypeNamed _ n -> (n, ctr)
G.TypeList _ lt -> flip go (ctr + 1) (G.unListType lt)
unwrapTy :: G.GType -> G.GType
unwrapTy =
\case
G.TypeList _ lt -> G.unListType lt
nt -> nt
2018-06-27 16:11:32 +03:00
groupListWith
:: (Eq k, Hashable k, Foldable t, Functor t)
=> (v -> k) -> t v -> Map.HashMap k (NE.NonEmpty v)
groupListWith f l =
groupTuples $ fmap (\v -> (f v, v)) l
groupTuples
:: (Eq k, Hashable k, Foldable t)
=> t (k, v) -> Map.HashMap k (NE.NonEmpty v)
groupTuples =
foldr groupFlds Map.empty
where
groupFlds (k, v) m = case Map.lookup k m of
Nothing -> Map.insert k (v NE.:| []) m
Just s -> Map.insert k (v NE.<| s) m
-- either duplicate keys or the map
mkMapWith
:: (Eq k, Hashable k, Foldable t, Functor t)
=> (v -> k) -> t v -> Either (NE.NonEmpty k) (Map.HashMap k v)
mkMapWith f l =
case NE.nonEmpty dups of
Just dupsNE -> Left dupsNE
Nothing -> Right $ Map.map NE.head mapG
where
mapG = groupListWith f l
dups = Map.keys $ Map.filter ((> 1) . length) mapG
showNames :: (Foldable t) => t G.Name -> Text
showNames names =
T.intercalate ", " $ map G.unName $ toList names
-- A simple graphql query to be used in generators
simpleGraphQLQuery :: Text
simpleGraphQLQuery = "query {author {id name}}"
-- | Convert a JSON value to a GraphQL value.
jsonValueToGValue :: A.Value -> G.Value
jsonValueToGValue = \case
A.String t -> G.VString $ G.StringValue t
-- TODO: Note the danger zone of scientific:
A.Number n -> either (\(_::Float) -> G.VFloat n) G.VInt (floatingOrInteger n)
A.Bool b -> G.VBoolean b
A.Object o -> G.VObject $ G.ObjectValueG $
map (uncurry G.ObjectFieldG . (G.Name *** jsonValueToGValue)) $ Map.toList o
A.Array a -> G.VList $ G.ListValueG $ map jsonValueToGValue $ toList a
A.Null -> G.VNull