{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}

-- |
-- Module      : Docs.Revision
-- Description : Generic Revision (Text or Tree)
-- License     : AGPL-3
-- Maintainer  : stu235271@mail.uni-kiel.de
--               stu236925@mail.uni-kiel.de
--
-- This module contains data types and related utility functions for a generic
-- revision, meaning text or tree.
module Docs.Revision
    ( RevisionID (..)
    , TextOrTree (..)
    , RevisionKey (..)
    , RevisionRef (..)
    , RevisionSelector (..)
    , selectorFromTextRevision
    , refFromTextRevision
    , specificRevision
    , latestRevisionAsOf
    , textRevisionRefFor
    , treeRevisionRefFor
    , prettyPrintRevisionRef
    ) where

import Control.Lens ((?~))
import Data.Aeson (FromJSON (parseJSON), ToJSON (toJSON))
import qualified Data.Aeson as Aeson
import Data.Function ((&))
import Data.OpenApi
    ( HasEnum (enum_)
    , HasExclusiveMinimum (exclusiveMinimum)
    , HasFormat (format)
    , HasMinimum (minimum_)
    , HasOneOf (oneOf)
    , HasType (type_)
    , NamedSchema (NamedSchema)
    , OpenApiType (OpenApiInteger, OpenApiString)
    , Referenced (Inline)
    , ToSchema
    , declareSchemaRef
    )
import Data.OpenApi.ParamSchema
import Data.OpenApi.Schema (declareNamedSchema)
import Data.Proxy (Proxy (Proxy))
import Data.Scientific (toBoundedInteger)
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Time (UTCTime)
import Docs.Document (DocumentID (unDocumentID))
import Docs.TextElement (TextElementRef (TextElementRef))
import Docs.TextRevision
    ( TextRevisionRef (TextRevisionRef)
    , TextRevisionSelector
    )
import qualified Docs.TextRevision as TextRevision
import Docs.TreeRevision (TreeRevisionRef (TreeRevisionRef))
import qualified Docs.TreeRevision as TreeRevision
import GHC.Generics (Generic)
import GHC.Int (Int64)
import Parse (parseFlexibleTime)
import Servant (FromHttpApiData (parseUrlPiece))
import Text.Read (readMaybe)

-- | The id of a revision
newtype RevisionID = RevisionID
    { RevisionID -> Int64
unRevisionID :: Int64
    }
    deriving (RevisionID -> RevisionID -> Bool
(RevisionID -> RevisionID -> Bool)
-> (RevisionID -> RevisionID -> Bool) -> Eq RevisionID
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RevisionID -> RevisionID -> Bool
== :: RevisionID -> RevisionID -> Bool
$c/= :: RevisionID -> RevisionID -> Bool
/= :: RevisionID -> RevisionID -> Bool
Eq, Eq RevisionID
Eq RevisionID =>
(RevisionID -> RevisionID -> Ordering)
-> (RevisionID -> RevisionID -> Bool)
-> (RevisionID -> RevisionID -> Bool)
-> (RevisionID -> RevisionID -> Bool)
-> (RevisionID -> RevisionID -> Bool)
-> (RevisionID -> RevisionID -> RevisionID)
-> (RevisionID -> RevisionID -> RevisionID)
-> Ord RevisionID
RevisionID -> RevisionID -> Bool
RevisionID -> RevisionID -> Ordering
RevisionID -> RevisionID -> RevisionID
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: RevisionID -> RevisionID -> Ordering
compare :: RevisionID -> RevisionID -> Ordering
$c< :: RevisionID -> RevisionID -> Bool
< :: RevisionID -> RevisionID -> Bool
$c<= :: RevisionID -> RevisionID -> Bool
<= :: RevisionID -> RevisionID -> Bool
$c> :: RevisionID -> RevisionID -> Bool
> :: RevisionID -> RevisionID -> Bool
$c>= :: RevisionID -> RevisionID -> Bool
>= :: RevisionID -> RevisionID -> Bool
$cmax :: RevisionID -> RevisionID -> RevisionID
max :: RevisionID -> RevisionID -> RevisionID
$cmin :: RevisionID -> RevisionID -> RevisionID
min :: RevisionID -> RevisionID -> RevisionID
Ord, Int -> RevisionID -> ShowS
[RevisionID] -> ShowS
RevisionID -> [Char]
(Int -> RevisionID -> ShowS)
-> (RevisionID -> [Char])
-> ([RevisionID] -> ShowS)
-> Show RevisionID
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RevisionID -> ShowS
showsPrec :: Int -> RevisionID -> ShowS
$cshow :: RevisionID -> [Char]
show :: RevisionID -> [Char]
$cshowList :: [RevisionID] -> ShowS
showList :: [RevisionID] -> ShowS
Show)

