ez-couch-0.3.1: A high level 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 from 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

create :: (MonadAction m, Doc a) => a -> m (Persisted a)Source

createMultiple :: (MonadAction m, Doc a) => [a] -> m [Persisted a]Source

Reading

All reading actions accept a ReadOptions parameter which specifies how filtering and ordering should go.

readExists :: (MonadAction m, Doc a, ToJSON k, FromJSON k) => ReadOptions a k -> m [(k, Bool)]Source

readKeys :: (MonadAction m, Doc a, ToJSON k, FromJSON k) => ReadOptions a k -> m [k]Source

Updating

Deleting

delete :: (MonadAction m, Doc a) => Persisted a -> m ()Source

Server Time

readTime :: MonadAction m => m UTCTimeSource

Current time according to server.

Working with Views

createOrUpdateViewSource

Arguments

:: (Doc a, MonadAction m) 
=> Text

map-function

-> Maybe Text

reduce-function

-> View a

view identifier

-> m () 

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 abstracting over it.

inIsolationSource

Arguments

:: MonadAction m 
=> Int

A timeout in seconds. If after reaching it a conflicting isolation marker still exists in the db, it gets considered to be zombie (probably caused by a client interruption). The marker gets deleted and the current action gets executed.

-> Text

A unique isolation identifier. It's a common practice to provide a persistedId of the primary entity involved in the transaction, which is supposed to uniquely identify it.

-> m a

The action to protect. Nothing of it will be executed if an isolation with the same id is already running.

-> m (Maybe a)

Either the action's result or Nothing if it didn't get executed.

Protect an action from being executed on multiple clients. Can be used to create transactions in a preemptive manner, i.e. instead of performing some actions and rolling back on transaction validation failure it does validation based on the provided identifier prior to actually executing the transaction. This function however does not provide you with atomicity guarantees (http://en.wikipedia.org/wiki/Atomicity_(database_systems)), as it does not rollback in case of client-interrupt - it's up to your algorithms to handle those cases.

Types

data Persisted a Source

Constructors

Persisted 

Instances

Typeable1 Persisted 
Eq a => Eq (Persisted a) 
Data a => Data (Persisted a) 
Ord a => Ord (Persisted a) 
Show a => Show (Persisted a) 

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.

ServerException Text

E.g., server provided an unexpected response

ConnectionException Text 

newtype View a Source

Identifies a Couch's design and view. The design name is implicitly resolved from the type parameter a and becomes the name of this type. The view name however must be specified explicitly.

Constructors

View 

Fields

viewName :: Text
 

Instances

Typeable1 View 
Eq (View a) 
Data a => Data (View a) 
Ord (View a) 
Show (View a) 

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 a modifying actions (Create, Update, Delete).

Execution Monad

class (MonadBaseControl IO m, MonadResource m, MonadReader (ConnectionSettings, Manager) m) => MonadAction m Source

All EZCouch operations are performed in this monad.

runWithManager :: t1 -> t -> ReaderT (t, t1) m a -> m aSource

Classes which records should implement

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

Methods

docType :: 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 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)