libmdbx-0.2.0.0: src/Mdbx/API.hs
{-|
Module : Mdbx.API
Copyright : (c) 2021 Francisco Vallarino
License : BSD-3-Clause (see the LICENSE file)
Maintainer : fjvallarino@gmail.com
Stability : experimental
Portability : non-portable
Thin wrappers over the low level API to provide MonadIO support and exception
based error handling.
-}
{-# LANGUAGE FlexibleContexts #-}
module Mdbx.API (
-- * Keys
keyCmp,
-- * Environment
envOpen,
envClose,
-- * Transaction
txnBegin,
txnCommit,
txnAbort,
-- * Database
dbiOpen,
dbiClose,
-- * Data manipulation
itemPut,
itemGet,
itemDel,
-- * Cursors
cursorOpen,
cursorClose,
cursorPut,
cursorDel,
cursorFirst,
cursorLast,
cursorAt,
cursorRange,
cursorNext,
cursorPrev,
cursorMove,
-- * Conversion for types used in keys
keyFromFloat,
keyFromDouble,
keyFromInt32,
keyFromInt64,
floatFromKey,
doubleFromKey,
int32FromKey,
int64FromKey
) where
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Fail (MonadFail)
import Data.Int
import Data.Word
import Mdbx.FFI
import Mdbx.Types
{-|
Compares two keys and returns -1, 0 or 1 if key1 is lower, equal or greater than
key2.
-}
keyCmp
:: MonadIO m
=> MdbxTxn
-> MdbxDbi
-> MdbxVal
-> MdbxVal
-> m Int
keyCmp txn dbi key1 key2 = liftIO $ mdbx_cmp txn dbi key1 key2
-- | Opens an environment.
envOpen
:: (MonadIO m, MonadFail m)
=> String
-> MdbxEnvGeometry
-> [MdbxEnvFlags]
-> m MdbxEnv
envOpen path geom flags = do
(retCreate, env) <- liftIO mdbx_env_create
checkError () retCreate
retGeometry <- liftIO $ mdbx_env_set_geometry env sizeMin sizeNow sizeMax growth shrink pageSize
checkError () retGeometry
retOpen <- liftIO $ mdbx_env_open env path flags 0o644
checkError env retOpen
where
MdbxEnvGeometry sizeMin sizeNow sizeMax growth shrink pageSize = geom
-- | Close an environment.
envClose
:: (MonadIO m, MonadFail m)
=> MdbxEnv
-> m ()
envClose env = do
ret <- liftIO $ mdbx_env_close env
checkError () ret
-- | Begins a transaction.
txnBegin
:: (MonadIO m, MonadFail m)
=> MdbxEnv
-> Maybe MdbxTxn
-> [MdbxTxnFlags]
-> m MdbxTxn
txnBegin env parent flags = do
(ret, txn) <- liftIO $ mdbx_txn_begin env parent flags
checkError txn ret
-- | Commits a transaction.
txnCommit
:: (MonadIO m, MonadFail m)
=> MdbxTxn
-> m ()
txnCommit txn = do
ret <- liftIO $ mdbx_txn_commit txn
checkError () ret
-- | Aborts a transaction.
txnAbort
:: (MonadIO m, MonadFail m)
=> MdbxTxn
-> m ()
txnAbort txn = do
ret <- liftIO $ mdbx_txn_abort txn
checkError () ret
-- | Opens a database (table).
dbiOpen
:: (MonadIO m, MonadFail m)
=> MdbxEnv
-> Maybe String
-> [MdbxDbFlags]
-> m MdbxDbi
dbiOpen env name flags = do
txn <- txnBegin env Nothing []
(ret, dbi) <- liftIO $ mdbx_dbi_open txn name flags
txnAbort txn
checkError dbi ret
-- | Closes a database.
dbiClose
:: (MonadIO m, MonadFail m)
=> MdbxEnv
-> MdbxDbi
-> m ()
dbiClose env dbi = do
ret <- liftIO $ mdbx_dbi_close env dbi
checkError () ret
-- | Returns the value associated to the given key, if any.
itemGet
:: (MonadIO m, MonadFail m)
=> MdbxTxn
-> MdbxDbi
-> MdbxVal
-> m (Maybe MdbxVal)
itemGet txn db key = do
(ret, val) <- liftIO $ mdbx_get txn db key
if ret == fromEnum MdbxNotfound
then return Nothing
else checkError (Just val) ret
-- | Saves the provided key/value pair.
itemPut
:: (MonadIO m, MonadFail m)
=> MdbxTxn
-> MdbxDbi
-> MdbxVal
-> MdbxVal
-> [MdbxPutFlags]
-> m ()
itemPut txn db key val flags = do
ret <- liftIO $ mdbx_put txn db key val flags
checkError () ret
-- | Deletes the value associated with the given key, if any.
itemDel
:: (MonadIO m, MonadFail m)
=> MdbxTxn
-> MdbxDbi
-> MdbxVal
-> Maybe MdbxVal
-> m ()
itemDel txn db key mval = do
ret <- liftIO $ mdbx_del txn db key mval
checkError () ret
-- | Opens a cursor.
cursorOpen
:: (MonadIO m, MonadFail m)
=> MdbxTxn
-> MdbxDbi
-> m MdbxCursor
cursorOpen txn dbi = do
(ret, cur) <- liftIO $ mdbx_cursor_open txn dbi
checkError cur ret
-- | Closes a cursor.
cursorClose
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> m ()
cursorClose cur = do
liftIO $ mdbx_cursor_close cur
-- | Stores the provided value at the given key, positioning the cursor on it.
cursorPut
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> MdbxVal
-> MdbxVal
-> [MdbxPutFlags]
-> m ()
cursorPut cur key val flags = do
ret <- liftIO $ mdbx_cursor_put cur key val flags
checkError () ret
-- | Deletes the value at the current position.
cursorDel
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> [MdbxPutFlags]
-> m ()
cursorDel cur flags = do
ret <- liftIO $ mdbx_cursor_del cur flags
checkError () ret
-- | Moves to the first key on the database.
cursorFirst
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> m (Maybe (MdbxVal, MdbxVal))
cursorFirst cur = cursorMove cur emptyMdbxVal MdbxFirst
-- | Moves to the last key on the database.
cursorLast
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> m (Maybe (MdbxVal, MdbxVal))
cursorLast cur = cursorMove cur emptyMdbxVal MdbxLast
-- | Moves to the given key.
cursorAt
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> MdbxVal
-> m (Maybe (MdbxVal, MdbxVal))
cursorAt cur key = cursorMove cur key MdbxSetKey
-- | Moves to the given key or first greater than it. Useful for searching.
cursorRange
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> MdbxVal
-> m (Maybe (MdbxVal, MdbxVal))
cursorRange cur key = cursorMove cur key MdbxSetRange
-- | Moves to the next key.
cursorNext
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> m (Maybe (MdbxVal, MdbxVal))
cursorNext cur = cursorMove cur emptyMdbxVal MdbxNext
-- | Moves to the previous key.
cursorPrev
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> m (Maybe (MdbxVal, MdbxVal))
cursorPrev cur = cursorMove cur emptyMdbxVal MdbxPrev
-- | Moves the cursor using the provided operation.
cursorMove
:: (MonadIO m, MonadFail m)
=> MdbxCursor
-> MdbxVal
-> MdbxCursorOp
-> m (Maybe (MdbxVal, MdbxVal))
cursorMove cur baseKey op = do
(ret, key, val) <- liftIO $ mdbx_cursor_get cur baseKey op
if ret == fromEnum MdbxNotfound
then return Nothing
else checkError (Just (key, val)) ret
-- | Converts a Float value to an unsigned Word that can be used by libmdbx's compare function.
keyFromFloat :: Float -> Word32
keyFromFloat = mdbx_key_from_float
-- | Converts a Double value to an unsigned Word that can be used by libmdbx's compare function.
keyFromDouble :: Double -> Word64
keyFromDouble = mdbx_key_from_double
-- | Converts a 32bits signed Int value to an unsigned Word that can be used by libmdbx's compare function.
keyFromInt32 :: Int32 -> Word32
keyFromInt32 = mdbx_key_from_int32
-- | Converts a 64bits signed Int value to an unsigned Word that can be used by libmdbx's compare function.
keyFromInt64 :: Int64 -> Word64
keyFromInt64 = mdbx_key_from_int64
-- | Converts an unsigned Word to a Float value.
floatFromKey :: Word32 -> Float
floatFromKey = mdbx_float_from_key
-- | Converts an unsigned Word to a Double value.
doubleFromKey :: Word64 -> Double
doubleFromKey = mdbx_double_from_key
-- | Converts an unsigned Word value to a 32bits signed Int.
int32FromKey :: Word32 -> Int32
int32FromKey = mdbx_int32_from_key
-- | Converts an unsigned Word value to a 64bits signed Int.
int64FromKey :: Word64 -> Int64
int64FromKey = mdbx_int64_from_key
-- Helpers
checkError
:: (MonadIO m, MonadFail m)
=> a
-> Int
-> m a
checkError val 0 = return val
checkError _ code = do
msg <- liftIO $ mdbx_strerror code
fail msg