instance ToJSON RevisionID where
    toJSON :: RevisionID -> Value
toJSON = Int64 -> Value
forall a. ToJSON a => a -> Value
toJSON (Int64 -> Value) -> (RevisionID -> Int64) -> RevisionID -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RevisionID -> Int64
unRevisionID

instance FromJSON RevisionID where
    parseJSON :: Value -> Parser RevisionID
parseJSON = (Int64 -> RevisionID) -> Parser Int64 -> Parser RevisionID
forall a b. (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int64 -> RevisionID
RevisionID (Parser Int64 -> Parser RevisionID)
-> (Value -> Parser Int64) -> Value -> Parser RevisionID
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Parser Int64
forall a. FromJSON a => Value -> Parser a
parseJSON

instance ToSchema RevisionID where
    declareNamedSchema :: Proxy RevisionID -> Declare (Definitions Schema) NamedSchema
declareNamedSchema Proxy RevisionID
_ = Proxy Int64 -> Declare (Definitions Schema) NamedSchema
forall a.
ToSchema a =>
Proxy a -> Declare (Definitions Schema) NamedSchema
declareNamedSchema (Proxy Int64
forall {k} (t :: k). Proxy t
Proxy :: Proxy Int64)

instance ToParamSchema RevisionID where
    toParamSchema :: Proxy RevisionID -> Schema
toParamSchema Proxy RevisionID
_ =
        Schema
forall a. Monoid a => a
mempty
            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe OpenApiType -> Identity (Maybe OpenApiType))
-> Schema -> Identity Schema
forall s a. HasType s a => Lens' s a
Lens' Schema (Maybe OpenApiType)
type_
                ((Maybe OpenApiType -> Identity (Maybe OpenApiType))
 -> Schema -> Identity Schema)
-> OpenApiType -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ OpenApiType
OpenApiInteger
            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe Scientific -> Identity (Maybe Scientific))
-> Schema -> Identity Schema
forall s a. HasMinimum s a => Lens' s a
Lens' Schema (Maybe Scientific)
minimum_
                ((Maybe Scientific -> Identity (Maybe Scientific))
 -> Schema -> Identity Schema)
-> Scientific -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Scientific
0
            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe Bool -> Identity (Maybe Bool)) -> Schema -> Identity Schema
forall s a. HasExclusiveMinimum s a => Lens' s a
Lens' Schema (Maybe Bool)
exclusiveMinimum
                ((Maybe Bool -> Identity (Maybe Bool))
 -> Schema -> Identity Schema)
-> Bool -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Bool
False

instance FromHttpApiData RevisionID where
    parseUrlPiece :: Text -> Either Text RevisionID
parseUrlPiece = (Int64 -> RevisionID
RevisionID (Int64 -> RevisionID)
-> Either Text Int64 -> Either Text RevisionID
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Either Text Int64 -> Either Text RevisionID)
-> (Text -> Either Text Int64) -> Text -> Either Text RevisionID
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either Text Int64
forall a. FromHttpApiData a => Text -> Either Text a
parseUrlPiece

-- | Selector for a revision
data RevisionSelector
    = -- | selects the latest revision
      Latest
    | -- | selects the latest revision at a specific point of time
      LatestAsOf UTCTime
    | -- | selects a specific revision by its id
      Specific RevisionID
    deriving (Int -> RevisionSelector -> ShowS
[RevisionSelector] -> ShowS
RevisionSelector -> [Char]
(Int -> RevisionSelector -> ShowS)
-> (RevisionSelector -> [Char])
-> ([RevisionSelector] -> ShowS)
-> Show RevisionSelector
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RevisionSelector -> ShowS
showsPrec :: Int -> RevisionSelector -> ShowS
$cshow :: RevisionSelector -> [Char]
show :: RevisionSelector -> [Char]
$cshowList :: [RevisionSelector] -> ShowS
showList :: [RevisionSelector] -> ShowS
Show)

