packages feed

montage-0.1: Network/Riak/Montage/Commands.hs

{-# LANGUAGE BangPatterns #-}
module Network.Riak.Montage.Commands where

import Network.Riak.Montage.Proto.Montage.MontageWireMessages
import Data.List (foldl')
import Data.Maybe (fromMaybe)
import qualified Network.Riak.Types as RT
import qualified Data.Sequence as Seq
import qualified Data.ByteString.Lazy.Char8 as L

import Network.Riak.Types

import Network.Riak.Montage.Proto.Montage.MontageObject (MontageObject(MontageObject))
import Network.Riak.Montage.Proto.Montage.MontageGetResponse
import Network.Riak.Montage.Proto.Montage.MontagePutResponse
import Network.Riak.Montage.Proto.Montage.MontagePutManyResponse
import Network.Riak.Montage.Proto.Montage.MontageGetStatus
import Network.Riak.Montage.Proto.Montage.MontageDeleteResponse

import Network.Riak.Montage.Types


makeObject :: (MontageRiakValue r) => L.ByteString -> L.ByteString -> (RiakRecord r, VClock, Maybe Int) -> MontageObject
makeObject buck key (rec, vclock, resolutions) =
    MontageObject
        (Just $ RT.fromVClock $ vclock)
        buck
        key
        (riakSerialize rec)
        (fmap fromIntegral resolutions)



exec :: ( MontageRiakValue r) => ChainCommand r -> ChainIteration r
exec (ChainGet buck key mfollow) =
    IterationRiakCommand [RiakGet buck key] $ fromMaybe finishGet mfollow
  where
    finishGet :: (MontageRiakValue r) => [RiakResponse r] -> ChainCommand r
    finishGet (mres:[]) =
        case mres of
            Just resp -> getResp (Seq.fromList [EXISTS]) obj Seq.empty
              where obj = (Just $ makeObject buck key resp)
            Nothing -> getResp (Seq.fromList [MISSING]) Nothing Seq.empty
    finishGet _ = error "Got unexpected value back from Riak"

    getResp status' master' subs' = ChainReturn $ ResponseProtobuf MONTAGE_GET_RESPONSE $
        MontageGetResponse status' master' subs'

exec (ChainPut vclock buck key rec mcallback) =
    IterationRiakCommand [RiakPut vclock buck key rec] $ fromMaybe finishPut mcallback
  where
    finishPut :: (MontageRiakValue r) => [RiakResponse r] -> ChainCommand r
    finishPut (mres:[]) = ChainReturn $ ResponseProtobuf MONTAGE_PUT_RESPONSE $ makePutResponse buck key mres
    finishPut _  = error "Got unexpected value back from Riak"

exec (ChainPutMany reqs mcallback) =
    IterationRiakCommand [RiakPut vc b k r | (vc, b, k, r) <- reqs] $ fromMaybe finishPutMany mcallback
  where
    finishPutMany :: (MontageRiakValue r) => [RiakResponse r] -> ChainCommand r
    finishPutMany resps =
        ChainReturn $ ResponseProtobuf MONTAGE_PUT_MANY_RESPONSE $ MontagePutManyResponse $ Seq.fromList $ map makeObjectResp $ zip resps reqs

    makeObjectResp :: (MontageRiakValue r) => (RiakResponse r, (VectorClock, RT.Bucket, RT.Key, RiakRecord u)) -> MontagePutResponse
    makeObjectResp (mresp, (_, buck, key, _)) = makePutResponse buck key mresp

exec (ChainGetMany reqs mmaster mcallback) =
    IterationRiakCommand [RiakGet b k | (b, k) <- reqs] $ fromMaybe finishGetMany mcallback
  where
    finishGetMany :: (MontageRiakValue r) => [RiakResponse r] -> ChainCommand r
    finishGetMany rx =
        ChainReturn $ ResponseProtobuf MONTAGE_GET_RESPONSE $
            MontageGetResponse (Seq.fromList $ map doesExist rx) mmaster
                (Seq.fromList $ reverse $ foldl' makeSubObject [] $ zip reqs rx)

    doesExist (Just _) = EXISTS
    doesExist Nothing  = MISSING

    makeSubObject acc (_, Nothing) = acc
    makeSubObject acc ((b, k), Just resp) = (makeObject b k resp) : acc

exec (ChainDelete buck key mcallback) =
    IterationRiakCommand [RiakDelete buck key] $ fromMaybe finishDelete mcallback
  where
    finishDelete :: (MontageRiakValue r) => [RiakResponse r] -> ChainCommand r
    finishDelete [Nothing] = ChainReturn $ ResponseProtobuf MONTAGE_DELETE_RESPONSE MontageDeleteResponse
    finishDelete _ = error "Delete should never return a result"

exec (ChainReference ref key targets) =
    IterationRiakCommand [RiakGet ref key] finishFollowRef
  where
    finishFollowRef :: (MontageRiakValue r) => [RiakResponse r] -> ChainCommand r
    finishFollowRef (r:[]) =
      case r of
            Just resp@(val, _, _) -> case getReferenceKey (ensureEval val) of
                Just realKey -> let firstLookup = (Just $ makeObject ref key resp) in
                    ChainGetMany [ (t, realKey) | t <- targets ] firstLookup Nothing
                Nothing -> nullResp
            Nothing -> nullResp
    finishFollowRef _ = error "Unexpected result back from RiakGet"

    nullResp = ChainReturn $ ResponseProtobuf MONTAGE_GET_RESPONSE $
                    MontageGetResponse Seq.empty Nothing Seq.empty


exec (ChainCustom cmd arg) = customCommandHandler cmd arg

exec (ChainCommandIO cmd) = ChainIterationIO cmd

-- Finally...
exec (ChainReturn resp) = IterationResponse resp


makePutResponse :: (MontageRiakValue r) => L.ByteString -> L.ByteString -> RiakResponse r -> MontagePutResponse
makePutResponse buck key mresp =
    case mresp of
        Just resp -> MontagePutResponse True $ makeObject buck key resp
        Nothing -> error "no return value on put??"