-- | -- Module: Network.Riak.JSON.Resolvable -- Copyright: (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Mark Hibberd <mark@hibberd.id.au>, Nathan Hunter <nhunter@janrain.com> -- Stability: experimental -- Portability: portable -- -- This module allows storage and retrieval of JSON-encoded data. -- -- Functions automatically resolve conflicts using 'Resolvable' -- instances. For instance, if a 'get' returns three siblings, a -- winner will be chosen using 'resolve'. If a 'put' results in a -- conflict, a winner will be chosen using 'resolve', and the winner -- will be 'put'; this will be repeated until either no conflict -- occurs or the process has been repeated too many times. module Network.Riak.JSON.Resolvable ( Resolvable(..) , ResolutionFailure(..) , get , getMany , modify , modify_ -- * Low-level modification functions , put , putIndexed , put_ , putMany , putMany_ ) where import Control.Monad.IO.Class import Data.Aeson.Types (FromJSON(..), ToJSON(..)) import Network.Riak.Resolvable.Internal (ResolutionFailure(..), Resolvable(..)) import Network.Riak.Types.Internal hiding (MessageTag(..)) import qualified Network.Riak.JSON as J import qualified Network.Riak.Resolvable.Internal as R -- | Retrieve a single value. If conflicting values are returned, -- 'resolve' is used to choose a winner. get :: (FromJSON c, ToJSON c, Resolvable c) => Connection -> Maybe BucketType -> Bucket -> Key -> R -> IO (Maybe (c, VClock)) get = R.get J.get {-# INLINE get #-} -- | Retrieve multiple values. If conflicting values are returned for -- a key, 'resolve' is used to choose a winner. getMany :: (FromJSON c, ToJSON c, Resolvable c) => Connection -> Maybe BucketType -> Bucket -> [Key] -> R -> IO [Maybe (c, VClock)] getMany = R.getMany J.getMany {-# INLINE getMany #-} -- | Modify a single value. The value, if any, is retrieved using -- 'get'; conflict resolution is performed if necessary. The -- modification function is called on the resulting value, and its -- result is stored using 'put', which may again perform conflict -- resolution. -- -- The result of this function is whatever was returned by 'put', -- along with the auxiliary value returned by the modification -- function. -- -- If the 'put' phase of this function gives up due to apparently -- being stuck in a conflict resolution loop, it will throw a -- 'ResolutionFailure' exception. modify :: (FromJSON a, ToJSON a, Resolvable a) => Connection -> Maybe BucketType -> Bucket -> Key -> R -> W -> DW -> (Maybe a -> IO (a,b)) -- ^ Modification function. Called with 'Just' the value if -- the key is present, 'Nothing' otherwise. -> IO (a,b) modify = R.modify J.get J.put {-# INLINE modify #-} -- | Modify a single value. The value, if any, is retrieved using -- 'get'; conflict resolution is performed if necessary. The -- modification function is called on the resulting value, and its -- result is stored using 'put', which may again perform conflict -- resolution. -- -- The result of this function is whatever was returned by 'put'. -- -- If the 'put' phase of this function gives up due to apparently -- being stuck in a conflict resolution loop, it will throw a -- 'ResolutionFailure' exception. modify_ :: (MonadIO m, FromJSON a, ToJSON a, Resolvable a) => Connection -> Maybe BucketType -> Bucket -> Key -> R -> W -> DW -> (Maybe a -> m a) -> m a modify_ = R.modify_ J.get J.put {-# INLINE modify_ #-} -- | Store a single value, automatically resolving any vector clock -- conflicts that arise. A single invocation of this function may -- involve several roundtrips to the server to resolve conflicts. -- -- If a conflict arises, a winner will be chosen using 'resolve', and -- the winner will be stored; this will be repeated until no conflict -- occurs or a (fairly large) number of retries has been attempted -- without success. -- -- If this function gives up due to apparently being stuck in a -- conflict resolution loop, it will throw a 'ResolutionFailure' -- exception. put :: (FromJSON c, ToJSON c, Resolvable c) => Connection -> Maybe BucketType -> Bucket -> Key -> Maybe VClock -> c -> W -> DW -> IO (c, VClock) put = R.put J.put {-# INLINE put #-} -- | Store a single value indexed. putIndexed :: (FromJSON c, ToJSON c, Resolvable c) => Connection -> Maybe BucketType -> Bucket -> Key -> [IndexValue] -> Maybe VClock -> c -> W -> DW -> IO (c, VClock) putIndexed c bt b k ixs vc cont w' dw' = R.put (\conn btype bucket' key' mvclock val w dw -> J.putIndexed conn btype bucket' key' ixs mvclock val w dw) c bt b k vc cont w' dw' {-# INLINE putIndexed #-} -- | Store a single value, automatically resolving any vector clock -- conflicts that arise. A single invocation of this function may -- involve several roundtrips to the server to resolve conflicts. -- -- If a conflict arises, a winner will be chosen using 'resolve', and -- the winner will be stored; this will be repeated until no conflict -- occurs or a (fairly large) number of retries has been attempted -- without success. -- -- If this function gives up due to apparently being stuck in a -- conflict resolution loop, it will throw a 'ResolutionFailure' -- exception. put_ :: (FromJSON c, ToJSON c, Resolvable c) => Connection -> Maybe BucketType -> Bucket -> Key -> Maybe VClock -> c -> W -> DW -> IO () put_ = R.put_ J.put {-# INLINE put_ #-} -- | Store multiple values, resolving any vector clock conflicts that -- arise. A single invocation of this function may involve several -- roundtrips to the server to resolve conflicts. -- -- If any conflicts arise, a winner will be chosen in each case using -- 'resolve', and the winners will be stored; this will be repeated -- until either no conflicts occur or a (fairly large) number of -- retries has been attempted without success. -- -- For each original value to be stored, the final value that was -- stored at the end of any conflict resolution is returned. -- -- If this function gives up due to apparently being stuck in a loop, -- it will throw a 'ResolutionFailure' exception. putMany :: (FromJSON c, ToJSON c, Resolvable c) => Connection -> Maybe BucketType -> Bucket -> [(Key, Maybe VClock, c)] -> W -> DW -> IO [(c, VClock)] putMany = R.putMany J.putMany {-# INLINE putMany #-} -- | Store multiple values, resolving any vector clock conflicts that -- arise. A single invocation of this function may involve several -- roundtrips to the server to resolve conflicts. -- -- If any conflicts arise, a winner will be chosen in each case using -- 'resolve', and the winners will be stored; this will be repeated -- until either no conflicts occur or a (fairly large) number of -- retries has been attempted without success. -- -- If this function gives up due to apparently being stuck in a loop, -- it will throw a 'ResolutionFailure' exception. putMany_ :: (FromJSON c, ToJSON c, Resolvable c) => Connection -> Maybe BucketType -> Bucket -> [(Key, Maybe VClock, c)] -> W -> DW -> IO () putMany_ = R.putMany_ J.putMany {-# INLINE putMany_ #-}