selectorFromTextRevision :: TextRevisionSelector -> RevisionSelector
selectorFromTextRevision :: TextRevisionSelector -> RevisionSelector
selectorFromTextRevision TextRevisionSelector
TextRevision.Latest = RevisionSelector
Latest
selectorFromTextRevision (TextRevision.LatestAsOf UTCTime
time) = UTCTime -> RevisionSelector
LatestAsOf UTCTime
time
selectorFromTextRevision (TextRevision.Specific TextRevisionID
id_) =
    RevisionID -> RevisionSelector
Specific (RevisionID -> RevisionSelector) -> RevisionID -> RevisionSelector
forall a b. (a -> b) -> a -> b
$ Int64 -> RevisionID
RevisionID (Int64 -> RevisionID) -> Int64 -> RevisionID
forall a b. (a -> b) -> a -> b
$ TextRevisionID -> Int64
TextRevision.unTextRevisionID TextRevisionID
id_

instance ToJSON RevisionSelector where
    toJSON :: RevisionSelector -> Value
toJSON RevisionSelector
Latest = Text -> Value
forall a. ToJSON a => a -> Value
toJSON (Text
"latest" :: Text)
    toJSON (LatestAsOf UTCTime
ts) = UTCTime -> Value
forall a. ToJSON a => a -> Value
toJSON UTCTime
ts
    toJSON (Specific RevisionID
id_) = RevisionID -> Value
forall a. ToJSON a => a -> Value
toJSON RevisionID
id_

instance FromJSON RevisionSelector where
    parseJSON :: Value -> Parser RevisionSelector
parseJSON Value
v = case Value
v of
        Aeson.String Text
"latest" -> RevisionSelector -> Parser RevisionSelector
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure RevisionSelector
Latest
        Aeson.String Text
_ -> UTCTime -> RevisionSelector
LatestAsOf (UTCTime -> RevisionSelector)
-> Parser UTCTime -> Parser RevisionSelector
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser UTCTime
forall a. FromJSON a => Value -> Parser a
parseJSON Value
v -- TODO: parseFlexibleTime?
        Aeson.Number Scientific
n -> case Scientific -> Maybe Int64
forall i. (Integral i, Bounded i) => Scientific -> Maybe i
toBoundedInteger Scientific
n of
            Just Int64
i -> RevisionSelector -> Parser RevisionSelector
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (RevisionSelector -> Parser RevisionSelector)
-> RevisionSelector -> Parser RevisionSelector
forall a b. (a -> b) -> a -> b
$ RevisionID -> RevisionSelector
Specific (RevisionID -> RevisionSelector) -> RevisionID -> RevisionSelector
forall a b. (a -> b) -> a -> b
$ Int64 -> RevisionID
RevisionID Int64
i
            Maybe Int64
Nothing -> [Char] -> Parser RevisionSelector
forall a. [Char] -> Parser a
forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"Invalid number for Int64"
        Value
_ -> [Char] -> Parser RevisionSelector
forall a. [Char] -> Parser a
forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"RevisionSelector must be either a string \"latest\" or an integer"

instance ToSchema RevisionSelector where
    declareNamedSchema :: Proxy RevisionSelector -> Declare (Definitions Schema) NamedSchema
declareNamedSchema Proxy RevisionSelector
_ = do
        Referenced Schema
intSchema <- Proxy Int64 -> Declare (Definitions Schema) (Referenced Schema)
forall a.
ToSchema a =>
Proxy a -> Declare (Definitions Schema) (Referenced Schema)
declareSchemaRef (Proxy Int64
forall {k} (t :: k). Proxy t
Proxy :: Proxy Int64)
        Referenced Schema
timestampSchema <- Proxy UTCTime -> Declare (Definitions Schema) (Referenced Schema)
forall a.
ToSchema a =>
Proxy a -> Declare (Definitions Schema) (Referenced Schema)
declareSchemaRef (Proxy UTCTime
forall {k} (t :: k). Proxy t
Proxy :: Proxy UTCTime)
        let latestSchema :: Referenced Schema
