packages feed

hasbolt-extras 0.0.0.7 → 0.0.0.8

raw patch · 7 files changed

+333/−4 lines, 7 filesdep +freedep +mtlPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependencies added: free, mtl

API changes (from Hackage documentation)

+ Database.Bolt.Extras.DSL: (#) :: a -> (a -> b) -> b
+ Database.Bolt.Extras.DSL: (:!-:) :: RelSelector -> NodeSelector -> PathPart
+ Database.Bolt.Extras.DSL: (:!->:) :: RelSelector -> NodeSelector -> PathPart
+ Database.Bolt.Extras.DSL: (:-!:) :: PathSelector -> PathPart -> PathSelector
+ Database.Bolt.Extras.DSL: (:<-!:) :: PathSelector -> PathPart -> PathSelector
+ Database.Bolt.Extras.DSL: Create :: Selectors -> next -> Expr next
+ Database.Bolt.Extras.DSL: Delete :: [Text] -> next -> Expr next
+ Database.Bolt.Extras.DSL: DetachDelete :: [Text] -> next -> Expr next
+ Database.Bolt.Extras.DSL: Match :: Selectors -> next -> Expr next
+ Database.Bolt.Extras.DSL: Merge :: Selectors -> next -> Expr next
+ Database.Bolt.Extras.DSL: NodeSelector :: Maybe Text -> [Text] -> [(Text, Value)] -> NodeSelector
+ Database.Bolt.Extras.DSL: OptionalMatch :: Selectors -> next -> Expr next
+ Database.Bolt.Extras.DSL: P :: NodeSelector -> PathSelector
+ Database.Bolt.Extras.DSL: PS :: PathSelector -> Selector
+ Database.Bolt.Extras.DSL: RelSelector :: Maybe Text -> Text -> [(Text, Value)] -> RelSelector
+ Database.Bolt.Extras.DSL: Return :: [Text] -> next -> Expr next
+ Database.Bolt.Extras.DSL: Set :: [Text] -> next -> Expr next
+ Database.Bolt.Extras.DSL: TS :: Text -> Selector
+ Database.Bolt.Extras.DSL: Text :: Text -> next -> Expr next
+ Database.Bolt.Extras.DSL: Where :: Cond -> next -> Expr next
+ Database.Bolt.Extras.DSL: [nodeIdentifier] :: NodeSelector -> Maybe Text
+ Database.Bolt.Extras.DSL: [nodeLabels] :: NodeSelector -> [Text]
+ Database.Bolt.Extras.DSL: [nodeProperties] :: NodeSelector -> [(Text, Value)]
+ Database.Bolt.Extras.DSL: [relIdentifier] :: RelSelector -> Maybe Text
+ Database.Bolt.Extras.DSL: [relLabel] :: RelSelector -> Text
+ Database.Bolt.Extras.DSL: [relProperties] :: RelSelector -> [(Text, Value)]
+ Database.Bolt.Extras.DSL: class SelectorLike a
+ Database.Bolt.Extras.DSL: createF :: Selectors -> Free Expr ()
+ Database.Bolt.Extras.DSL: data Expr next
+ Database.Bolt.Extras.DSL: data NodeSelector
+ Database.Bolt.Extras.DSL: data PathPart
+ Database.Bolt.Extras.DSL: data PathSelector
+ Database.Bolt.Extras.DSL: data RelSelector
+ Database.Bolt.Extras.DSL: data Selector
+ Database.Bolt.Extras.DSL: defaultNode :: NodeSelector
+ Database.Bolt.Extras.DSL: defaultRel :: RelSelector
+ Database.Bolt.Extras.DSL: deleteF :: [Text] -> Free Expr ()
+ Database.Bolt.Extras.DSL: detachDeleteF :: [Text] -> Free Expr ()
+ Database.Bolt.Extras.DSL: formQuery :: Free Expr () -> Text
+ Database.Bolt.Extras.DSL: matchF :: Selectors -> Free Expr ()
+ Database.Bolt.Extras.DSL: mergeF :: Selectors -> Free Expr ()
+ Database.Bolt.Extras.DSL: optionalMatchF :: Selectors -> Free Expr ()
+ Database.Bolt.Extras.DSL: returnF :: [Text] -> Free Expr ()
+ Database.Bolt.Extras.DSL: setF :: [Text] -> Free Expr ()
+ Database.Bolt.Extras.DSL: textF :: Text -> Free Expr ()
+ Database.Bolt.Extras.DSL: toNodeSelector :: Node -> NodeSelector
+ Database.Bolt.Extras.DSL: toRelSelector :: URelationship -> RelSelector
+ Database.Bolt.Extras.DSL: type Cond = [Text]
+ Database.Bolt.Extras.DSL: type Selectors = [Selector]
+ Database.Bolt.Extras.DSL: whereF :: Cond -> Free Expr ()
+ Database.Bolt.Extras.DSL: withIdentifier :: SelectorLike a => Text -> a -> a
+ Database.Bolt.Extras.DSL: withLabel :: SelectorLike a => Text -> a -> a
+ Database.Bolt.Extras.DSL: withProp :: SelectorLike a => (Text, Value) -> a -> a

Files

CHANGELOG.md view
@@ -6,6 +6,10 @@  ## [Unreleased] +## [0.0.0.8] - 2018-05-14+### Added+- Added `DSL` for `Cypher`.+ ## [0.0.0.7] - 2018-04-23 ### Added - Added ability to delete nodes by their `BoltId`s.
hasbolt-extras.cabal view
@@ -1,5 +1,5 @@ name:           hasbolt-extras-version:        0.0.0.7+version:        0.0.0.8 synopsis:       Extras for hasbolt library description:    Extras for hasbolt library homepage:       https://github.com/biocad/hasbolt-extras#readme@@ -30,6 +30,7 @@                      , Database.Bolt.Extras.Query                      , Database.Bolt.Extras.Template                      , Database.Bolt.Extras.Utils+                     , Database.Bolt.Extras.DSL   other-modules:       Database.Bolt.Extras.Query.Get                      , Database.Bolt.Extras.Query.Put                      , Database.Bolt.Extras.Query.Set@@ -40,14 +41,21 @@                      , Database.Bolt.Extras.Template.Types                      , Database.Bolt.Extras.Template.Instances                      , Database.Bolt.Extras.Template.Converters++                     , Database.Bolt.Extras.DSL.Internal.Types+                     , Database.Bolt.Extras.DSL.Internal.Language+                     , Database.Bolt.Extras.DSL.Internal.Executer+                     , Database.Bolt.Extras.DSL.Internal.Instances                      build-depends:       base >=4.7 && <5-                     , text-                     , hasbolt                      , containers+                     , free+                     , hasbolt+                     , lens+                     , mtl                      , neat-interpolation                      , template-haskell+                     , text                      , th-lift-instances-                     , lens   ghc-options:     -Wall -O2   default-language: Haskell2010
+ src/Database/Bolt/Extras/DSL.hs view
@@ -0,0 +1,11 @@+module Database.Bolt.Extras.DSL+  (+    module Database.Bolt.Extras.DSL.Internal.Types+  , module Database.Bolt.Extras.DSL.Internal.Language+  , module Database.Bolt.Extras.DSL.Internal.Executer+  ) where++import Database.Bolt.Extras.DSL.Internal.Types+import Database.Bolt.Extras.DSL.Internal.Language+import Database.Bolt.Extras.DSL.Internal.Executer+import Database.Bolt.Extras.DSL.Internal.Instances ()
+ src/Database/Bolt/Extras/DSL/Internal/Executer.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE OverloadedStrings #-}++module Database.Bolt.Extras.DSL.Internal.Executer+  (+    formQuery+  ) where++import           Control.Monad.Free                          (Free (..),+                                                              foldFree)+import           Control.Monad.Writer                        (Writer,+                                                              execWriter, tell)+import           Data.Monoid                                 ((<>))+import           Data.Text                                   as T (Text,+                                                                   intercalate,+                                                                   unwords)+import           Database.Bolt.Extras.DSL.Internal.Instances ()+import           Database.Bolt.Extras.DSL.Internal.Types     (Expr (..))+import           Database.Bolt.Extras.Query.Cypher           (ToCypher (..))++-- | Translates 'Expr' to cypher query.+--+execute :: Expr a -> Writer [Text] a+execute (Create s n)        = executeHelperS "CREATE " s n+execute (Match s n)         = executeHelperS "MATCH " s n+execute (OptionalMatch s n) = executeHelperS "OPTIONAL MATCH " s n+execute (Merge s n)         = executeHelperS "MERGE " s n+execute (Where c n)         = executeHelperT "WHERE " c n+execute (Set t n)           = executeHelperT "SET " t n+execute (Delete t n)        = executeHelperT "DELETE " t n+execute (DetachDelete t n)  = executeHelperT "DETACH DELETE " t n+execute (Return t n)        = executeHelperT "RETURN " t n+execute (Text t n)          = tell [t] >> pure n++-- | Helper to translate 'Expr' with 'Selector's+--+executeHelperS :: ToCypher a => Text -> a -> b -> Writer [Text] b+executeHelperS txt s n = tell [txt <> toCypher s] >> pure n++-- | Helper to translate 'Expr' with 'Text's+--+executeHelperT :: Text -> [Text] -> b -> Writer [Text] b+executeHelperT txt t n = tell [txt <> intercalate ", " t] >> pure n++formQueryW :: Free Expr () -> Writer [Text] ()+formQueryW = foldFree execute++formQuery :: Free Expr () -> Text+formQuery = T.unwords . execWriter . formQueryW
+ src/Database/Bolt/Extras/DSL/Internal/Instances.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE RecordWildCards      #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Database.Bolt.Extras.DSL.Internal.Instances () where++import           Control.Monad.Writer                    (execWriter, tell)+import           Data.Text                               (intercalate)+import           Database.Bolt.Extras.DSL.Internal.Types+import           Database.Bolt.Extras.Query.Cypher       (ToCypher (..))++instance SelectorLike NodeSelector where+    withIdentifier idx node = node { nodeIdentifier = Just idx }+    withLabel lbl node      = node { nodeLabels = lbl : nodeLabels node }+    withProp prop node      = node { nodeProperties = prop : nodeProperties node }++instance SelectorLike RelSelector where+    withIdentifier idx rel = rel { relIdentifier = Just idx }+    withLabel lbl rel      = rel { relLabel = lbl }+    withProp prop rel      = rel { relProperties = prop : relProperties rel }++instance ToCypher NodeSelector where+  toCypher NodeSelector{..} = execWriter $ do+    tell "("+    case nodeIdentifier of+      Just idx -> tell idx+      Nothing  -> pure ()+    case nodeLabels of+      [] -> pure ()+      _  -> tell $ toCypher nodeLabels+    case nodeProperties of+      [] -> pure ()+      _  -> do tell "{"+               tell $ toCypher nodeProperties+               tell "}"+    tell ")"++instance ToCypher RelSelector where+  toCypher RelSelector{..} = execWriter $ do+    tell "["+    case relIdentifier of+      Just idx -> tell idx+      Nothing  -> pure ()+    case relLabel of+      "" -> pure ()+      _  -> tell $ toCypher relLabel+    case relProperties of+      [] -> pure ()+      _  -> do tell "{"+               tell $ toCypher relProperties+               tell "}"+    tell "]"++instance ToCypher PathSelector where+  toCypher (ps :-!: rs :!->: ns) = execWriter $ do+    tell $ toCypher ps+    tell "-"+    tell $ toCypher rs+    tell "->"+    tell $ toCypher ns+  toCypher (ps :<-!: rs :!-: ns) = execWriter $ do+    tell $ toCypher ps+    tell "<-"+    tell $ toCypher rs+    tell "-"+    tell $ toCypher ns+  toCypher (ps :-!: rs :!-: ns) = execWriter $ do+    tell $ toCypher ps+    tell "-"+    tell $ toCypher rs+    tell "-"+    tell $ toCypher ns+  toCypher (P ns) = execWriter $+    tell $ toCypher ns+  toCypher (_ :<-!: _ :!->: _) = error "Database.Bolt.Extras.DSL: incorrect path"++instance ToCypher Selector where+  toCypher (PS ps)  = toCypher ps+  toCypher (TS txt) = txt++instance ToCypher Selectors where+  toCypher = intercalate ", " . fmap toCypher
+ src/Database/Bolt/Extras/DSL/Internal/Language.hs view
@@ -0,0 +1,68 @@+module Database.Bolt.Extras.DSL.Internal.Language+  (+    createF+  , matchF+  , optionalMatchF+  , mergeF+  , whereF+  , setF+  , deleteF+  , detachDeleteF+  , returnF+  , textF+  ) where++import           Control.Monad.Free                      (Free (..), liftF)+import           Data.Text                               (Text)+import           Database.Bolt.Extras.DSL.Internal.Types (Cond, Expr (..),+                                                          Selectors)++-- | Prepare 'CREATE' query+--+createF :: Selectors -> Free Expr ()+createF sels = liftF (Create sels ())++-- | Prepare 'MATCH' query+--+matchF :: Selectors -> Free Expr ()+matchF sels = liftF (Match sels ())++-- | Prepare 'OPTIONAL MATCH' query+--+optionalMatchF :: Selectors -> Free Expr ()+optionalMatchF sels = liftF (OptionalMatch sels ())++-- | Prepare 'MERGE' query+--+mergeF :: Selectors -> Free Expr ()+mergeF sels = liftF (Merge sels ())++-- | Prepare 'WHERE' query+--+whereF :: Cond -> Free Expr ()+whereF cond = liftF (Where cond ())++-- | Prepare 'SET' query+--+setF :: [Text] -> Free Expr ()+setF txts = liftF (Set txts ())++-- | Prepare 'DELETE' query+--+deleteF :: [Text] -> Free Expr ()+deleteF txts = liftF (Delete txts ())++-- | Prepare 'DETACH DELETE' query+--+detachDeleteF :: [Text] -> Free Expr ()+detachDeleteF txts = liftF (DetachDelete txts ())++-- | Prepare 'RETURN' query+--+returnF :: [Text] -> Free Expr ()+returnF txts = liftF (Return txts ())++-- | Prepare query with custom text+--+textF :: Text -> Free Expr ()+textF txt = liftF (Text txt ())
+ src/Database/Bolt/Extras/DSL/Internal/Types.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE DeriveFunctor        #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE RecordWildCards      #-}+{-# LANGUAGE TypeSynonymInstances #-}++module Database.Bolt.Extras.DSL.Internal.Types+  (+    NodeSelector (..)+  , RelSelector (..)+  , PathPart (..)+  , PathSelector (..)+  , Selector (..)+  , Selectors+  , Cond+  , Expr (..)+  , SelectorLike (..)+  , (#)+  , defaultNode+  , defaultRel+  , toNodeSelector+  , toRelSelector+  ) where++import           Data.Map.Strict (toList)+import           Data.Text       (Text)+import           Database.Bolt   (Node (..), URelationship (..), Value (..))++-- | Class for Selectors, which can update identifier, labels and props.+--+class SelectorLike a where+   withIdentifier :: Text -> a -> a+   withLabel      :: Text -> a -> a+   withProp       :: (Text, Value) -> a -> a++-- | Selector for 'Node's.+--+data NodeSelector = NodeSelector { nodeIdentifier :: Maybe Text+                                 , nodeLabels     :: [Text]+                                 , nodeProperties :: [(Text, Value)]+                                 }+  deriving (Show, Eq)++-- | Selector for 'URelationship's.+--+data RelSelector = RelSelector { relIdentifier :: Maybe Text+                               , relLabel      :: Text+                               , relProperties :: [(Text, Value)]+                               }+  deriving (Show, Eq)+++(#) :: a -> (a -> b) -> b+(#) = flip ($)++-- | Selector for paths.+--+infixl 2 :!->:+infixl 2 :!-:+data PathPart = RelSelector :!->: NodeSelector+              | RelSelector :!-: NodeSelector+  deriving (Show, Eq)++infixl 1 :-!:+infixl 1 :<-!:+data PathSelector = PathSelector :-!: PathPart+                  | PathSelector :<-!: PathPart+                  | P NodeSelector+  deriving (Show, Eq)++data Selector = PS PathSelector | TS Text+  deriving (Show, Eq)++type Selectors = [Selector]++type Cond = [Text]++-- | Expression in Cypher language.+--+data Expr next = Create Selectors next+               | Match Selectors next+               | OptionalMatch Selectors next+               | Merge Selectors next+               | Where Cond next+               | Set [Text] next+               | Delete [Text] next+               | DetachDelete [Text] next+               | Return [Text] next+               | Text Text next+  deriving (Show, Eq, Functor)++defaultNode :: NodeSelector+defaultNode = NodeSelector Nothing [] []++defaultRel :: RelSelector+defaultRel = RelSelector Nothing "" []++toNodeSelector :: Node -> NodeSelector+toNodeSelector Node{..} = defaultNode { nodeLabels      = labels+                                      , nodeProperties  = filter ((/= N ()) . snd) (toList nodeProps)+                                      }++toRelSelector :: URelationship -> RelSelector+toRelSelector URelationship{..} = defaultRel { relLabel      = urelType+                                             , relProperties = toList urelProps+                                             }