Added key and value types
Getty Ritter
9 years ago
| 43 | 43 |
createEphemeralDb ls = EDB (M.fromList [ (encode k, encode v) | (k, v) <- ls ])
|
| 44 | 44 |
|
| 45 | 45 |
-- | Run a 'Tansu' operation with an empty in-memory table.
|
| 46 | |
withNewEphemeralDb :: (TansuDb -> IO a) -> IO a
|
| 46 |
withNewEphemeralDb :: (TansuDb k v -> IO a) -> IO a
|
| 47 | 47 |
withNewEphemeralDb = withEphemeralDb $ EDB M.empty
|
| 48 | 48 |
|
| 49 | 49 |
-- | Run a 'Tansu' operation with an existing in-memory table.
|
| 50 | |
withEphemeralDb :: EphemeralDb -> (TansuDb -> IO a) -> IO a
|
| 50 |
withEphemeralDb :: EphemeralDb -> (TansuDb k v -> IO a) -> IO a
|
| 51 | 51 |
withEphemeralDb init comp = do
|
| 52 | 52 |
lock <- newMVar ()
|
| 53 | 53 |
table <- newIORef (fromEDB init)
|
| 46 | 46 |
-- @.lock@ file in the specified directory, but note that
|
| 47 | 47 |
-- file locking is not a guaranteed way of ensuring exclusion,
|
| 48 | 48 |
-- and that the files themselves are not locked in any way.
|
| 49 | |
withFilesystemDb :: FilePath -> (TansuDb -> IO a) -> IO a
|
| 49 |
withFilesystemDb :: FilePath -> (TansuDb k v -> IO a) -> IO a
|
| 50 | 50 |
withFilesystemDb path comp = do
|
| 51 | 51 |
createDirectoryIfMissing True path
|
| 52 | 52 |
comp $ TansuDb { dbSet = filePathSet path
|
| 23 | 23 |
-- should treat this as an abstract type, but the full definition
|
| 24 | 24 |
-- is exposed by the "Database.Tansu.Internal" module so that
|
| 25 | 25 |
-- other libraries can implement new storage backends.
|
| 26 | |
data TansuDb = TansuDb
|
| 26 |
--
|
| 27 |
-- A given instantiation of the database will have
|
| 28 |
data TansuDb k v = TansuDb
|
| 27 | 29 |
{ dbSet :: ByteString -> ByteString -> IO (Either TansuError ())
|
| 28 | 30 |
, dbGet :: ByteString -> IO (Either TansuError ByteString)
|
| 29 | 31 |
, dbDel :: ByteString -> IO (Either TansuError ())
|
| 1 |
{-# LANGUAGE RankNTypes #-}
|
| 2 |
|
| 1 | 3 |
module Database.Tansu ( -- * The 'Tansu' monad
|
| 2 | 4 |
Tansu
|
| 3 | 5 |
, TansuDb
|
|
| 24 | 26 |
)
|
| 25 | 27 |
import Database.Tansu.Internal
|
| 26 | 28 |
|
| 27 | |
type TansuM a = ReaderT TansuDb (ExceptionT TansuError IO) a
|
| 29 |
type TansuM k v a = ReaderT (TansuDb k v) (ExceptionT TansuError IO) a
|
| 28 | 30 |
|
| 29 | 31 |
-- | The 'Tansu' type is a monad which represents some sequence
|
| 30 | 32 |
-- of 'get' and 'set' operations. Ideally, backends should
|
| 31 | 33 |
-- make some guarantee about the atomicity of a given
|
| 32 | 34 |
-- 'Tansu' computation, but you should consult the documentation
|
| 33 | 35 |
-- about a given backend to make sure that holds.
|
| 34 | |
newtype Tansu k v a = Tansu { runTansu :: TansuM a }
|
| 36 |
newtype Tansu k v a = Tansu { runTansu :: TansuM k v a }
|
| 35 | 37 |
|
| 36 | 38 |
instance Functor (Tansu k v) where
|
| 37 | 39 |
fmap f (Tansu t) = Tansu (fmap f t)
|
|
| 94 | 96 |
-- | Given a storage backend and a 'Tansu' computation, execute the
|
| 95 | 97 |
-- sequence of 'get' and 'set' commands and produce either the value
|
| 96 | 98 |
-- or the error encountered while running the computation.
|
| 97 | |
run :: TansuDb -> Tansu k v a -> IO (Either TansuError a)
|
| 99 |
run :: TansuDb k v -> Tansu k v a -> IO (Either TansuError a)
|
| 98 | 100 |
run db (Tansu comp) =
|
| 99 | 101 |
dbRunTransaction db (runExceptionT (runReaderT db comp))
|
| 68 | 68 |
del :: (Serialize k) => k -> Tansu k v ()
|
| 69 | 69 |
|
| 70 | 70 |
-- run a Tansu computation
|
| 71 | |
run :: TansuDb -> Tansu k v a -> IO (Either TansuError a)
|
| 71 |
run :: TansuDb k v -> Tansu k v a -> IO (Either TansuError a)
|
| 72 | 72 |
~~~
|
| 73 | 73 |
|
| 74 | 74 |
A value of type `TansuDb` should be supplied by a _backend_, which can
|
|
| 80 | 80 |
backends can be simply implemented separately from the core `tansu`
|
| 81 | 81 |
library, and backends can be easily swapped out as desired.
|
| 82 | 82 |
|
| 83 |
## Tansu Backends
|
| 84 |
|
| 85 |
[...]
|
| 86 |
|
| 83 | 87 |
## About the Name
|
| 84 | 88 |
|
| 85 | 89 |
A _tansu_ is a kind of
|
| 13 | 13 |
putStrLn "Testing ephemeral db"
|
| 14 | 14 |
withNewEphemeralDb sample
|
| 15 | 15 |
|
| 16 | |
sample :: TansuDb -> IO ()
|
| 16 |
sample :: TansuDb String String -> IO ()
|
| 17 | 17 |
sample db = do
|
| 18 | 18 |
putStrLn "Populating test database"
|
| 19 | 19 |
run db $ do
|