{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}
module Main where
import Control.Applicative ((<$>))
import Control.Monad (void, join)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Default
import Data.Monoid (Monoid, mappend)
import Data.Int (Int64)
import Data.Maybe (fromJust)
import Data.String (fromString)
import qualified Data.Aeson as J
import qualified Data.ByteString as S
import qualified Data.HashMap.Lazy as M
import qualified Data.HashSet as HS
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.Vector as V
import qualified Data.List as L
import qualified Network.HTTP.Types as HT
import Control.Exception (handle)
import Test.Framework.TH (defaultMainGenerator)
import Test.Framework.Providers.HUnit (testCase)
import Test.HUnit.Base hiding (Test, Node)
import Database.Neo4j
import qualified Database.Neo4j.Batch as B
import qualified Database.Neo4j.Cypher as C
import qualified Database.Neo4j.Graph as G
import qualified Database.Neo4j.Transactional.Cypher as TC
import qualified Database.Neo4j.Traversal as T
(<>) :: Monoid a => a -> a -> a
(<>) = mappend
-- Get the string of a exception raised by an action
getException :: IO a -> IO (Maybe Neo4jException)
getException action = handle (return . Just) $ do
_ <- action
return Nothing
assertException :: Neo4jException -> IO a -> Assertion
assertException exExc action = do
resExc <- getException action
checkExc resExc
where --checkExc :: (Exception e, Show e) => Maybe e -> Assertion
checkExc Nothing = assertFailure $ "Expected exception " <> show exExc <> " but none raised"
checkExc (Just e) = assertEqual "" exExc e
-- | handy assertEqual inside a Neo4j monad
neo4jEqual :: (Show a, Eq a) => a -> a -> Neo4j ()
neo4jEqual a b = liftIO $ assertEqual "" a b
-- | handy assertBool inside a Neo4j monad
neo4jBool :: Bool -> Neo4j ()
neo4jBool f = liftIO $ assertBool "" f
main :: IO ()
main = $(defaultMainGenerator)
-- TODO: Is it possible to avoid so many type declarations for literals when constructing properties??
-- | Dummy properties
someProperties :: Properties
someProperties = M.fromList ["mytext" |: ("mytext" :: T.Text),
"textarrayprop" |: ["a" :: T.Text, "", "adeu"],
"int" |: (-12 :: Int64),
"intarray" |: [1 :: Int64, 2],
"double" |: (-12.23 :: Double),
"doublearray" |: [0.1, -12.23 :: Double],
"bool" |: False,
"aboolproparray" |: [False, True]
]
-- | Default Neo4j port
port :: Port
port = 7474
-- | Default Neo4j host
host :: Hostname
host = "localhost"
creds :: Credentials
creds = ("neo4j","test")
someOtherProperties :: Properties
someOtherProperties = M.fromList ["hola" |: ("adeu" :: T.Text), "proparray" |: ["a" :: T.Text, "", "adeu"]]
anotherProperties :: Properties
anotherProperties = M.empty
myRelType :: T.Text
myRelType = "MYREL"
-- | Test connecting to a non-existing server
case_NoConnection :: Assertion
case_NoConnection = assertException expException $ withConnection "localhost" 77 $ createNode someProperties
where expException = Neo4jHttpException "FailedConnectionException2 \"localhost\" 77 False connect: does not exist (Connection refused)"
-- | Test connecting to a server with improper credentials
case_ImproperCredentials :: Assertion
case_ImproperCredentials = do
mExp <- getException $ withConnection host port $ createNode someProperties
case mExp of
Nothing -> return () -- Old Neo4j version or auth disabled, no need to test this
Just _ -> assertException expException (
withAuthConnection host port ("fake", "pass") $ createNode someProperties)
where expException = Neo4jUnexpectedResponseException HT.status401
-- | Test getDatabaseVersion
case_getDatabaseVersion :: Assertion
case_getDatabaseVersion = do
withAuthConnection host port creds $ getDatabaseVersion >> return ()
-- | Test get and create a node
case_CreateGetDeleteNode :: Assertion
case_CreateGetDeleteNode = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- getNode n
neo4jEqual (Just n) newN
deleteNode n
-- | Test delete and get a node
case_CreateDeleteGetNode :: Assertion
case_CreateDeleteGetNode = withAuthConnection host port creds $ do
n <- createNode someProperties
deleteNode n
newN <- getNode n
neo4jEqual Nothing newN
-- | Test double delete
case_DoubleDeleteNode :: Assertion
case_DoubleDeleteNode = withAuthConnection host port creds $ do
n <- createNode someProperties
deleteNode n
deleteNode n
-- | Test get node by id
case_GetNodeById :: Assertion
case_GetNodeById = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- getNode (nodeId n)
neo4jEqual (Just n) newN
deleteNode n
-- | Test get node with unexisting id
case_GetUnexistingNodeById :: Assertion
case_GetUnexistingNodeById = withAuthConnection host port creds $ do
newN <- getNode ("unexistingnode" :: S.ByteString)
neo4jEqual Nothing newN
-- | Test delete node by id
case_DeleteNodeById :: Assertion
case_DeleteNodeById = withAuthConnection host port creds $ do
n <- createNode someProperties
deleteNode (nodeId n)
-- | Test delete unexisting node by id
case_DeleteUnexistingNodeById :: Assertion
case_DeleteUnexistingNodeById = withAuthConnection host port creds $ deleteNode ("unexistingnode" :: S.ByteString)
-- | Refresh node properties from the DB
case_getNodeProperties :: Assertion
case_getNodeProperties = withAuthConnection host port creds $ do
n <- createNode someProperties
props <- getProperties n
neo4jEqual someProperties props
deleteNode n
-- | Get node properties from a deleted node
case_getDeletedNodeProperties :: Assertion
case_getDeletedNodeProperties = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
getProperties n
-- | Get a property from a node
case_getNodeProperty :: Assertion
case_getNodeProperty = withAuthConnection host port creds $ do
n <- createNode someProperties
prop <- getProperty n "intarray"
neo4jEqual (M.lookup "intarray" someProperties) prop
deleteNode n
-- | Get an unexisting property from a node
case_getNodeUnexistingProperty :: Assertion
case_getNodeUnexistingProperty = withAuthConnection host port creds $ do
n <- createNode someProperties
prop <- getProperty n "noproperty"
neo4jEqual Nothing prop
deleteNode n
-- | Get a property from an unexisting node
case_getUnexistingNodeProperty :: Assertion
case_getUnexistingNodeProperty = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
_ <- getProperty n "noproperty"
return ()
-- | Get change the properties of a node
case_changeNodeProperties :: Assertion
case_changeNodeProperties = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- setProperties n otherProperties
neo4jEqual otherProperties (getNodeProperties newN)
renewN <- getNode n
neo4jEqual otherProperties (getNodeProperties $ fromJust renewN)
deleteNode newN
where otherProperties = M.insert "newbool" (newval True) someProperties
-- | Get change the properties of a node that doesn't exist
case_changeUnexistingNodeProperties :: Assertion
case_changeUnexistingNodeProperties = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
setProperties n someProperties
-- | Change a property of a node
case_changeNodeProperty :: Assertion
case_changeNodeProperty = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- setProperty n otherValName otherVal
neo4jEqual otherProperties (getNodeProperties newN)
renewN <- getNode n
neo4jEqual otherProperties (getNodeProperties $ fromJust renewN)
deleteNode newN
where otherProperties = M.insert otherValName otherVal someProperties
otherValName = "int"
otherVal = newval False
-- | Change an array property of a node to empty
case_changeNodePropertyToEmpty :: Assertion
case_changeNodePropertyToEmpty = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- setProperty n otherValName otherVal
neo4jEqual otherProperties (getNodeProperties newN)
renewN <- getNode n
neo4jEqual otherProperties (getNodeProperties $ fromJust renewN)
deleteNode newN
where otherProperties = M.insert otherValName otherVal someProperties
otherValName = "intarray"
otherVal = newval ([] :: [Int64])
-- | Set an unexisting property of a node
case_changeNodeUnexistingProperty :: Assertion
case_changeNodeUnexistingProperty = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- setProperty n otherValName otherVal
neo4jEqual otherProperties (getNodeProperties newN)
renewN <- getNode n
neo4jEqual otherProperties (getNodeProperties $ fromJust renewN)
deleteNode newN
where otherProperties = M.insert otherValName otherVal someProperties
otherValName = "mynewbool"
otherVal = newval False
-- | Set property of an unexisting node
case_changeUnexistingNodeProperty :: Assertion
case_changeUnexistingNodeProperty = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
_ <- setProperty n otherValName otherVal
return ()
where otherValName = "mynewbool"
otherVal = newval False
-- | Delete node properties
case_deleteNodeProperties :: Assertion
case_deleteNodeProperties = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- deleteProperties n
neo4jEqual M.empty (getNodeProperties newN)
renewN <- getNode n
neo4jEqual M.empty (getNodeProperties $ fromJust renewN)
deleteNode newN
-- | Delete unexisting node properties
case_deleteUnexistingNodeProperties :: Assertion
case_deleteUnexistingNodeProperties = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
_ <- deleteProperties n
return ()
-- | Delete a node property
case_deleteNodeProperty :: Assertion
case_deleteNodeProperty = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- deleteProperty n valName
neo4jEqual otherProperties (getNodeProperties newN)
renewN <- getNode n
neo4jEqual otherProperties (getNodeProperties $ fromJust renewN)
deleteNode newN
where otherProperties = M.delete valName someProperties
valName = "int"
-- | Delete an unexisting property from a node
case_deleteNodeUnexistingProperty :: Assertion
case_deleteNodeUnexistingProperty = withAuthConnection host port creds $ do
n <- createNode someProperties
newN <- deleteProperty n valName
neo4jEqual otherProperties (getNodeProperties newN)
renewN <- getNode n
neo4jEqual otherProperties (getNodeProperties $ fromJust renewN)
deleteNode newN
where otherProperties = M.delete valName someProperties
valName = "noproperty"
-- | Delete a property from an unexisting node
case_deleteUnexistingNodeProperty :: Assertion
case_deleteUnexistingNodeProperty = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
_ <- deleteProperty n valName
return ()
where valName = "noproperty"
setupRelTests :: Neo4j (Node, Node, Relationship)
setupRelTests = do
nodeFrom <- createNode anotherProperties
nodeTo <- createNode someOtherProperties
r <- createRelationship myRelType someProperties nodeFrom nodeTo
return (nodeFrom, nodeTo, r)
teardownRelTests :: Node -> Node -> Relationship -> Neo4j()
teardownRelTests f t r = do
deleteRelationship r
deleteNode f
deleteNode t
-- | Delete a node with a relationship
case_deleteNodeWithRelationship :: Assertion
case_deleteNodeWithRelationship = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNonOrphanNodeDeletionException $ runNodeIdentifier nodeFrom
assertException expException $ withAuthConnection host port creds $ deleteNode nodeFrom
withAuthConnection host port creds $ teardownRelTests nodeFrom nodeTo r
-- | Test get and create a relationship
case_CreateGetDeleteRelationship :: Assertion
case_CreateGetDeleteRelationship = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- getRelationship r
neo4jEqual (Just r) newN
teardownRelTests nodeFrom nodeTo r
-- | Test get all relationship properties
case_allRelationshipProperties :: Assertion
case_allRelationshipProperties = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
rs <- allRelationshipTypes
neo4jBool $ myRelType `elem` rs
teardownRelTests nodeFrom nodeTo r
-- | Test get the start and end of a relationship
case_relationshipFromTo :: Assertion
case_relationshipFromTo = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
nfrom <- getRelationshipFrom r
neo4jEqual nodeFrom nfrom
nto <- getRelationshipTo r
neo4jEqual nodeTo nto
teardownRelTests nodeFrom nodeTo r
-- | Test get the start of relationship that doesn't exist any more
case_nonExistingRelationshipFrom :: Assertion
case_nonExistingRelationshipFrom = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runNodeIdentifier nodeFrom
assertException expException $ withAuthConnection host port creds $ do
deleteRelationship r
deleteNode nodeFrom
n <- getRelationshipFrom r
neo4jEqual nodeFrom n -- Doing this to force the evaluation of n (the exception is thrown after parsing)
return ()
withAuthConnection host port creds $ teardownRelTests nodeFrom nodeTo r
-- | Test get the end of relationship that doesn't exist any more
case_nonExistingRelationshipTo :: Assertion
case_nonExistingRelationshipTo = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runNodeIdentifier nodeTo
assertException expException $ withAuthConnection host port creds $ do
deleteRelationship r
deleteNode nodeTo
n <- getRelationshipTo r
neo4jEqual nodeTo n -- Doing this to force the evaluation of n (the exception is thrown after parsing)
return ()
withAuthConnection host port creds $ teardownRelTests nodeFrom nodeTo r
-- | Create relationship with missing node from
case_CreateRelationshipMissingFrom :: Assertion
case_CreateRelationshipMissingFrom = do
(nodeFrom, nodeTo) <- withAuthConnection host port creds $ do
nodeFrom <- createNode anotherProperties
nodeTo <- createNode someOtherProperties
return (nodeFrom, nodeTo)
let expException = Neo4jNoEntityException $ runNodeIdentifier nodeFrom
assertException expException $ withAuthConnection host port creds $ do
deleteNode nodeFrom
_ <- createRelationship myRelType someProperties nodeFrom nodeTo
return ()
withAuthConnection host port creds $ deleteNode nodeTo
-- | Create relationship with missing node to
case_CreateRelationshipMissingTo :: Assertion
case_CreateRelationshipMissingTo = do
(nodeFrom, nodeTo) <- withAuthConnection host port creds $ do
nodeFrom <- createNode anotherProperties
nodeTo <- createNode someOtherProperties
return (nodeFrom, nodeTo)
let expException = Neo4jNoEntityException $ runNodeIdentifier nodeTo
assertException expException $ withAuthConnection host port creds $ do
deleteNode nodeTo
_ <- createRelationship myRelType someProperties nodeFrom nodeTo
return ()
withAuthConnection host port creds $ deleteNode nodeFrom
-- | Test delete and get a relationship
case_CreateDeleteGetRelationship :: Assertion
case_CreateDeleteGetRelationship = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
deleteRelationship r
newN <- getRelationship r
neo4jEqual Nothing newN
teardownRelTests nodeFrom nodeTo r
-- | Test double delete
case_DoubleDeleteRelationship :: Assertion
case_DoubleDeleteRelationship = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
deleteRelationship r
deleteRelationship r
teardownRelTests nodeFrom nodeTo r
-- | Test get relationship by id
case_GetRelationshipById :: Assertion
case_GetRelationshipById = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- getRelationship (relId r)
neo4jEqual (Just r) newN
teardownRelTests nodeFrom nodeTo r
-- | Test get relationship with unexisting id
case_GetUnexistingRelationshipById :: Assertion
case_GetUnexistingRelationshipById = withAuthConnection host port creds $ do
newN <- getRelationship ("unexistingrelationship" :: S.ByteString)
neo4jEqual Nothing newN
-- | Test delete relationship by id
case_DeleteRelationshipById :: Assertion
case_DeleteRelationshipById = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
deleteRelationship (relId r)
teardownRelTests nodeFrom nodeTo r
-- | Test delete unexisting relationship by id
case_DeleteUnexistingRelationshipById :: Assertion
case_DeleteUnexistingRelationshipById = withAuthConnection host port creds $
deleteRelationship ("unexistingrelationship" :: S.ByteString)
-- | Refresh relationship properties from the DB
case_getRelationshipProperties :: Assertion
case_getRelationshipProperties = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
props <- getProperties r
neo4jEqual someProperties props
teardownRelTests nodeFrom nodeTo r
-- | Get relationship properties from a deleted node
case_getDeletedRelationshipProperties :: Assertion
case_getDeletedRelationshipProperties = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runRelIdentifier r
assertException expException $ withAuthConnection host port creds $ do
deleteRelationship r
deleteNode nodeFrom
deleteNode nodeTo
getProperties r
-- | Get a property from a relationship
case_getRelationshipProperty :: Assertion
case_getRelationshipProperty = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
prop <- getProperty r "intarray"
neo4jEqual (M.lookup "intarray" someProperties) prop
teardownRelTests nodeFrom nodeTo r
-- | Get an unexisting property from a relationship
case_getRelationshipUnexistingProperty :: Assertion
case_getRelationshipUnexistingProperty = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
prop <- getProperty r "noproperty"
neo4jEqual Nothing prop
teardownRelTests nodeFrom nodeTo r
-- | Get a property from an unexisting relationship
case_getUnexistingRelationshipProperty :: Assertion
case_getUnexistingRelationshipProperty = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runRelIdentifier r
assertException expException $ withAuthConnection host port creds $ do
teardownRelTests nodeFrom nodeTo r
_ <- getProperty r "noproperty"
return ()
-- | Get change the properties of a relationship
case_changeRelationshipProperties :: Assertion
case_changeRelationshipProperties = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- setProperties r otherProperties
neo4jEqual otherProperties (getRelProperties newN)
renewN <- getRelationship r
neo4jEqual otherProperties (getRelProperties $ fromJust renewN)
teardownRelTests nodeFrom nodeTo newN
where otherProperties = M.insert "newbool" (newval True) someProperties
-- | Get change the properties of a relationship that doesn't exist
case_changeUnexistingRelationshipProperties :: Assertion
case_changeUnexistingRelationshipProperties = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runRelIdentifier r
assertException expException $ withAuthConnection host port creds $ do
deleteRelationship r
deleteNode nodeFrom
deleteNode nodeTo
setProperties r someProperties
-- | Change a property of a relationship
case_changeRelationshipProperty :: Assertion
case_changeRelationshipProperty = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- setProperty r otherValName otherVal
neo4jEqual otherProperties (getRelProperties newN)
renewN <- getRelationship r
neo4jEqual otherProperties (getRelProperties $ fromJust renewN)
teardownRelTests nodeFrom nodeTo newN
where otherProperties = M.insert otherValName otherVal someProperties
otherValName = "int"
otherVal = newval False
-- | Change an array property of a relationship to empty
case_changeRelationshipPropertyToEmpty :: Assertion
case_changeRelationshipPropertyToEmpty = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- setProperty r otherValName otherVal
neo4jEqual otherProperties (getRelProperties newN)
renewN <- getRelationship r
neo4jEqual otherProperties (getRelProperties $ fromJust renewN)
teardownRelTests nodeFrom nodeTo newN
where otherProperties = M.insert otherValName otherVal someProperties
otherValName = "intarray"
otherVal = newval ([] :: [Int64])
-- | Set an unexisting property of a relationship
case_changeRelationshipUnexistingProperty :: Assertion
case_changeRelationshipUnexistingProperty = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- setProperty r otherValName otherVal
neo4jEqual otherProperties (getRelProperties newN)
renewN <- getRelationship r
neo4jEqual otherProperties (getRelProperties $ fromJust renewN)
teardownRelTests nodeFrom nodeTo newN
where otherProperties = M.insert otherValName otherVal someProperties
otherValName = "mynewbool"
otherVal = newval False
-- | Set property of an unexisting node
case_changeUnexistingRelationshipProperty :: Assertion
case_changeUnexistingRelationshipProperty = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runRelIdentifier r
assertException expException $ withAuthConnection host port creds $ do
deleteRelationship r
_ <- setProperty r otherValName otherVal
return ()
withAuthConnection host port creds $ teardownRelTests nodeFrom nodeTo r
where otherValName = "mynewbool"
otherVal = newval False
-- | Delete relationship properties
case_deleteRelationshipProperties :: Assertion
case_deleteRelationshipProperties = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- deleteProperties r
neo4jEqual M.empty (getRelProperties newN)
renewN <- getRelationship r
neo4jEqual M.empty (getRelProperties $ fromJust renewN)
teardownRelTests nodeFrom nodeTo newN
-- | Delete unexisting relationship properties
case_deleteUnexistingRelationshipProperties :: Assertion
case_deleteUnexistingRelationshipProperties = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runRelIdentifier r
assertException expException $ withAuthConnection host port creds $ do
deleteRelationship r
_ <- deleteProperties r
return ()
withAuthConnection host port creds $ teardownRelTests nodeFrom nodeTo r
-- | Delete a relationship property
case_deleteRelationshipProperty :: Assertion
case_deleteRelationshipProperty = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- deleteProperty r valName
neo4jEqual otherProperties (getRelProperties newN)
renewN <- getRelationship r
neo4jEqual otherProperties (getRelProperties $ fromJust renewN)
teardownRelTests nodeFrom nodeTo newN
where otherProperties = M.delete valName someProperties
valName = "int"
-- | Delete an unexisting property from a relationship
case_deleteRelationshipUnexistingProperty :: Assertion
case_deleteRelationshipUnexistingProperty = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
newN <- deleteProperty r valName
neo4jEqual otherProperties (getRelProperties newN)
renewN <- getRelationship r
neo4jEqual otherProperties (getRelProperties $ fromJust renewN)
teardownRelTests nodeFrom nodeTo newN
where otherProperties = M.delete valName someProperties
valName = "noproperty"
-- | Delete a property from an unexisting relationship
case_deleteUnexistingRelationshipProperty :: Assertion
case_deleteUnexistingRelationshipProperty = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runRelIdentifier r
assertException expException $ withAuthConnection host port creds $ do
deleteRelationship r
_ <- deleteProperty r valName
return ()
withAuthConnection host port creds $ teardownRelTests nodeFrom nodeTo r
where valName = "noproperty"
-- | Get relationships for a node
case_GetNodeRelationships :: Assertion
case_GetNodeRelationships = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
-- test getting relationships for the origin node
rsAny <- getRelationships nodeFrom Any []
neo4jEqual [r] rsAny
rsOutgoing <- getRelationships nodeFrom Outgoing []
neo4jEqual [r] rsOutgoing
rsIncoming <- getRelationships nodeFrom Incoming []
neo4jEqual [] rsIncoming
-- test getting relationships for the destination node
rsAnyTo <- getRelationships nodeTo Any []
neo4jEqual [r] rsAnyTo
rsOutgoingTo <- getRelationships nodeTo Outgoing []
neo4jEqual [] rsOutgoingTo
rsIncomingTo <- getRelationships nodeTo Incoming []
neo4jEqual [r] rsIncomingTo
teardownRelTests nodeFrom nodeTo r
-- | Get relationships for an unexisting node
case_GetUnexistingNodeRelationships :: Assertion
case_GetUnexistingNodeRelationships = do
(nodeFrom, nodeTo, r) <- withAuthConnection host port creds setupRelTests
let expException = Neo4jNoEntityException $ runNodeIdentifier nodeFrom
assertException expException $ withAuthConnection host port creds $ do
teardownRelTests nodeFrom nodeTo r
_ <- getRelationships nodeFrom Any []
return ()
-- | Get relationships for a node with multiple relationships
case_GetNodeRelationshipsMultiple :: Assertion
case_GetNodeRelationshipsMultiple = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
r2 <- createRelationship myRelType someOtherProperties nodeTo nodeFrom
rsAny <- getRelationships nodeFrom Any []
neo4jBool (r `elem` rsAny)
neo4jBool (r2 `elem` rsAny)
neo4jEqual 2 (length rsAny)
rsOutgoing <- getRelationships nodeFrom Outgoing []
neo4jEqual [r] rsOutgoing
rsIncoming <- getRelationships nodeFrom Incoming []
neo4jEqual [r2] rsIncoming
deleteRelationship r2
teardownRelTests nodeFrom nodeTo r
-- | Get relationships for a node with a type filter
case_GetNodeRelationshipsWithType :: Assertion
case_GetNodeRelationshipsWithType = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
rsAny <- getRelationships nodeFrom Any [myRelType]
neo4jEqual [r] rsAny
teardownRelTests nodeFrom nodeTo r
-- | Get relationships for a node with an unexisting type filter
case_GetNodeRelationshipsWithUnexistingType :: Assertion
case_GetNodeRelationshipsWithUnexistingType = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
rsAny <- getRelationships nodeFrom Any ["notype"]
neo4jEqual [] rsAny
teardownRelTests nodeFrom nodeTo r
-- | Get relationships for a node with a type filter with multiple elements
case_GetNodeRelationshipsWithTypes :: Assertion
case_GetNodeRelationshipsWithTypes = withAuthConnection host port creds $ do
(nodeFrom, nodeTo, r) <- setupRelTests
-- Create another relationship with another type
r2 <- createRelationship type2 anotherProperties nodeTo nodeFrom
rsAny <- getRelationships nodeFrom Any [myRelType, type2, "notype"]
neo4jBool (r `elem` rsAny)
neo4jBool (r2 `elem` rsAny)
neo4jEqual 2 (length rsAny)
deleteRelationship r2
teardownRelTests nodeFrom nodeTo r
where type2 = "reltype2"
-- | Get all labels in the DB (We don't have control of all the labels the DB has)
case_getLabels :: Assertion
case_getLabels = withAuthConnection host port creds $ do
n <- createNode someProperties
addLabels [lbl] n
lbls <- allLabels
neo4jBool $ lbl `elem` lbls
deleteNode n
where lbl = "label1"
-- | Get labels for a node it doesn't have any
case_getNodeLabelsWithNone :: Assertion
case_getNodeLabelsWithNone = withAuthConnection host port creds $ do
n <- createNode someProperties
lbls <- getLabels n
neo4jEqual [] lbls
deleteNode n
-- | Get labels for an unexisting node
case_getUnexistingNodeLabels :: Assertion
case_getUnexistingNodeLabels = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
_ <- getLabels n
return ()
-- | Add labels to a node and get them
case_getAddAndGetNodeLabels :: Assertion
case_getAddAndGetNodeLabels = withAuthConnection host port creds $ do
n <- createNode someProperties
addLabels [lbl1, lbl2] n
addLabels [lbl3] n
lbls <- getLabels n
neo4jEqual 3 (length lbls)
neo4jBool $ all (`elem` lbls) [lbl1, lbl2, lbl3]
deleteNode n
where lbl1 = "mylabel1"
lbl2 = "mylabel2"
lbl3 = "mylabel3"
-- | Add labels to an unexisting node
case_addUnexistingNodeLabels :: Assertion
case_addUnexistingNodeLabels = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
addLabels ["mylabel"] n
-- | Change node labels
case_changeNodeLabels :: Assertion
case_changeNodeLabels = withAuthConnection host port creds $ do
n <- createNode someProperties
addLabels [lbl1, lbl2] n
changeLabels [lbl3] n
lbls <- getLabels n
neo4jEqual [lbl3] lbls
deleteNode n
where lbl1 = "mylabel1"
lbl2 = "mylabel2"
lbl3 = "otherlabel"
-- | Change node labels to empty
case_changeNodeLabelsToEmpty :: Assertion
case_changeNodeLabelsToEmpty = withAuthConnection host port creds $ do
n <- createNode someProperties
addLabels [lbl1, lbl2] n
changeLabels [] n
lbls <- getLabels n
neo4jEqual [] lbls
deleteNode n
where lbl1 = "mylabel1"
lbl2 = "mylabel2"
-- | Change labels for an unexisting node
case_changeUnexistingNodeLabels :: Assertion
case_changeUnexistingNodeLabels = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
changeLabels ["mylabel"] n
-- | Remove a label from a node
case_removeNodeLabel :: Assertion
case_removeNodeLabel = withAuthConnection host port creds $ do
n <- createNode someProperties
addLabels [lbl1, lbl2] n
removeLabel lbl1 n
lbls <- getLabels n
neo4jEqual [lbl2] lbls
deleteNode n
where lbl1 = "mylabel1"
lbl2 = "mylabel2"
-- | Remove an unexisting label from a node (nothing should happen)
case_removeNodeUnexistingLabel :: Assertion
case_removeNodeUnexistingLabel = withAuthConnection host port creds $ do
n <- createNode someProperties
addLabels [lbl1] n
removeLabel "nolabel" n
lbls <- getLabels n
neo4jEqual [lbl1] lbls
deleteNode n
where lbl1 = "mylabel1"
-- | Remove label for an unexisting node
case_removeUnexistingNodeLabel :: Assertion
case_removeUnexistingNodeLabel = do
n <- withAuthConnection host port creds $ createNode someProperties
let expException = Neo4jNoEntityException $ runNodeIdentifier n
assertException expException $ withAuthConnection host port creds $ do
deleteNode n
removeLabel "mylabel" n
-- | Get all nodes with a label
case_allNodesWithLabel :: Assertion
case_allNodesWithLabel = withAuthConnection host port creds $ do
n1 <- createNode someProperties
n2 <- createNode someProperties
n3 <- createNode someProperties
addLabels [lbl1, lbl2] n1
addLabels [lbl2] n2
addLabels [lbl1] n3
ns <- getNodesByLabelAndProperty lbl1 Nothing
neo4jEqual 2 (length ns)
neo4jBool $ all (`elem` ns) [n1, n3]
ns2 <- getNodesByLabelAndProperty "nolbl" Nothing
neo4jEqual [] ns2
mapM_ deleteNode [n1, n2, n3]
where lbl1 = "lbl1"
lbl2 = "lbl2"
-- | Get all nodes with a label and a property
case_allNodesWithLabelAndProperty :: Assertion
case_allNodesWithLabelAndProperty = withAuthConnection host port creds $ do
n1 <- createNode someProperties
n2 <- createNode someProperties
n3 <- createNode anotherProperties
addLabels [lbl1, lbl2] n1
addLabels [lbl2] n2
addLabels [lbl1] n3
ns <- getNodesByLabelAndProperty lbl1 $ Just ("doublearray", newval [0.1, -12.23 :: Double])
neo4jEqual [n1] ns
ns2 <- getNodesByLabelAndProperty lbl1 $ Just ("doublearray", newval [0.1, -12.22 :: Double])
neo4jEqual [] ns2
mapM_ deleteNode [n1, n2, n3]
where lbl1 = "lbl1"
lbl2 = "lbl2"
-- | Create, get and destroy index
case_createGetDropIndex :: Assertion
case_createGetDropIndex = withAuthConnection host port creds $ do
dropIndex lbl prop1
dropIndex lbl prop2
dropIndex lbl2 prop1
dropIndex lbl2 prop2
idx1 <- createIndex lbl prop1
idx2 <- createIndex lbl prop2
idx3 <- createIndex lbl2 prop1
idx4 <- createIndex lbl2 prop2
idxs <- getIndexes lbl
neo4jBool $ all (`elem` idxs) [idx1, idx2]
neo4jBool $ all (not . (`elem` idxs)) [idx3, idx4]
idxs2 <- getIndexes lbl2
neo4jBool $ all (not . (`elem` idxs2)) [idx1, idx2]
neo4jBool $ all (`elem` idxs2) [idx3, idx4]
dropIndex lbl prop1
dropIndex lbl prop2
dropIndex lbl2 prop1
dropIndex lbl2 prop2
idxs3 <- getIndexes lbl
idxs4 <- getIndexes lbl2
neo4jBool $ all (not . (`elem` idxs3)) [idx1, idx2]
neo4jBool $ all (not . (`elem` idxs4)) [idx3, idx4]
where lbl = "mylabel11"
lbl2 = "mylabel2"
prop1 = "myprop"
prop2 = "myprop2"
-- | Test batch, create a node and get it again
case_batchCreateGetNode :: Assertion
case_batchCreateGetNode = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n <- B.createNode someProperties
B.getNode n
neo4jEqual 1 (length $ G.getNodes g)
neo4jBool $ someProperties `elem` map getNodeProperties (G.getNodes g)
deleteNode (head $ G.getNodes g)
-- | Test batch, create two nodes in a batch
case_batchCreate2Nodes :: Assertion
case_batchCreate2Nodes = withAuthConnection host port creds $ do
g <- B.runBatch $ do
_ <- B.createNode someProperties
B.createNode anotherProperties
neo4jEqual 2 (length $ G.getNodes g)
neo4jBool $ someProperties `elem` map getNodeProperties (G.getNodes g)
neo4jBool $ anotherProperties `elem` map getNodeProperties (G.getNodes g)
mapM_ deleteNode (G.getNodes g)
-- | Test batch, create and delete
case_batchCreateDeleteNode :: Assertion
case_batchCreateDeleteNode = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n <- B.createNode someProperties
B.deleteNode n
neo4jEqual 0 (length $ G.getNodes g)
-- | Test batch, create two nodes and two relationships between them
case_batchCreateRelationships :: Assertion
case_batchCreateRelationships = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
_ <- B.createRelationship "type1" someOtherProperties n1 n2
B.createRelationship "type2" someProperties n2 n1
neo4jEqual 2 (length $ G.getNodes g)
neo4jEqual 2 (length $ G.getRelationships g)
neo4jBool $ someOtherProperties `elem` map getRelProperties (G.getRelationships g)
neo4jBool $ someProperties `elem` map getRelProperties (G.getRelationships g)
neo4jBool $ "type1" `elem` map getRelType (G.getRelationships g)
neo4jBool $ "type2" `elem` map getRelType (G.getRelationships g)
let r1 : r2 : [] = G.getRelationships g
neo4jEqual (G.getRelationshipNodeFrom r1 g) (G.getRelationshipNodeTo r2 g)
neo4jEqual (G.getRelationshipNodeFrom r2 g) (G.getRelationshipNodeTo r1 g)
_ <- B.runBatch $ do
mapM_ B.deleteRelationship (G.getRelationships g)
mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, create and delete a relationship
case_batchCreateDelRelationships :: Assertion
case_batchCreateDelRelationships = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
r <- B.createRelationship "type1" someOtherProperties n1 n2
B.deleteRelationship r
neo4jEqual 2 (length $ G.getNodes g)
neo4jEqual 0 (length $ G.getRelationships g)
mapM_ deleteRelationship (G.getRelationships g)
mapM_ deleteNode (G.getNodes g)
-- | Test batch getRelationshipFrom
case_batchRelationshipNodeFrom :: Assertion
case_batchRelationshipNodeFrom = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
B.createRelationship "type1" someOtherProperties n1 n2
g2 <- B.runBatch $ B.getRelationshipFrom (head $ G.getRelationships g)
neo4jEqual 1 (length $ G.getNodes g2)
neo4jEqual 0 (length $ G.getRelationships g2)
neo4jBool $ someProperties `elem` map getNodeProperties (G.getNodes g2)
_ <- B.runBatch $ do
mapM_ B.deleteRelationship (G.getRelationships g)
mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch getRelationshipTo
case_batchRelationshipNodeTo :: Assertion
case_batchRelationshipNodeTo = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
B.createRelationship "type1" someOtherProperties n1 n2
g2 <- B.runBatch $ B.getRelationshipTo (head $ G.getRelationships g)
neo4jEqual 1 (length $ G.getNodes g2)
neo4jEqual 0 (length $ G.getRelationships g2)
neo4jBool $ anotherProperties `elem` map getNodeProperties (G.getNodes g2)
_ <- B.runBatch $ do
mapM_ B.deleteRelationship (G.getRelationships g)
mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, get all relationships with filter
case_batchGetRelationships :: Assertion
case_batchGetRelationships = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
_ <- B.createRelationship "type1" someOtherProperties n1 n2
B.createRelationship "type2" someProperties n2 n1
g2 <- B.runBatch $ do
let n = head $ G.getNodes g
B.getRelationships n Any ["type1", "type2"]
neo4jEqual 2 (length $ G.getRelationships g2)
neo4jBool $ someOtherProperties `elem` map getRelProperties (G.getRelationships g2)
neo4jBool $ someProperties `elem` map getRelProperties (G.getRelationships g2)
neo4jBool $ "type1" `elem` map getRelType (G.getRelationships g2)
neo4jBool $ "type2" `elem` map getRelType (G.getRelationships g2)
mapM_ deleteRelationship (G.getRelationships g)
mapM_ deleteNode (G.getNodes g)
-- | Test batch, set properties
case_batchSetProperties :: Assertion
case_batchSetProperties = withAuthConnection host port creds $ do
let newProperties = M.fromList ["croqueta" |: ("2" :: T.Text)]
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
r <- B.createRelationship "type1" someOtherProperties n1 n2
_ <- B.setProperties n1 newProperties
B.setProperties r newProperties
neo4jEqual 2 (length $ G.getNodes g)
neo4jEqual 1 (length $ G.getRelationships g)
neo4jBool $ newProperties `elem` map getRelProperties (G.getRelationships g)
neo4jBool $ newProperties `elem` map getNodeProperties (G.getNodes g)
_ <- B.runBatch $ do
mapM_ B.deleteRelationship (G.getRelationships g)
mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, set property
case_batchSetProperty :: Assertion
case_batchSetProperty = withAuthConnection host port creds $ do
let key = "hola"
let val = newval False
let newSomeProperties = M.insert key val someProperties
let newSomeOtherProperties = M.insert key val someOtherProperties
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
r <- B.createRelationship "type1" someOtherProperties n1 n2
_ <- B.setProperty n1 key val
B.setProperty r key val
neo4jEqual 2 (length $ G.getNodes g)
neo4jEqual 1 (length $ G.getRelationships g)
neo4jBool $ newSomeProperties `elem` map getNodeProperties (G.getNodes g)
neo4jBool $ newSomeOtherProperties `elem` map getRelProperties (G.getRelationships g)
_ <- B.runBatch $ do
mapM_ B.deleteRelationship (G.getRelationships g)
mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, delete properties
case_batchDeleteProperties :: Assertion
case_batchDeleteProperties = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
r <- B.createRelationship "type1" someOtherProperties n1 n2
_ <- B.deleteProperties n1
B.deleteProperties r
neo4jEqual 2 (length $ G.getNodes g)
neo4jEqual 1 (length $ G.getRelationships g)
neo4jBool $ emptyProperties `elem` map getRelProperties (G.getRelationships g)
neo4jBool $ emptyProperties `elem` map getNodeProperties (G.getNodes g)
_ <- B.runBatch $ do
mapM_ B.deleteRelationship (G.getRelationships g)
mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, delete property
case_batchDeleteProperty :: Assertion
case_batchDeleteProperty= withAuthConnection host port creds $ do
let key = "mytext"
let newSomeProperties = M.delete key someProperties
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
r <- B.createRelationship "type1" someProperties n1 n2
_ <- B.deleteProperty n1 key
B.deleteProperty r key
neo4jEqual 2 (length $ G.getNodes g)
neo4jEqual 1 (length $ G.getRelationships g)
neo4jBool $ newSomeProperties `elem` map getNodeProperties (G.getNodes g)
neo4jBool $ newSomeProperties `elem` map getRelProperties (G.getRelationships g)
_ <- B.runBatch $ do
mapM_ B.deleteRelationship (G.getRelationships g)
mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, delete an unknown property, it should raise an exception
case_batchDeleteUnknownProperty :: Assertion
case_batchDeleteUnknownProperty= do
n <- withAuthConnection host port creds $ createNode someProperties
let excMsg = "Node[" <> TE.decodeUtf8 (nodeId n) <>"] does not have a property \"" <> prop <> "\""
let expException = Neo4jNoSuchProperty excMsg
assertException expException $ withAuthConnection host port creds $ do
g <- B.runBatch $ B.deleteProperty n prop
neo4jEqual G.empty g -- Doing this to force evaluation
withAuthConnection host port creds $ deleteNode n
where prop = "noprop" :: T.Text
-- | Test batch, set add labels
case_batchAddLabels :: Assertion
case_batchAddLabels = withAuthConnection host port creds $ do
let label1 = "label1"
let label2 = "label2"
let label3 = "label3"
let labelset = HS.fromList [label1, label2, label3]
g <- B.runBatch $ do
n1 <- B.createNode someProperties
_ <- B.createNode anotherProperties
_ <- B.addLabels [label1, label2] n1
B.addLabels [label3] n1
neo4jEqual 2 (length $ G.getNodes g)
neo4jBool $ labelset `elem` map (`G.getNodeLabels` g) (G.getNodes g)
neo4jBool $ HS.empty `elem` map (`G.getNodeLabels` g) (G.getNodes g)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, change labels
case_batchChangeLabels :: Assertion
case_batchChangeLabels = withAuthConnection host port creds $ do
let label1 = "label1"
let label2 = "label2"
let label3 = "label3"
let labelset = HS.fromList [label2]
g <- B.runBatch $ do
n1 <- B.createNode someProperties
_ <- B.addLabels [label1, label2, label3] n1
B.changeLabels [label2] n1
neo4jBool $ labelset `elem` map (`G.getNodeLabels` g) (G.getNodes g)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, remove label
case_batchRemoveLabel :: Assertion
case_batchRemoveLabel = withAuthConnection host port creds $ do
let label1 = "label1"
let label2 = "label2"
let label3 = "label3"
let labelset = HS.fromList [label2, label3]
g <- B.runBatch $ do
n1 <- B.createNode someProperties
_ <- B.addLabels [label1, label2, label3] n1
B.removeLabel label1 n1
neo4jBool $ labelset `elem` map (`G.getNodeLabels` g) (G.getNodes g)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes g)
return ()
-- | Test batch, get all nodes with a label
case_batchAllNodesWithLabel :: Assertion
case_batchAllNodesWithLabel = withAuthConnection host port creds $ do
gp <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode someProperties
n3 <- B.createNode someProperties
_ <- B.addLabels [lbl1, lbl2] n1
_ <- B.addLabels [lbl2] n2
B.addLabels [lbl1] n3
g <- B.runBatch $ B.getNodesByLabelAndProperty lbl1 Nothing
neo4jEqual 2 (length $ G.getNodes g)
neo4jBool $ all (`elem` G.getNodes gp) (G.getNodes g)
gempty <- B.runBatch $ B.getNodesByLabelAndProperty "nolbl" Nothing
neo4jEqual [] (G.getNodes gempty)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where lbl1 = "la21bl1"
lbl2 = "la21bl2"
-- | Test batch, get all nodes with a label and a property
case_batchAllNodesWithLabelAndProperty :: Assertion
case_batchAllNodesWithLabelAndProperty = withAuthConnection host port creds $ do
gp <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode someProperties
n3 <- B.createNode anotherProperties
_ <- B.addLabels [lbl1, lbl2] n1
_ <- B.addLabels [lbl2] n2
B.addLabels [lbl1] n3
g <- B.runBatch $ B.getNodesByLabelAndProperty lbl1 $ Just ("doublearray", newval [0.1, -12.23 :: Double])
neo4jEqual 1 (length $ G.getNodes g)
neo4jBool $ all (`elem` G.getNodes gp) (G.getNodes g)
g2 <- B.runBatch $ B.getNodesByLabelAndProperty lbl1 $ Just ("doublearray", newval [0.1, -12.22 :: Double])
neo4jEqual [] (G.getNodes g2)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where lbl1 = "lbl1"
lbl2 = "lbl2"
-- | Test cypher basic test
case_cypherBasic :: Assertion
case_cypherBasic = withAuthConnection host port creds $ do
-- create initial data
gp <- B.runBatch $ do
n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
B.createRelationship "know" M.empty n1 n2
-- actual test
res <- C.cypher query params
neo4jBool $ C.isSuccess res
neo4jEqual ["TYPE(r)"] (C.cols $ C.fromSuccess res)
neo4jBool $ ["know"] `elem` (C.vals $ C.fromSuccess res)
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "MATCH (x {name: {startName}})-[r]-(friend) WHERE friend.name = {name} RETURN TYPE(r)"
params = M.fromList [("startName", C.newparam ("I" :: T.Text)), ("name", C.newparam ("you" :: T.Text))]
-- | Test cypher create a node
case_cypherCreateNode :: Assertion
case_cypherCreateNode = withAuthConnection host port creds $ do
res <- C.cypher query params
neo4jBool $ C.isSuccess res
let gp = G.addCypher (C.fromSuccess res) G.empty
let props = M.fromList ["name" |: ("Andres" :: T.Text)]
neo4jEqual 1 (length $ G.getNodes gp)
neo4jBool $ props `elem` map getNodeProperties (G.getNodes gp)
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "CREATE (n:Person { name : {name} }) RETURN n"
params = M.fromList [("name", C.newparam ("Andres" :: T.Text))]
-- | Test cypher create a node with multiple properties
case_cypherCreateNodeMultipleProperties :: Assertion
case_cypherCreateNodeMultipleProperties = withAuthConnection host port creds $ do
res <- C.cypher query params
neo4jBool $ C.isSuccess res
let gp = G.addCypher (C.fromSuccess res) G.empty
neo4jEqual 1 (length $ G.getNodes gp)
neo4jBool $ props `elem` map getNodeProperties (G.getNodes gp)
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "CREATE (n:Person { props }) RETURN n"
props = M.fromList ["name" |: ("Michael" :: T.Text), "position" |: ("Developer" :: T.Text),
"awesome" |: True, "children" |: (3 :: Int64)]
params = M.fromList [("props", C.ParamProperties props)]
-- | Test cypher create multiple nodes
case_cypherCreateMultipleNodes :: Assertion
case_cypherCreateMultipleNodes = withAuthConnection host port creds $ do
res <- C.cypher query params
neo4jBool $ C.isSuccess res
let gp = G.addCypher (C.fromSuccess res) G.empty
neo4jEqual 2 (length $ G.getNodes gp)
neo4jBool $ propsA `elem` map getNodeProperties (G.getNodes gp)
neo4jBool $ propsB `elem` map getNodeProperties (G.getNodes gp)
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "CREATE (n:Person { props }) RETURN n"
propsA = M.fromList ["name" |: ("Andres" :: T.Text), "position" |: ("Developer" :: T.Text)]
propsB = M.fromList ["name" |: ("Michael" :: T.Text), "position" |: ("Developer" :: T.Text)]
params = M.fromList [("props", C.ParamPropertiesArray [propsA, propsB])]
-- | Test cypher set all properties on a node
case_cypherSetAllNodeProperties :: Assertion
case_cypherSetAllNodeProperties = withAuthConnection host port creds $ do
res <- C.cypher query params
neo4jBool $ C.isSuccess res
let gp = G.addCypher (C.fromSuccess res) G.empty
neo4jEqual 1 (length $ G.getNodes gp)
neo4jBool $ props `elem` map getNodeProperties (G.getNodes gp)
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "CREATE (n:Person { name: 'this property is to be deleted' } ) SET n = { props } RETURN n"
props = M.fromList ["name" |: ("Michael" :: T.Text), "position" |: ("Developer" :: T.Text),
"awesome" |: True, "children" |: (3 :: Int64)]
params = M.fromList [("props", C.ParamProperties props)]
-- | Test cypher basic query
case_cypherBasicQuery :: Assertion
case_cypherBasicQuery = withAuthConnection host port creds $ do
-- create initial data
gp <- B.runBatch $ do
n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
n3 <- B.createNode $ M.fromList ["name" |: ("him" :: T.Text), "age" |: (25 :: Int64)]
_ <- B.createRelationship "know" M.empty n1 n2
B.createRelationship "know" M.empty n1 n3
-- actual test
res <- C.cypher query params
neo4jBool $ C.isSuccess res
neo4jEqual ["type(r)", "n.name", "n.age"] (C.cols $ C.fromSuccess res)
neo4jBool $ ["know", "him", J.Number 25] `elem` (C.vals $ C.fromSuccess res)
neo4jBool $ ["know", "you", J.Null] `elem` (C.vals $ C.fromSuccess res)
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "MATCH (x {name: 'I'})-[r]->(n) RETURN type(r), n.name, n.age"
params = M.empty
-- | Test cypher basic query get relationships
case_cypherBasicQueryGetRels :: Assertion
case_cypherBasicQueryGetRels = withAuthConnection host port creds $ do
-- create initial data
gp <- B.runBatch $ do
n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
n3 <- B.createNode $ M.fromList ["name" |: ("him" :: T.Text), "age" |: (25 :: Int64)]
_ <- B.createRelationship "know" M.empty n1 n2
B.createRelationship "know" M.empty n1 n3
-- actual test
res <- C.cypher query params
neo4jBool $ C.isSuccess res
let gres = G.addCypher (C.fromSuccess res) G.empty
neo4jBool $ (length $ G.getRelationships gres) >= 2
neo4jBool $ all (\r -> getRelType r == "know") (G.getRelationships gres)
neo4jEqual ["r"] (C.cols $ C.fromSuccess res)
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "MATCH (x {name: 'I'})-[r]->(n) RETURN r"
params = M.empty
-- | Test cypher nested results
case_cypherNestedResults :: Assertion
case_cypherNestedResults = withAuthConnection host port creds $ do
-- create initial data
gp <- B.runBatch $ do
n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
B.createRelationship "know" M.empty n1 n2
-- actual test
res <- C.cypher query params
neo4jBool $ C.isSuccess res
neo4jEqual ["collect(n.name)"] (C.cols $ C.fromSuccess res)
let v = case (head $ head $ C.vals $ C.fromSuccess res) of
J.Array vec -> vec
_ -> V.empty
neo4jBool $ "you" `V.elem` v
neo4jBool $ "I" `V.elem` v
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "MATCH (n) WHERE n.name in ['I', 'you'] RETURN collect(n.name)"
params = M.empty
-- | Test cypher errors
case_cypherError :: Assertion
case_cypherError = withAuthConnection host port creds $ do
-- create initial data
gp <- B.runBatch $ do
B.createNode $ M.fromList ["age" |: (26 :: Int64)]
-- actual test
res <- C.cypher query params
neo4jBool $ res `elem` [Left "BadInputException", Left "ArithmeticException"]
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "MATCH (x) WHERE has(x.age) RETURN x.age / 0"
params = M.empty
-- | Test lone transaction cypher basic query
case_loneTransactionBasicQuery :: Assertion
case_loneTransactionBasicQuery = withAuthConnection host port creds $ do
-- create initial data
gp <- B.runBatch $ do
n1 <- B.createNode $ M.fromList ["name" |: ("I" :: T.Text)]
n2 <- B.createNode $ M.fromList ["name" |: ("you" :: T.Text)]
n3 <- B.createNode $ M.fromList ["name" |: ("him" :: T.Text), "age" |: (25 :: Int64)]
_ <- B.createRelationship "know" M.empty n1 n2
B.createRelationship "know" M.empty n1 n3
-- actual test
res <- TC.loneQuery query params
neo4jBool $ TC.isSuccess res
neo4jEqual ["type(r)", "n.name", "n.age"] (TC.cols $ TC.fromSuccess res)
neo4jBool $ ["know", "him", J.Number 25] `elem` (TC.vals $ TC.fromSuccess res)
neo4jBool $ ["know", "you", J.Null] `elem` (TC.vals $ TC.fromSuccess res)
neo4jEqual TC.emptyStats (TC.stats $ TC.fromSuccess res)
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "MATCH (x {name: 'I'})-[r]->(n) RETURN type(r), n.name, n.age"
params = M.empty
-- | Test cypher errors in a transaction
case_cypherTransactionError :: Assertion
case_cypherTransactionError = withAuthConnection host port creds $ do
-- create initial data
gp <- B.runBatch $ B.createNode $ M.fromList ["age" |: (26 :: Int64)]
-- actual test
res <- TC.loneQuery query params
neo4jEqual (Left ("Neo.ClientError.Statement.ArithmeticError","/ by zero")) res
-- cleanup
_ <- B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
return ()
where query = "MATCH (x) WHERE has(x.age) RETURN x.age / 0"
params = M.empty
-- | Test a cypher transaction
case_cypherTransaction :: Assertion
case_cypherTransaction = withAuthConnection host port creds $ do
res <- TC.runTransaction $ do
result <- TC.cypher "CREATE (pere: PERSON {age: {age}}) CREATE (pau: PERSON {props}) \
\CREATE p1 = (pere)-[:KNOWS]->(pau) RETURN pere, pau, p1, pere.age" $
M.fromList [("age", TC.newparam (78 :: Int64)),
("props", TC.ParamProperties $ M.fromList["age" |: (99 :: Int64)])]
voidIO $ assertEqual "" ["pere", "pau", "p1", "pere.age"] (TC.cols result)
voidIO $ assertEqual "" (TC.Stats True 2 0 2 1 0 2 0 0 0 0 0) (TC.stats result)
let vals = TC.vals result
voidIO $ assertEqual "" 1 (length vals)
voidIO $ assertEqual "" 4 (length $ head vals)
voidIO $ assertEqual "" (J.Number 78.0) (head vals !! 3)
voidIO $ assertEqual "" 1 (length $ TC.graph result)
voidIO $ assertEqual "" 1 (length $ G.getRelationships (head $ TC.graph result))
voidIO $ assertEqual "" 2 (length $ G.getNodes (head $ TC.graph result))
return result
neo4jBool $ TC.isSuccess res
let (Right tresult) = res
let gp = head $ TC.graph tresult
void $ B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
void $ B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
where voidIO x = void $ liftIO x
-- | Test a cypher transaction with a explicit commit
case_cypherTransactionExplicitCommit :: Assertion
case_cypherTransactionExplicitCommit = withAuthConnection host port creds $ do
res <- TC.runTransaction $ do
result <- TC.cypher "CREATE (pere: PERSON {age: {age}}) CREATE (pau: PERSON {props}) \
\CREATE p1 = (pere)-[:KNOWS]->(pau) RETURN pere, pau, p1, pere.age" $
M.fromList [("age", TC.newparam (78 :: Int64)),
("props", TC.ParamProperties $ M.fromList["age" |: (99 :: Int64)])]
void $ TC.cypher "CREATE (pep: PERSON {age: 55})" M.empty
TC.commit
return result
neo4jBool $ TC.isSuccess res
let (Right result) = res
voidIO $ assertEqual "" ["pere", "pau", "p1", "pere.age"] (TC.cols result)
voidIO $ assertEqual "" (TC.Stats True 2 0 2 1 0 2 0 0 0 0 0) (TC.stats result)
let vals = TC.vals result
voidIO $ assertEqual "" 1 (length vals)
voidIO $ assertEqual "" 4 (length $ head vals)
voidIO $ assertEqual "" (J.Number 78.0) (head vals !! 3)
voidIO $ assertEqual "" 1 (length $ TC.graph result)
voidIO $ assertEqual "" 1 (length $ G.getRelationships (head $ TC.graph result))
voidIO $ assertEqual "" 2 (length $ G.getNodes (head $ TC.graph result))
let gp = head $ TC.graph result
void $ B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
void $ B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
where voidIO x = void $ liftIO x
-- | Test a cypher transaction with a keepalive
case_cypherTransactionKeepAlive :: Assertion
case_cypherTransactionKeepAlive = withAuthConnection host port creds $ do
res <- TC.runTransaction $ do
TC.keepalive
void $ TC.cypher "CREATE (pep: PERSON {age: 55})" M.empty
TC.keepalive
result <- TC.cypher "CREATE (pere: PERSON {age: {age}}) CREATE (pau: PERSON {props}) \
\CREATE p1 = (pere)-[:KNOWS]->(pau) RETURN pere, pau, p1, pere.age" $
M.fromList [("age", TC.newparam (78 :: Int64)),
("props", TC.ParamProperties $ M.fromList["age" |: (99 :: Int64)])]
return result
neo4jBool $ TC.isSuccess res
let (Right result) = res
voidIO $ assertEqual "" ["pere", "pau", "p1", "pere.age"] (TC.cols result)
voidIO $ assertEqual "" (TC.Stats True 2 0 2 1 0 2 0 0 0 0 0) (TC.stats result)
let vals = TC.vals result
voidIO $ assertEqual "" 1 (length vals)
voidIO $ assertEqual "" 4 (length $ head vals)
voidIO $ assertEqual "" (J.Number 78.0) (head vals !! 3)
voidIO $ assertEqual "" 1 (length $ TC.graph result)
voidIO $ assertEqual "" 1 (length $ G.getRelationships (head $ TC.graph result))
voidIO $ assertEqual "" 2 (length $ G.getNodes (head $ TC.graph result))
let gp = head $ TC.graph result
void $ B.runBatch $ mapM_ B.deleteRelationship (G.getRelationships gp)
void $ B.runBatch $ mapM_ B.deleteNode (G.getNodes gp)
where voidIO x = void $ liftIO x
-- | Test a cypher transaction with an error
case_cypherErrorInTransaction :: Assertion
case_cypherErrorInTransaction = withAuthConnection host port creds $ do
res <- TC.runTransaction $ do
-- query with wrong syntax
void $ TC.cypher "i" M.empty
TC.cypher "CREATE (pere: PERSON {age: {age}}) CREATE (pau: PERSON {props}) \
\CREATE p1 = (pere)-[:KNOWS]->(pau) RETURN pere, pau, p1, pere.age" $
M.fromList [("age", TC.newparam (78 :: Int64)),
("props", TC.ParamProperties $ M.fromList["age" |: (99 :: Int64)])]
neo4jBool $ not $ TC.isSuccess res
neo4jEqual (Left ("Neo.ClientError.Statement.InvalidSyntax", "")) (procRes res)
where procRes r@(Right _) = r
procRes r@(Left (err, _))= Left (err, "")
-- | Test a cypher rollback transaction
case_cypherTransactionRollback :: Assertion
case_cypherTransactionRollback = withAuthConnection host port creds $ do
void $ TC.runTransaction $ do
void $ TC.cypher "CREATE (pepe: PERSON {age: 55})" M.empty
result <- TC.cypher "CREATE (pere: PERSON {age: {age}}) CREATE (pau: PERSON {props}) \
\CREATE p1 = (pere)-[:KNOWS]->(pau) RETURN pere, pau, p1, pere.age" $
M.fromList [("age", TC.newparam (78 :: Int64)),
("props", TC.ParamProperties $ M.fromList["age" |: (99 :: Int64)])]
TC.rollback
return result
-- | Test a cypher rollback and leave transaction
case_cypherTransactionRollbackAndLeave :: Assertion
case_cypherTransactionRollbackAndLeave = withAuthConnection host port creds $ do
res <- TC.runTransaction $ do
void $ TC.cypher "CREATE (pepe: PERSON {age: 55})" M.empty
result <- TC.cypher "CREATE (pere: PERSON {age: {age}}) CREATE (pau: PERSON {props}) \
\CREATE p1 = (pere)-[:KNOWS]->(pau) RETURN pere, pau, p1, pere.age" $
M.fromList [("age", TC.newparam (78 :: Int64)),
("props", TC.ParamProperties $ M.fromList["age" |: (99 :: Int64)])]
TC.rollbackAndLeave "My message"
TC.commit
TC.rollback
return result
neo4jEqual (Left ("Rollback", "My message")) res
-- | Test issuing a commits after a rollback
case_cypherTransactionEnded :: Assertion
case_cypherTransactionEnded = assertException expException $ withAuthConnection host port creds $ do
void $ TC.runTransaction $ do
void $ TC.cypher "CREATE (pepe: PERSON {age: 55})" M.empty
result <- TC.cypher "CREATE (pere: PERSON {age: {age}}) CREATE (pau: PERSON {props}) \
\CREATE p1 = (pere)-[:KNOWS]->(pau) RETURN pere, pau, p1, pere.age" $
M.fromList [("age", TC.newparam (78 :: Int64)),
("props", TC.ParamProperties $ M.fromList["age" |: (99 :: Int64)])]
TC.rollback
TC.commit
return result
where expException = TransactionEndedExc
-- | Test graph union op
case_graphUnion :: Assertion
case_graphUnion = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
void $ B.addLabels ["a"] n1
_ <- B.createRelationship "type1" someOtherProperties n1 n2
B.createRelationship "type2" someProperties n2 n1
g2 <- B.runBatch $ do
n1 <- B.createNode someOtherProperties
n2 <- B.createNode anotherProperties
void $ B.addLabels ["b"] n1
_ <- B.createRelationship "type1" someOtherProperties n1 n2
B.createRelationship "type2" someProperties n2 n1
let g3 = g `G.union` g2
neo4jEqual 4 (length $ G.getNodes g3)
neo4jEqual 4 (length $ G.getRelationships g3)
neo4jBool $ someOtherProperties `elem` map getRelProperties (G.getRelationships g3)
neo4jBool $ someProperties `elem` map getRelProperties (G.getRelationships g3)
neo4jBool $ someOtherProperties `elem` map getNodeProperties (G.getNodes g3)
neo4jBool $ someProperties `elem` map getNodeProperties (G.getNodes g3)
neo4jBool $ "type1" `elem` map getRelType (G.getRelationships g3)
neo4jBool $ "type2" `elem` map getRelType (G.getRelationships g3)
neo4jBool $ "a" `elem` (join $ map (HS.toList . (flip G.getNodeLabels g3)) (G.getNodes g3))
neo4jBool $ "b" `elem` (join $ map (HS.toList . (flip G.getNodeLabels g3)) (G.getNodes g3))
mapM_ deleteRelationship (G.getRelationships g3)
mapM_ deleteNode (G.getNodes g3)
-- | Test graph difference op
case_graphDifference :: Assertion
case_graphDifference = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
void $ B.addLabels ["a"] n1
_ <- B.createRelationship "type1" someOtherProperties n1 n2
B.createRelationship "type2" someProperties n2 n1
let g2 = g `G.difference` g
neo4jEqual 0 (length $ G.getRelationships g2)
neo4jEqual 0 (length $ G.getNodes g2)
let subGraph = G.deleteNode (head $ G.getNodes g) g
let g3 = g `G.difference` (G.deleteRelationship (head $ G.getRelationships subGraph) subGraph)
neo4jEqual 1 (length $ G.getRelationships g3)
neo4jEqual 1 (length $ G.getNodes g3)
-- | Test graph intersection op
case_graphIntersection :: Assertion
case_graphIntersection = withAuthConnection host port creds $ do
g <- B.runBatch $ do
n1 <- B.createNode someProperties
n2 <- B.createNode anotherProperties
void $ B.addLabels ["a"] n1
_ <- B.createRelationship "type1" someOtherProperties n1 n2
B.createRelationship "type2" someProperties n2 n1
g2 <- B.runBatch $ do
B.createNode someProperties
let g3 = G.addNode (head $ G.getNodes g) g2
let g4 = g `G.intersection` (G.addRelationship (head $ G.getRelationships g) g3)
neo4jEqual 1 (length $ G.getRelationships g4)
neo4jEqual 1 (length $ G.getNodes g4)
neo4jEqual (head $ G.getRelationships g) (head $ G.getRelationships g4)
neo4jEqual (head $ G.getNodes g) (head $ G.getNodes g4)
-- | Environment for traversal tests
setUpTraversalTest :: Neo4j G.Graph
setUpTraversalTest = B.runBatch $ do
root <- _createNode "Root"
johan <- _createNode "Johan"
mattias <- _createNode "Mattias"
emil <- _createNode "Emil"
peter <- _createNode "Peter"
tobias <- _createNode "Tobias"
sara <- _createNode "Sara"
gumersindo <- _createNode "Gumersindo"
_createRel "Root-Johan" "knows" root johan
_createRel "Root-Mattias" "knows" root mattias
_createRel "Johan-Emil" "knows" johan emil
_createRel "Emil-Peter" "knows" emil peter
_createRel "Emil-Tobias" "knows" emil tobias
_createRel "Tobias-Sara" "loves" tobias sara
_createRel "Gumersindo-Tobias" "hates" gumersindo tobias
_createRel "Gumersindo-Sara" "admires" sara gumersindo
where _createNode name = B.createNamedNode name $ M.fromList ["name" |: (fromString name :: T.Text)]
_createRel name t from to = void $ B.createNamedRelationship name t M.empty from to
-- | clean up a traversal test
cleanUpTraversalTest :: G.Graph -> Neo4j ()
cleanUpTraversalTest g = void $ B.runBatch $ do
mapM_ B.deleteRelationship (G.getRelationships g)
mapM_ B.deleteNode (G.getNodes g)
-- | Test a traversal with an unexisting start
case_traversalNotFound :: Assertion
case_traversalNotFound = do
g <- withAuthConnection host port creds $ setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let expException = Neo4jNoEntityException $ (TE.encodeUtf8 . runNodePath . nodePath) start
assertException expException $ withAuthConnection host port creds $ do
let rels = map (\n -> fromJust $ G.getNamedRelationship n g) ["Root-Johan", "Root-Mattias"]
mapM_ deleteRelationship rels
deleteNode start
void $ T.traverseGetNodes def start
withAuthConnection host port creds $ cleanUpTraversalTest g
-- | Test a default traversal returning nodes
case_defaultTraversalNodes :: Assertion
case_defaultTraversalNodes = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
ns <- T.traverseGetNodes def start
let expected = map (\n -> fromJust $ G.getNamedNode n g) ["Root", "Mattias", "Johan"]
neo4jEqual (L.sort expected) (L.sort ns)
cleanUpTraversalTest g
-- | Test a default traversal returning relationships
case_defaultTraversalRels :: Assertion
case_defaultTraversalRels = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
rs <- T.traverseGetRels def start
let expected = map (\n -> fromJust $ G.getNamedRelationship n g) ["Root-Mattias", "Root-Johan"]
neo4jEqual (L.sort expected) (L.sort rs)
cleanUpTraversalTest g
-- | Test a default traversal returning id paths
case_defaultTraversalIdPath :: Assertion
case_defaultTraversalIdPath = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
ps <- L.sort <$> T.traverseGetPath def start
neo4jEqual 3 (length ps)
-- check we've received the expected paths
let _getNodePath = \name -> nodePath $ fromJust $ G.getNamedNode name g
let _getRelPath = \name -> relPath $ fromJust $ G.getNamedRelationship name g
let checkPath = \p nodes rels -> do
neo4jEqual (map _getNodePath nodes) (T.pathNodes p)
let resRels = T.pathRels p
neo4jEqual (map _getRelPath (map fst rels)) (map fst resRels)
neo4jEqual (map snd rels) (map snd resRels)
checkPath (ps !! 0) ["Root"] []
checkPath (ps !! 1) ["Root", "Johan"] [("Root-Johan", T.Out)]
checkPath (ps !! 2) ["Root", "Mattias"] [("Root-Mattias", T.Out)]
cleanUpTraversalTest g
-- | Test a default traversal returning full paths
case_defaultTraversalFullPath :: Assertion
case_defaultTraversalFullPath = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
ps <- L.sort <$> T.traverseGetFullPath def start
neo4jEqual 3 (length ps)
-- check we've received the expected paths
let _getNode = \name -> fromJust $ G.getNamedNode name g
let _getRel = \name -> fromJust $ G.getNamedRelationship name g
let checkPath = \p nodes rels -> do
neo4jEqual (L.sort $ map _getNode nodes) (L.sort $ T.pathNodes p)
neo4jEqual (L.sort $ map _getRel rels) (L.sort $ T.pathRels p)
let checkPath' = \p nodes rels -> (L.sort $ map _getNode nodes) == (L.sort $ T.pathNodes p) &&
(L.sort $ map _getRel rels) == (L.sort $ T.pathRels p)
checkPath (ps !! 0) ["Root"] []
if checkPath' (ps !! 1) ["Root", "Johan"] ["Root-Johan"]
then checkPath (ps !! 1) ["Root", "Johan"] ["Root-Johan"]
else checkPath (ps !! 1) ["Root", "Mattias"] ["Root-Mattias"]
if checkPath' (ps !! 2) ["Root", "Johan"] ["Root-Johan"]
then checkPath (ps !! 2) ["Root", "Johan"] ["Root-Johan"]
else checkPath (ps !! 2) ["Root", "Mattias"] ["Root-Mattias"]
cleanUpTraversalTest g
-- | Test a traversal with an unexisting start
case_pagedTraversalNotFound :: Assertion
case_pagedTraversalNotFound = do
g <- withAuthConnection host port creds $ setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let expException = Neo4jNoEntityException $ (TE.encodeUtf8 . runNodePath . nodePath) start
assertException expException $ withAuthConnection host port creds $ do
let rels = map (\n -> fromJust $ G.getNamedRelationship n g) ["Root-Johan", "Root-Mattias"]
mapM_ deleteRelationship rels
deleteNode start
void $ T.pagedTraverseGetNodes def def start
withAuthConnection host port creds $ cleanUpTraversalTest g
-- | Test a paged traversal returning nodes
case_pagedTraversalNodes :: Assertion
case_pagedTraversalNodes = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let desc = def {T.travDepth = Left 2}
let paging = def {T.pageSize = 1}
pg <- T.pagedTraverseGetNodes desc paging start
let _getNode = \name -> fromJust $ G.getNamedNode name g
neo4jEqual False (T.pagedTraversalDone pg)
neo4jEqual [_getNode "Root"] (T.getPagedValues pg)
pg2 <- T.nextTraversalPage pg
neo4jEqual False (T.pagedTraversalDone pg2)
pg3 <- T.nextTraversalPage pg2
neo4jEqual False (T.pagedTraversalDone pg3)
neo4jEqual (L.sort $ map _getNode ["Johan", "Mattias"]) (L.sort $ T.getPagedValues pg2 ++ T.getPagedValues pg3)
pg4 <- T.nextTraversalPage pg3
neo4jEqual False (T.pagedTraversalDone pg4)
neo4jEqual [_getNode "Emil"] (T.getPagedValues pg4)
pg5 <- T.nextTraversalPage pg4
neo4jEqual True (T.pagedTraversalDone pg5)
pg6 <- T.nextTraversalPage pg5
neo4jEqual True (T.pagedTraversalDone pg6)
cleanUpTraversalTest g
-- | Test a paged traversal returning relationships
case_pagedTraversalRels :: Assertion
case_pagedTraversalRels = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let desc = def
let paging = def {T.pageSize = 1}
pg <- T.pagedTraverseGetRels desc paging start
let _getRel = \name -> fromJust $ G.getNamedRelationship name g
neo4jEqual False (T.pagedTraversalDone pg)
pg2 <- T.nextTraversalPage pg
neo4jEqual False (T.pagedTraversalDone pg2)
pg3 <- T.nextTraversalPage pg2
neo4jEqual False (T.pagedTraversalDone pg3)
neo4jEqual (L.sort $ map _getRel ["Root-Johan", "Root-Mattias"]) (
L.sort $ T.getPagedValues pg ++ T.getPagedValues pg2 ++ T.getPagedValues pg3)
pg4 <- T.nextTraversalPage pg3
neo4jEqual True (T.pagedTraversalDone pg4)
cleanUpTraversalTest g
-- | Test a paged traversal returning id paths
case_pagedTraversalIdPaths :: Assertion
case_pagedTraversalIdPaths = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let desc = def
let paging = def {T.pageSize = 1}
let _getNodePath = \name -> nodePath $ fromJust $ G.getNamedNode name g
let _getRelPath = \name -> relPath $ fromJust $ G.getNamedRelationship name g
let checkPath = \p nodes rels -> do
neo4jEqual (map _getNodePath nodes) (T.pathNodes p)
let resRels = T.pathRels p
neo4jEqual (map _getRelPath (map fst rels)) (map fst resRels)
neo4jEqual (map snd rels) (map snd resRels)
pg <- T.pagedTraverseGetPath desc paging start
neo4jEqual False (T.pagedTraversalDone pg)
checkPath (T.getPagedValues pg !! 0) ["Root"] []
pg2 <- T.nextTraversalPage pg
neo4jEqual False (T.pagedTraversalDone pg2)
pg3 <- T.nextTraversalPage pg2
neo4jEqual False (T.pagedTraversalDone pg3)
let ps = L.sort $ T.getPagedValues pg2 ++ T.getPagedValues pg3
checkPath (ps !! 0) ["Root", "Johan"] [("Root-Johan", T.Out)]
checkPath (ps !! 1) ["Root", "Mattias"] [("Root-Mattias", T.Out)]
pg4 <- T.nextTraversalPage pg3
neo4jEqual True (T.pagedTraversalDone pg4)
cleanUpTraversalTest g
-- | Test a paged traversal returning full paths
case_pagedTraversalFullPaths :: Assertion
case_pagedTraversalFullPaths = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let desc = def
let paging = def {T.pageSize = 1}
let _getNode = \name -> fromJust $ G.getNamedNode name g
let _getRel = \name -> fromJust $ G.getNamedRelationship name g
let checkPath = \p nodes rels -> do
neo4jEqual (L.sort $ map _getNode nodes) (L.sort $ T.pathNodes p)
neo4jEqual (L.sort $ map _getRel rels) (L.sort $ T.pathRels p)
pg <- T.pagedTraverseGetFullPath desc paging start
neo4jEqual False (T.pagedTraversalDone pg)
checkPath (T.getPagedValues pg !! 0) ["Root"] []
pg2 <- T.nextTraversalPage pg
neo4jEqual False (T.pagedTraversalDone pg2)
pg3 <- T.nextTraversalPage pg2
neo4jEqual False (T.pagedTraversalDone pg3)
let ps = L.sort $ T.getPagedValues pg2 ++ T.getPagedValues pg3
checkPath (ps !! 0) ["Root", "Johan"] ["Root-Johan"]
checkPath (ps !! 1) ["Root", "Mattias"] ["Root-Mattias"]
pg4 <- T.nextTraversalPage pg3
neo4jEqual True (T.pagedTraversalDone pg4)
cleanUpTraversalTest g
-- | Test traversal depth first search
case_dfsTraversalNodes :: Assertion
case_dfsTraversalNodes = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let desc = def {T.travDepth = Left 2, T.travOrder = T.DepthFirst}
ns <- T.traverseGetNodes desc start
let expected = map (\n -> fromJust $ G.getNamedNode n g) ["Root", "Johan", "Emil", "Mattias"]
neo4jEqual (L.sort expected) (L.sort ns)
cleanUpTraversalTest g
-- | Test traversal with a relation filter
case_relFilterTraversalNodes :: Assertion
case_relFilterTraversalNodes = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Tobias" g
let desc = def {T.travRelFilter = [("loves", Outgoing)]}
ns <- T.traverseGetNodes desc start
let expected = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Sara"]
neo4jEqual (L.sort expected) (L.sort ns)
let desc2 = def {T.travRelFilter = [("hates", Incoming)]}
ns2 <- T.traverseGetNodes desc2 start
let expected2 = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Gumersindo"]
neo4jEqual (L.sort expected2) (L.sort ns2)
let desc3 = def {T.travRelFilter = [("hates", Any)]}
ns3 <- T.traverseGetNodes desc3 start
let expected3 = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Gumersindo"]
neo4jEqual (L.sort expected3) (L.sort ns3)
let desc4 = def {T.travRelFilter = [("hates", Incoming), ("loves", Outgoing)]}
ns4 <- T.traverseGetNodes desc4 start
let expected4 = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Sara", "Gumersindo"]
neo4jEqual (L.sort expected4) (L.sort ns4)
let desc5 = def {T.travRelFilter = [("htes", Incoming)]}
ns5 <- T.traverseGetNodes desc5 start
let expected5 = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias"]
neo4jEqual (L.sort expected5) (L.sort ns5)
cleanUpTraversalTest g
-- | Test traversal with a uniqueness constraint
case_uniquenessTraversalNodes :: Assertion
case_uniquenessTraversalNodes = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Tobias" g
let desc = def {T.travDepth = Left 2, T.travRelFilter = [("loves", Any), ("hates", Any), ("admires", Any)]}
ns <- T.traverseGetNodes desc start
let expected = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Sara", "Gumersindo", "Sara", "Gumersindo"]
neo4jEqual (L.sort expected) (L.sort ns)
let desc2 = desc {T.travUniqueness = Just T.NodeGlobal}
ns2 <- T.traverseGetNodes desc2 start
let expected2 = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Sara", "Gumersindo"]
neo4jEqual (L.sort expected2) (L.sort ns2)
let desc3 = desc {T.travUniqueness = Just T.RelationshipGlobal}
ns3 <- T.traverseGetNodes desc3 start
let expected3 = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Gumersindo", "Sara", "Gumersindo"]
neo4jEqual (L.sort expected3) (L.sort ns3)
let desc4 = desc {T.travUniqueness = Just T.NodePathUnique}
ns4 <- T.traverseGetNodes desc4 start
let expected4 = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Sara", "Gumersindo", "Sara", "Gumersindo"]
neo4jEqual (L.sort expected4) (L.sort ns4)
let desc5 = desc {T.travUniqueness = Just T.RelationshipPath}
ns5 <- T.traverseGetNodes desc5 start
let expected5 = map (\n -> fromJust $ G.getNamedNode n g) ["Tobias", "Sara", "Gumersindo", "Sara", "Gumersindo"]
neo4jEqual (L.sort expected5) (L.sort ns5)
cleanUpTraversalTest g
-- | Test traversal with a javascript depth expression
case_progDepthTraversalNodes :: Assertion
case_progDepthTraversalNodes = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let desc = def {T.travDepth = Right "position.length() >= 2;"}
ns <- T.traverseGetNodes desc start
let expected = map (\n -> fromJust $ G.getNamedNode n g) ["Root", "Johan", "Mattias", "Emil"]
neo4jEqual (L.sort expected) (L.sort ns)
cleanUpTraversalTest g
-- | Test traversal with a wrong javascript depth expression
case_wrongProgDepthTraversalNodes :: Assertion
case_wrongProgDepthTraversalNodes = do
g <- withAuthConnection host port creds $ setUpTraversalTest
assertException expException $ withAuthConnection host port creds $ do
let start = fromJust $ G.getNamedNode "Root" g
let desc = def {T.travDepth = Right "positionlength() >= 2;"}
void $ T.traverseGetNodes desc start
withAuthConnection host port creds $ cleanUpTraversalTest g
where expException = Neo4jUnexpectedResponseException HT.status400
-- | Test traversal without initial node
case_returnButFirstTraversal :: Assertion
case_returnButFirstTraversal = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let desc = def {T.travNodeFilter = Left T.ReturnAllButStartNode}
ns <- T.traverseGetNodes desc start
let expected = map (\n -> fromJust $ G.getNamedNode n g) ["Johan", "Mattias"]
neo4jEqual (L.sort expected) (L.sort ns)
cleanUpTraversalTest g
-- | Test filter nodes without initial node
case_filterNodesTraversal :: Assertion
case_filterNodesTraversal = withAuthConnection host port creds $ do
g <- setUpTraversalTest
let start = fromJust $ G.getNamedNode "Root" g
let desc = def {T.travNodeFilter = Right "position.endNode().getProperty('name').toLowerCase().contains('t');"}
ns <- T.traverseGetNodes desc start
let expected = map (\n -> fromJust $ G.getNamedNode n g) ["Root", "Mattias"]
neo4jEqual (L.sort expected) (L.sort ns)
cleanUpTraversalTest g
-- | Test traversal with a filter expression
case_wrongFilterNodesTraversal :: Assertion
case_wrongFilterNodesTraversal = do
g <- withAuthConnection host port creds $ setUpTraversalTest
assertException expException $ withAuthConnection host port creds $ do
let start = fromJust $ G.getNamedNode "Root" g
let desc = def {T.travNodeFilter = Right "posiiiitionlength() >= 2;"}
void $ T.traverseGetNodes desc start
withAuthConnection host port creds $ cleanUpTraversalTest g
where expException = Neo4jUnexpectedResponseException HT.status400