packages feed

cayley-client 0.2.0.0 → 0.2.1.0

raw patch · 6 files changed

+216/−197 lines, 6 filesdep +binarydep ~aesondep ~attoparsecdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: binary

Dependency ranges changed: aeson, attoparsec, base, bytestring, exceptions, http-client, http-conduit, lens, lens-aeson, mtl, text, transformers, unordered-containers, vector

API changes (from Hackage documentation)

+ Database.Cayley.Types: instance Data.Binary.Class.Binary Database.Cayley.Types.Quad
+ Database.Cayley.Types: instance GHC.Generics.Generic Database.Cayley.Types.Quad
- Database.Cayley.Client: Quad :: Text -> Text -> Text -> Maybe Text -> Quad
+ Database.Cayley.Client: Quad :: !Text -> !Text -> !Text -> !(Maybe Text) -> Quad
- Database.Cayley.Client: [label] :: Quad -> Maybe Text
+ Database.Cayley.Client: [label] :: Quad -> !(Maybe Text)
- Database.Cayley.Client: [object] :: Quad -> Text
+ Database.Cayley.Client: [object] :: Quad -> !Text
- Database.Cayley.Client: [predicate] :: Quad -> Text
+ Database.Cayley.Client: [predicate] :: Quad -> !Text
- Database.Cayley.Client: [subject] :: Quad -> Text
+ Database.Cayley.Client: [subject] :: Quad -> !Text
- Database.Cayley.Types: Link :: Integer -> Integer -> Integer -> Link
+ Database.Cayley.Types: Link :: !Integer -> !Integer -> !Integer -> Link
- Database.Cayley.Types: Node :: Integer -> Maybe [Tag] -> Maybe [Value] -> Bool -> Bool -> Node
+ Database.Cayley.Types: Node :: !Integer -> !(Maybe [Tag]) -> !(Maybe [Value]) -> !Bool -> !Bool -> Node
- Database.Cayley.Types: Quad :: Text -> Text -> Text -> Maybe Text -> Quad
+ Database.Cayley.Types: Quad :: !Text -> !Text -> !Text -> !(Maybe Text) -> Quad
- Database.Cayley.Types: Shape :: [Node] -> [Link] -> Shape
+ Database.Cayley.Types: Shape :: ![Node] -> ![Link] -> Shape
- Database.Cayley.Types: [id] :: Node -> Integer
+ Database.Cayley.Types: [id] :: Node -> !Integer
- Database.Cayley.Types: [isFixed] :: Node -> Bool
+ Database.Cayley.Types: [isFixed] :: Node -> !Bool
- Database.Cayley.Types: [isLinkNode] :: Node -> Bool
+ Database.Cayley.Types: [isLinkNode] :: Node -> !Bool
- Database.Cayley.Types: [label] :: Quad -> Maybe Text
+ Database.Cayley.Types: [label] :: Quad -> !(Maybe Text)
- Database.Cayley.Types: [linkNode] :: Link -> Integer
+ Database.Cayley.Types: [linkNode] :: Link -> !Integer
- Database.Cayley.Types: [links] :: Shape -> [Link]
+ Database.Cayley.Types: [links] :: Shape -> ![Link]
- Database.Cayley.Types: [nodes] :: Shape -> [Node]
+ Database.Cayley.Types: [nodes] :: Shape -> ![Node]
- Database.Cayley.Types: [object] :: Quad -> Text
+ Database.Cayley.Types: [object] :: Quad -> !Text
- Database.Cayley.Types: [predicate] :: Quad -> Text
+ Database.Cayley.Types: [predicate] :: Quad -> !Text
- Database.Cayley.Types: [source] :: Link -> Integer
+ Database.Cayley.Types: [source] :: Link -> !Integer
- Database.Cayley.Types: [subject] :: Quad -> Text
+ Database.Cayley.Types: [subject] :: Quad -> !Text
- Database.Cayley.Types: [tags] :: Node -> Maybe [Tag]
+ Database.Cayley.Types: [tags] :: Node -> !(Maybe [Tag])
- Database.Cayley.Types: [target] :: Link -> Integer
+ Database.Cayley.Types: [target] :: Link -> !Integer
- Database.Cayley.Types: [values] :: Node -> Maybe [Value]
+ Database.Cayley.Types: [values] :: Node -> !(Maybe [Value])

Files

