greskell 1.0.0.1 → 1.0.1.0
raw patch · 5 files changed
+495/−7 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Greskell.GTraversal: RepeatHead :: RepeatPos
+ Data.Greskell.GTraversal: RepeatLabel :: Text -> RepeatLabel
+ Data.Greskell.GTraversal: RepeatTail :: RepeatPos
+ Data.Greskell.GTraversal: [RepeatEmitT] :: (WalkType cc, WalkType c, Split cc c) => GTraversal cc s e -> RepeatEmit c s
+ Data.Greskell.GTraversal: [RepeatEmit] :: RepeatEmit c s
+ Data.Greskell.GTraversal: [RepeatTimes] :: Greskell Int -> RepeatUntil c s
+ Data.Greskell.GTraversal: [RepeatUntilT] :: (WalkType cc, WalkType c, Split cc c) => GTraversal cc s e -> RepeatUntil c s
+ Data.Greskell.GTraversal: [unRepeatLabel] :: RepeatLabel -> Text
+ Data.Greskell.GTraversal: data RepeatEmit c s
+ Data.Greskell.GTraversal: data RepeatPos
+ Data.Greskell.GTraversal: data RepeatUntil c s
+ Data.Greskell.GTraversal: gBarrier :: WalkType c => Maybe (Greskell Int) -> Walk c s s
+ Data.Greskell.GTraversal: gChoose3 :: (ToGTraversal g, Split cc c, WalkType cc, WalkType c) => g cc s ep -> g c s e -> g c s e -> Walk c s e
+ Data.Greskell.GTraversal: gConstant :: Greskell a -> Walk Transform s a
+ Data.Greskell.GTraversal: gCyclicPath :: WalkType c => Walk c a a
+ Data.Greskell.GTraversal: gCyclicPath' :: Walk Filter a a
+ Data.Greskell.GTraversal: gDedup :: Maybe (ByProjection s e) -> Walk Transform s s
+ Data.Greskell.GTraversal: gDedupN :: AsLabel a -> [AsLabel a] -> Maybe (ByProjection a e) -> Walk Transform s s
+ Data.Greskell.GTraversal: gEmitHead :: Maybe (RepeatPos, RepeatEmit c s)
+ Data.Greskell.GTraversal: gEmitHeadT :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatEmit c s)
+ Data.Greskell.GTraversal: gEmitTail :: Maybe (RepeatPos, RepeatEmit c s)
+ Data.Greskell.GTraversal: gEmitTailT :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatEmit c s)
+ Data.Greskell.GTraversal: gIs :: WalkType c => Greskell v -> Walk c v v
+ Data.Greskell.GTraversal: gIs' :: Greskell v -> Walk Filter v v
+ Data.Greskell.GTraversal: gIsP :: WalkType c => Greskell (P v) -> Walk c v v
+ Data.Greskell.GTraversal: gIsP' :: Greskell (P v) -> Walk Filter v v
+ Data.Greskell.GTraversal: gLocal :: (ToGTraversal g, WalkType c) => g c s e -> Walk c s e
+ Data.Greskell.GTraversal: gLoops :: Maybe RepeatLabel -> Walk Transform s Int
+ Data.Greskell.GTraversal: gRepeat :: (ToGTraversal g, WalkType c) => Maybe RepeatLabel -> Maybe (RepeatPos, RepeatUntil c s) -> Maybe (RepeatPos, RepeatEmit c s) -> g c s s -> Walk c s s
+ Data.Greskell.GTraversal: gSimplePath :: WalkType c => Walk c a a
+ Data.Greskell.GTraversal: gSimplePath' :: Walk Filter a a
+ Data.Greskell.GTraversal: gTimes :: Greskell Int -> Maybe (RepeatPos, RepeatUntil c s)
+ Data.Greskell.GTraversal: gUnfold :: AsIterator a => Walk Transform a (IteratorItem a)
+ Data.Greskell.GTraversal: gUnion :: (ToGTraversal g, WalkType c) => [g c s e] -> Walk c s e
+ Data.Greskell.GTraversal: gUntilHead :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatUntil c s)
+ Data.Greskell.GTraversal: gUntilTail :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatUntil c s)
+ Data.Greskell.GTraversal: instance Data.Greskell.GTraversal.WalkType c => GHC.Base.Monoid (Data.Greskell.GTraversal.MWalk c s s)
+ Data.Greskell.GTraversal: instance Data.Greskell.GTraversal.WalkType c => GHC.Base.Semigroup (Data.Greskell.GTraversal.MWalk c s s)
+ Data.Greskell.GTraversal: instance Data.Greskell.Greskell.ToGreskell Data.Greskell.GTraversal.RepeatLabel
+ Data.Greskell.GTraversal: instance Data.String.IsString Data.Greskell.GTraversal.RepeatLabel
+ Data.Greskell.GTraversal: instance GHC.Classes.Eq Data.Greskell.GTraversal.RepeatLabel
+ Data.Greskell.GTraversal: instance GHC.Classes.Eq Data.Greskell.GTraversal.RepeatPos
+ Data.Greskell.GTraversal: instance GHC.Classes.Ord Data.Greskell.GTraversal.RepeatLabel
+ Data.Greskell.GTraversal: instance GHC.Classes.Ord Data.Greskell.GTraversal.RepeatPos
+ Data.Greskell.GTraversal: instance GHC.Enum.Bounded Data.Greskell.GTraversal.RepeatPos
+ Data.Greskell.GTraversal: instance GHC.Enum.Enum Data.Greskell.GTraversal.RepeatPos
+ Data.Greskell.GTraversal: instance GHC.Show.Show (Data.Greskell.GTraversal.MWalk c s e)
+ Data.Greskell.GTraversal: instance GHC.Show.Show (Data.Greskell.GTraversal.RepeatEmit c s)
+ Data.Greskell.GTraversal: instance GHC.Show.Show (Data.Greskell.GTraversal.RepeatUntil c s)
+ Data.Greskell.GTraversal: instance GHC.Show.Show Data.Greskell.GTraversal.RepeatLabel
+ Data.Greskell.GTraversal: instance GHC.Show.Show Data.Greskell.GTraversal.RepeatPos
+ Data.Greskell.GTraversal: newtype RepeatLabel
Files
- ChangeLog.md +36/−0
- greskell.cabal +2/−2
- src/Data/Greskell/GTraversal.hs +396/−1
- test/Data/Greskell/GTraversalSpec.hs +37/−3
- test/ServerTest.hs +24/−1
ChangeLog.md view
@@ -1,5 +1,41 @@ # Revision history for greskell +## 1.0.1.0 -- 2020-04-24++### GTraversal module++* Add the following functions.+ * `gRepeat`+ * `gTimes`+ * `gUntilHead`+ * `gUntilTail`+ * `gEmitHead`+ * `gEmitTail`+ * `gEmitHeadT`+ * `gEmitTailT`+ * `gLoops`+ * `gIs`+ * `gIs'`+ * `gIsP`+ * `gIsP'`+ * `gCyclicPath`+ * `gCyclicPath'`+ * `gSimplePath`+ * `gSimplePath'`+ * `gUnion`+ * `gChoose3`+ * `gConstant`+ * `gLocal`+ * `gBarrier`+ * `gDedup`+ * `gDedupN`+ * `gUnfold`+* Add the follwing types.+ * `RepeatUntil`+ * `RepeatEmit`+ * `RepeatPos`+ * `RepeatLabel`+ ## 1.0.0.1 -- 2019-12-30 * Confirm test with `base-4.13.0.0`
greskell.cabal view
@@ -1,5 +1,5 @@ name: greskell-version: 1.0.0.1+version: 1.0.1.0 author: Toshio Ito <debug.ito@gmail.com> maintainer: Toshio Ito <debug.ito@gmail.com> license: BSD3@@ -26,7 +26,7 @@ -- default-extensions: other-extensions: OverloadedStrings, GeneralizedNewtypeDeriving, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, TypeFamilies,- GADTs, DeriveTraversable, DeriveGeneric+ GADTs, DeriveTraversable, DeriveGeneric, StandaloneDeriving exposed-modules: Data.Greskell, Data.Greskell.Gremlin, Data.Greskell.Binder,
src/Data/Greskell/GTraversal.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE OverloadedStrings, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, TypeFamilies, GADTs #-}+{-# LANGUAGE OverloadedStrings, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses,+ TypeFamilies, GADTs, GeneralizedNewtypeDeriving, StandaloneDeriving #-} {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} -- | -- Module: Data.Greskell.GTraversal@@ -57,6 +58,15 @@ gIdentity, gIdentity', gFilter,+ gCyclicPath,+ gCyclicPath',+ gSimplePath,+ gSimplePath',+ -- ** Is step+ gIs,+ gIs',+ gIsP,+ gIsP', -- ** Has steps gHas1, gHas1',@@ -91,10 +101,34 @@ gLimit, gTail, gSkip,+ -- ** Repeat step+ gRepeat,+ gTimes,+ gUntilHead,+ gUntilTail,+ gEmitHead,+ gEmitTail,+ gEmitHeadT,+ gEmitTailT,+ gLoops,+ RepeatUntil(..),+ RepeatEmit(..),+ RepeatPos(..),+ RepeatLabel(..),+ -- ** Branching steps+ gLocal,+ gUnion,+ gChoose3,+ -- ** Barrier steps+ gBarrier,+ gDedup,+ gDedupN, -- ** Transformation steps gFlatMap, gV, gV',+ gConstant,+ gUnfold, -- ** As step gAs, -- ** Accessor steps@@ -175,6 +209,7 @@ T, Key, Cardinality, KeyValue(..), Keys(..) )+import qualified Data.Greskell.Greskell as Greskell import Data.Greskell.GraphSON (GValue, FromGraphSON) import Data.Greskell.Gremlin ( Comparator(..),@@ -553,6 +588,60 @@ gFilter :: (ToGTraversal g, WalkType c, WalkType p, Split c p) => g c s e -> Walk p s s gFilter walk = unsafeWalk "filter" [travToG walk] +-- | @.cyclicPath@ step.+--+-- @since 1.0.1.0+gCyclicPath :: (WalkType c) => Walk c a a+gCyclicPath = liftWalk gCyclicPath'++-- | Monomorphic version of 'gCyclicPath'.+--+-- @since 1.0.1.0+gCyclicPath' :: Walk Filter a a+gCyclicPath' = unsafeWalk "cyclicPath" []++-- | @.simplePath@ step.+--+-- @since 1.0.1.0+gSimplePath :: (WalkType c) => Walk c a a+gSimplePath = liftWalk gSimplePath'++-- | Monomorphic version of 'gSimplePath'.+--+-- @since 1.0.1.0+gSimplePath' :: Walk Filter a a+gSimplePath' = unsafeWalk "simplePath" []++-- | @.is@ step of simple equality.+--+-- >>> toGremlin (source "g" & sV' [] &. gValues ["age" :: Key AVertex Int] &. gIs 30)+-- "g.V().values(\"age\").is(30)"+--+-- @since 1.0.1.0+gIs :: (WalkType c) => Greskell v -> Walk c v v+gIs = liftWalk . gIs'++-- | Monomorphic version of 'gIs'.+--+-- @since 1.0.1.0+gIs' :: Greskell v -> Walk Filter v v+gIs' v = unsafeWalk "is" [toGremlin v]++-- | @.is@ step with predicate 'P'.+--+-- >>> toGremlin (source "g" & sV' [] &. gValues ["age" :: Key AVertex Int] &. gIsP (pLte 30))+-- "g.V().values(\"age\").is(P.lte(30))"+--+-- @since 1.0.1.0+gIsP :: (WalkType c) => Greskell (P v) -> Walk c v v+gIsP = liftWalk . gIsP'++-- | Monomorphic version of 'gIsP'.+--+-- @since 1.0.1.0+gIsP' :: Greskell (P v) -> Walk Filter v v+gIsP' p = unsafeWalk "is" [toGremlin p]+ -- | @.has@ step with one argument. -- -- >>> toGremlin (source "g" & sV' [] &. gHas1 "age")@@ -748,7 +837,289 @@ gSkip :: Greskell Int -> Walk Transform s s gSkip num = unsafeWalk "skip" [toGremlin num] +-- | A label that points to a loop created by @.repeat@ step. It can+-- be used by @.loops@ step to specify the loop.+--+-- @since 1.0.1.0+newtype RepeatLabel =+ RepeatLabel { unRepeatLabel :: Text }+ deriving (Show,Eq,Ord,IsString) +-- | Return Gremlin String literal.+instance ToGreskell RepeatLabel where+ type GreskellReturn RepeatLabel = Text+ toGreskell (RepeatLabel t) = Greskell.string t++-- | Position of a step modulator relative to @.repeat@ step.+--+-- @since 1.0.1.0+data RepeatPos = RepeatHead -- ^ Modulator before the @.repeat@ step.+ | RepeatTail -- ^ Modulator after the @.repeat@ step.+ deriving (Show,Eq,Ord,Enum,Bounded)++-- | @.until@ or @.times@ modulator step.+--+-- Type @c@ is the 'WalkType' of the parent @.repeat@ step. Type @s@+-- is the start (and end) type of the @.repeat@ step.+--+-- @since 1.0.1.0+data RepeatUntil c s where+ -- | @.times@ modulator.+ RepeatTimes :: Greskell Int -> RepeatUntil c s+ -- | @.until@ modulator with a sub-traversal as the predicate to+ -- decide if the repetition should stop.+ RepeatUntilT :: (WalkType cc, WalkType c, Split cc c) => GTraversal cc s e -> RepeatUntil c s++deriving instance Show (RepeatUntil c s)++makeUntilWalk :: WalkType c => RepeatUntil c s -> Walk c s s+makeUntilWalk (RepeatTimes count) = unsafeWalk "times" [toGremlin count]+makeUntilWalk (RepeatUntilT trav) = unsafeWalk "until" [toGremlin trav]++-- | @.emit@ modulator step.+--+-- Type @c@ is the 'WalkType' of the parent @.repeat@ step. Type @s@+-- is the start (and end) type of the @.repeat@ step.+--+-- @since 1.0.1.0+data RepeatEmit c s where+ -- | @.emit@ modulator without argument. It always emits the input+ -- traverser of type @s@.+ RepeatEmit :: RepeatEmit c s+ -- | @.emit@ modulator with a sub-traversal as the predicate to+ -- decide if it emits the traverser.+ RepeatEmitT :: (WalkType cc, WalkType c, Split cc c) => GTraversal cc s e -> RepeatEmit c s++deriving instance Show (RepeatEmit c s)++makeEmitWalk :: WalkType c => RepeatEmit c s -> Walk c s s+makeEmitWalk (RepeatEmit) = unsafeWalk "emit" []+makeEmitWalk (RepeatEmitT trav) = unsafeWalk "emit" [toGremlin trav]++++-- | Zero or more Gremlin steps.+--+-- @since 1.0.1.0+newtype MWalk c s e = MWalk (Maybe (Walk c s e))+ deriving (Show)++deriving instance WalkType c => Semigroup (MWalk c s s)+deriving instance WalkType c => Monoid (MWalk c s s)++toMWalk :: Walk c s e -> MWalk c s e+toMWalk = MWalk . Just++-- | @MWalk Nothing@ is coverted to identity step.+fromMWalk :: WalkType c => MWalk c s s -> Walk c s s+fromMWalk (MWalk Nothing) = mempty+fromMWalk (MWalk (Just w)) = w++++-- | @.repeat@ step.+--+-- @since 1.0.1.0+gRepeat :: (ToGTraversal g, WalkType c)+ => Maybe RepeatLabel -- ^ Label for the loop.+ -> Maybe (RepeatPos, RepeatUntil c s)+ -- ^ @.until@ or @.times@ modulator. You can use 'gTimes',+ -- 'gUntilHead', 'gUntilTail' to make this argument.+ -> Maybe (RepeatPos, RepeatEmit c s)+ -- ^ @.emit@ modulator. You can use 'gEmitHead', 'gEmitTail',+ -- 'gEmitHeadT', 'gEmitTailT' to make this argument.+ -> g c s s -- ^ Repeated traversal+ -> Walk c s s+gRepeat mlabel muntil memit repeated_trav = fromMWalk (head_walk <> toMWalk repeat_body <> tail_walk)+ where+ repeat_body = unsafeWalk "repeat" (label_args ++ [toGremlin $ toGTraversal repeated_trav])+ label_args = maybe [] (\l -> [toGremlin l]) mlabel+ head_walk = head_until <> head_emit+ tail_walk = tail_until <> tail_emit+ (head_until, tail_until) =+ case muntil of+ Nothing -> (mempty, mempty)+ Just (pos, u) ->+ case pos of+ RepeatHead -> (toMWalk $ makeUntilWalk u, mempty)+ RepeatTail -> (mempty, toMWalk $ makeUntilWalk u)+ (head_emit, tail_emit) =+ case memit of+ Nothing -> (mempty, mempty)+ Just (pos, e) ->+ case pos of+ RepeatHead -> (toMWalk $ makeEmitWalk e, mempty)+ RepeatTail -> (mempty, toMWalk $ makeEmitWalk e)++-- | @.times@ modulator before the @.repeat@ step. It always returns+-- 'Just'.+--+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing (gTimes 3) Nothing (gOut' []))+-- "g.V().times(3).repeat(__.out())"+--+-- @since 1.0.1.0+gTimes :: Greskell Int+ -- ^ Repeat count. If it's less than or equal to 0, the+ -- repeated traversal is never executed.+ -> Maybe (RepeatPos, RepeatUntil c s)+gTimes c = Just (RepeatHead, RepeatTimes c)++-- | @.until@ modulator before the @.repeat@ step. It always returns+-- 'Just'.+--+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilHead $ gHasLabel' "person") Nothing (gOut' []))+-- "g.V().until(__.hasLabel(\"person\")).repeat(__.out())"+--+-- @since 1.0.1.0+gUntilHead :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatUntil c s)+gUntilHead trav = Just (RepeatHead, RepeatUntilT $ toGTraversal trav)++-- | @.until@ modulator after the @.repeat@ step. It always returns+-- 'Just'.+--+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilTail $ gHasLabel' "person") Nothing (gOut' []))+-- "g.V().repeat(__.out()).until(__.hasLabel(\"person\"))"+--+-- @since 1.0.1.0+gUntilTail :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatUntil c s)+gUntilTail trav = Just (RepeatTail, RepeatUntilT $ toGTraversal trav)++-- | @.emit@ modulator without argument before the @.repeat@ step. It+-- always returns 'Just'.+--+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing gEmitHead (gOut' []))+-- "g.V().emit().repeat(__.out())"+--+-- @since 1.0.1.0+gEmitHead :: Maybe (RepeatPos, RepeatEmit c s)+gEmitHead = Just (RepeatHead, RepeatEmit)++-- | @.emit@ modulator without argument after the @.repeat@ step. It+-- always returns 'Just'.+--+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing gEmitTail (gOut' []))+-- "g.V().repeat(__.out()).emit()"+--+-- @since 1.0.1.0+gEmitTail :: Maybe (RepeatPos, RepeatEmit c s)+gEmitTail = Just (RepeatTail, RepeatEmit)++-- | @.emit@ modulator with a sub-traversal argument before the+-- @.repeat@ step. It always returns 'Just'.+--+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing (gEmitHeadT $ gHasLabel' "person") (gOut' []))+-- "g.V().emit(__.hasLabel(\"person\")).repeat(__.out())"+--+-- @since 1.0.1.0+gEmitHeadT :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatEmit c s)+gEmitHeadT trav = Just (RepeatHead, RepeatEmitT $ toGTraversal trav)++-- | @.emit@ modulator with a sub-traversal argument after the+-- @.repeat@ step. It always returns 'Just'.+--+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing (gEmitTailT $ gHasLabel' "person") (gOut' []))+-- "g.V().repeat(__.out()).emit(__.hasLabel(\"person\"))"+--+-- @since 1.0.1.0+gEmitTailT :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatEmit c s)+gEmitTailT trav = Just (RepeatTail, RepeatEmitT $ toGTraversal trav)++-- | @.loops@ step.+--+-- >>> let loop_label = Just "the_loop"+-- >>> toGremlin (source "g" & sV' [] &. gRepeat loop_label (gUntilTail $ gLoops loop_label >>> gIs 3) Nothing (gOut' []))+-- "g.V().repeat(\"the_loop\",__.out()).until(__.loops(\"the_loop\").is(3))"+--+-- @since 1.0.1.0+gLoops :: Maybe RepeatLabel -> Walk Transform s Int+gLoops mlabel = unsafeWalk "loops" $ maybe [] (\l -> [toGremlin l]) mlabel++-- | @.local@ step.+--+-- >>> toGremlin (source "g" & sV' [] &. gLocal ( gOut' [] >>> gLimit 3 ))+-- "g.V().local(__.out().limit(3))"+--+-- @since 1.0.1.0+gLocal :: (ToGTraversal g, WalkType c) => g c s e -> Walk c s e+gLocal t = unsafeWalk "local" [toGremlin $ toGTraversal t]++-- | @.union@ step.+--+-- >>> let key_age = ("age" :: Key AVertex Int)+-- >>> let key_birth_year = ("birth_year" :: Key AVertex Int)+-- >>> toGremlin (source "g" & sV' [] &. gUnion [gValues [key_age], gValues [key_birth_year]])+-- "g.V().union(__.values(\"age\"),__.values(\"birth_year\"))"+--+-- @since 1.0.1.0+gUnion :: (ToGTraversal g, WalkType c) => [g c s e] -> Walk c s e+gUnion ts = unsafeWalk "union" $ map (toGremlin . toGTraversal) ts++-- | @.choose@ step with if-then-else style.+--+-- >>> let key_age = ("age" :: Key AVertex Int)+-- >>> toGremlin (source "g" & sV' [] &. gChoose3 (gHas2' key_age 30) (gIn' []) (gOut' []))+-- "g.V().choose(__.has(\"age\",30),__.in(),__.out())"+--+-- @since 1.0.1.0+gChoose3 :: (ToGTraversal g, Split cc c, WalkType cc, WalkType c)+ => g cc s ep -- ^ the predicate traversal.+ -> g c s e -- ^ The traversal executed if the predicate traversal outputs something.+ -> g c s e -- ^ The traversal executed if the predicate traversal outputs nothing.+ -> Walk c s e+gChoose3 pt tt ft = unsafeWalk "choose"+ [ toGremlin $ toGTraversal pt,+ toGremlin $ toGTraversal tt,+ toGremlin $ toGTraversal ft+ ]++-- | @.barrier@ step.+--+-- @since 1.0.1.0+gBarrier :: WalkType c+ => Maybe (Greskell Int)+ -- ^ Max number of traversers kept at this barrier.+ -> Walk c s s+gBarrier mmax = unsafeWalk "barrier" $ maybe [] (\m -> [toGremlin m]) mmax++-- | @.dedup@ step without argument.+--+-- @.dedup@ step is 'Transform' because the filtering decision depends+-- on the sequence (order) of input elements.+--+-- >>> toGremlin (source "g" & sV' [] &. gDedup Nothing)+-- "g.V().dedup()"+-- >>> let key_age = ("age" :: Key AVertex Int)+-- >>> toGremlin (source "g" & sV' [] &. gDedup (Just $ gBy key_age))+-- "g.V().dedup().by(\"age\")"+--+-- @since 1.0.1.0+gDedup :: Maybe (ByProjection s e)+ -- ^ @.by@ modulator. If specified, the result of type @e@ is+ -- used as the criterion of deduplication.+ -> Walk Transform s s+gDedup mp = gDedupGeneric [] mp++-- | @.dedup@ step with at least one argument. The tuple specified by+-- the 'AsLabel's is used as the criterion of deduplication.+--+-- >>> let label_a = ("a" :: AsLabel AVertex)+-- >>> let label_b = ("b" :: AsLabel AVertex)+-- >>> toGremlin (source "g" & sV' [] &. gAs label_a &. gOut' [] &. gAs label_b &. gDedupN label_a [label_b] Nothing)+-- "g.V().as(\"a\").out().as(\"b\").dedup(\"a\",\"b\")"+--+-- @since 1.0.1.0+gDedupN :: AsLabel a -> [AsLabel a] -> Maybe (ByProjection a e) -> Walk Transform s s+gDedupN l ls mp = gDedupGeneric (map toGremlin (l : ls)) mp++gDedupGeneric :: [Text] -> Maybe (ByProjection a b) -> Walk Transform s s+gDedupGeneric args mp = + case mp of+ Nothing -> main_walk+ Just (ByProjection g) -> modulateWith main_walk [unsafeWalk "by" [toGremlin g]]+ where+ main_walk = unsafeWalk "dedup" args++ -- | Data types that mean a projection from one type to another. class ProjectionLike p where type ProjectionLikeStart p@@ -913,6 +1284,30 @@ -- @since 0.2.0.0 gV' :: [Greskell (ElementID AVertex)] -> Walk Transform s AVertex gV' = gV++-- | @.constant@ step.+--+-- >>> toGremlin (source "g" & sV' [] &. gConstant (10 :: Greskell Int))+-- "g.V().constant(10)"+--+-- @since 1.0.1.0+gConstant :: Greskell a -> Walk Transform s a+gConstant v = unsafeWalk "constant" [toGremlin v]++-- | @.unfold@ step.+--+-- Note that we use 'AsIterator' here because basically the @.unfold@+-- step does the same thing as @IteratorUtils.asIterator@ function in+-- Tinkerpop. However, Tinkerpop's implementation of @.unfold@ step+-- doesn't necessarily use @asIterator@, so there may be some corner+-- cases where @asIterator@ and @.unfold@ step behave differently.+--+-- >>> toGremlin (source "g" & sV' [] &. gFold &. gUnfold)+-- "g.V().fold().unfold()"+--+-- @since 1.0.1.0+gUnfold :: AsIterator a => Walk Transform a (IteratorItem a)+gUnfold = unsafeWalk "unfold" [] -- | @.as@ step. --
test/Data/Greskell/GTraversalSpec.hs view
@@ -22,13 +22,16 @@ import Data.Greskell.Greskell ( toGremlin, Greskell, gvalueInt) import Data.Greskell.GTraversal- ( Walk, Transform,+ ( Walk, Transform, Filter, source, (&.), ($.), sV', sE',- gHas1, gHas2, gHas2P, gHasLabelP, gHasIdP,+ gHas1, gHas2, gHas2P, gHasLabelP, gHasIdP, gIs, gOut', gRange, gValues, gNot, gIn', gOrder, gProperties, gHasKeyP, gHasValueP,- ByComparator(..), gBy2, gBy1, gBy+ ByComparator(..), gBy2, gBy1, gBy,+ gRepeat, gTimes, gUntilHead, gUntilTail,+ gEmitHead, gEmitTail, gEmitHeadT, gEmitTailT,+ gLoops ) @@ -41,6 +44,7 @@ spec_order_by spec_compose_steps spec_has+ spec_repeat spec_GraphTraversalSource :: Spec@@ -130,3 +134,33 @@ specify "P" $ do toGremlin (source "g" & sV' [] &. gProperties ["age" :: Key e Int] &. gHasValueP (pGte 20)) `shouldBe` "g.V().properties(\"age\").hasValue(P.gte(20))"++spec_repeat :: Spec+spec_repeat = do+ let hasName :: Greskell Text -> Walk Filter AVertex AVertex+ hasName v = gHas2 keyName v+ keyName :: Key AVertex Text+ keyName = "name"+ describe "gRepeat" $ do+ specify "no modulation" $ do+ toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing Nothing (gOut' []))+ `shouldBe` "g.V().repeat(__.out())"+ specify "gTimes and gEmitHead" $ do+ toGremlin (source "g" & sV' [] &. gRepeat Nothing (gTimes 3) gEmitHead (gOut' []))+ `shouldBe` "g.V().times(3).emit().repeat(__.out())"+ specify "gUntilHead and gEmitTail" $ do+ toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilHead $ hasName "foo") gEmitTail (gOut' []))+ `shouldBe` "g.V().until(__.has(\"name\",\"foo\")).repeat(__.out()).emit()"+ specify "gUntilTail and gEmitHeadT" $ do+ toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilTail $ hasName "foo") (gEmitHeadT $ hasName "bar") (gOut' []))+ `shouldBe` "g.V().emit(__.has(\"name\",\"bar\")).repeat(__.out()).until(__.has(\"name\",\"foo\"))"+ specify "gUntilTail and gEmitTailT" $ do+ toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilTail $ hasName "foo") (gEmitTailT $ hasName "bar") (gOut' []))+ `shouldBe` "g.V().repeat(__.out()).until(__.has(\"name\",\"foo\")).emit(__.has(\"name\",\"bar\"))"+ specify "gLoops without label" $ do+ toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilTail $ gLoops Nothing >>> gIs 5) Nothing (gOut' []))+ `shouldBe` "g.V().repeat(__.out()).until(__.loops().is(5))"+ specify "gLoops with label" $ do+ let loop_label = "LP"+ toGremlin (source "g" & sV' [] &. gRepeat (Just loop_label) (gUntilTail $ gLoops (Just loop_label) >>> gIs 5) Nothing (gOut' []))+ `shouldBe` "g.V().repeat(\"LP\",__.out()).until(__.loops(\"LP\").is(5))"
test/ServerTest.hs view
@@ -50,7 +50,8 @@ gAs, gSelect1, gSelectN, gSelectBy1, gSelectByN, gFilter, gOut', gOutV, gOutV', gInV, gInV', gId, gLabel, gProject, gValueMap,- gProject, gByL+ gProject, gByL,+ gRepeat, gTimes, gEmitHead, gUntilTail, gLoops, gIsP ) import Data.Greskell.PMap (lookupAsM, lookupListAs, pMapToThrow) @@ -70,6 +71,7 @@ spec_as spec_selectBy spec_project+ spec_repeat spec_basics :: SpecWith (String,Int) spec_basics = do@@ -454,3 +456,24 @@ 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]