ez-couch-0.6.2: A high level static library for working with CouchDB

Safe HaskellNone

EZCouch

Contents

Description

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.

Synopsis

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

Reading

readEntitiesSource

Arguments

:: (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] 

readRandomEntitiesSource

Arguments

:: (MonadAction m, Entity a) 
=> Maybe Int

Limit

-> m [Persisted a] 

readEntitySource

Arguments

:: (MonadAction m, Entity a, ToJSON k) 
=> View a k

View

-> KeysSelection k

Keys selection mode

-> Int

Skip

-> Bool

Descending

-> m (Maybe (Persisted a)) 

readKeysExistSource

Arguments

:: (MonadAction m, Entity a, ToJSON k, FromJSON k) 
=> View a k

View

-> KeysSelection k

Keys selection mode

-> m [(k, Bool)]

An associative list of Bool values by keys designating the existance of appropriate entities

readKeysSource

Arguments

:: (MonadAction m, Entity a, ToJSON k, FromJSON k) 
=> View a k

View

-> KeysSelection k

Keys selection mode

-> m [k] 

readCountSource

Arguments

:: (MonadAction m, Entity a, ToJSON k, FromJSON k) 
=> View a k

View

-> KeysSelection k

Keys selection mode

-> m Int 

Updating

Deleting

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

Constructors

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) 

Instances

Eq (View entity keys) 
Show (View entity keys) 
Hashable (View entity keys) 

data ViewKey a Source

Constructors

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 "b.c" will emit the values of the c field of a JSON object representing the record B in a view key of type ViewKey A.

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 Math.random() value as a key. This is what makes the querying for random entities possible.

Instances

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.

isolateEntitySource

Arguments

:: (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.

releaseIsolationSource

Arguments

:: (MonadAction m, Entity e) 
=> Isolation e

The isolation returned by isolateEntity.

-> m (Persisted e)

The restored entity.

Restore the entity document under the same id and drop the isolation.

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.

Types

data Persisted a Source

A wrapper for entity values which preserves the information required for identifying the appropriate documents in the db.

Constructors

Persisted 

Instances

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.

data EZCouchException Source

Constructors

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

class (ToJSON a, FromJSON a) => Entity a whereSource

Methods

entityType :: a -> TextSource

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 of Data.
  • If your compiler has support for the DeriveGeneric and DefaultSignatures language extensions (GHC 7.2 and newer), toJSON will have a default generic implementation.

To use the latter option, simply add a deriving Generic clause to your datatype and declare a 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

Methods

toJSON :: a -> Value

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 use mzero 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 of Data.
  • If your compiler has support for the DeriveGeneric and DefaultSignatures language extensions, parseJSON will have a default generic implementation.

To use this, simply add a deriving Generic clause to your datatype and declare a 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

Methods

parseJSON :: Value -> Parser a

Instances

FromJSON Bool 
FromJSON Char 
FromJSON Double 
FromJSON Float 
FromJSON Int 
FromJSON Int8 
FromJSON Int16 
FromJSON Int32 
FromJSON Int64 
FromJSON Integer 
FromJSON Word 
FromJSON Word8 
FromJSON Word16 
FromJSON Word32 
FromJSON Word64 
FromJSON () 
FromJSON ByteString 
FromJSON Number 
FromJSON Text 
FromJSON UTCTime 
FromJSON DotNetTime 
FromJSON Value 
FromJSON ByteString 
FromJSON Text 
FromJSON IntSet 
FromJSON ZonedTime 
FromJSON [Char] 
FromJSON a => FromJSON [a] 
FromJSON (Ratio Integer) 
FromJSON a => FromJSON (Maybe a) 
HasResolution a => FromJSON (Fixed a) 
FromJSON a => FromJSON (Dual a) 
FromJSON a => FromJSON (First a) 
FromJSON a => FromJSON (Last a) 
FromJSON a => FromJSON (Vector a) 
(Eq a, Hashable a, FromJSON a) => FromJSON (HashSet a) 
(Ord a, FromJSON a) => FromJSON (Set a) 
FromJSON a => FromJSON (IntMap a) 
(Vector Vector a, FromJSON a) => FromJSON (Vector a) 
(Storable a, FromJSON a) => FromJSON (Vector a) 
(Prim a, FromJSON a) => FromJSON (Vector a) 
FromJSON a => FromJSON (Persisted a) 
(FromJSON a, FromJSON b) => FromJSON (Either a b) 
(FromJSON a, FromJSON b) => FromJSON (a, b) 
FromJSON v => FromJSON (HashMap String v) 
FromJSON v => FromJSON (HashMap ByteString v) 
FromJSON v => FromJSON (HashMap Text v) 
FromJSON v => FromJSON (HashMap ByteString v) 
FromJSON v => FromJSON (HashMap Text v) 
FromJSON v => FromJSON (Map String v) 
FromJSON v => FromJSON (Map ByteString v) 
FromJSON v => FromJSON (Map Text v) 
FromJSON v => FromJSON (Map ByteString v) 
FromJSON v => FromJSON (Map Text v) 
(FromJSON a, FromJSON b, FromJSON c) => FromJSON (a, b, c) 
(FromJSON a, FromJSON b, FromJSON c, FromJSON d) => FromJSON (a, b, c, d)