{-# LANGUAGE OverloadedStrings #-} module Grakn.Client ( Graph(Graph, keyspace, url) , Concept(Concept, cid, cname, ctype, value) , GraknError , Result(MatchResult, InsertResult, AskResult, CountResult, DeleteResult) , defaultUrl , defaultKeyspace , execute ) where import Control.Applicative (empty) import Data.Aeson (FromJSON, ToJSON, encode, parseJSON, (.:), (.:?)) import qualified Data.Aeson as Aeson import Data.Foldable (asum) import Data.Map (Map) import Data.Proxy (Proxy (Proxy)) import Data.Text (Text) import Grakn.Property (Name, Value, Var) import Grakn.Query (IsQuery (queryString)) import Network.HTTP.Client (defaultManagerSettings, newManager) import Network.HTTP.Media ((//)) import Servant.API import Servant.API.ContentTypes (eitherDecodeLenient) import Servant.Client data Graph = Graph { url :: BaseUrl , keyspace :: String } newtype GraknError = GraknError String deriving (Eq, Show) -- |A result of a match query, binding variables to concepts data Result = MatchResult [Map Var Concept] | InsertResult [Text] | AskResult Bool | CountResult Integer | DeleteResult deriving (Show, Eq) -- |A concept in the graph data Concept = Concept { cid :: Text , cname :: Maybe Name , ctype :: Maybe Name , value :: Maybe Value } deriving (Show, Eq) -- |The default Grakn URL, accessing localhost defaultUrl :: BaseUrl defaultUrl = BaseUrl Http "localhost" 4567 "" -- |The default Grakn keyspace defaultKeyspace :: String defaultKeyspace = "grakn" execute :: IsQuery q => Graph -> q -> IO (Either ServantError Result) execute (Graph u ks) query = do manager <- newManager defaultManagerSettings let env = ClientEnv manager u runClientM (graqlGet (queryString query) ks) env type Keyspace = QueryParam "keyspace" String type Infer = QueryParam "infer" Bool type Materialise = QueryParam "materialise" Bool type Body = ReqBody '[ PlainText] String type GraknParams = Keyspace :> Infer :> Materialise :> Body :> Post '[ GraqlJSON] Result -- |A type describing the REST API we use to execute queries type GraknAPI = "graph" :> "graql" :> "execute" :> GraknParams graknAPI :: Proxy GraknAPI graknAPI = Proxy graqlGet :: String -> String -> ClientM Result graqlGet query ks = client graknAPI (Just ks) (Just False) (Just False) query instance FromJSON Concept where parseJSON (Aeson.Object obj) = Concept <$> (obj .: "id") <*> (obj .:? "name") <*> (obj .:? "isa") <*> (obj .:? "value") parseJSON _ = empty instance FromJSON Result where parseJSON val = asum [ MatchResult <$> parseJSON val , InsertResult <$> parseJSON val , AskResult <$> parseJSON val , CountResult <$> parseJSON val , pure DeleteResult ] data GraqlJSON instance Accept GraqlJSON where contentType _ = "application" // "graql+json" instance ToJSON a => MimeRender GraqlJSON a where mimeRender _ = encode instance FromJSON a => MimeUnrender GraqlJSON a where mimeUnrender _ = eitherDecodeLenient