{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-| This implements the 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 ]