Database/Cayley/Client.hs view
@@ -6,14 +6,14 @@        Quad (..) -    -- * Connect & query+    -- * Connection     , defaultCayleyConfig     , connectCayley++    -- * Operations     , query     , Shape     , queryShape--    -- * REST API operations     , write     , writeQuad     , writeQuads@@ -50,50 +50,53 @@ -- connectCayley :: CayleyConfig -> IO CayleyConnection connectCayley c =-    newManager defaultManagerSettings >>= \m -> return $ CayleyConnection (c,m)+  newManager defaultManagerSettings >>= \m -> return $ CayleyConnection (c,m)  -- | Perform a query, in Gremlin graph query language per default (or in MQL). -- -- >λ> query conn "graph.Vertex('Humphrey Bogart').In('name').All()" -- >Right (Array (fromList [Object (fromList [("id",String "/en/humphrey_bogart")])])) ---query :: CayleyConnection -> Query -> IO (Either String A.Value)+query :: CayleyConnection+      -> Query+      -> IO (Either String A.Value) query c q =-    runReaderT (doQuery (getManager c) (encodeUtf8 q)) (getConfig c)+  runReaderT (doQuery (getManager c) (encodeUtf8 q)) (getConfig c)   where     doQuery m _q = do-        CayleyConfig {..} <- ask+        CayleyConfig{..} <- ask         r <- apiRequest-                 m (urlBase serverName apiVersion-                   ++ "/query/" ++ show queryLang)-                 serverPort (RequestBodyBS _q)+               m (urlBase serverName apiVersion+                 ++ "/query/" ++ show queryLang)+               serverPort (RequestBodyBS _q)         return $ case r of-            Just a  ->-                case a ^? key "result" of-                    Just v  -> Right v-                    Nothing ->-                      case a ^? key "error" of-                          Just e  ->-                              case A.fromJSON e of-                                  A.Success s -> Left s-                                  A.Error _e  -> Left _e-                          Nothing ->-                              Left "No JSON response from Cayley server"-            Nothing -> Left "Can't get any response from Cayley server"+          Just a  ->+            case a ^? key "result" of+              Just v  -> Right v+              Nothing ->+                case a ^? key "error" of+                  Just e  ->+                    case A.fromJSON e of+                      A.Success s -> Left s+                      A.Error _e  -> Left _e+                  Nothing -> Left "No JSON response from Cayley server"+          Nothing -> Left "Can't get any response from Cayley server" --- | Return the description of the given query.-queryShape :: CayleyConnection -> Query -> IO (A.Result Shape)+-- | Return the description of the given executed query.+queryShape :: CayleyConnection+           -> Query+           -> IO (A.Result Shape) queryShape c q =-    runReaderT (doShape (getManager c) (encodeUtf8 q)) (getConfig c)+  runReaderT (doShape (getManager c) (encodeUtf8 q)) (getConfig c)   where     doShape m _q = do-        CayleyConfig {..} <- ask-        r <- apiRequest-                 m (urlBase serverName apiVersion ++ "/shape/" ++ show queryLang)-                 serverPort (RequestBodyBS _q)-        case r of-            Just o  -> return $ A.fromJSON o-            Nothing -> return $ A.Error "API request error"+      CayleyConfig{..} <- ask+      r <- apiRequest+             m (urlBase serverName apiVersion ++ "/shape/" ++ show queryLang)+             serverPort (RequestBodyBS _q)+      case r of+        Just o  -> return $ A.fromJSON o+        Nothing -> return $ A.Error "API request error"  -- | Write a 'Quad' with the given subject, predicate, object and optional -- label. Throw result or extract amount of query 'successfulResults'@@ -109,10 +112,12 @@           -> Maybe Label           -> IO (Maybe A.Value) writeQuad c s p o l =-   writeQuads c [Quad { subject = s, predicate = p, object = o, label = l }]+  writeQuads c [Quad { subject = s, predicate = p, object = o, label = l }]  -- | Write the given 'Quad'.-write :: CayleyConnection -> Quad -> IO (Maybe A.Value)+write :: CayleyConnection+      -> Quad+      -> IO (Maybe A.Value) write c q = writeQuads c [q]  -- | Delete the 'Quad' defined by the given subject, predicate, object@@ -124,34 +129,38 @@            -> Maybe Label            -> IO (Maybe A.Value) deleteQuad c s p o l =-    deleteQuads c [Quad { subject = s, predicate = p, object = o, label = l }]+  deleteQuads c [Quad { subject = s, predicate = p, object = o, label = l }]  -- | Delete the given 'Quad'. delete :: CayleyConnection -> Quad -> IO (Maybe A.Value) delete c q = deleteQuads c [q]  -- | Write the given list of 'Quad'(s).-writeQuads :: CayleyConnection -> [Quad] -> IO (Maybe A.Value)+writeQuads :: CayleyConnection+           -> [Quad]+           -> IO (Maybe A.Value) writeQuads c qs =-    runReaderT (_write (getManager c) qs) (getConfig c)+  runReaderT (_write (getManager c) qs) (getConfig c)   where     _write m _qs = do-         CayleyConfig {..} <- ask-         apiRequest-             m (urlBase serverName apiVersion ++ "/write")-             serverPort (toRequestBody _qs)+      CayleyConfig{..} <- ask+      apiRequest+        m (urlBase serverName apiVersion ++ "/write")+        serverPort (toRequestBody _qs)  -- | Delete the given list of 'Quad'(s).-deleteQuads :: CayleyConnection -> [Quad] -> IO (Maybe A.Value)+deleteQuads :: CayleyConnection+            -> [Quad]+            -> IO (Maybe A.Value) deleteQuads c qs =-    runReaderT (_delete (getManager c) qs) (getConfig c)+  runReaderT (_delete (getManager c) qs) (getConfig c)   where     _delete m _qs = do-        CayleyConfig {..} <- ask-        apiRequest-            m (urlBase serverName apiVersion ++ "/delete")-            serverPort-            (toRequestBody _qs)+      CayleyConfig{..} <- ask+      apiRequest+        m (urlBase serverName apiVersion ++ "/delete")+        serverPort+        (toRequestBody _qs)  -- | Write a N-Quad file. --@@ -163,32 +172,36 @@                -> FilePath                -> m (Maybe A.Value) writeNQuadFile c p =-    runReaderT (writenq (getManager c) p) (getConfig c)+  runReaderT (writenq (getManager c) p) (getConfig c)   where     writenq m _p = do-        CayleyConfig {..} <- ask-        r <- parseUrl (urlBase serverName apiVersion ++ "/write/file/nquad")-                 >>= \r -> return r { port = serverPort }-        t <- liftIO $-                 try $-                    flip httpLbs m-                        =<< formDataBody [partFileSource "NQuadFile" _p] r-        return $ case t of-            Right _r -> A.decode $ responseBody _r-            Left e   -> Just $-                A.object ["error" A..= T.pack (show (e :: SomeException))]+      CayleyConfig{..} <- ask+      r <- parseUrl (urlBase serverName apiVersion ++ "/write/file/nquad")+             >>= \r -> return r { port = serverPort }+      t <- liftIO $+             try $+               flip httpLbs m+                 =<< formDataBody [partFileSource "NQuadFile" _p] r+      return $ case t of+        Right _r -> A.decode $ responseBody _r+        Left e   -> Just $+          A.object ["error" A..= T.pack (show (e :: SomeException))]  -- | A valid 'Quad' has its subject, predicate and object not empty. isValid :: Quad -> Bool-isValid Quad {..} = T.empty `notElem` [subject, predicate, object]+isValid Quad{..} = T.empty `notElem` [subject, predicate, object]  -- | Given a subject, a predicate, an object and an optional label, -- create a valid 'Quad'.-createQuad :: Subject -> Predicate -> Object -> Maybe Label -> Maybe Quad+createQuad :: Subject+           -> Predicate+           -> Object+           -> Maybe Label+           -> Maybe Quad createQuad s p o l =-    if T.empty `notElem` [s,p,o]-        then Just Quad { subject = s, predicate = p, object = o, label = l }-        else Nothing+  if T.empty `notElem` [s,p,o]+    then Just Quad { subject = s, predicate = p, object = o, label = l }+    else Nothing  -- | Get amount of successful results from a write/delete 'Quad'(s) -- operation, or an explicite error message.@@ -196,32 +209,32 @@ -- >λ> writeNQuadFile conn "testdata.nq" >>= successfulResults -- >Right 11 ---successfulResults :: Maybe A.Value -> IO (Either String Int)+successfulResults :: Maybe A.Value+                  -> IO (Either String Int) successfulResults m = return $-    case m of-        Just a  ->-            case a ^? key "result" of-                Just v  ->-                    case A.fromJSON v of-                        A.Success s ->-                            case AT.parse getAmount s of-                                AT.Done "" b -> Right b-                                _            ->-                                    Left "Can't get amount of successful results"-                        A.Error e   -> Left e-                Nothing ->-                    case a ^? key "error" of-                        Just e  ->-                            case A.fromJSON e of-                                A.Success s -> Left s-                                A.Error r   -> Left r-                        Nothing -> Left "No JSON response from Cayley server"-        Nothing -> Left "Can't get any response from Cayley server"+  case m of+    Just a  ->+      case a ^? key "result" of+        Just v  ->+          case A.fromJSON v of+            A.Success s ->+              case AT.parse getAmount s of+                AT.Done "" b -> Right b+                _            -> Left "Can't get amount of successful results"+            A.Error e   -> Left e+        Nothing ->+          case a ^? key "error" of+            Just e  ->+              case A.fromJSON e of+                A.Success s -> Left s+                A.Error r   -> Left r+            Nothing -> Left "No JSON response from Cayley server"+    Nothing -> Left "Can't get any response from Cayley server"   where-    getAmount = do-        _ <- AT.string "Successfully "-        _ <- AT.string "deleted " <|> AT.string "wrote "-        a <- AT.decimal-        _ <- AT.string " quads."-        return a+  getAmount = do+      _ <- AT.string "Successfully "+      _ <- AT.string "deleted " <|> AT.string "wrote "+      a <- AT.decimal+      _ <- AT.string " quads."+      return a 
Database/Cayley/Internal.hs view
@@ -18,15 +18,14 @@            -> RequestBody            -> ReaderT CayleyConfig IO (Maybe A.Value) apiRequest m u p b = do-    r <- parseUrl u >>= \c ->-             return c { method = "POST", port = p, requestBody = b }-    t <- liftIO $ try $ httpLbs r m-    case t of-        Right _r -> return $ A.decode $ responseBody _r-        Left  e ->-            return $-                Just $-                    A.object ["error" A..= T.pack (show (e :: SomeException))]+  r <- parseUrl u >>= \c ->+         return c { method = "POST", port = p, requestBody = b }+  t <- liftIO $ try $ httpLbs r m+  case t of+    Right _r -> return $ A.decode $ responseBody _r+    Left  e ->+      return $+        Just $ A.object ["error" A..= T.pack (show (e :: SomeException))]  toRequestBody :: [Quad] -> RequestBody toRequestBody = RequestBodyLBS . A.encode . fromList . map A.toJSON
Database/Cayley/Types.hs view
@@ -1,12 +1,15 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-}  module Database.Cayley.Types where  import           Control.Monad       (mzero) import qualified Data.Aeson          as A import qualified Data.Aeson.Types    as AT+import           Data.Binary import qualified Data.Text           as T import qualified Data.Vector         as V+import           GHC.Generics        (Generic) import           Network.HTTP.Client (Manager)  data APIVersion = V1@@ -17,82 +20,85 @@ data QueryLang = Gremlin | MQL  instance Show QueryLang where-    show Gremlin = "gremlin"-    show MQL     = "mql"+  show Gremlin = "gremlin"+  show MQL     = "mql"  data CayleyConfig = CayleyConfig-    { serverPort :: Int-    , serverName :: String-    , apiVersion :: APIVersion-    , queryLang  :: QueryLang-    } deriving (Show)+  { serverPort :: Int+  , serverName :: String+  , apiVersion :: APIVersion+  , queryLang  :: QueryLang+  } deriving (Show)  -- | CayleyConfig { serverPort = 64210 , serverName = "localhost" , apiVersion = V1 , queryLang  = Gremlin } defaultCayleyConfig :: CayleyConfig defaultCayleyConfig = CayleyConfig-    { serverPort = 64210-    , serverName = "localhost"-    , apiVersion = V1-    , queryLang  = Gremlin-    }+  { serverPort = 64210+  , serverName = "localhost"+  , apiVersion = V1+  , queryLang  = Gremlin+  }  data CayleyConnection = CayleyConnection (CayleyConfig, Manager)  data Quad = Quad-    { subject   :: T.Text       -- ^ Subject node-    , predicate :: T.Text       -- ^ Predicate node-    , object    :: T.Text       -- ^ Object node-    , label     :: Maybe T.Text -- ^ Label node-    }+  { subject   :: !T.Text         -- ^ Subject node+  , predicate :: !T.Text         -- ^ Predicate node+  , object    :: !T.Text         -- ^ Object node+  , label     :: !(Maybe T.Text) -- ^ Label node+  } deriving (Generic) +instance Binary Quad+ instance Show Quad where-    show (Quad s p o (Just l)) = T.unpack s-                                 ++ " -- "-                                 ++ T.unpack p-                                 ++ " -> "-                                 ++ T.unpack o-                                 ++ " ("-                                 ++ T.unpack l-                                 ++ ")"-    show (Quad s p o Nothing)  = T.unpack s-                                 ++ " -- "-                                 ++ T.unpack p-                                 ++ " -> "-                                 ++ T.unpack o+  show (Quad s p o (Just l)) = T.unpack s+                               ++ " -- "+                               ++ T.unpack p+                               ++ " -> "+                               ++ T.unpack o+                               ++ " ("+                               ++ T.unpack l+                               ++ ")"+  show (Quad s p o Nothing)  = T.unpack s+                               ++ " -- "+                               ++ T.unpack p+                               ++ " -> "+                               ++ T.unpack o  -- | Two quads are equals when subject, predicate, object /and/ label are equals. instance Eq Quad where-    Quad s p o l == Quad s' p' o' l' = s == s' && p == p' && o == o' && l == l'+  Quad s p o l == Quad s' p' o' l' = s == s' && p == p' && o == o' && l == l'  instance A.ToJSON Quad where-    toJSON (Quad s p o l) =-        A.object [ "subject"   A..= s-                 , "predicate" A..= p-                 , "object"    A..= o-                 , "label"     A..= l-                 ]+  toJSON (Quad s p o l) =+    A.object [ "subject"   A..= s+             , "predicate" A..= p+             , "object"    A..= o+             , "label"     A..= l+             ]  instance A.FromJSON Quad where-    parseJSON (A.Object v) = Quad <$>-                             v A..: "subject" <*>-                             v A..: "predicate" <*>-                             v A..: "object" <*>-                             v A..: "label"-    parseJSON _            = mzero+  parseJSON (A.Object v) =+    Quad <$>+    v A..: "subject" <*>+    v A..: "predicate" <*>+    v A..: "object" <*>+    v A..:? "label"+  parseJSON _            = mzero  data Shape = Shape-    { nodes :: [Node]-    , links :: [Link]+    { nodes :: ![Node]+    , links :: ![Link]     } deriving (Eq, Show)  instance A.FromJSON Shape where-    parseJSON (A.Object v) = do-        vnds <- v A..: "nodes"-        nds  <- mapM parseNode $ V.toList vnds-        vlks <- v A..: "links"-        lks  <- mapM parseLink $ V.toList vlks-        return Shape { nodes = nds, links = lks}-    parseJSON _            = mzero+  parseJSON (A.Object v) = do+    vnds <- v A..: "nodes"+    nds  <- mapM parseNode $ V.toList vnds+    vlks <- v A..: "links"+    lks  <- mapM parseLink $ V.toList vlks+    return Shape { nodes = nds, links = lks }+  parseJSON _            = mzero  parseNode :: A.Value -> AT.Parser Node parseNode (A.Object v) = Node <$>@@ -111,18 +117,18 @@ parseLink _            = fail "Link expected"  data Node = Node-    { id           :: Integer-    , tags         :: Maybe [Tag]   -- ^ list of tags from the query-    , values       :: Maybe [Value] -- ^ Known values from the query-    , isLinkNode   :: Bool          -- ^ Does the node represent the link or the node (the oval shapes)-    , isFixed      :: Bool          -- ^ Is the node a fixed starting point of the query-    } deriving (Eq, Show)+  { id           :: !Integer+  , tags         :: !(Maybe [Tag])   -- ^ list of tags from the query+  , values       :: !(Maybe [Value]) -- ^ Known values from the query+  , isLinkNode   :: !Bool            -- ^ Does the node represent the link or the node (the oval shapes)+  , isFixed      :: !Bool            -- ^ Is the node a fixed starting point of the query+  } deriving (Eq, Show)  data Link = Link-    { source    :: Integer -- ^ Node ID-    , target    :: Integer -- ^ Node ID-    , linkNode  :: Integer -- ^ Node ID-    } deriving (Eq, Show)+  { source    :: !Integer -- ^ Node ID+  , target    :: !Integer -- ^ Node ID+  , linkNode  :: !Integer -- ^ Node ID+  } deriving (Eq, Show)  type Query = T.Text 
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2015, Michel Boucey+Copyright (c) 2015-2016, Michel Boucey All rights reserved.  Redistribution and use in source and binary forms, with or without
README.md view
@@ -1,3 +1,3 @@-#A Cayley client for Haskell [![Build Status](https://travis-ci.org/MichelBoucey/cayley-client.svg?branch=master)](https://travis-ci.org/MichelBoucey/cayley-client)+# A Cayley client for Haskell [![Build Status](https://travis-ci.org/MichelBoucey/cayley-client.svg?branch=master)](https://travis-ci.org/MichelBoucey/cayley-client) -Cayley-client is a Haskell library that implements the [RESTful API](https://github.com/google/cayley/blob/master/docs/HTTP.md) of [Cayley database graph](https://github.com/google/cayley).+Cayley-client implements the [RESTful API](https://github.com/google/cayley/blob/master/docs/HTTP.md) of [Cayley database graph](https://github.com/google/cayley).
cayley-client.cabal view
@@ -1,13 +1,13 @@ name:                cayley-client-version:             0.2.0.0+version:             0.2.1.0 synopsis:            A Haskell client for the Cayley graph database description:         cayley-client implements the RESTful API of the Cayley graph database. homepage:            https://github.com/MichelBoucey/cayley-client license:             BSD3 license-file:        LICENSE author:              Michel Boucey-maintainer:          michel.boucey@gmail.com-copyright:           Copyright (c) 2015-2016 - Michel Boucey+maintainer:          michel.boucey@cybervisible.fr+copyright:           (c) 2015-2016 - Michel Boucey category:            Database build-type:          Simple cabal-version:       >=1.10@@ -19,35 +19,36 @@   Location: https://github.com/MichelBoucey/cayley-client.git  library-  exposed-modules:     Database.Cayley.Client-                     , Database.Cayley.Types-  other-modules:       Database.Cayley.Internal-  other-extensions:    OverloadedStrings-  build-depends:       base >=4.7 && <5-                     , mtl >=2.1-                     , transformers >=0.3-                     , attoparsec >=0.12-                     , bytestring >=0.10-                     , text >=1.2-                     , vector >=0.10-                     , http-conduit >=2.1-                     , http-client >=0.4-                     , aeson >=0.8-                     , lens >= 4.6.0.1-                     , lens-aeson >=1.0.0.3-                     , unordered-containers >=0.2-                     , exceptions >= 0.6-  default-language:    Haskell2010-  GHC-Options:       -Wall+  exposed-modules:    Database.Cayley.Client+                    , Database.Cayley.Types+  other-modules:      Database.Cayley.Internal+  other-extensions:   OverloadedStrings+  build-depends:      base >=4.7 && <5+                    , mtl >=2.1+                    , transformers >=0.3+                    , attoparsec >=0.12+                    , binary >=0.7.5+                    , bytestring >=0.10+                    , text >=1.2+                    , vector >=0.10+                    , http-conduit >=2.1+                    , http-client >=0.4+                    , aeson >=0.8+                    , lens >= 4.6.0.1+                    , lens-aeson >=1.0.0.3+                    , unordered-containers >=0.2+                    , exceptions >= 0.6+  default-language:   Haskell2010+  GHC-Options:      -Wall  test-suite tests-  type:                exitcode-stdio-1.0-  hs-source-dirs:      tests-  main-is:             hspec.hs-  build-depends:       hspec >= 2.2.2-                     , base >= 4.7 && < 5-                     , cayley-client-                     , aeson >=0.8-                     , unordered-containers >= 0.2.5-  default-language:    Haskell2010+  type:               exitcode-stdio-1.0+  hs-source-dirs:     tests+  main-is:            hspec.hs+  build-depends:      hspec >= 2.2.2+                    , base >= 4.7 && < 5+                    , cayley-client+                    , aeson >=0.8+                    , unordered-containers >= 0.2.5+  default-language:   Haskell2010