latestSchema =
                Schema -> Referenced Schema
forall a. a -> Referenced a
Inline (Schema -> Referenced Schema) -> Schema -> Referenced Schema
forall a b. (a -> b) -> a -> b
$
                    Schema
forall a. Monoid a => a
mempty
                        Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe OpenApiType -> Identity (Maybe OpenApiType))
-> Schema -> Identity Schema
forall s a. HasType s a => Lens' s a
Lens' Schema (Maybe OpenApiType)
type_ ((Maybe OpenApiType -> Identity (Maybe OpenApiType))
 -> Schema -> Identity Schema)
-> OpenApiType -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ OpenApiType
OpenApiString
                        Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe [Value] -> Identity (Maybe [Value]))
-> Schema -> Identity Schema
forall s a. HasEnum s a => Lens' s a
Lens' Schema (Maybe [Value])
enum_ ((Maybe [Value] -> Identity (Maybe [Value]))
 -> Schema -> Identity Schema)
-> [Value] -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ [Value
"latest"]
        NamedSchema -> Declare (Definitions Schema) NamedSchema
forall a. a -> DeclareT (Definitions Schema) Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (NamedSchema -> Declare (Definitions Schema) NamedSchema)
-> NamedSchema -> Declare (Definitions Schema) NamedSchema
forall a b. (a -> b) -> a -> b
$
            Maybe Text -> Schema -> NamedSchema
NamedSchema (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"RevisionSelector") (Schema -> NamedSchema) -> Schema -> NamedSchema
forall a b. (a -> b) -> a -> b
$
                Schema
forall a. Monoid a => a
mempty Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe [Referenced Schema] -> Identity (Maybe [Referenced Schema]))
-> Schema -> Identity Schema
forall s a. HasOneOf s a => Lens' s a
Lens' Schema (Maybe [Referenced Schema])
oneOf ((Maybe [Referenced Schema]
  -> Identity (Maybe [Referenced Schema]))
 -> Schema -> Identity Schema)
-> [Referenced Schema] -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ [Referenced Schema
latestSchema, Referenced Schema
intSchema, Referenced Schema
timestampSchema]

instance ToParamSchema RevisionSelector where
    toParamSchema :: Proxy RevisionSelector -> Schema
toParamSchema Proxy RevisionSelector
_ =
        Schema
forall a. Monoid a => a
mempty
            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe [Referenced Schema] -> Identity (Maybe [Referenced Schema]))
-> Schema -> Identity Schema
forall s a. HasOneOf s a => Lens' s a
Lens' Schema (Maybe [Referenced Schema])
oneOf
                ((Maybe [Referenced Schema]
  -> Identity (Maybe [Referenced Schema]))
 -> Schema -> Identity Schema)
-> [Referenced Schema] -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ [ Schema -> Referenced Schema
forall a. a -> Referenced a
Inline (Schema -> Referenced Schema) -> Schema -> Referenced Schema
forall a b. (a -> b) -> a -> b
$
                        Schema
forall a. Monoid a => a
mempty
                            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe OpenApiType -> Identity (Maybe OpenApiType))
-> Schema -> Identity Schema
forall s a. HasType s a => Lens' s a
Lens' Schema (Maybe OpenApiType)
type_ ((Maybe OpenApiType -> Identity (Maybe OpenApiType))
 -> Schema -> Identity Schema)
-> OpenApiType -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ OpenApiType
OpenApiString
                            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe [Value] -> Identity (Maybe [Value]))
-> Schema -> Identity Schema
forall s a. HasEnum s a => Lens' s a
Lens' Schema (Maybe [Value])
enum_ ((Maybe [Value] -> Identity (Maybe [Value]))
 -> Schema -> Identity Schema)
-> [Value] -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ [Value
"latest"]
                   , Schema -> Referenced Schema
forall a. a -> Referenced a
Inline (Schema -> Referenced Schema) -> Schema -> Referenced Schema
forall a b. (a -> b) -> a -> b
$
                        Schema
forall a. Monoid a => a
mempty
                            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe OpenApiType -> Identity (Maybe OpenApiType))
-> Schema -> Identity Schema
forall s a. HasType s a => Lens' s a
Lens' Schema (Maybe OpenApiType)
type_ ((Maybe OpenApiType -> Identity (Maybe OpenApiType))
 -> Schema -> Identity Schema)
