@@ -29,6 +29,7 @@
2929module Database.Bloodhound.Types
3030 ( defaultCache
3131 , defaultIndexSettings
32+ , defaultIndexDocumentSettings
3233 , mkSort
3334 , showText
3435 , unpackId
@@ -41,6 +42,8 @@ module Database.Bloodhound.Types
4142 , mkTermsAggregation
4243 , mkTermsScriptAggregation
4344 , mkDateHistogram
45+ , mkDocVersion
46+ , docVersionNumber
4447 , toTerms
4548 , toDateHistogram
4649 , omitNulls
@@ -56,6 +59,10 @@ module Database.Bloodhound.Types
5659 , Server(..)
5760 , Reply
5861 , EsResult(..)
62+ , DocVersion
63+ , ExternalDocVersion(..)
64+ , VersionControl(..)
65+ , IndexDocumentSettings(..)
5966 , Query(..)
6067 , Search(..)
6168 , SearchResult(..)
@@ -218,10 +225,12 @@ import qualified Data.ByteString.Lazy.Char8 as L
218225import Data.List (nub)
219226import Data.List.NonEmpty (NonEmpty (..), toList)
220227import qualified Data.Map.Strict as M
228+import Data.Maybe
221229import Data.Text (Text)
222230import qualified Data.Text as T
223231import Data.Time.Clock (UTCTime)
224232import qualified Data.Vector as V
233+import GHC.Enum
225234import GHC.Generics (Generic)
226235import Network.HTTP.Client
227236import qualified Network.HTTP.Types.Method as NHTM
@@ -371,10 +380,78 @@ data BulkOperation =
371380data EsResult a = EsResult { _index :: Text
372381 , _type :: Text
373382 , _id :: Text
374− , _version :: Int
383+ , _version :: DocVersion
375384 , found :: Maybe Bool
376385 , _source :: a } deriving (Eq, Show)
377386
387+{-| 'DocVersion' is an integer version number for a document between 1
388+and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
389+-}
390+newtype DocVersion = DocVersion {
391+ docVersionNumber :: Int
392+ } deriving (Eq, Show, Ord, ToJSON)
393+
394+-- | Smart constructor for in-range doc version
395+mkDocVersion :: Int -> Maybe DocVersion
396+mkDocVersion i
397+ | i >= (docVersionNumber minBound) && i <= (docVersionNumber maxBound) =
398+ Just $ DocVersion i
399+ | otherwise = Nothing
400+
401+
402+{-| 'ExternalDocVersion' is a convenience wrapper if your code uses its
403+own version numbers instead of ones from ES.
404+-}
405+newtype ExternalDocVersion = ExternalDocVersion DocVersion
406+ deriving (Eq, Show, Ord, Bounded, Enum, ToJSON)
407+
408+{-| 'VersionControl' is specified when indexing documents as a
409+optimistic concurrency control.
410+-}
411+data VersionControl = NoVersionControl
412+ -- ^ Don't send a version. This is a pure overwrite.
413+ | InternalVersion DocVersion
414+ -- ^ Use the default ES versioning scheme. Only
415+ -- index the document if the version is the same
416+ -- as the one specified. Only applicable to
417+ -- updates, as you should be getting Version from
418+ -- a search result.
419+ | ExternalGT ExternalDocVersion
420+ -- ^ Use your own version numbering. Only index
421+ -- the document if the version is strictly higher
422+ -- OR the document doesn't exist. The given
423+ -- version will be used as the new version number
424+ -- for the stored document. N.B. All updates must
425+ -- increment this number, meaning there is some
426+ -- global, external ordering of updates.
427+ | ExternalGTE ExternalDocVersion
428+ -- ^ Use your own version numbering. Only index
429+ -- the document if the version is equal or higher
430+ -- than the stored version. Will succeed if there
431+ -- is no existing document. The given version will
432+ -- be used as the new version number for the
433+ -- stored document. Use with care, as this could
434+ -- result in data loss.
435+ | ForceVersion ExternalDocVersion
436+ -- ^ The document will always be indexed and the
437+ -- given version will be the new version. This is
438+ -- typically used for correcting errors. Use with
439+ -- care, as this could result in data loss.
440+ deriving (Show, Eq, Ord)
441+
442+{-| 'IndexDocumentSettings' are special settings supplied when indexing
443+a document. For the best backwards compatiblity when new fields are
444+added, you should probably prefer to start with 'defaultIndexDocumentSettings'
445+-}
446+data IndexDocumentSettings = IndexDocumentSettings {
447+ idsVersionControl :: VersionControl
448+ }
449+
450+{-| Reasonable default settings. Chooses no version control.
451+-}
452+defaultIndexDocumentSettings :: IndexDocumentSettings
453+defaultIndexDocumentSettings = IndexDocumentSettings NoVersionControl
454+
378455{-| 'Sort' is a synonym for a list of 'SortSpec's. Sort behavior is order
379456 dependent with later sorts acting as tie-breakers for earlier sorts.
380457-}
@@ -2173,3 +2250,26 @@ instance FromJSON ShardResult where
21732250 v .: "successful" <*>
21742251 v .: "failed"
21752252 parseJSON _ = empty
2253+
2254+
2255+instance FromJSON DocVersion where
2256+ parseJSON v = do
2257+ i <- parseJSON v
2258+ maybe (fail "DocVersion out of range") return $ mkDocVersion i
2259+
2260+instance Bounded DocVersion where
2261+ minBound = DocVersion 1
2262+ maxBound = DocVersion 9200000000000000000 -- 9.2e+18
2263+
2264+instance Enum DocVersion where
2265+ succ x
2266+ | x /= maxBound = DocVersion (succ $ docVersionNumber x)
2267+ | otherwise = succError "DocVersion"
2268+ pred x
2269+ | x /= minBound = DocVersion (pred $ docVersionNumber x)
2270+ | otherwise = predError "DocVersion"
2271+ toEnum i =
2272+ fromMaybe (error $ show i ++ " out of DocVersion range") $ mkDocVersion i
2273+ fromEnum = docVersionNumber
2274+ enumFrom = boundedEnumFrom
2275+ enumFromThen = boundedEnumFromThen