{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE RecordWildCards       #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeApplications      #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Database.Bolt.Extras.DSL.Internal.Instances () where

import           Control.Monad.Writer                    (execWriter, tell)
import           Data.Function                           ((&))
import           Data.Proxy                              (Proxy (..))
import           Data.Text                               (intercalate, pack)
import           Database.Bolt.Extras                    (ToCypher (..),
                                                          fromInt)
import           GHC.OverloadedLabels                    (IsLabel (..))
import           GHC.TypeLits                            (KnownSymbol,
                                                          symbolVal)
import           NeatInterpolation                       (text)
import           Text.Printf                             (printf)

import           Database.Bolt.Extras.DSL.Internal.Types

instance KnownSymbol x => IsLabel x NodeSelector where
  fromLabel :: NodeSelector
fromLabel = NodeSelector
defaultNode NodeSelector -> (NodeSelector -> NodeSelector) -> NodeSelector
forall a b. a -> (a -> b) -> b
& Text -> NodeSelector -> NodeSelector
forall a. SelectorLike a => Text -> a -> a
withIdentifier (String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Proxy x -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal @x Proxy x
forall k (t :: k). Proxy t
Proxy)

instance KnownSymbol x => IsLabel x RelSelector where
  fromLabel :: RelSelector
fromLabel = RelSelector
defaultRel RelSelector -> (RelSelector -> RelSelector) -> RelSelector
forall a b. a -> (a -> b) -> b
& Text -> RelSelector -> RelSelector
forall a. SelectorLike a => Text -> a -> a
withIdentifier (String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Proxy x -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal @x Proxy x
forall k (t :: k). Proxy t
Proxy)

instance SelectorLike NodeSelector where
    withIdentifier :: Text -> NodeSelector -> NodeSelector
withIdentifier Text
idx NodeSelector
node = NodeSelector
node { nodeIdentifier :: Maybe Text
nodeIdentifier = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
idx }
    withLabel :: Text -> NodeSelector -> NodeSelector
withLabel Text
lbl NodeSelector
node      = NodeSelector
node { nodeLabels :: [Text]
nodeLabels = Text
lbl Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: NodeSelector -> [Text]
nodeLabels NodeSelector
node }
    withProp :: (Text, Value) -> NodeSelector -> NodeSelector
withProp (Text, Value)
prop NodeSelector
node      = NodeSelector
node { nodeProperties :: [(Text, Value)]
nodeProperties = (Text, Value)
prop (Text, Value) -> [(Text, Value)] -> [(Text, Value)]
forall a. a -> [a] -> [a]
: NodeSelector -> [(Text, Value)]
nodeProperties NodeSelector
node }
    withParam :: (Text, Text) -> NodeSelector -> NodeSelector
withParam (Text, Text)
prop NodeSelector
node     = NodeSelector
node { nodeParams :: [(Text, Text)]
nodeParams = (Text, Text)
prop (Text, Text) -> [(Text, Text)] -> [(Text, Text)]
forall a. a -> [a] -> [a]
: NodeSelector -> [(Text, Text)]
nodeParams NodeSelector
node }

instance SelectorLike RelSelector where
    withIdentifier :: Text -> RelSelector -> RelSelector
withIdentifier Text
idx RelSelector
rel = RelSelector
rel { relIdentifier :: Maybe Text
relIdentifier = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
idx }
    withLabel :: Text -> RelSelector -> RelSelector
withLabel Text
lbl RelSelector
rel      = RelSelector
rel { relLabel :: Text
relLabel = Text
lbl }
    withProp :: (Text, Value) -> RelSelector -> RelSelector
withProp (Text, Value)
prop RelSelector
rel      = RelSelector
rel { relProperties :: [(Text, Value)]
relProperties = (Text, Value)
prop (Text, Value) -> [(Text, Value)] -> [(Text, Value)]
forall a. a -> [a] -> [a]
: RelSelector -> [(Text, Value)]
relProperties RelSelector
rel }
    withParam :: (Text, Text) -> RelSelector -> RelSelector
withParam (Text, Text)
prop RelSelector
rel     = RelSelector
rel { relParams :: [(Text, Text)]
relParams = (Text, Text)
prop (Text, Text) -> [(Text, Text)] -> [(Text, Text)]
forall a. a -> [a] -> [a]
: RelSelector -> [(Text, Text)]
relParams RelSelector
rel }

instance ToCypher NodeSelector where
  toCypher :: NodeSelector -> Text
toCypher NodeSelector{[(Text, Text)]
[(Text, Value)]
[Text]
Maybe Text
nodeParams :: [(Text, Text)]
nodeProperties :: [(Text, Value)]
nodeLabels :: [Text]
nodeIdentifier :: Maybe Text
nodeParams :: NodeSelector -> [(Text, Text)]
nodeProperties :: NodeSelector -> [(Text, Value)]
nodeLabels :: NodeSelector -> [Text]
nodeIdentifier :: NodeSelector -> Maybe Text
..} = Writer Text () -> Text
forall w a. Writer w a -> w
execWriter (Writer Text () -> Text) -> Writer Text () -> Text
forall a b. (a -> b) -> a -> b
$ do
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"("
    case Maybe Text
nodeIdentifier of
      Just Text
idx -> Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
idx
      Maybe Text
Nothing  -> () -> Writer Text ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    case [Text]
nodeLabels of
      [] -> () -> Writer Text ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
      [Text]
_  -> Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ [Text] -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher [Text]
nodeLabels
    case [(Text, Value)]
nodeProperties of
      [] -> case [(Text, Text)]
nodeParams of
              [] -> () -> Writer Text ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
              [(Text, Text)]
_ -> do
                Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"{"
                Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ [(Text, Text)] -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher [(Text, Text)]
nodeParams
                Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"}"
      [(Text, Value)]
_ -> do
        Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"{"
        Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ [(Text, Value)] -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher [(Text, Value)]
nodeProperties
        case [(Text, Text)]
nodeParams of
          [] -> () -> Writer Text ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
          [(Text, Text)]
_ -> do
            Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
","
            Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ [(Text, Text)] -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher [(Text, Text)]
nodeParams
        Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"}"

    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
")"

instance ToCypher RelSelector where
  toCypher :: RelSelector -> Text
toCypher RelSelector{[(Text, Text)]
[(Text, Value)]
Maybe Text
Text
relParams :: [(Text, Text)]
relProperties :: [(Text, Value)]
relLabel :: Text
relIdentifier :: Maybe Text
relParams :: RelSelector -> [(Text, Text)]
relProperties :: RelSelector -> [(Text, Value)]
relLabel :: RelSelector -> Text
relIdentifier :: RelSelector -> Maybe Text
..} = Writer Text () -> Text
forall w a. Writer w a -> w
execWriter (Writer Text () -> Text) -> Writer Text () -> Text
forall a b. (a -> b) -> a -> b
$ do
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"["
    case Maybe Text
relIdentifier of
      Just Text
idx -> Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
idx
      Maybe Text
Nothing  -> () -> Writer Text ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    case Text
relLabel of
      Text
"" -> () -> Writer Text ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
      Text
_  -> Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ Text -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher Text
relLabel
    case [(Text, Value)]
relProperties of
      [] -> case [(Text, Text)]
relParams of
              [] -> () -> Writer Text ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
              [(Text, Text)]
_ -> do
                Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"{"
                Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ [(Text, Text)] -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher [(Text, Text)]
relParams
                Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"}"
      [(Text, Value)]
_ -> do
        Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"{"
        Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ [(Text, Value)] -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher [(Text, Value)]
relProperties
        case [(Text, Text)]
relParams of
          [] -> () -> Writer Text ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
          [(Text, Text)]
_ -> do
            Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
","
            Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ [(Text, Text)] -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher [(Text, Text)]
relParams
        Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"}"

    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"]"

instance ToCypher PathSelector where
  toCypher :: PathSelector -> Text
toCypher (PathSelector
ps :-!: RelSelector
rs :!->: NodeSelector
ns) = Writer Text () -> Text
forall w a. Writer w a -> w
execWriter (Writer Text () -> Text) -> Writer Text () -> Text
forall a b. (a -> b) -> a -> b
$ do
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ PathSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher PathSelector
ps
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"-"
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ RelSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher RelSelector
rs
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"->"
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ NodeSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher NodeSelector
ns
  toCypher (PathSelector
ps :<-!: RelSelector
rs :!-: NodeSelector
ns) = Writer Text () -> Text
forall w a. Writer w a -> w
execWriter (Writer Text () -> Text) -> Writer Text () -> Text
forall a b. (a -> b) -> a -> b
$ do
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ PathSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher PathSelector
ps
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"<-"
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ RelSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher RelSelector
rs
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"-"
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ NodeSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher NodeSelector
ns
  toCypher (PathSelector
ps :-!: RelSelector
rs :!-: NodeSelector
ns) = Writer Text () -> Text
forall w a. Writer w a -> w
execWriter (Writer Text () -> Text) -> Writer Text () -> Text
forall a b. (a -> b) -> a -> b
$ do
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ PathSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher PathSelector
ps
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"-"
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ RelSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher RelSelector
rs
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell Text
"-"
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ NodeSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher NodeSelector
ns
  toCypher (P NodeSelector
ns) = Writer Text () -> Text
forall w a. Writer w a -> w
execWriter (Writer Text () -> Text) -> Writer Text () -> Text
forall a b. (a -> b) -> a -> b
$
    Text -> Writer Text ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell (Text -> Writer Text ()) -> Text -> Writer Text ()
forall a b. (a -> b) -> a -> b
$ NodeSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher NodeSelector
ns
  toCypher (PathSelector
_ :<-!: RelSelector
_ :!->: NodeSelector
_) = String -> Text
forall a. HasCallStack => String -> a
error String
"Database.Bolt.Extras.DSL: incorrect path"

instance ToCypher Selector where
  toCypher :: Selector -> Text
toCypher (PS PathSelector
ps)  = PathSelector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher PathSelector
ps
  toCypher (TS Text
txt) = Text
txt

instance ToCypher Selectors where
  toCypher :: Selectors -> Text
toCypher = Text -> [Text] -> Text
intercalate Text
", " ([Text] -> Text) -> (Selectors -> [Text]) -> Selectors -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Selector -> Text) -> Selectors -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Selector -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher

