module Database.LMDB.Simple.View
(
View
, newView
, (!)
, (!?)
, null
, size
, member
, notMember
, lookup
, findWithDefault
, foldr
, foldl
, foldrWithKey
, foldlWithKey
, foldViewWithKey
, elems
, keys
, toList
) where
import Prelude hiding
( foldl
, foldr
, lookup
, null
)
import Control.Concurrent.MVar
( MVar
, newMVar
, mkWeakMVar
, takeMVar
, tryReadMVar
)
import Control.Monad
( (>=>)
)
import Database.LMDB.Raw
( MDB_txn
, MDB_dbi'
, mdb_txn_begin
, mdb_txn_commit
, mdb_get'
, mdb_stat'
, ms_entries
)
import Database.LMDB.Simple
( Database
)
import Database.LMDB.Simple.Internal
( Database (Db)
, Serialise
, forEachForward
, forEachReverse
, marshalOut
, marshalIn
, peekVal
)
import Data.Maybe
( fromMaybe
, isJust
)
import Foreign
( alloca
, nullPtr
)
import System.IO.Unsafe
( unsafePerformIO
)
newtype View k v = View (MVar (MDB_txn, MDB_dbi'))
newView :: Database k v -> IO (View k v)
newView (Db env dbi) = do
txn <- mdb_txn_begin env Nothing True
var <- newMVar (txn, dbi)
mkWeakMVar var $ finalize var
return (View var)
where finalize :: MVar (MDB_txn, MDB_dbi') -> IO ()
finalize = takeMVar >=> mdb_txn_commit . fst
viewIO :: View k v -> ((MDB_txn, MDB_dbi') -> IO a) -> a
viewIO (View var) f = unsafePerformIO $
tryReadMVar var >>= maybe (fail "finalized txn") (f >=> seq var . return)
null :: View k v -> Bool
null view = viewIO view $ \(txn, dbi) -> do
stat <- mdb_stat' txn dbi
return (ms_entries stat == 0)
size :: View k v -> Int
size view = viewIO view $ \(txn, dbi) -> do
stat <- mdb_stat' txn dbi
return (fromIntegral $ ms_entries stat)
member :: Serialise k => k -> View k v -> Bool
member key view = viewIO view $ \(txn, dbi) ->
marshalOut key $ \kval -> isJust <$> mdb_get' txn dbi kval
notMember :: Serialise k => k -> View k v -> Bool
notMember key view = not (member key view)
(!) :: (Serialise k, Serialise v) => View k v -> k -> v
view ! key = fromMaybe notFoundError $ lookup key view
where notFoundError = error "View.!: given key is not found in the database"
infixl 9 !
(!?) :: (Serialise k, Serialise v) => View k v -> k -> Maybe v
(!?) = flip lookup
infixl 9 !?
lookup :: (Serialise k, Serialise v) => k -> View k v -> Maybe v
lookup key view = viewIO view $ \(txn, dbi) -> marshalOut key $
mdb_get' txn dbi >=> maybe (return Nothing) (fmap Just . marshalIn)
findWithDefault :: (Serialise k, Serialise v) => v -> k -> View k v -> v
findWithDefault def key = fromMaybe def . lookup key
foldr :: Serialise v => (v -> b -> b) -> b -> View k v -> b
foldr f z view = viewIO view $ \(txn, dbi) ->
alloca $ \vptr ->
forEachForward txn dbi nullPtr vptr z $ \rest ->
f <$> peekVal vptr <*> rest
foldrWithKey :: (Serialise k, Serialise v)
=> (k -> v -> b -> b) -> b -> View k v -> b
foldrWithKey f z view = viewIO view $ \(txn, dbi) ->
alloca $ \kptr ->
alloca $ \vptr ->
forEachForward txn dbi kptr vptr z $ \rest ->
f <$> peekVal kptr <*> peekVal vptr <*> rest
foldl :: Serialise v => (a -> v -> a) -> a -> View k v -> a
foldl f z view = viewIO view $ \(txn, dbi) ->
alloca $ \vptr ->
forEachReverse txn dbi nullPtr vptr z $ \rest ->
flip f <$> peekVal vptr <*> rest
foldlWithKey :: (Serialise k, Serialise v)
=> (a -> k -> v -> a) -> a -> View k v -> a
foldlWithKey f z view = viewIO view $ \(txn, dbi) ->
alloca $ \kptr ->
alloca $ \vptr ->
forEachReverse txn dbi kptr vptr z $ \rest ->
(\k v a -> f a k v) <$> peekVal kptr <*> peekVal vptr <*> rest
foldViewWithKey :: (Monoid m, Serialise k, Serialise v)
=> (k -> v -> m) -> View k v -> m
foldViewWithKey f = foldrWithKey (\k v a -> f k v `mappend` a) mempty
elems :: Serialise v => View k v -> [v]
elems = foldr (:) []
keys :: Serialise k => View k v -> [k]
keys view = viewIO view $ \(txn, dbi) ->
alloca $ \kptr ->
forEachForward txn dbi kptr nullPtr [] $ \rest ->
(:) <$> peekVal kptr <*> rest
toList :: (Serialise k, Serialise v) => View k v -> [(k, v)]
toList = foldrWithKey (\k v -> ((k, v) :)) []