-> OpenApiType -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ OpenApiType
OpenApiString
                            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe Text -> Identity (Maybe Text)) -> Schema -> Identity Schema
forall s a. HasFormat s a => Lens' s a
Lens' Schema (Maybe Text)
format ((Maybe Text -> Identity (Maybe Text))
 -> Schema -> Identity Schema)
-> Text -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Text
"date-time"
                   , Schema -> Referenced Schema
forall a. a -> Referenced a
Inline (Schema -> Referenced Schema) -> Schema -> Referenced Schema
forall a b. (a -> b) -> a -> b
$
                        Schema
forall a. Monoid a => a
mempty
                            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe OpenApiType -> Identity (Maybe OpenApiType))
-> Schema -> Identity Schema
forall s a. HasType s a => Lens' s a
Lens' Schema (Maybe OpenApiType)
type_ ((Maybe OpenApiType -> Identity (Maybe OpenApiType))
 -> Schema -> Identity Schema)
-> OpenApiType -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ OpenApiType
OpenApiInteger
                            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe Scientific -> Identity (Maybe Scientific))
-> Schema -> Identity Schema
forall s a. HasMinimum s a => Lens' s a
Lens' Schema (Maybe Scientific)
minimum_ ((Maybe Scientific -> Identity (Maybe Scientific))
 -> Schema -> Identity Schema)
-> Scientific -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Scientific
0
                            Schema -> (Schema -> Schema) -> Schema
forall a b. a -> (a -> b) -> b
& (Maybe Bool -> Identity (Maybe Bool)) -> Schema -> Identity Schema
forall s a. HasExclusiveMinimum s a => Lens' s a
Lens' Schema (Maybe Bool)
exclusiveMinimum ((Maybe Bool -> Identity (Maybe Bool))
 -> Schema -> Identity Schema)
-> Bool -> Schema -> Schema
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Bool
False
                   ]

instance FromHttpApiData RevisionSelector where
    parseUrlPiece :: Text -> Either Text RevisionSelector
parseUrlPiece Text
txt
        | Text -> Text
Text.toLower Text
txt Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
"latest" = RevisionSelector -> Either Text RevisionSelector
forall a b. b -> Either a b
Right RevisionSelector
Latest
        | Bool
otherwise =
            case [Char] -> Maybe Int64
forall a. Read a => [Char] -> Maybe a
readMaybe (Text -> [Char]
Text.unpack Text
txt) of
                Just Int64
i -> RevisionSelector -> Either Text RevisionSelector
forall a b. b -> Either a b
Right (RevisionSelector -> Either Text RevisionSelector)
-> RevisionSelector -> Either Text RevisionSelector
forall a b. (a -> b) -> a -> b
$ RevisionID -> RevisionSelector
Specific (RevisionID -> RevisionSelector) -> RevisionID -> RevisionSelector
forall a b. (a -> b) -> a -> b
$ Int64 -> RevisionID
RevisionID Int64
i
                Maybe Int64
Nothing ->
                    case [Char] -> Maybe UTCTime
parseFlexibleTime (Text -> [Char]
Text.unpack Text
txt) of
                        Just UTCTime
ts -> RevisionSelector -> Either Text RevisionSelector
forall a b. b -> Either a b
Right (RevisionSelector -> Either Text RevisionSelector)
-> RevisionSelector -> Either Text RevisionSelector
forall a b. (a -> b) -> a -> b
$ UTCTime -> RevisionSelector
LatestAsOf UTCTime
ts
                        Maybe UTCTime
Nothing -> Text -> Either Text RevisionSelector
forall a b. a -> Either a b
Left (Text -> Either Text RevisionSelector)
-> Text -> Either Text RevisionSelector
forall a b. (a -> b) -> a -> b
$ Text
"Invalid RevisionSelector: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
txt

-- | The revision id if it is a @Specific@ selector; @Nothing@ otherwise.
specificRevision :: RevisionSelector -> Maybe RevisionID
specificRevision :: RevisionSelector -> Maybe RevisionID
specificRevision (Specific RevisionID
id_) = RevisionID -> Maybe RevisionID
forall a. a -> Maybe a
Just RevisionID
id_
specificRevision RevisionSelector
_ = Maybe RevisionID
forall a. Maybe a
Nothing

