greskell-2.0.3.3: test/ServerTest.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE 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 (Text, unpack)
import Data.Traversable (traverse)
import qualified Data.Vector as V
import qualified Network.Greskell.WebSocket.Client as WS
import Test.Hspec
import Data.Greskell.AsIterator (AsIterator (IteratorItem))
import Data.Greskell.AsLabel (AsLabel (..), lookupAsM)
import qualified Data.Greskell.AsLabel as As
import Data.Greskell.Binder (Binder, newBind, runBinder)
import Data.Greskell.Extra (gWhenEmptyInput)
import Data.Greskell.GMap (GMapEntry, unGMapEntry)
import Data.Greskell.Graph (AEdge (..), AProperty (..), AVertex (..),
AVertexProperty (..), ElementID (..), Key,
Keys (..), Path (..), T, cList, makePathEntry,
singletonKeys, tId, tKey, tLabel, tValue, (-:),
(=:))
import Data.Greskell.GraphSON (FromGraphSON, GValue, nonTypedGValue,
parseEither)
import Data.Greskell.Gremlin (Order, P, Predicate (..), cCompare, oAsc, oDesc,
pAnd, pEq, pGte, pLt, pNot, pTest)
import Data.Greskell.Greskell (Greskell, ToGreskell (..), false, gvalueInt,
list, number, single, toGremlin, toGreskell,
true, unsafeGreskell, unsafeMethodCall, value)
import Data.Greskell.GTraversal (GTraversal, SideEffect, Transform, Walk, gAddE',
gAddV, gAs, gBy, gBy1, gByL, gChoose3,
gEmitHead, gFilter, gHas2, gHasLabel, gId,
gIdentity, gInV, gInV', gIsP, gIsP', gIterate,
gLabel, gLoops, gMatch, gOrder, gOut', gOutV,
gOutV', gPath, gPathBy, gProject, gProperties,
gProperty, gPropertyV, gRepeat, gSelect1,
gSelectBy1, gSelectByN, gSelectN, gTimes, gTo,
gUntilTail, gV', gValueMap, gValues, gWhereP1,
gWhereP2, liftWalk, mPattern, sAddV', sE', sV',
source, unsafeGTraversal, unsafeWalk, ($.))
import Data.Greskell.Logic (Logic (..))
import Data.Greskell.PMap (lookupAsM, lookupListAs, pMapToThrow)
import ServerTest.Common (withClient, withEnv)
main :: IO ()
main = hspec spec
spec :: Spec
spec = withEnv $ do
spec_basics
spec_binder
spec_comparator
spec_predicate
spec_T
spec_P
spec_graph
spec_as
spec_selectBy
spec_project
spec_repeat
spec_upsert
spec_path
spec_where
spec_match
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]
checkBinder :: (AsIterator a, b ~ IteratorItem a, FromGraphSON b, Eq b, Show b)
=> [b] -> Binder (Greskell a) -> SpecWith (String, Int)
checkBinder expected binder = specify label $ withClient $ \client -> do
got <- WS.slurpResults =<< WS.submit client script (Just binding)
got `shouldBe` V.fromList expected
where
(script, binding) = runBinder binder
label = (unpack $ toGremlin script) ++ " with " ++ show binding
spec_binder :: SpecWith (String, Int)
spec_binder = describe "server and Binder" $ do
checkBinder [100 :: Int] $ newBind (100 :: Int)
checkBinder [110 :: Int] $ do
b <- newBind (100 :: Int)
return $ b + (10 :: Greskell Int)
spec_comparator :: SpecWith (String,Int)
spec_comparator = do
let oAsc' :: Greskell (Order Int)
oAsc' = oAsc
oDesc' :: Greskell (Order Int)
oDesc' = oDesc
checkOne (cCompare oAsc' 20 20) 0
checkOne (cCompare oAsc' 10 20) (-1)
checkOne (cCompare oAsc' 20 10) 1
checkOne (cCompare oDesc' 20 20) 0
checkOne (cCompare oDesc' 10 20) 1
checkOne (cCompare oDesc' 20 10) (-1)
spec_predicate :: SpecWith (String,Int)
spec_predicate = do
checkOne (pTest the_p 5) False
checkOne (pTest the_p 10) True
checkOne (pTest the_p 15) True
checkOne (pTest the_p 20) False
where
the_p :: Greskell (P Int)
the_p = pLt 20 `pAnd` pGte 10
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 :: Greskell (P Scientific)
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 <> " }"]
plusWalk :: Greskell Int -> Walk Transform Int Int
plusWalk n = unsafeWalk "map" ["{ it.get() + " <> toGremlin n <> " }"]
squareWalk :: Walk Transform Int Int
squareWalk = unsafeWalk "map" ["{ it.get() * it.get() }"]
appendWalk :: Greskell Text -> Walk Transform Text Text
appendWalk t = unsafeWalk "map" ["{ it.get() + " <> toGremlin t <> " }"]
-- toLowerWalk :: Walk Transform Text Text
-- toLowerWalk = unsafeWalk "map" ["{ it.get().toLowerCase() }"]
lengthWalk :: Walk Transform Text Int
lengthWalk = unsafeWalk "map" ["{ it.get().length() }"]
substrWalk :: Greskell Int -> Greskell Int -> Walk Transform Text Text
substrWalk s e = unsafeWalk "map" ["{ it.get().substring(" <> toGremlin s <> ", " <> toGremlin e <> ") }"]
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
spec_where :: SpecWith (String,Int)
spec_where = do
let start :: GTraversal Transform () Int
start = unsafeGTraversal "__(1,2,3)"
specify "gWhereP1 (without modulation)" $ withClient $ \client -> do
let g = gWhereP1 (pEq label_s) Nothing $. squareWalk $. gAs label_s $. start
label_s = "s"
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client g Nothing
got `shouldBe` [1]
specify "gWhereP1 (with modulation)" $ withClient $ \client -> do
let g = gWhereP1 (pEq label_s) (Just $ gBy $ mapper) $. multiplyWalk 5 $. gAs label_s $. start
label_s = "s"
mapper = gChoose3 (gIsP' $ pGte 12)
(plusWalk (-12))
gIdentity
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client g Nothing
got `shouldBe` [15]
specify "gWhereP2 (without modulation)" $ withClient $ \client -> do
let g = gWhereP2 label_s (pEq label_m) Nothing $. plusWalk 10 $. gAs label_m $. squareWalk $. gAs label_s $. start
label_s = "s"
label_m = "m"
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client g Nothing
got `shouldBe` [11]
specify "gWhereP2 (with modulation)" $ withClient $ \client -> do
let start_str :: GTraversal Transform () Text
start_str = unsafeGTraversal "__(\"foo\", \"bar\", \"quux\", \"hoge\")"
g = gWhereP2 label_s (pEq label_a) (Just $ gBy $ mapper) $. gAs label_a $. appendWalk "FOO" $. gAs label_s $. start_str
label_s = "s"
label_a = "a"
mapper = gChoose3 (gIsP (pGte 6) <<< lengthWalk)
(substrWalk 0 3)
gIdentity
got <- fmap V.toList $ WS.slurpResults =<< WS.submit client g Nothing
got `shouldBe` ["fooFOO", "barFOO"]
spec_match :: SpecWith (String,Int)
spec_match = do
specify "gMatch" $ withClient $ \client -> do
let start_str :: GTraversal Transform () Text
start_str = unsafeGTraversal "__(\"foo\", \"hoge\", \"bar\", \"quux\")"
g = gSelectN label_s label_ss [label_len, label_dlen] $. gMatch pat $. start_str
pat = And
( mPattern label_s (gAs label_len <<< lengthWalk) )
[ mPattern label_s (gAs label_ss <<< appendWalk "HOGE"),
mPattern label_len (gAs label_dlen <<< squareWalk),
mPattern label_ss (gWhereP1 (pLt label_dlen) Nothing <<< plusWalk 5 <<< lengthWalk)
]
label_s = "s"
label_ss = "ss"
label_len = "len"
label_dlen = "dlen"
extract sm = (,,,)
<$> lookupAsM label_s sm
<*> lookupAsM label_ss sm
<*> lookupAsM label_len sm
<*> lookupAsM label_dlen sm
got <- traverse extract =<< (fmap V.toList $ WS.slurpResults =<< WS.submit client g Nothing)
got `shouldBe` [ ("hoge", "hogeHOGE", 4, 16),
("quux", "quuxHOGE", 4, 16)
]