dixi-0.2.0.0: Dixi/Database.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE RankNTypes #-}
module Dixi.Database
( Database , emptyDB
, Amend (..)
, GetDiff (..)
, GetHistory (..)
, GetLatest (..)
, GetVersion (..)
, Revert (..)
) where
import Control.Applicative
import Control.Lens
import Data.Acid
import Data.Compositions.Snoc (Compositions)
import Data.Foldable
import Data.Map (Map)
import Data.Maybe
import Data.Monoid
import Data.Patch (Patch)
import Data.SafeCopy hiding (Version)
import Data.Text (Text)
import Data.Time
import Data.Typeable
import qualified Data.Compositions.Snoc as C
import qualified Data.Patch as P
import qualified Data.Text as T
import qualified Data.Vector as V
import Dixi.Common
import Dixi.Database.Orphans ()
import Dixi.Page
import Dixi.PatchUtils
data Database = DB { _db :: Map Key (Compositions (Page (Patch Char)))}
deriving (Typeable)
emptyDB :: Database
emptyDB = DB mempty
deriveSafeCopy 0 'base ''Database
makeLenses ''Database
getLatest :: Key -> Query Database (Version, Page Text)
getLatest k = do
b <- (view (db . ix k))
return (C.length b, patchToText <$> C.composed b)
getVersion :: Key -> Version -> Query Database (Page Text)
getVersion k v = do
b <- view (db . ix k)
return $ patchToText <$> C.composed (C.take v b)
getHistory :: Key -> Query Database [Page PatchSummary]
getHistory k = view (db . ix k . to (fmap (fmap patchSummary) . toList))
getDiff :: Key -> (Version, Version) -> Query Database (Page (P.Hunks Char))
getDiff k (v1 , v2) | v1 > v2 = getDiff k (v2, v1)
| otherwise = do
b <- view (db . ix k)
let y = patchToVector (C.composed (C.take v1 b) ^. body)
return $ fmap (\z -> P.hunks z y) (C.dropComposed v1 (C.take v2 b))
amendPatch :: Key -> Version -> Patch Char -> Maybe Text -> UTCTime -> Update Database (Version)
amendPatch k v q com tim = do
(db . at k) %= \mb ->
let b = fromMaybe mempty mb
p = C.dropComposed v b ^. body
r = snd $ P.transformWith P.theirs p q
in Just (C.snoc b (Page r (Last com) (Last $ Just tim)))
C.length <$> use (db . ix k)
amend :: Key -> Version -> Text -> Maybe Text -> UTCTime -> Update Database (Version)
amend k v new com tim = do
b <- use (db . ix k)
let n = V.fromList (T.unpack new)
o = C.composed (C.take v b) ^. body . to patchToVector
q = P.diff o n
amendPatch k v q com tim
revert :: Key -> (Version, Version) -> Maybe Text -> UTCTime -> Update Database Version
revert k (v1,v2) com tim | v2 < v1 = revert k (v2, v1) com tim
revert k (v1,v2) com tim = do
b <- use (db . ix k)
let p = C.dropComposed v1 (C.take v2 b) ^. body
amendPatch k (max v1 v2) (P.inverse p) com tim
makeAcidic ''Database ['getLatest, 'getVersion, 'getHistory, 'getDiff, 'amend, 'revert]