{-# LANGUAGE OverloadedStrings #-} -- | Module to provide Cypher support. -- Currently we allow sending queries with parameters, the result is a collection of column headers -- and JSON data values, the Graph object has the function addCypher that tries to find -- nodes and relationships in a cypher query result and insert them in a "Database.Neo4j.Graph" object -- -- > import qualified Database.Neo4j.Cypher as C -- > -- > withConnection host port $ do -- > ... -- > -- Run a cypher query with parameters -- > res <- C.cypher "CREATE (n:Person { name : {name} }) RETURN n" M.fromList [("name", C.newparam ("Pep" :: T.Text))] -- > -- > -- Get all nodes and relationships that this query returned and insert them in a Graph object -- > let graph = G.addCypher (C.fromSuccess res) G.empty -- > -- > -- Get the column headers -- > let columnHeaders = C.cols $ C.fromSuccess res -- > -- > -- Get the rows of JSON values received -- > let values = C.vals $ C.fromSuccess res module Database.Neo4j.Cypher ( -- * Types Response(..), ParamValue(..), Params, newparam, -- * Sending queries cypher, fromResult, fromSuccess, isSuccess ) where import Data.Aeson ((.=), (.:)) import Control.Applicative ((<$>), (<*>)) import Control.Monad (mzero) import qualified Data.Aeson as J import qualified Data.ByteString as S import qualified Data.HashMap.Lazy as M import qualified Data.Text as T import Database.Neo4j.Types import Database.Neo4j.Http -- | Type for a Cypher response with tuples containing column name and their values data Response = Response {cols :: [T.Text], vals :: [[J.Value]]} deriving (Show, Eq) -- | How to create a response object from a cypher JSON response instance J.FromJSON Response where parseJSON (J.Object o) = Response <$> (o .: "columns" >>= J.parseJSON) <*> (o .: "data" >>= J.parseJSON) parseJSON _ = mzero cypherAPI :: S.ByteString cypherAPI = "/db/data/cypher" -- | Value for a cypher parmeter value, might be a literal, a property map or a list of property maps data ParamValue = ParamLiteral PropertyValue | ParamProperties Properties | ParamPropertiesArray [Properties] deriving (Show, Eq) newparam :: PropertyValueConstructor a => a -> ParamValue newparam = ParamLiteral . newval -- | Instance toJSON for param values so we can serialize them in queries instance J.ToJSON ParamValue where toJSON (ParamLiteral l) = J.toJSON l toJSON (ParamProperties p) = J.toJSON p toJSON (ParamPropertiesArray ps) = J.toJSON ps -- | We use hashmaps to represent Cypher parameters type Params = M.HashMap T.Text ParamValue -- | Run a cypher query cypher :: T.Text -> Params -> Neo4j (Either T.Text Response) cypher cmd params = Neo4j $ \conn -> httpCreate4XXExplained conn cypherAPI body where body = J.encode $ J.object ["query" .= cmd, "params" .= J.toJSON params] -- | Get the result of the response or a default value fromResult :: Response -> Either T.Text Response -> Response fromResult def (Left _) = def fromResult _ (Right resp) = resp -- | Get the result of the response or a default value fromSuccess :: Either T.Text Response -> Response fromSuccess (Left _) = error "Cypher.fromSuccess but is Error" fromSuccess (Right resp) = resp -- | True if the operation succeeded isSuccess :: Either T.Text Response -> Bool isSuccess (Left _) = False isSuccess (Right _) = True