packages feed

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 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]