packages feed

greskell 2.0.3.2 → 2.0.3.3

raw patch · 7 files changed

+87/−50 lines, 7 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

Files

ChangeLog.md view
@@ -1,5 +1,13 @@ # Revision history for greskell +## 2.0.3.3  -- 2025-01-30++* Binder: now `newBind` produces an expression like `((__v0))`, that is, a variable name wrapped with double parens.+  (see https://github.com/debug-ito/greskell/issues/18 )+  While this is basically backward-compatible, it can break a user code if it depends on the internal of the `Greskell` returned by `newBind`.+* Support ghc-9.12 (base-4.21).+  + ## 2.0.3.2  -- 2024-11-05  * Bump dependency version bounds.
greskell.cabal view
@@ -1,5 +1,5 @@ name:                   greskell-version:                2.0.3.2+version:                2.0.3.3 author:                 Toshio Ito <debug.ito@gmail.com> maintainer:             Toshio Ito <debug.ito@gmail.com> license:                BSD3@@ -40,7 +40,7 @@                         Data.Greskell.NonEmptyLike,                         Data.Greskell.Logic   -- other-modules:        -  build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0,+  build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0 || ^>=4.21.0,                         greskell-core ^>=1.0.0,                         text ^>=1.2.3 || ^>=2.0.2 || ^>=2.1,                         transformers ^>=0.5.6 || ^>=0.6.1,@@ -69,7 +69,7 @@                         Data.Greskell.LogicSpec,                         ExamplesSpec   build-tool-depends:   hspec-discover:hspec-discover-  build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0,+  build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0 || ^>=4.21.0,                         text ^>=1.2.3 || ^>=2.0.2 || ^>=2.1,                         aeson ^>=2.0.2 || ^>=2.1.0 || ^>=2.2.3,                         unordered-containers ^>=0.2.15,@@ -84,7 +84,7 @@   hs-source-dirs:       test   ghc-options:          -Wall -fno-warn-unused-imports "-with-rtsopts=-M512m"   main-is:              Typecheck.hs-  build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0,+  build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0 || ^>=4.21.0,                         hspec ^>=2.9.1 || ^>=2.10.6 || ^>=2.11.9,                         greskell,                         should-not-typecheck ^>=2.1.0@@ -104,7 +104,7 @@   other-modules:        ServerTest.Common   if flag(server-test)     -- Explicitly remove dependency. See https://github.com/haskell/cabal/issues/1725-    build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0,+    build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0 || ^>=4.21.0,                           aeson ^>=2.0.2 || ^>=2.1.0 || ^>=2.2.3,                           hspec ^>=2.9.1 || ^>=2.10.6 || ^>=2.11.9,                           text ^>=1.2.3 || ^>=2.0.2 || ^>=2.1,@@ -135,7 +135,7 @@   other-extensions:     OverloadedStrings   other-modules:        ServerTest.Common   if flag(server-behavior-test)-    build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0,+    build-depends:        base ^>=4.13.0 || ^>=4.14.0 || ^>=4.15.0 || ^>=4.16.0 || ^>=4.17.0 || ^>=4.18.0 || ^>=4.19.0 || ^>=4.20.0 || ^>=4.21.0,                           aeson ^>=2.0.2 || ^>=2.1.0 || ^>=2.2.3,                           hspec ^>=2.9.1 || ^>=2.10.6 || ^>=2.11.9,                           text ^>=1.2.3 || ^>=2.0.2 || ^>=2.1,
src/Data/Greskell/Binder.hs view
@@ -88,7 +88,11 @@ -- Unsafely create a placeholder variable of arbitrary type with the -- given index. unsafePlaceHolder :: PlaceHolderIndex -> Greskell a-unsafePlaceHolder = unsafeGreskellLazy . toPlaceHolderVariable+unsafePlaceHolder = unsafeGreskellLazy . wrapWithParens  . toPlaceHolderVariable+  where+    wrapWithParens v = "((" <> v <> "))"+    -- This is necessary to ensure the v is always treated as a varible name (NOT a type name) in Groovy script.+    -- See https://github.com/debug-ito/greskell/issues/18  -- | __This function is only for internal use.__ --
src/Data/Greskell/Extra.hs view
@@ -125,21 +125,21 @@     for_writePropertyKeyValues =       let binder = (writePropertyKeyValues [("age", (21 :: Int))] :: Binder (Walk SideEffect AVertex AVertex))           (walk, binding) = runBinder binder-      in [ (unpack $ toGremlin walk, "__.property(\"age\",__v0).identity()")+      in [ (unpack $ toGremlin walk, "__.property(\"age\",((__v0))).identity()")          , (show $ sortBy (comparing fst) $ KeyMap.toList binding, "[(\"__v0\",Number 21.0)]")          ]     for_writeKeyValues =       let keyAge = ("age" :: Key AVertex Int)           keyName = ("name" :: Key AVertex Text)           (walk, binding) = runBinder $ writeKeyValues <$> sequence [keyAge <=:> 21, keyName <=:> "Josh"]-      in [ (unpack $ toGremlin walk, "__.property(\"age\",__v0).property(\"name\",__v1).identity()")+      in [ (unpack $ toGremlin walk, "__.property(\"age\",((__v0))).property(\"name\",((__v1))).identity()")          , (show $ sortBy (comparing fst) $ KeyMap.toList binding, "[(\"__v0\",Number 21.0),(\"__v1\",String \"Josh\")]")          ]     for_operators =       let keyNName = ("nickname" :: Key AVertex (Maybe Text))           keyCompany = ("company" :: Key AVertex (Maybe Text))           (walk, binding) = runBinder $ writeKeyValues <$> sequence [keyNName <=?> Nothing, keyCompany <=?> Just "foobar.com"]-      in [ (unpack $ toGremlin walk, "__.property(\"company\",__v0).identity()")+      in [ (unpack $ toGremlin walk, "__.property(\"company\",((__v0))).identity()")          , (show $ sortBy (comparing fst) $ KeyMap.toList binding, "[(\"__v0\",String \"foobar.com\")]")          ]     for_gWhenEmptyInput =
test/Data/Greskell/BinderSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module Data.Greskell.BinderSpec     ( main     , spec@@ -8,7 +9,8 @@ import           Data.Aeson             (toJSON) import qualified Data.Aeson.Key         as Key import qualified Data.Aeson.KeyMap      as KM-import           Data.Text              (unpack)+import           Data.Text              (Text)+import qualified Data.Text              as T import           Test.Hspec  import           Data.Greskell.AsLabel  (AsLabel)@@ -18,50 +20,57 @@ main :: IO () main = hspec spec -shouldBeVariable :: Greskell a -> IO ()-shouldBeVariable got_greskell =-  case unpack $ toGremlin got_greskell of-   [] -> expectationFailure "Expect a Gremlin variable, but got empty script."-   (h : rest) -> do-     h `shouldSatisfy` (`elem` variableHeads)-     forM_ rest (`shouldSatisfy` (`elem` variableRests))+extractVarName :: Greskell a -> IO Text+extractVarName got_greskell = checkVarName =<< (stripParens $ toGremlin got_greskell)   where+    stripParens v =+      case T.stripPrefix "((" =<< T.stripSuffix "))" v of+        Nothing -> do+          expectationFailure "Binder should produce an expression of a variable wrapped with double parens"+          return ""+        Just a  -> return a+    checkVarName v =+      case T.unpack v of+        [] -> do+          expectationFailure "Expect a Gremlin variable, but got empty script."+          return ""+        (h : rest) -> do+          h `shouldSatisfy` (`elem` variableHeads)+          forM_ rest (`shouldSatisfy` (`elem` variableRests))+          return v     variableHeads = '_' : (['a' .. 'z'] ++ ['A' .. 'Z'])     variableRests = variableHeads ++ ['0' .. '9'] -toKey :: Greskell a -> Key.Key-toKey = Key.fromText . toGremlin- spec :: Spec spec = describe "Binder" $ do   it "should keep bound values" $ do     let b = do           v1 <- newBind (100 :: Int)-          v2 <- newBind "hogehoge"+          v2 <- newBind ("hogehoge" :: Text)           return (v1, v2)         ((got_v1, got_v2), got_bind) = runBinder b     toGremlin got_v1 `shouldNotBe` toGremlin got_v2-    shouldBeVariable got_v1-    shouldBeVariable got_v2-    got_bind `shouldBe` KM.fromList [ (toKey got_v1, toJSON (100 :: Int)),-                                      (toKey got_v2, toJSON "hogehoge")+    v1Name <- extractVarName got_v1+    v2Name <- extractVarName got_v2+    got_bind `shouldBe` KM.fromList [ (Key.fromText v1Name, toJSON (100 :: Int)),+                                      (Key.fromText v2Name, toJSON ("hogehoge" :: Text))                                     ]   it "should compose and produce new variables" $ do-    let b = newBind "foobar"+    let b = newBind ("foobar" :: Text)         ((got_v1, got_v2), got_bind) = runBinder $ ((,) <$> b <*> b)     toGremlin got_v1 `shouldNotBe` toGremlin got_v2-    shouldBeVariable got_v1-    shouldBeVariable got_v2-    got_bind `shouldBe` KM.fromList [ (toKey got_v1, toJSON "foobar"),-                                      (toKey got_v2, toJSON "foobar")+    v1Name <- extractVarName got_v1+    v2Name <- extractVarName got_v2+    got_bind `shouldBe` KM.fromList [ (Key.fromText v1Name, toJSON ("foobar" :: Text)),+                                      (Key.fromText v2Name, toJSON ("foobar" :: Text))                                     ]   it "should also be able to produce AsLabels" $ do     let newIntLabel :: Binder (AsLabel Int)         newIntLabel = newAsLabel-        newVar = newBind "foobar"+        newVar = newBind ("foobar" :: Text)         ((got_v1, got_l1, got_v2, got_l2), _) =           runBinder $ ((,,,) <$> newVar <*> newIntLabel <*> newVar <*> newIntLabel)-    shouldBeVariable got_v1-    shouldBeVariable got_v2+    _ <- extractVarName got_v1+    _ <- extractVarName got_v2     toGremlin got_v1 `shouldNotBe` toGremlin got_v2     got_l1 `shouldNotBe` got_l2
test/Data/Greskell/ExtraSpec.hs view
@@ -35,15 +35,15 @@       let input :: [(Text, Int)]           input = [("age", 24)]       (runBoundWalk $ writePropertyKeyValues input)-        `shouldBe` ( "__.property(\"age\",__v0).identity()",+        `shouldBe` ( "__.property(\"age\",((__v0))).identity()",                      KM.fromList [("__v0", Number 24)]                    )     specify "multiple props" $ do       let input :: [(Text, Value)]           input = [("age", Number 24), ("name", String "Toshio"), ("foo", String "bar")]       (runBoundWalk $ writePropertyKeyValues input)-        `shouldBe` ( "__.property(\"age\",__v0).property(\"name\",__v1)"-                     <> ".property(\"foo\",__v2).identity()",+        `shouldBe` ( "__.property(\"age\",((__v0))).property(\"name\",((__v1)))"+                     <> ".property(\"foo\",((__v2))).identity()",                      KM.fromList [ ("__v0", Number 24),                                    ("__v1", String "Toshio"),                                    ("__v2", String "bar")
test/ServerTest.hs view
@@ -23,7 +23,7 @@ import           Data.Greskell.AsIterator          (AsIterator (IteratorItem)) import           Data.Greskell.AsLabel             (AsLabel (..), lookupAsM) import qualified Data.Greskell.AsLabel             as As-import           Data.Greskell.Binder              (newBind, runBinder)+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 (..),@@ -33,8 +33,8 @@                                                     (=:)) import           Data.Greskell.GraphSON            (FromGraphSON, GValue, nonTypedGValue,                                                     parseEither)-import           Data.Greskell.Gremlin             (Order, P, Predicate (..), cCompare, oDecr,-                                                    oIncr, pAnd, pEq, pGte, pLt, pNot, pTest)+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)@@ -60,6 +60,7 @@ spec :: Spec spec = withEnv $ do   spec_basics+  spec_binder   spec_comparator   spec_predicate   spec_T@@ -155,19 +156,34 @@          => 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 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)+  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