orchestrate-0.2.0.0: src/Database/Orchestrate/KeyValue.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-|
This implements the <http://orchestrate.io/api/keyvalue Key/Value> API.
Generally, the data stored knows about its own key using via the
'OrchestrateData' class instance defined for it.
-}
module Database.Orchestrate.KeyValue
(
-- * Accessing Data
lookup
, listVals
-- * Adding and Updating Data
, putV
, putKV
, postV
-- * Deleting Data
, deleteV
, deleteKV
, purgeV
, purgeKV
) where
import Control.Applicative
import Control.Arrow
import Control.Error
import Control.Lens
import Control.Monad (join, void)
import Data.Aeson
import qualified Data.Text as T
import Network.Wreq
import Prelude hiding (lookup)
import Database.Orchestrate.Types
import Database.Orchestrate.Utils
-- | This retrieves a value from a collection.
--
-- > lookup "contacts" "mom"
lookup :: FromJSON v => Collection -> Key -> OrchestrateIO (Maybe v)
lookup c k =
join . fmap (decode . (^.responseBody)) <$> api404 [] [c, k] [] getWith
-- | This inserts data into the database or updates existing data using
-- a key generated by the 'OrchestrateData' instance.
--
-- > putV data NoMatch
putV :: OrchestrateData v
=> v -- ^ The data to store in the database.
-> IfMatch -- ^ If specified, this operation only succeeds
-- if the ref specified matches the
-- currently stored ref for this data.
-> OrchestrateIO Location -- ^ Returns the location of the data.
putV v = putKV (dataKey v) v
-- | This inserts data into the database or updates data in the database.
-- This overrides the key provided by the data type's 'OrchestrateData'
-- instance. However, it still requires an implementation of that data type
-- for the collection name.
--
-- > putKV "key" data NoMatch
putKV :: OrchestrateData v
=> Key -- ^ The key to store the data under.
-> v -- ^ The data to store.
-> IfMatch -- ^ If specified, this operation only succeeds
-- if the ref specified matches the currently
-- stored ref for this data.
-> OrchestrateIO Location -- ^ Returns the location of the data.
putKV k v m =
getLocation <$> api (ifMatch m) [tableName v, k] [] (rot putWith v')
where v' = toJSON v
-- | This inserts data in the database, generating a new database key for
-- it.
--
-- > postV data
postV :: OrchestrateData v
=> v -- ^ The data to store.
-> OrchestrateIO (Location, Maybe Key) -- ^ The 'Location' and key for the data.
postV v = (id &&& firstOf locationKey) . getLocation
<$> api [] [tableName v] [] (rot postWith (toJSON v))
-- | This removes data from the database.
--
-- > deleteV data Nothing
deleteV :: OrchestrateData v
=> v -- ^ The data to remove.
-> IfMatch' -- ^ If given, this operation only succeeds
-- if the ref specified matches the currently
-- stored ref for this data.
-> OrchestrateIO ()
deleteV v = deleteKV (dataKey v) v
-- | This removes data from the database.
--
-- > deleteKV "key" data Nothing
deleteKV :: OrchestrateData v
=> Key -- ^ The key the data is stored under.
-> v -- ^ The data to remove.
-> IfMatch' -- ^ If given, this operation only succeeds
-- if the ref specified matches the
-- currently stored ref for this data.
-> OrchestrateIO ()
deleteKV k v m = void $ apiCheck (ifMatch' m) [tableName v, k] [] deleteWith
-- | This purges data from the database. Purging not only removes the data,
-- but also all history and secondary items for it.
--
-- > purgeV data Nothing
purgeV :: OrchestrateData v
=> v -- ^ The data to remove.
-> IfMatch' -- ^ If given, this operation only succeeds
-- if the ref specified matches the
-- currently stored ref for this data.
-> OrchestrateIO ()
purgeV v = purgeKV (dataKey v) v
-- | This purges data from the database. Purging not only removes the data,
-- but also all history and secondary items for it.
--
-- > purgeKV "key" data Nothing
purgeKV :: OrchestrateData v
=> Key -- ^ The key the data is stored under.
-> v -- ^ The data to remove.
-> IfMatch' -- ^ If given, this operation only succeeds
-- if the ref specified matches the
-- currently stored ref for this data.
-> OrchestrateIO ()
purgeKV k v m =
void $ apiCheck (ifMatch' m) [tableName v, k]
["purge" := ("true" :: T.Text)] deleteWith
-- | This lists all the data in the collection within the range given.
--
-- > listVals "coll-name" Nothing (Open, Open)
listVals :: FromJSON v
=> Collection -- ^ The collection to list data from.
-> Maybe Int -- ^ The maximum number of items to retrieve.
-> Range Key -- ^ The range of keys to query.
-> OrchestrateIO (KVList v) -- ^ Returns a collection of data.
listVals c limit (start, end) = apiCheckDecode [] [c] ps getWith
where ps = catMaybes [ ("limit" :=) <$> limit
, rangeStart "Key" start
, rangeEnd "Key" end
]