instance ToCypher Cond where
  toCypher :: Cond -> Text
toCypher (ID Text
t BoltId
bId)   = String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> Text -> BoltId -> String
forall r. PrintfType r => String -> r
printf String
"ID(%s)=%d" Text
t (BoltId -> BoltId
fromInt BoltId
bId)
  toCypher (IDs Text
t [BoltId]
bIds) = String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> Text -> Text -> String
forall r. PrintfType r => String -> r
printf String
"ID(%s) in [%s]" Text
t (Text -> [Text] -> Text
intercalate Text
", " ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ (BoltId -> Text) -> [BoltId] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String -> Text
pack (String -> Text) -> (BoltId -> String) -> BoltId -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BoltId -> String
forall a. Show a => a -> String
show) [BoltId]
bIds)
  toCypher (IN Text
t [Text]
txts)  = String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> Text -> Text -> String
forall r. PrintfType r => String -> r
printf String
"%s in [%s]" Text
t (Text -> [Text] -> Text
intercalate Text
", " ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ (Text -> Text) -> [Text] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Text
s -> [text|"$s"|]) [Text]
txts)
  toCypher (TC Text
txt)     = Text
txt

instance ToCypher Conds where
  toCypher :: Conds -> Text
toCypher (Conds
fcp :&&: Conds
scp) = Conds -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher Conds
fcp Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" AND " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Conds -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher Conds
scp
  toCypher (Conds
fcp :||: Conds
scp) = Conds -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher Conds
fcp Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" OR " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Conds -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher Conds
scp
  toCypher (Not Conds
cp)       = Text
"NOT " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Conds -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher Conds
cp
  toCypher (C Cond
cp)         = Cond -> Text
forall a. (ToCypher a, HasCallStack) => a -> Text
toCypher Cond
cp