{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleInstances #-} module Database.Neo4j.Batch.Label where import Data.Maybe (fromMaybe) import Data.String (fromString) import Network.HTTP.Base (urlEncodeVars) import qualified Data.Aeson as J import qualified Data.ByteString.Char8 as S import qualified Data.ByteString.Lazy as L import qualified Data.Text as T import qualified Network.HTTP.Types as HT import qualified Database.Neo4j.Graph as G import Database.Neo4j.Types import Database.Neo4j.Batch.Node import Database.Neo4j.Batch.Types parseLabelsPath :: J.Value -> T.Text -> NodeUrl parseLabelsPath j suf = NodeUrl $ let p = tryParseFrom j in fromMaybe p $ T.stripSuffix suf p -- | Retrieve all labels for a node, if the node doesn't exist already it will raise an exception -- | Raises Neo4jNoEntityException if the node doesn't exist getLabels :: NodeBatchIdentifier a => a -> Batch (BatchFuture [Label]) getLabels n = nextState cmd where cmd = defCmd{cmdMethod = HT.methodGet, cmdPath = path, cmdBody = "", cmdParse = parser} path = getNodeBatchId n <> "/labels" parser jn = G.setNodeLabels (parseLabelsPath jn "/labels") (tryParseBody jn) -- | Get all nodes using a label and a property getNodesByLabelAndProperty :: Label -> Maybe (T.Text, PropertyValue) -> Batch (BatchFuture [Node]) getNodesByLabelAndProperty lbl prop = nextState cmd where cmd = defCmd{cmdMethod = HT.methodGet, cmdPath = path, cmdBody = "", cmdParse = parser} path = "/label/" <> lbl <> "/nodes" <> fromString (propUrl prop) propUrl Nothing = "" propUrl (Just (name, value)) = '?' : urlEncodeVars [(T.unpack name, lbsToStr $ J.encode value)] lbsToStr = S.unpack . L.toStrict parser jn g = foldl (\gacc n -> G.addNodeLabel n lbl (G.addNode n gacc)) g (tryParseBody jn) -- | Add labels to a node -- | Raises Neo4jNoEntityException if the node doesn't exist addLabels :: NodeBatchIdentifier a => [Label] -> a -> Batch (BatchFuture ()) addLabels lbls n = nextState cmd where cmd = defCmd{cmdMethod = HT.methodPost, cmdPath = path, cmdBody = J.toJSON lbls, cmdParse = parser} path = getNodeBatchId n <> "/labels" parser jn g = let from = parseLabelsPath jn "/labels" in foldl (flip (G.addNodeLabel from)) g lbls -- | Change node labels -- | Raises Neo4jNoEntityException if the node doesn't exist changeLabels :: NodeBatchIdentifier a => [Label] -> a -> Batch (BatchFuture ()) changeLabels lbls n = nextState cmd where cmd = defCmd{cmdMethod = HT.methodPut, cmdPath = path, cmdBody = J.toJSON lbls, cmdParse = parser} path = getNodeBatchId n <> "/labels" parser jn = G.setNodeLabels (parseLabelsPath jn "/labels") lbls -- | Remove a label for a node -- | Raises Neo4jNoEntityException if the node doesn't exist removeLabel :: NodeBatchIdentifier a => Label -> a -> Batch (BatchFuture ()) removeLabel lbl n = nextState cmd where cmd = defCmd{cmdMethod = HT.methodDelete, cmdPath = path, cmdBody = "", cmdParse = parser} suffix = "/labels/" <> lbl path = getNodeBatchId n <> suffix parser jn = G.deleteNodeLabel (parseLabelsPath jn suffix) lbl