Safe Haskell | None |
---|
EZCouch is a library which takes a mission of bringing the topmost level of abstraction for working with CouchDB in Haskell. It abstracts away from loose concepts of this database and brings a strict static API over standard ADTs.
- createEntity :: (MonadAction m, Entity a) => a -> m (Persisted a)
- createEntities :: (MonadAction m, Entity a) => [a] -> m [Persisted a]
- readEntities :: (MonadAction m, Entity a, ToJSON k) => View a k -> KeysSelection k -> Int -> Maybe Int -> Bool -> m [Persisted a]
- readRandomEntities :: (MonadAction m, Entity a) => Maybe Int -> m [Persisted a]
- readEntity :: (MonadAction m, Entity a, ToJSON k) => View a k -> KeysSelection k -> Int -> Bool -> m (Maybe (Persisted a))
- readKeysExist :: (MonadAction m, Entity a, ToJSON k, FromJSON k) => View a k -> KeysSelection k -> m [(k, Bool)]
- readKeys :: (MonadAction m, Entity a, ToJSON k, FromJSON k) => View a k -> KeysSelection k -> m [k]
- readCount :: (MonadAction m, Entity a, ToJSON k, FromJSON k) => View a k -> KeysSelection k -> m Int
- data KeysSelection k
- = KeysSelectionAll
- | KeysSelectionRange k k
- | KeysSelectionRangeStart k
- | KeysSelectionRangeEnd k
- | KeysSelectionList [k]
- updateEntity :: (MonadAction m, Entity a) => Persisted a -> m (Persisted a)
- updateEntities :: (MonadAction m, Entity a) => [Persisted a] -> m [Persisted a]
- deleteEntity :: (MonadAction m, Entity a) => Persisted a -> m ()
- deleteEntities :: (MonadAction m, Entity a) => [Persisted a] -> m ()
- readTime :: MonadAction m => m UTCTime
- data View entity keys where
- ViewById :: View entity Text
- ViewByKeys1 :: ViewKey a -> View entity a
- ViewByKeys2 :: ViewKey a -> ViewKey b -> View entity (a, b)
- ViewByKeys3 :: ViewKey a -> ViewKey b -> ViewKey c -> View entity (a, b, c)
- ViewByKeys4 :: ViewKey a -> ViewKey b -> ViewKey c -> ViewKey d -> View entity (a, b, c, d)
- ViewByKeys5 :: ViewKey a -> ViewKey b -> ViewKey c -> ViewKey d -> ViewKey e -> View entity (a, b, c, d, e)
- ViewByKeys6 :: ViewKey a -> ViewKey b -> ViewKey c -> ViewKey d -> ViewKey e -> ViewKey f -> View entity (a, b, c, d, e, f)
- ViewByKeys7 :: ViewKey a -> ViewKey b -> ViewKey c -> ViewKey d -> ViewKey e -> ViewKey f -> ViewKey g -> View entity (a, b, c, d, e, f, g)
- data ViewKey a
- isolateEntity :: (MonadAction m, Entity e) => Int -> Persisted e -> m (Maybe (Isolation e))
- isolateEntities :: (MonadAction m, Entity e) => Int -> [Persisted e] -> m [Maybe (Isolation e)]
- releaseIsolation :: (MonadAction m, Entity e) => Isolation e -> m (Persisted e)
- releaseIsolations :: (MonadAction m, Entity e) => [Isolation e] -> m [Persisted e]
- deleteIsolation :: (MonadAction m, Entity e) => Isolation e -> m ()
- deleteIsolations :: (MonadAction m, Entity e) => [Isolation e] -> m ()
- data Isolation e
- isolationEntity :: Isolation t1 -> t1
- data Persisted a = Persisted {
- persistedId :: Text
- persistedRev :: Text
- persistedValue :: a
- persistedIdHashPart :: Entity a => Persisted a -> Text
- tryOperation :: MonadAction m => m a -> m (Maybe a)
- class (MonadBaseControl IO m, MonadResource m, MonadReader Environment m) => MonadAction m
- type Environment = (ConnectionSettings, Manager, NominalDiffTime)
- run :: (MonadIO m, MonadBaseControl IO m, MonadThrow m, MonadUnsafeIO m) => ConnectionSettings -> ReaderT (ConnectionSettings, Manager, NominalDiffTime) (ResourceT m) a -> m a
- runWithManager :: (MonadBaseControl IO m, MonadResource m) => Manager -> ConnectionSettings -> ReaderT (ConnectionSettings, Manager, NominalDiffTime) m a -> m a
- data ConnectionSettings = ConnectionSettings {}
- defaultPort :: Int
- data EZCouchException
- class (ToJSON a, FromJSON a) => Entity a where
- entityType :: a -> Text
- class ToJSON a where
- class FromJSON a where
CRUD Monadic Functions for Working with Records
All monadic functions are split into CRUD categories. The functions with a Multiple suffix are better alternatives for performing multiple operations at once.
Creating
createEntity :: (MonadAction m, Entity a) => a -> m (Persisted a)Source
createEntities :: (MonadAction m, Entity a) => [a] -> m [Persisted a]Source
Reading
:: (MonadAction m, Entity a, ToJSON k) | |
=> View a k | View |
-> KeysSelection k | Keys selection mode |
-> Int | Skip |
-> Maybe Int | Limit |
-> Bool | Descending |
-> m [Persisted a] |
:: (MonadAction m, Entity a) | |
=> Maybe Int | Limit |
-> m [Persisted a] |
:: (MonadAction m, Entity a, ToJSON k) | |
=> View a k | View |
-> KeysSelection k | Keys selection mode |
-> Int | Skip |
-> Bool | Descending |
-> m (Maybe (Persisted a)) |
:: (MonadAction m, Entity a, ToJSON k, FromJSON k) | |
=> View a k | View |
-> KeysSelection k | Keys selection mode |
-> m [(k, Bool)] | An associative list of |
:: (MonadAction m, Entity a, ToJSON k, FromJSON k) | |
=> View a k | View |
-> KeysSelection k | Keys selection mode |
-> m [k] |
:: (MonadAction m, Entity a, ToJSON k, FromJSON k) | |
=> View a k | View |
-> KeysSelection k | Keys selection mode |
-> m Int |
data KeysSelection k Source
KeysSelectionAll | |
KeysSelectionRange k k | |
KeysSelectionRangeStart k | |
KeysSelectionRangeEnd k | |
KeysSelectionList [k] |
Eq k => Eq (KeysSelection k) | |
Show k => Show (KeysSelection k) |
Updating
updateEntity :: (MonadAction m, Entity a) => Persisted a -> m (Persisted a)Source
updateEntities :: (MonadAction m, Entity a) => [Persisted a] -> m [Persisted a]Source
Deleting
deleteEntity :: (MonadAction m, Entity a) => Persisted a -> m ()Source
deleteEntities :: (MonadAction m, Entity a) => [Persisted a] -> m ()Source
Server Time
readTime :: MonadAction m => m UTCTimeSource
Current time according to server. This function doesn't actually emit any requests to the server, calculating the value from a deviation of local time from server time determined at the beginning of the EZCouch session.
Working with Views
data View entity keys whereSource
ViewById :: View entity Text | |
ViewByKeys1 :: ViewKey a -> View entity a | |
ViewByKeys2 :: ViewKey a -> ViewKey b -> View entity (a, b) | |
ViewByKeys3 :: ViewKey a -> ViewKey b -> ViewKey c -> View entity (a, b, c) | |
ViewByKeys4 :: ViewKey a -> ViewKey b -> ViewKey c -> ViewKey d -> View entity (a, b, c, d) | |
ViewByKeys5 :: ViewKey a -> ViewKey b -> ViewKey c -> ViewKey d -> ViewKey e -> View entity (a, b, c, d, e) | |
ViewByKeys6 :: ViewKey a -> ViewKey b -> ViewKey c -> ViewKey d -> ViewKey e -> ViewKey f -> View entity (a, b, c, d, e, f) | |
ViewByKeys7 :: ViewKey a -> ViewKey b -> ViewKey c -> ViewKey d -> ViewKey e -> ViewKey f -> ViewKey g -> View entity (a, b, c, d, e, f, g) |
ViewKeyField Text | A path to a field value. Assuming the following record declarations: data A = A { b :: B } data B = B { c :: Int } A path value of Yes, it's not static. But it's probably the only place in the library that the compiler doesn't check for you. |
ViewKeyRandom | This will emit a JavaScript |
Transactions
CouchDB doesn't provide a way to do traditional locking-based transactions, as it applies an Optimistic Concurrency Control strategy (http://en.wikipedia.org/wiki/Optimistic_concurrency_control). EZCouch approaches the issue by providing a way to easily isolate entities from being accessed by concurrent clients, which you can use to build all kinds of transactions upon.
:: (MonadAction m, Entity e) | |
=> Int | A timeout in seconds. If the isolation does not get released when it passes, it gets considered to be zombie caused by client interrupt, then when the sweeper daemon hits the next cycle it will release the entity. |
-> Persisted e | The entity to isolate. |
-> m (Maybe (Isolation e)) | Either the isolation or nothing if the entity has been already isolated by concurrent client. |
Protect the entity from being accessed by concurrent clients until you
release it using releaseIsolation
, delete it with the isolation using
deleteIsolation
, or the timeout passes and it gets considered to be zombie
and gets released automatically some time later.
The automatic releasing gets done by a sweeper daemon running in background when EZCouch is being used on a timely basis and on its launch.
isolateEntities :: (MonadAction m, Entity e) => Int -> [Persisted e] -> m [Maybe (Isolation e)]Source
Does the same as isolateEntity
but for multiple entities and in a single
request.
:: (MonadAction m, Entity e) | |
=> Isolation e | The isolation returned by |
-> m (Persisted e) | The restored entity. |
Restore the entity document under the same id and drop the isolation.
releaseIsolations :: (MonadAction m, Entity e) => [Isolation e] -> m [Persisted e]Source
deleteIsolation :: (MonadAction m, Entity e) => Isolation e -> m ()Source
Get rid of both the isolation and the entity. The entity won't get restored by the sweeper daemon after.
deleteIsolations :: (MonadAction m, Entity e) => [Isolation e] -> m ()Source
isolationEntity :: Isolation t1 -> t1Source
Types
A wrapper for entity values which preserves the information required for identifying the appropriate documents in the db.
Persisted | |
|
persistedIdHashPart :: Entity a => Persisted a -> TextSource
Helpers
tryOperation :: MonadAction m => m a -> m (Maybe a)Source
Return Nothing
if an action throws an OperationException
or Just
its
result otherwise.
This is only useful for writing actions (Create, Update, Delete).
Execution Monad
class (MonadBaseControl IO m, MonadResource m, MonadReader Environment m) => MonadAction m Source
All EZCouch operations are performed in this monad.
(MonadResource m, MonadBaseControl IO m) => MonadAction (ReaderT Environment m) |
run :: (MonadIO m, MonadBaseControl IO m, MonadThrow m, MonadUnsafeIO m) => ConnectionSettings -> ReaderT (ConnectionSettings, Manager, NominalDiffTime) (ResourceT m) a -> m aSource
runWithManager :: (MonadBaseControl IO m, MonadResource m) => Manager -> ConnectionSettings -> ReaderT (ConnectionSettings, Manager, NominalDiffTime) m a -> m aSource
data ConnectionSettings Source
(MonadResource m, MonadBaseControl IO m) => MonadAction (ReaderT Environment m) |
data EZCouchException Source
ParsingException Text | A response from CouchDB could not be parsed. |
OperationException Text | An operation failed, e.g. a document couldn't be created or deleted. |
ResponseException Text | E.g., server provided an unexpected response |
ConnectionException Text | Either a connection got closed or a timeout passed |
ServerException Text | A weird status 500 response |
Classes which records should implement
Aeson re-exports
class ToJSON a where
A type that can be converted to JSON.
An example type and instance:
{-# LANGUAGE OverloadedStrings #-} data Coord { x :: Double, y :: Double } instance ToJSON Coord where toJSON (Coord x y) =object
["x".=
x, "y".=
y]
Note the use of the OverloadedStrings
language extension which enables
Text
values to be written as string literals.
Instead of manually writing your ToJSON
instance, there are three options
to do it automatically:
- Data.Aeson.TH provides template-haskell functions which will derive an instance at compile-time. The generated instance is optimized for your type so will probably be more efficient than the following two options:
- Data.Aeson.Generic provides a generic
toJSON
function that accepts any type which is an instance ofData
. - If your compiler has support for the
DeriveGeneric
andDefaultSignatures
language extensions (GHC 7.2 and newer),toJSON
will have a default generic implementation.
To use the latter option, simply add a deriving
clause to your
datatype and declare a Generic
ToJSON
instance for your datatype without giving a
definition for toJSON
.
For example the previous example can be simplified to just:
{-# LANGUAGE DeriveGeneric #-} import GHC.Generics data Coord { x :: Double, y :: Double } deriving Generic instance ToJSON Coord
class FromJSON a where
A type that can be converted from JSON, with the possibility of failure.
When writing an instance, use empty
, mzero
, or fail
to make a
conversion fail, e.g. if an Object
is missing a required key, or
the value is of the wrong type.
An example type and instance:
{-# LANGUAGE OverloadedStrings #-} data Coord { x :: Double, y :: Double } instance FromJSON Coord where parseJSON (Object
v) = Coord<$>
v.:
"x"<*>
v.:
"y" -- A non-Object
value is of the wrong type, so usemzero
to fail. parseJSON _ =mzero
Note the use of the OverloadedStrings
language extension which enables
Text
values to be written as string literals.
Instead of manually writing your FromJSON
instance, there are three options
to do it automatically:
- Data.Aeson.TH provides template-haskell functions which will derive an instance at compile-time. The generated instance is optimized for your type so will probably be more efficient than the following two options:
- Data.Aeson.Generic provides a generic
fromJSON
function that parses to any type which is an instance ofData
. - If your compiler has support for the
DeriveGeneric
andDefaultSignatures
language extensions,parseJSON
will have a default generic implementation.
To use this, simply add a deriving
clause to your datatype and
declare a Generic
FromJSON
instance for your datatype without giving a definition
for parseJSON
.
For example the previous example can be simplified to just:
{-# LANGUAGE DeriveGeneric #-} import GHC.Generics data Coord { x :: Double, y :: Double } deriving Generic instance FromJSON Coord