-- | The timestampt, if ti is a @LatestAsOf@ selector; @Nothing@ otherwise.
latestRevisionAsOf :: RevisionSelector -> Maybe UTCTime
latestRevisionAsOf :: RevisionSelector -> Maybe UTCTime
latestRevisionAsOf (LatestAsOf UTCTime
ts) = UTCTime -> Maybe UTCTime
forall a. a -> Maybe a
Just UTCTime
ts
latestRevisionAsOf RevisionSelector
_ = Maybe UTCTime
forall a. Maybe a
Nothing

-- | Reference of a revision
data RevisionRef
    = RevisionRef DocumentID RevisionSelector
    deriving ((forall x. RevisionRef -> Rep RevisionRef x)
-> (forall x. Rep RevisionRef x -> RevisionRef)
-> Generic RevisionRef
forall x. Rep RevisionRef x -> RevisionRef
forall x. RevisionRef -> Rep RevisionRef x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. RevisionRef -> Rep RevisionRef x
from :: forall x. RevisionRef -> Rep RevisionRef x
$cto :: forall x. Rep RevisionRef x -> RevisionRef
to :: forall x. Rep RevisionRef x -> RevisionRef
Generic)

-- | Get an arbitrary ref from a @TextRevisionRef@.
refFromTextRevision :: TextRevisionRef -> RevisionRef
refFromTextRevision :: TextRevisionRef -> RevisionRef
refFromTextRevision (TextRevisionRef (TextElementRef DocumentID
docID TextElementID
_) TextRevisionSelector
selector) =
    DocumentID -> RevisionSelector -> RevisionRef
RevisionRef DocumentID
docID (RevisionSelector -> RevisionRef)
-> RevisionSelector -> RevisionRef
forall a b. (a -> b) -> a -> b
$ TextRevisionSelector -> RevisionSelector
selectorFromTextRevision TextRevisionSelector
selector

instance ToJSON RevisionRef

instance FromJSON RevisionRef

instance ToSchema RevisionRef

-- | @RevisionRef@. Schöööööööön.
prettyPrintRevisionRef :: RevisionRef -> String
prettyPrintRevisionRef :: RevisionRef -> [Char]
prettyPrintRevisionRef (RevisionRef DocumentID
docID RevisionSelector
revSelector) =
    Int64 -> [Char]
