packages feed

bolty-0.1.0.0: src/Database/Bolty/Stats.hs

-- | 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
  { nodesCreated          :: !Int64
  , nodesDeleted          :: !Int64
  , relationshipsCreated  :: !Int64
  , relationshipsDeleted  :: !Int64
  , propertiesSet         :: !Int64
  , labelsAdded           :: !Int64
  , labelsRemoved         :: !Int64
  , indexesAdded           :: !Int64
  , indexesRemoved         :: !Int64
  , constraintsAdded      :: !Int64
  , constraintsRemoved    :: !Int64
  , containsUpdates       :: !Bool
  , containsSystemUpdates :: !Bool
  , systemUpdates         :: !Int64
  }
  deriving stock (Show, 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 Nothing = Nothing
parseStats (Just (PsDictionary m)) = Just QueryStats
  { nodesCreated          = intField "nodes-created" m
  , nodesDeleted          = intField "nodes-deleted" m
  , relationshipsCreated  = intField "relationships-created" m
  , relationshipsDeleted  = intField "relationships-deleted" m
  , propertiesSet         = intField "properties-set" m
  , labelsAdded           = intField "labels-added" m
  , labelsRemoved         = intField "labels-removed" m
  , indexesAdded           = intField "indexes-added" m
  , indexesRemoved         = intField "indexes-removed" m
  , constraintsAdded      = intField "constraints-added" m
  , constraintsRemoved    = intField "constraints-removed" m
  , containsUpdates       = boolField "contains-updates" m
  , containsSystemUpdates = boolField "contains-system-updates" m
  , systemUpdates         = intField "system-updates" m
  }
parseStats (Just _) = Nothing


intField :: T.Text -> H.HashMap T.Text Ps -> Int64
intField key m = case H.lookup key m of
  Just (PsInteger n) -> case fromPSInteger n of
    Just i  -> i
    Nothing -> 0
  _ -> 0


boolField :: T.Text -> H.HashMap T.Text Ps -> Bool
boolField key m = case H.lookup key m of
  Just (PsBoolean b) -> b
  _                  -> False