greskell-1.1.0.0: test/ServerTest.hs
{-# LANGUAGE OverloadedStrings, TypeFamilies #-}
module Main (main,spec) where
import Control.Category ((<<<), (>>>))
import qualified Data.Aeson as Aeson
import Data.Either (isRight)
import Data.Foldable (toList)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HM
import Data.List (sort)
import Data.Monoid (mempty, (<>))
import Data.Scientific (Scientific)
import Data.Text (unpack, Text)
import qualified Data.Vector as V
import qualified Network.Greskell.WebSocket.Client as WS
import Test.Hspec
import Data.Greskell.AsLabel (AsLabel(..))
import qualified Data.Greskell.AsLabel as As
import Data.Greskell.AsIterator
( AsIterator(IteratorItem)
)
import Data.Greskell.Binder (newBind, runBinder)
import Data.Greskell.Extra (gWhenEmptyInput)
import Data.Greskell.GMap (GMapEntry, unGMapEntry)
import Data.Greskell.Gremlin
( oIncr, oDecr, cCompare, Order,
Predicate(..), pLt, pAnd, pGte, pNot, pEq, pTest
)
import Data.Greskell.Greskell
( toGremlin, Greskell, toGreskell, ToGreskell(..),
true, false, list, value, single, number, gvalueInt,
unsafeMethodCall, unsafeGreskell
)
import Data.Greskell.Graph
( AVertex(..), AEdge(..), AProperty(..), AVertexProperty(..),
Key, Keys(..), (-:), singletonKeys,
T, tId, tLabel, tKey, tValue, cList, (=:),
ElementID(..),
Path(..), makePathEntry
)
import Data.Greskell.GraphSON
( FromGraphSON, nonTypedGValue, GValue,
parseEither
)
import Data.Greskell.GTraversal
( Walk, GTraversal, SideEffect,
source, sV', sE', gV', sAddV', gAddE', gTo,
($.), gOrder, gBy1, gBy, gByL,
Transform, unsafeWalk, unsafeGTraversal,
gProperties, gProperty, gPropertyV, liftWalk, gValues,
gAs, gSelect1, gSelectN, gSelectBy1, gSelectByN,
gFilter, gOut', gOutV, gOutV', gInV, gInV', gId, gLabel, gProject,
gValueMap,
gProject, gByL,
gRepeat, gTimes, gEmitHead, gUntilTail, gLoops, gIsP,
gHasLabel, gHas2, gAddV, gIterate,
gPath, gPathBy
)
import Data.Greskell.PMap (lookupAsM, lookupListAs, pMapToThrow)
import ServerTest.Common (withEnv, withClient)
main :: IO ()
main = hspec spec
spec :: Spec
spec = withEnv $ do
spec_basics
spec_comparator
spec_predicate
spec_T
spec_P
spec_graph
spec_as
spec_selectBy
spec_project
spec_repeat
spec_upsert
spec_path
spec_basics :: SpecWith (String,Int)
spec_basics = do
describe "Num" $ do
let checkInt :: Greskell Int -> Int -> SpecWith (String,Int)
checkInt = checkOne
checkInt 100 100
checkInt (20 + 30) (20 + 30)
checkInt (10 - 3 * 6) (10 - 3 * 6)
checkInt (-99) (-99)
checkInt (abs (-53)) (abs (-53))
checkInt (signum 0) (signum 0)
checkInt (signum 99) (signum 99)
checkInt (signum (-12)) (signum (-12))
describe "Fractional" $ do
let checkFrac :: Greskell Scientific -> Scientific -> SpecWith (String,Int)
checkFrac = checkOne
checkFrac (20.5) (20.5)
checkFrac (20.123) (20.123)
checkFrac (32.25 / 2.5) (32.25 / 2.5)
checkFrac (19.2 * recip 12.5) (19.2 * recip 12.5)
describe "Monoid" $ do
let checkT :: Greskell Text -> Text -> SpecWith (String,Int)
checkT = checkOne
checkT mempty mempty
checkT ("hello, " <> "world!") ("hello, " <> "world!")
checkT ("!\"#$%&'()=~\\|><+*;:@{}[]/?_\r\n\t ") ("!\"#$%&'()=~\\|><+*;:@{}[]/?_\r\n\t ")
describe "Bool" $ do
let checkB :: Greskell Bool -> Bool -> SpecWith (String,Int)
checkB = checkOne
checkB true True
checkB false False
describe "list" $ do
let checkL :: Greskell [Int] -> [Int] -> SpecWith (String,Int)
checkL = checkRaw
checkL (list []) []
checkL (list [20,30,20,10]) [20,30,20,10]
describe "number" $ do
let checkN :: Greskell Scientific -> Scientific -> SpecWith (String,Int)
checkN = checkOne
checkN (number 3.1415) (3.1415)
checkN (number 2.31e12) (2.31e12)
checkN (number (-434.23e-19)) (-434.23e-19)
describe "nested map" $ do
let check :: Greskell (HashMap Int (HashMap Text Int)) -> [(Int, (HashMap Text Int))] -> SpecWith (String,Int)
check = checkRawMapped unGMapEntry
check (unsafeGreskell "[:]") []
check (unsafeGreskell "[100: [\"foo\": 55], 200: [:], 300: [\"bar\": 60, \"buzz\": 65]]")
[ (100, HM.fromList [("foo", 55)]),
(200, mempty),
(300, HM.fromList [("bar", 60), ("buzz", 65)])
]
describe "array in map" $ do
let check :: Greskell (HashMap Text [Int]) -> [(Text, [Int])] -> SpecWith (String,Int)
check = checkRawMapped unGMapEntry
check (unsafeGreskell "[:]") []
check (unsafeGreskell "[\"foo\": [], \"bar\": [1,2,3]]")
[ ("foo", []),
("bar", [1,2,3])
]
checkRawMapped :: (AsIterator a, b ~ IteratorItem a, FromGraphSON b, Eq c, Show c)
=> (b -> c)
-> Greskell a
-> [c]
-> SpecWith (String, Int)
checkRawMapped mapResult input expected = specify label $ withClient $ \client -> do
got <- WS.slurpResults =<< WS.submit client input Nothing
fmap mapResult got `shouldBe` V.fromList expected
where
label = unpack $ toGremlin input
checkRaw :: (AsIterator a, b ~ IteratorItem a, FromGraphSON b, Eq b, Show b)
=> Greskell a
-> [b]
-> SpecWith (String, Int)
checkRaw = checkRawMapped id
checkOne :: (AsIterator a, b ~ IteratorItem a, FromGraphSON b, Eq b, Show b)
=> Greskell a -> b -> SpecWith (String, Int)
checkOne input expected = checkRaw input [expected]
spec_comparator :: SpecWith (String,Int)
spec_comparator = do
let oIncr' :: Greskell (Order Int)
oIncr' = oIncr
oDecr' :: Greskell (Order Int)
oDecr' = oDecr
checkOne (cCompare oIncr' 20 20) 0
checkOne (cCompare oIncr' 10 20) (-1)
checkOne (cCompare oIncr' 20 10) 1
checkOne (cCompare oDecr' 20 20) 0
checkOne (cCompare oDecr' 10 20) 1
checkOne (cCompare oDecr' 20 10) (-1)
spec_predicate :: SpecWith (String,Int)
spec_predicate = do
checkOne (pTest (pLt 20 `pAnd` pGte 10) (5 :: Greskell Int)) False
checkOne (pTest (pLt 20 `pAnd` pGte 10) (10 :: Greskell Int)) True
checkOne (pTest (pLt 20 `pAnd` pGte 10) (15 :: Greskell Int)) True
checkOne (pTest (pLt 20 `pAnd` pGte 10) (20 :: Greskell Int)) False
iterateTraversal :: GTraversal c s e -> Greskell ()
iterateTraversal gt = unsafeMethodCall (toGreskell gt) "iterate" []
spec_T :: SpecWith (String,Int)
spec_T = describe "T enum" $ do
specFor' "tId" (gMapT tId) (parseEither . unElementID) [(Right 10 :: Either String Int)]
specFor "tLabel" (gMapT tLabel) ["VLABEL"]
specFor "tKey" (gMapT tKey <<< gProperties ["vprop"]) ["vprop"]
specFor' "tValue" (gMapT tValue <<< gProperties ["vprop"]) parseEither [(Right 400 :: Either String Int)]
where
gMapT :: Greskell (T a b) -> Walk Transform a b
gMapT t = unsafeWalk "map" ["{ " <> toGremlin (unsafeMethodCall t "apply" ["it.get()"]) <> " }"]
prefixedTraversal :: Walk Transform AVertex a -> GTraversal Transform () a
prefixedTraversal mapper = unsafeGTraversal (prelude <> body)
where
prelude =
( "graph = org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph.open(); "
<> "g = graph.traversal(); "
<> "graph.addVertex(id, 10, label, \"VLABEL\"); "
<> ( toGremlin $ iterateTraversal
$ gPropertyV Nothing "vprop" (gvalueInt $ (400 :: Int))
["a" =: ("A" :: Greskell Text), "b" =: ("B" :: Greskell Text)]
$. liftWalk $ sV' [] $ source "g"
) <> "; "
)
body = toGremlin $ mapper $. sV' [] $ source "g"
specFor' :: (FromGraphSON a, Eq b, Show b) => String -> Walk Transform AVertex a -> (a -> b) -> [b] -> SpecWith (String,Int)
specFor' desc mapper convResult expected = specify desc $ withClient $ \client -> do
got <- WS.slurpResults =<< WS.submit client (prefixedTraversal mapper) Nothing
(fmap convResult got) `shouldBe` V.fromList expected
specFor :: (FromGraphSON a, Eq a, Show a) => String -> Walk Transform AVertex a -> [a] -> SpecWith (String,Int)
specFor desc mapper expected = specFor' desc mapper id expected
spec_P :: SpecWith (String,Int)
spec_P = describe "P class" $ specify "pNot, pEq, pTest" $ withClient $ \client -> do
let p = pNot $ pEq $ number 10
test v = WS.slurpResults =<< WS.submit client (pTest p $ v) Nothing
test (number 10) `shouldReturn` V.fromList [False]
test (number 15) `shouldReturn` V.fromList [True]
withPrelude :: (ToGreskell a) => Greskell () -> a -> Greskell (GreskellReturn a)
withPrelude prelude orig = unsafeGreskell (toGremlin prelude <> toGremlin orig)
statements :: [Text] -> Greskell ()
statements = unsafeGreskell . mconcat . map (<> "; ")
-- | This test is supported TinkerPop 3.1.0 and above, because it uses
-- 'gAddE'' function.
spec_graph :: SpecWith (String,Int)
spec_graph = do
specify "AProperty (edge properties)" $ withClient $ \client -> do
let trav = gProperties [] $. sE' [] $ source "g"
prop t = AProperty "condition" $ Right (t :: Text)
expected = map prop [ ">=0.11.2.1",
">=1.2.2.1",
">=1.2.3"
]
got <- WS.slurpResults =<< WS.submit client (withPrelude' trav) Nothing
(map (fmap parseEither) $ V.toList got) `shouldMatchList` expected
specify "AProperty (vertex property meta-properties)" $ withClient $ \client -> do
let trav = gProperties [] $. gProperties [] $. sV' [] $ source "g"
prop t = AProperty "date" $ Right (t :: Text)
expected = map prop [ "2018-04-08",
"2018-05-10",
"2017-09-20",
"2017-12-27",
"2017-12-23"
]
got <- WS.slurpResults =<< WS.submit client (withPrelude' trav) Nothing
(map (fmap parseEither) $ V.toList got) `shouldMatchList` expected
specify "AEdge" $ withClient $ \client -> do
let lOutV :: AsLabel Text
lOutV = "outV_name"
lInV :: AsLabel Text
lInV = "inV_name"
lProps = "props"
lEdge = "edge"
lProj = "projections"
kCond :: Key AEdge Text
kCond = "condition"
trav = gSelectN lEdge lProj [] $. gAs lProj $.
( gProject
( gByL lOutV (gOutV' >>> gValues ["name"]) )
[ gByL lInV (gInV' >>> gValues ["name"]),
gByL lProps (gValueMap KeysNil)
]
) $.
gAs lEdge $. sE' [] $ source "g"
parseResult pm = do
edge <- lookupAsM lEdge pm
pj <- lookupAsM lProj pm
(,,,) (aeLabel edge)
<$> (lookupAsM lOutV pj)
<*> (lookupAsM lInV pj)
<*> (lookupAsM kCond =<< lookupAsM lProps pj)
expected = [ ("depends_on", "greskell", "aeson", ">=0.11.2.1"),
("depends_on", "greskell", "text", ">=1.2.2.1"),
("depends_on", "aeson", "text", ">=1.2.3")
]
got <- traverse parseResult =<< WS.slurpResults =<< WS.submit client (withPrelude' trav) Nothing
V.toList got `shouldMatchList` expected
specify "AVertexProperty" $ withClient $ \client -> do
let lAV = "vertex_property"
lProps = "props"
kDate :: Key (AVertexProperty GValue) Text
kDate = "date"
trav = gSelectN lAV lProps [] $. gAs lProps $. gValueMap (singletonKeys kDate) $.
gAs lAV $. gProperties [] $. sV' [] $ source "g"
parseResult pm = do
av <- lookupAsM lAV pm
let label = avpLabel av
e_val = parseEither $ avpValue av
m_date <- if label == "version"
then fmap Just (lookupAsM kDate =<< lookupAsM lProps pm)
else return Nothing
return (label, e_val, m_date)
expected :: [(Text, Either String Text, Maybe Text)]
expected = [ ("name", Right "greskell", Nothing),
("name", Right "aeson", Nothing),
("name", Right "text", Nothing),
("version", Right "0.1.1.0", Just "2018-04-08"),
("version", Right "1.3.1.1", Just "2018-05-10"),
("version", Right "1.2.2.0", Just "2017-09-20"),
("version", Right "1.2.3.0", Just "2017-12-27"),
("version", Right "1.2.2.0", Just "2017-12-23")
]
got <- traverse parseResult =<< WS.slurpResults =<< WS.submit client (withPrelude' trav) Nothing
V.toList got `shouldMatchList` expected
specify "AVertex" $ withClient $ \client -> do
let lVertex = "vertex"
kName :: Key AVertex Text
kName = "name"
kVer :: Key AVertex Text
kVer = "version"
lProps = "props"
trav = gSelectN lVertex lProps [] $. gAs lProps $. gValueMap (kName -: kVer -: KeysNil) $.
gAs lVertex $. sV' [] $ source "g"
parseResult pm = do
v <- lookupAsM lVertex pm
let label = avLabel v
evid = parseEither $ unElementID $ avId v
props <- lookupAsM lProps pm
names <- fmap toList $ pMapToThrow $ lookupListAs kName props
vers <- fmap (sort . toList) $ pMapToThrow $ lookupListAs kVer props
return (evid, label, names, vers)
expected :: [(Either String Int, Text, [Text], [Text])]
expected = [ (Right 1, "package", ["greskell"], ["0.1.1.0"]),
(Right 2, "package", ["aeson"], ["1.2.2.0", "1.3.1.1"]),
(Right 3, "package", ["text"], ["1.2.2.0", "1.2.3.0"])
]
got <- traverse parseResult =<< WS.slurpResults =<< WS.submit client (withPrelude' trav) Nothing
V.toList got `shouldMatchList` expected
where
withPrelude' :: (ToGreskell a) => a -> Greskell (GreskellReturn a)
withPrelude' = withPrelude prelude
prelude :: Greskell ()
prelude = statements
( [ "graph = org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph.open()",
"g = graph.traversal()",
"graph.addVertex(id, 1, label, 'package')",
"graph.addVertex(id, 2, label, 'package')",
"graph.addVertex(id, 3, label, 'package')",
finalize $ setName 1 "greskell",
finalize $ setName 2 "aeson",
finalize $ setName 3 "text",
finalize $ dependsOn 1 2 ">=0.11.2.1",
finalize $ dependsOn 1 3 ">=1.2.2.1",
finalize $ dependsOn 2 3 ">=1.2.3"
]
++ addVersion 1 "0.1.1.0" "2018-04-08"
++ addVersion 2 "1.3.1.1" "2018-05-10"
++ addVersion 2 "1.2.2.0" "2017-09-20"
++ addVersion 3 "1.2.3.0" "2017-12-27"
++ addVersion 3 "1.2.2.0" "2017-12-23"
)
finalize :: GTraversal c s e -> Text
finalize gt = toGremlin $ iterateTraversal gt
num :: Integer -> Greskell (ElementID AVertex)
num = fmap ElementID . gvalueInt
setName :: Integer -> Greskell Text -> GTraversal SideEffect () AVertex
setName vid name = gProperty "name" name $. liftWalk $ sV' [num vid] $ source "g"
dependsOn :: Integer -> Integer -> Greskell Text -> GTraversal SideEffect () AEdge
dependsOn from_id to_id version_cond =
gProperty "condition" version_cond
$. (gAddE' "depends_on" $ gTo (gV' [num to_id]))
$. liftWalk $ sV' [num from_id] $ source "g"
addVersion :: Integer -> Greskell Text -> Greskell Text -> [Text]
addVersion vid ver date =
[ finalize $ gPropertyV (Just cList) "version" ver ["date" =: date] $. liftWalk $ sV' [num vid] $ source "g"
]
multiplyWalk :: Greskell Int -> Walk Transform Int Int
multiplyWalk factor = unsafeWalk "map" ["{ it.get() * " <> toGremlin factor <> " }"]
spec_as :: SpecWith (String,Int)
spec_as = do
let start :: GTraversal Transform () Int
start = unsafeGTraversal "__(1,2,3)"
mult = multiplyWalk
specify "gAs and gSelect1" $ withClient $ \client -> do
let label :: AsLabel Int
label = AsLabel "a"
got <- WS.slurpResults =<< WS.submit client (gSelect1 label $. mult 100 $. gAs label $. start) Nothing
V.toList got `shouldBe` [1,2,3]
specify "gAs and gSelectN" $ withClient $ \client -> do
let lorig, lmul :: AsLabel Int
lorig = AsLabel "a"
lmul = AsLabel "b"
gt = gSelectN lorig lmul [] $. mult 5 $. gAs lmul $. mult 100 $. gAs lorig $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client gt Nothing
mapM (lookupAsM lorig) got `shouldReturn` [1,2,3]
mapM (lookupAsM lmul) got `shouldReturn` [100,200,300]
spec_selectBy :: SpecWith (String,Int)
spec_selectBy = do
let prelude :: Greskell ()
prelude = statements
[ "graph = org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph.open()",
"g = graph.traversal()",
"graph.addVertex(id, 1, label, 'person')",
"graph.addVertex(id, 2, label, 'person')",
"g.V(1).property('name', 'ito').property('age', 23).iterate()",
"g.V(2).property('name', 'tanaka').property('age', 18).iterate()",
"g.V(1).addE('knows').to(V(2)).iterate()"
]
specify "gAs and gSelectBy1" $ withClient $ \client -> do
let src :: AsLabel AVertex
src = AsLabel "s"
gt = gSelectBy1 src (gBy ("name" :: Key AVertex Text)) $. gAs src $. gFilter (gOut' ["knows"]) $. sV' [] $ source "g"
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client (withPrelude prelude gt) Nothing
got `shouldBe` ["ito"]
specify "gAs and gSelectByN" $ withClient $ \client -> do
let src, dest :: AsLabel AVertex
src = AsLabel "s"
dest = AsLabel "d"
gt = gSelectByN src dest [] (gBy ("age" :: Key AVertex Int))
$. gAs dest $. gOut' ["knows"]
$. gAs src $. gFilter (gOut' ["knows"]) $. sV' [] $ source "g"
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client (withPrelude prelude gt) Nothing
map (As.lookup src) got `shouldBe` [Just 23]
map (As.lookup dest) got `shouldBe` [Just 18]
spec_project :: SpecWith (String,Int)
spec_project = do
let start :: GTraversal Transform () Int
start = unsafeGTraversal "__(1,2,3)"
specify "gProject with single item" $ withClient $ \client -> do
let l2 = "l2"
trav = gProject (gByL l2 $ multiplyWalk 2) [] $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
got_l2 <- traverse (lookupAsM l2) got
got_l2 `shouldBe` [2,4,6]
specify "gProject with two items" $ withClient $ \client -> do
let l2 = "l2"
l3 = "l3"
trav = gProject (gByL l2 $ multiplyWalk 2) [gByL l3 $ multiplyWalk 3] $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
got_l2 <- traverse (lookupAsM l2) got
got_l2 `shouldBe` [2,4,6]
got_l3 <- traverse (lookupAsM l3) got
got_l3 `shouldBe` [3,6,9]
specify "gProject with more than one items in 'by' traversal" $ withClient $ \client -> do
let rep_mul3 :: Walk Transform Int Int
rep_mul3 = unsafeWalk "flatMap" ["{ def a = it.get(); return [a * 3, a * 4, a * 5].iterator() }"]
lab = "rep_mul3"
trav = gProject (gByL lab $ rep_mul3) [] $. start
got_simple <- fmap V.toList $ WS.slurpResults =<< WS.submit client (rep_mul3 $. start) Nothing
got_simple `shouldBe` [3, 4, 5, 6, 8, 10, 9, 12, 15]
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
got_l <- traverse (lookupAsM lab) got
got_l `shouldBe` [3, 6, 9]
-- only the first item from the by-projection traversal.
specify "gProject with gSelect1 in by-projection" $ withClient $ \client -> do
let as_orig = "as_orig"
l_orig = "orig"
l_mapped = "mapped"
trav = gProject
(gByL l_mapped $ multiplyWalk 4)
[gByL l_orig $ gSelect1 as_orig ] $.
gAs as_orig $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
traverse (lookupAsM l_mapped) got `shouldReturn` [4, 8, 12]
traverse (lookupAsM l_orig) got `shouldReturn` [1, 2, 3]
spec_repeat :: SpecWith (String,Int)
spec_repeat = do
specify "gRepeat and gTimes" $ withClient $ \client -> do
let start :: GTraversal Transform () Int
start = unsafeGTraversal "__(1,2,3)"
trav = gRepeat Nothing (gTimes 3) Nothing (multiplyWalk 2) $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
got `shouldBe` [8, 16, 24]
specify "gRepeat, gTimes and gEmitHead" $ withClient $ \client -> do
let start :: GTraversal Transform () Int
start = unsafeGTraversal "__(1, 10, 100)"
trav = gRepeat Nothing (gTimes 3) gEmitHead (multiplyWalk 2) $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
sort got `shouldBe` [1, 2, 4, 8, 10, 20, 40, 80, 100, 200, 400, 800]
specify "gRepeat, gUntilTail and gLoops" $ withClient $ \client -> do
let start :: GTraversal Transform () Int
start = unsafeGTraversal "__(1, 10, 100)"
trav = gRepeat Nothing (gUntilTail $ gIsP (pGte 4) <<< gLoops Nothing) Nothing (multiplyWalk 2) $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
sort got `shouldBe` [16, 160, 1600]
spec_upsert :: SpecWith (String,Int)
spec_upsert = do
describe "upsert vertex" $ do
specify "upsert outputs the vertex" $ withClient $ \client -> do
let body = liftWalk getName $. upsert "foo"
pre = statements prelude
got <- WS.slurpResults =<< WS.submit client (withPrelude pre body) Nothing
V.toList got `shouldBe` ["foo"]
specify "upsert adds a vertex" $ withClient $ \client -> do
let pre = statements $ prelude ++
[ toGremlin (gIterate $ upsert "foo")
]
body = getName $. getAllPersons
got <- WS.slurpResults =<< WS.submit client (withPrelude pre body) Nothing
V.toList got `shouldBe` ["foo"]
specify "upsert adds different vertices" $ withClient $ \client -> do
let pre = statements $ prelude ++
[ toGremlin (gIterate $ upsert "foo"),
toGremlin (gIterate $ upsert "bar"),
toGremlin (gIterate $ upsert "foo"),
toGremlin (gIterate $ upsert "buzz"),
toGremlin (gIterate $ upsert "bar")
]
body = getName $. getAllPersons
got <- WS.slurpResults =<< WS.submit client (withPrelude pre body) Nothing
V.toList got `shouldMatchList` ["foo", "bar", "buzz"]
specify "upsert returns existing vertex" $ withClient $ \client -> do
let pre = statements $ prelude ++
[ toGremlin (gIterate $ upsert "foo"),
toGremlin (gIterate $ upsert "foo")
]
body = liftWalk getName $. upsert "foo"
got <- WS.slurpResults =<< WS.submit client (withPrelude pre body) Nothing
V.toList got `shouldBe` ["foo"]
where
prelude :: [Text]
prelude =
[ "graph = org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph.open()",
"g = graph.traversal()"
]
getAllPersons :: GTraversal Transform () AVertex
getAllPersons = gHasLabel "person" $. sV' [] $ source "g"
getPerson :: Greskell Text -> GTraversal Transform () AVertex
getPerson name = gHas2 "name" name $. getAllPersons
insert :: Greskell Text -> Walk SideEffect a AVertex
insert name = gProperty "name" name <<< gAddV "person"
upsert :: Greskell Text -> GTraversal SideEffect () AVertex
upsert name = gWhenEmptyInput (insert name) $. liftWalk $ getPerson name
getName :: Walk Transform AVertex Text
getName = gValues ["name"]
spec_path :: SpecWith (String,Int)
spec_path = do
let start :: GTraversal Transform () Int
start = unsafeGTraversal "__(1,2,3)"
mult = multiplyWalk
specify "gPath" $ withClient $ \client -> do
let g = gPath $. gAs "c" $. mult 10 $. mult 10 $. gAs "b" $. gAs "a" $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client g Nothing
let parsed = traverse (traverse parseEither) got
expected :: [Path Int]
expected = [ Path
[ makePathEntry ["a", "b"] 1,
makePathEntry [] 10,
makePathEntry ["c"] 100
],
Path
[ makePathEntry ["a", "b"] 2,
makePathEntry [] 20,
makePathEntry ["c"] 200
],
Path
[ makePathEntry ["a", "b"] 3,
makePathEntry [] 30,
makePathEntry ["c"] 300
]
]
parsed `shouldBe` Right expected
specify "gPathBy" $ withClient $ \client -> do
let g = gPathBy (gBy $ mult 50) [gBy $ mult 800] $. mult 10 $. gAs "b" $. mult 10 $. gAs "a" $. start
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client g Nothing
let expected :: [Path Int]
expected = [ Path
[ makePathEntry ["a"] 50,
makePathEntry ["b"] 8000,
makePathEntry [] 5000
],
Path
[ makePathEntry ["a"] 100,
makePathEntry ["b"] 16000,
makePathEntry [] 10000
],
Path
[ makePathEntry ["a"] 150,
makePathEntry ["b"] 24000,
makePathEntry [] 15000
]
]
got `shouldBe` expected