forall a. Show a => a -> [Char]
show (DocumentID -> Int64
unDocumentID DocumentID
docID) [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
".rev." [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ RevisionSelector -> [Char]
forall a. Show a => a -> [Char]
show RevisionSelector
revSelector

-- | A @TextRevisionRef@ or a @TreeRevisionRef@.
data TextOrTree
    = Text TextRevisionRef
    | Tree TreeRevisionRef
    deriving ((forall x. TextOrTree -> Rep TextOrTree x)
-> (forall x. Rep TextOrTree x -> TextOrTree) -> Generic TextOrTree
forall x. Rep TextOrTree x -> TextOrTree
forall x. TextOrTree -> Rep TextOrTree x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. TextOrTree -> Rep TextOrTree x
from :: forall x. TextOrTree -> Rep TextOrTree x
$cto :: forall x. Rep TextOrTree x -> TextOrTree
to :: forall x. Rep TextOrTree x -> TextOrTree
Generic)

instance ToJSON TextOrTree

instance FromJSON TextOrTree

instance ToSchema TextOrTree

-- | An arbitrary revision, but the type (tree or text) is known.
data RevisionKey = RevisionKey
    { RevisionKey -> UTCTime
timestamp :: UTCTime
    , RevisionKey -> TextOrTree
revision :: TextOrTree
    }
    deriving ((forall x. RevisionKey -> Rep RevisionKey x)
-> (forall x. Rep RevisionKey x -> RevisionKey)
-> Generic RevisionKey
forall x. Rep RevisionKey x -> RevisionKey
forall x. RevisionKey -> Rep RevisionKey x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. RevisionKey -> Rep RevisionKey x
from :: forall x. RevisionKey -> Rep RevisionKey x
$cto :: forall x. Rep RevisionKey x -> RevisionKey
to :: forall x. Rep RevisionKey x -> RevisionKey
Generic)

instance ToJSON RevisionKey

instance FromJSON RevisionKey

instance ToSchema RevisionKey

-- | Get the ref for a given text revision with respect to a @RevisionKey@.
-- If the revision key belongs to the given @TextElementRef@, it is returned as a
-- @TextRevisionRef@. Otherwise, a selector for the latest revision for the given text
-- element for the timestamp of the given @RevisionKey@ is returned.
textRevisionRefFor :: TextElementRef -> RevisionKey -> TextRevisionRef
textRevisionRefFor :: TextElementRef -> RevisionKey -> TextRevisionRef
textRevisionRefFor
    TextElementRef
forTextRef
    ( RevisionKey
            { timestamp :: RevisionKey -> UTCTime
timestamp = UTCTime
ts
            , revision :: RevisionKey -> TextOrTree
revision = Text ref :: TextRevisionRef
ref@(TextRevisionRef TextElementRef
textRef TextRevisionSelector
_)
            }
        )
        | TextElementRef
textRef TextElementRef -> TextElementRef -> Bool
forall a. Eq a => a -> a -> Bool
== TextElementRef
forTextRef = TextRevisionRef
ref
        | Bool
otherwise = TextElementRef -> TextRevisionSelector -> TextRevisionRef
TextRevisionRef TextElementRef
forTextRef (TextRevisionSelector -> TextRevisionRef)
-> TextRevisionSelector -> TextRevisionRef
forall a b. (a -> b) -> a -> b
$ UTCTime -> TextRevisionSelector
TextRevision.LatestAsOf UTCTime
ts
textRevisionRefFor TextElementRef
forTextRef (RevisionKey {timestamp :: RevisionKey -> UTCTime
timestamp = UTCTime
ts}) =
    TextElementRef -> TextRevisionSelector -> TextRevisionRef
TextRevisionRef TextElementRef
forTextRef (TextRevisionSelector -> TextRevisionRef)
-> TextRevisionSelector -> TextRevisionRef
forall a b. (a -> b) -> a -> b
$ UTCTime -> TextRevisionSelector
TextRevision.LatestAsOf UTCTime
ts

-- | Get the ref for a given tree revision with respect to a @RevisionKey@.
-- If the revision key belongs to the given @DocumentID@, it is returned as a
-- @TreeRevisionRef@. Otherwise, a selector for the latest revision for the given tree
-- element for the timestamp of the given @RevisionKey@ is returned.
treeRevisionRefFor :: DocumentID -> RevisionKey -> TreeRevisionRef
treeRevisionRefFor :: DocumentID -> RevisionKey -> TreeRevisionRef
treeRevisionRefFor
    DocumentID
forDocID
    ( RevisionKey
            { timestamp :: RevisionKey -> UTCTime
timestamp = UTCTime
ts
            , revision :: RevisionKey -> TextOrTree
revision = Tree ref :: TreeRevisionRef
ref@(TreeRevisionRef DocumentID
docID TreeRevisionSelector
_)
            }
        )
        | DocumentID
docID DocumentID -> DocumentID -> Bool
forall a. Eq a => a -> a -> Bool
== DocumentID
forDocID = TreeRevisionRef
ref
        | Bool
otherwise = DocumentID -> TreeRevisionSelector -> TreeRevisionRef
TreeRevisionRef DocumentID
forDocID (TreeRevisionSelector -> TreeRevisionRef)
-> TreeRevisionSelector -> TreeRevisionRef
forall a b. (a -> b) -> a -> b
$ UTCTime -> TreeRevisionSelector
TreeRevision.LatestAsOf UTCTime
ts
treeRevisionRefFor DocumentID
forDocID (RevisionKey {timestamp :: RevisionKey -> UTCTime
timestamp = UTCTime
ts}) =
    DocumentID -> TreeRevisionSelector -> TreeRevisionRef
TreeRevisionRef DocumentID
forDocID (TreeRevisionSelector -> TreeRevisionRef)
-> TreeRevisionSelector -> TreeRevisionRef
forall a b. (a -> b) -> a -> b
$ UTCTime -> TreeRevisionSelector
TreeRevision.LatestAsOf UTCTime
ts