{-# 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