-- | Query statistics (nodes created, relationships deleted, etc.).
module Database.Bolty.Stats
  ( QueryStats(..)
  , parseStats
  ) where

import           Prelude

import           Data.Int                      (Int64)
import           Data.Kind                     (Type)
import qualified Data.HashMap.Lazy             as H
import qualified Data.Text                     as T

import           Data.PackStream.Ps            (Ps(..))
import           Data.PackStream.Integer       (fromPSInteger)


-- | Typed query statistics from the PULL SUCCESS metadata.
-- All integer fields default to 0 and booleans to False when absent.
type QueryStats :: Type
data QueryStats = QueryStats
  { QueryStats -> Int64
nodesCreated          :: !Int64
  , QueryStats -> Int64
nodesDeleted          :: !Int64
  , QueryStats -> Int64
relationshipsCreated  :: !Int64
  , QueryStats -> Int64
relationshipsDeleted  :: !Int64
  , QueryStats -> Int64
propertiesSet         :: !Int64
  , QueryStats -> Int64
labelsAdded           :: !Int64
  , QueryStats -> Int64
labelsRemoved         :: !Int64
  , QueryStats -> Int64
indexesAdded           :: !Int64
  , QueryStats -> Int64
indexesRemoved         :: !Int64
  , QueryStats -> Int64
constraintsAdded      :: !Int64
  , QueryStats -> Int64
constraintsRemoved    :: !Int64
  , QueryStats -> Bool
containsUpdates       :: !Bool
  , QueryStats -> Bool
containsSystemUpdates :: !Bool
  , QueryStats -> Int64
systemUpdates         :: !Int64
  }
  deriving stock (Int -> QueryStats -> ShowS
[QueryStats] -> ShowS
QueryStats -> String
(Int -> QueryStats -> ShowS)
-> (QueryStats -> String)
-> ([QueryStats] -> ShowS)
-> Show QueryStats
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> QueryStats -> ShowS
showsPrec :: Int -> QueryStats -> ShowS
$cshow :: QueryStats -> String
show :: QueryStats -> String
$cshowList :: [QueryStats] -> ShowS
showList :: [QueryStats] -> ShowS
Show, QueryStats -> QueryStats -> Bool
(QueryStats -> QueryStats -> Bool)
-> (QueryStats -> QueryStats -> Bool) -> Eq QueryStats
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: QueryStats -> QueryStats -> Bool
== :: QueryStats -> QueryStats -> Bool
$c/= :: QueryStats -> QueryStats -> Bool
/= :: QueryStats -> QueryStats -> Bool
Eq)


-- | Parse the raw @stats@ field from PULL SUCCESS metadata.
-- Returns 'Nothing' if the field is absent (read-only queries).
-- The server uses hyphenated keys (e.g. @"nodes-created"@).
parseStats :: Maybe Ps -> Maybe QueryStats
parseStats :: Maybe Ps -> Maybe QueryStats
parseStats Maybe Ps
Nothing = Maybe QueryStats
forall a. Maybe a
Nothing
parseStats (Just (PsDictionary HashMap Text Ps
m)) = QueryStats -> Maybe QueryStats
forall a. a -> Maybe a
Just QueryStats
  { nodesCreated :: Int64
nodesCreated          = Text -> HashMap Text Ps -> Int64
intField Text
"nodes-created" HashMap Text Ps
m
  , nodesDeleted :: Int64
nodesDeleted          = Text -> HashMap Text Ps -> Int64
intField Text
"nodes-deleted" HashMap Text Ps
m
  , relationshipsCreated :: Int64
relationshipsCreated  = Text -> HashMap Text Ps -> Int64
intField Text
"relationships-created" HashMap Text Ps
m
  , relationshipsDeleted :: Int64
relationshipsDeleted  = Text -> HashMap Text Ps -> Int64
intField Text
"relationships-deleted" HashMap Text Ps
m
  , propertiesSet :: Int64
propertiesSet         = Text -> HashMap Text Ps -> Int64
intField Text
"properties-set" HashMap Text Ps
m
  , labelsAdded :: Int64
labelsAdded           = Text -> HashMap Text Ps -> Int64
intField Text
"labels-added" HashMap Text Ps
m
  , labelsRemoved :: Int64
labelsRemoved         = Text -> HashMap Text Ps -> Int64
intField Text
"labels-removed" HashMap Text Ps
m
  , indexesAdded :: Int64
indexesAdded           = Text -> HashMap Text Ps -> Int64
intField Text
"indexes-added" HashMap Text Ps
m
  , indexesRemoved :: Int64
indexesRemoved         = Text -> HashMap Text Ps -> Int64
intField Text
"indexes-removed" HashMap Text Ps
m
  , constraintsAdded :: Int64
constraintsAdded      = Text -> HashMap Text Ps -> Int64
intField Text
"constraints-added" HashMap Text Ps
m
  , constraintsRemoved :: Int64
constraintsRemoved    = Text -> HashMap Text Ps -> Int64
intField Text
"constraints-removed" HashMap Text Ps
m
  , containsUpdates :: Bool
containsUpdates       = Text -> HashMap Text Ps -> Bool
boolField Text
"contains-updates" HashMap Text Ps
m
  , containsSystemUpdates :: Bool
containsSystemUpdates = Text -> HashMap Text Ps -> Bool
boolField Text
"contains-system-updates" HashMap Text Ps
m
  , systemUpdates :: Int64
systemUpdates         = Text -> HashMap Text Ps -> Int64
intField Text
"system-updates" HashMap Text Ps
m
  }
parseStats (Just Ps
_) = Maybe QueryStats
forall a. Maybe a
Nothing


intField :: T.Text -> H.HashMap T.Text Ps -> Int64
intField :: Text -> HashMap Text Ps -> Int64
intField Text
key HashMap Text Ps
m = case Text -> HashMap Text Ps -> Maybe Ps
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
H.lookup Text
key HashMap Text Ps
m of
  Just (PsInteger PSInteger
n) -> case PSInteger -> Maybe Int64
forall a. FromPSInteger a => PSInteger -> Maybe a
fromPSInteger PSInteger
n of
    Just Int64
i  -> Int64
i
    Maybe Int64
Nothing -> Int64
0
  Maybe Ps
_ -> Int64
0


boolField :: T.Text -> H.HashMap T.Text Ps -> Bool
boolField :: Text -> HashMap Text Ps -> Bool
boolField Text
key HashMap Text Ps
m = case Text -> HashMap Text Ps -> Maybe Ps
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
H.lookup Text
key HashMap Text Ps
m of
  Just (PsBoolean Bool
b) -> Bool
b
  Maybe Ps
_                  -> Bool
False