packages feed

bloodhound-0.20.0.0: src/Database/Bloodhound/Internal/Client/Doc.hs

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Database.Bloodhound.Internal.Client.Doc
  ( DocVersion (..),
    ExternalDocVersion (..),
    mkDocVersion,
    VersionControl (..),
  )
where

import Data.Aeson
import Data.Maybe
import GHC.Enum

-- | 'DocVersion' is an integer version number for a document between 1
-- and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
newtype DocVersion = DocVersion
  { docVersionNumber :: Int
  }
  deriving stock (Eq, Show, Ord)
  deriving newtype (ToJSON)

-- | Smart constructor for in-range doc version
mkDocVersion :: Int -> Maybe DocVersion
mkDocVersion i
  | i >= docVersionNumber minBound
      && i <= docVersionNumber maxBound =
    Just $ DocVersion i
  | otherwise = Nothing

instance Bounded DocVersion where
  minBound = DocVersion 1
  maxBound = DocVersion 9200000000000000000 -- 9.2e+18

instance Enum DocVersion where
  succ x
    | x /= maxBound = DocVersion (succ $ docVersionNumber x)
    | otherwise = succError "DocVersion"
  pred x
    | x /= minBound = DocVersion (pred $ docVersionNumber x)
    | otherwise = predError "DocVersion"
  toEnum i =
    fromMaybe (error $ show i ++ " out of DocVersion range") $ mkDocVersion i
  fromEnum = docVersionNumber
  enumFrom = boundedEnumFrom
  enumFromThen = boundedEnumFromThen

instance FromJSON DocVersion where
  parseJSON v = do
    i <- parseJSON v
    maybe (fail "DocVersion out of range") return $ mkDocVersion i

-- | 'ExternalDocVersion' is a convenience wrapper if your code uses its
-- own version numbers instead of ones from ES.
newtype ExternalDocVersion = ExternalDocVersion DocVersion
  deriving (Eq, Show, Ord, Bounded, Enum, ToJSON)

-- | 'VersionControl' is specified when indexing documents as a
-- optimistic concurrency control.
data VersionControl
  = -- | Don't send a version. This is a pure overwrite.
    NoVersionControl
  | -- | Use the default ES versioning scheme. Only
    -- index the document if the version is the same
    -- as the one specified. Only applicable to
    -- updates, as you should be getting Version from
    -- a search result.
    InternalVersion DocVersion
  | -- | Use your own version numbering. Only index
    -- the document if the version is strictly higher
    -- OR the document doesn't exist. The given
    -- version will be used as the new version number
    -- for the stored document. N.B. All updates must
    -- increment this number, meaning there is some
    -- global, external ordering of updates.
    ExternalGT ExternalDocVersion
  | -- | Use your own version numbering. Only index
    -- the document if the version is equal or higher
    -- than the stored version. Will succeed if there
    -- is no existing document. The given version will
    -- be used as the new version number for the
    -- stored document. Use with care, as this could
    -- result in data loss.
    ExternalGTE ExternalDocVersion
  | -- | The document will always be indexed and the
    -- given version will be the new version. This is
    -- typically used for correcting errors. Use with
    -- care, as this could result in data loss.
    ForceVersion ExternalDocVersion
  deriving (Eq, Show, Ord)