diff --git a/Database/RethinkDB.hs b/Database/RethinkDB.hs
--- a/Database/RethinkDB.hs
+++ b/Database/RethinkDB.hs
@@ -25,6 +25,7 @@
   SuccessCode(..),
   ErrorCode(..),
   ReQL,
+  JSON(..),
 
   -- * Manipulating databases
 
@@ -33,7 +34,7 @@
 
   -- * Manipulating Tables
 
-  Table(..), TableCreateOptions(..),
+  Table(..), TableCreateOptions(..), IndexCreateOptions(..),
   table, tableCreate, tableDrop, tableList,
   indexCreate, indexDrop, indexList,
 
@@ -42,15 +43,16 @@
   WriteResponse(..),
   insert, upsert,
   update, replace, delete,
-  returnVals,
+  returnVals, nonAtomic,
 
   -- * Selecting data
 
+  Bound(..),
   get, filter, between, getAll,
 
   -- * Joins
 
-  innerJoin, outerJoin, eqJoin, mergeRightLeft,
+  innerJoin, outerJoin, eqJoin, mergeLeftRight,
 
   -- * Transformations
 
@@ -58,10 +60,10 @@
   (!!), slice,
   orderBy,  Order(..),
   indexesOf, isEmpty, (++), sample,
-  
+
   -- * Aggregation
 
-  reduce, reduce1, distinct, groupBy, member,
+  reduce, reduce1, nub, groupBy, elem,
 
   -- * Aggregators
 
@@ -94,7 +96,7 @@
   
   -- * Control structures
 
-  apply, Javascript(js), if', forEach, error,
+  apply, js, if', forEach, error,
   handle, Expr(..), coerceTo,
   asArray, asString, asNumber, asObject, asBool,
   typeOf, info, json,
diff --git a/Database/RethinkDB/Driver.hs b/Database/RethinkDB/Driver.hs
--- a/Database/RethinkDB/Driver.hs
+++ b/Database/RethinkDB/Driver.hs
@@ -6,10 +6,14 @@
   Result(..),
   runOpts,
   RunOptions(..),
-  WriteResponse(..)
+  WriteResponse(..),
+  JSON(..)
   ) where
 
-import Data.Aeson (Value(..), FromJSON(..), fromJSON, (.:), (.:?))
+import Data.Aeson (Value(..), FromJSON(..), fromJSON, (.:), (.:?), encode)
+import Data.Aeson.Encode (fromValue)
+import Data.Text.Lazy (unpack)
+import Data.Text.Lazy.Builder (toLazyText)
 import qualified Data.Aeson (Result(Error, Success))
 import Control.Monad
 import Control.Concurrent.MVar (MVar, takeMVar)
@@ -20,7 +24,7 @@
 import Database.RethinkDB.Protobuf.Ql2.Query (Query(..))
 import Database.RethinkDB.Protobuf.Ql2.Query.AssocPair (AssocPair(..))
 import Database.RethinkDB.Protobuf.Ql2.Term as Term (Term(..))
-import Database.RethinkDB.Protobuf.Ql2.Term.TermType
+import Database.RethinkDB.Protobuf.Ql2.Term.TermType (TermType(DATUM))
 import Database.RethinkDB.Protobuf.Ql2.Datum as Datum
 import Database.RethinkDB.Protobuf.Ql2.Datum.DatumType
 import Text.ProtocolBuffers.Basic (uFromString, defaultValue)
@@ -59,8 +63,8 @@
 run :: (Expr query, Result r) => RethinkDBHandle -> query -> IO r
 run h = runOpts h []
 
--- | Run a given query and return a Value
-run' :: Expr query => RethinkDBHandle -> query -> IO [Value]
+-- | Run a given query and return a JSON
+run' :: Expr query => RethinkDBHandle -> query -> IO [JSON]
 run' h t = do
   c <- run h t
   collect c
@@ -120,3 +124,11 @@
     <*> o .:? "old_val"
     <*> o .:? "new_val"
   parseJSON _ = mzero
+
+data JSON = JSON Value
+
+instance Show JSON where
+  show (JSON a) = unpack . toLazyText . fromValue $ a
+
+instance FromJSON JSON where
+  parseJSON = fmap JSON . parseJSON
diff --git a/Database/RethinkDB/Functions.hs b/Database/RethinkDB/Functions.hs
--- a/Database/RethinkDB/Functions.hs
+++ b/Database/RethinkDB/Functions.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE FlexibleInstances, OverloadedStrings #-}
+{-# LANGUAGE FlexibleInstances, OverloadedStrings, GADTs #-}
 
 -- TODO: operator fixity
 
@@ -20,131 +20,284 @@
 import Prelude (($), return, Double, Bool, String)
 import qualified Prelude as P
 
--- | Arithmetic Operator
 infixl 6 +, -
 infixl 7 *, /
-(+), (-), (*), (/), mod
-  :: (Expr a, Expr b) => a -> b -> ReQL
+
+-- | Addition or concatenation
+--
+-- Use the Num instance, or a qualified operator.
+--
+-- > >>> run h $ 2 + 5 :: IO (Maybe Int)
+-- > Just 7
+-- > >>> run h $ 2 R.+ 5 :: IO (Maybe Int)
+-- > Just 7
+-- > >>> run h $ (str "foo") + (str "bar") :: IO (Just String)
+-- > Just "foobar"
+(+) :: (Expr a, Expr b) => a -> b -> ReQL
 (+) a b = op ADD (a, b) ()
+
+-- | Subtraction
+--
+-- > >>> run h $ 2 - 5 :: IO (Maybe Int)
+-- > Just (-3)
+(-) :: (Expr a, Expr b) => a -> b -> ReQL
 (-) a b = op SUB (a, b) ()
+
+-- | Multiplication
+--
+-- > >>> run h $ 2 * 5 :: IO (Maybe Int)
+-- > Just 10
+(*) :: (Expr a, Expr b) => a -> b -> ReQL
 (*) a b = op MUL (a, b) ()
+
+-- | Division
+--
+-- > >>> run h $ 2 R./ 5 :: IO (Maybe Double)
+-- > Just 0.4
+(/) :: (Expr a, Expr b) => a -> b -> ReQL
 (/) a b = op DIV (a, b) ()
+
+-- | Mod
+--
+-- > >>> run h $ 5 `mod` 2 :: IO (Maybe Int)
+-- > Just 1
+mod :: (Expr a, Expr b) => a -> b -> ReQL
 mod a b = op MOD (a, b) ()
 
--- | Boolean operator
 infixr 2 ||
 infixr 3 &&
-(||), (&&) :: (Expr a, Expr b) => a -> b -> ReQL
+
+-- | Boolean or
+--
+-- > >>> run h $ True R.|| False :: IO (Maybe Bool)
+-- > Just True
+(||) :: (Expr a, Expr b) => a -> b -> ReQL
 a || b = op ANY (a, b) ()
+
+-- | Boolean and
+--
+-- > >>> run h $ True R.&& False :: IO (Maybe Bool)
+-- > Just False
+(&&) :: (Expr a, Expr b) => a -> b -> ReQL
 a && b = op ALL (a, b) ()
 
--- | Comparison operator
 infix 4 ==, /=
-(==), (/=) :: (Expr a, Expr b) => a -> b -> ReQL
+
+-- | Test for equality
+--
+-- > >>> run h $ obj ["a" := 1] R.== obj ["a" := 1] :: IO (Maybe Bool)
+-- > Just True
+(==) :: (Expr a, Expr b) => a -> b -> ReQL
 a == b = op EQ (a, b) ()
+
+-- | Test for inequality
+--
+-- > >>> run h $ 1 R./= False :: IO (Maybe Bool)
+-- > Just True
+(/=) :: (Expr a, Expr b) => a -> b -> ReQL
 a /= b = op NE (a, b) ()
 
 infix 4 >, <, <=, >=
--- | Comparison operator
-(>), (>=), (<), (<=)
-  :: (Expr a, Expr b) => a -> b -> ReQL
+
+-- | Greater than
+--
+-- > >>> run h $ 3 R.> 2 :: IO (Maybe Bool)
+-- > Just True
+(>) :: (Expr a, Expr b) => a -> b -> ReQL
 a > b = op GT (a, b) ()
+
+-- | Lesser than
+--
+-- > >>> run h $ (str "a") R.< (str "b") :: IO (Maybe Bool)
+-- > Just True
+(<) :: (Expr a, Expr b) => a -> b -> ReQL
 a < b = op LT (a, b) ()
-a >=b = op GE (a, b) ()
-a <=b = op LE (a, b) ()
 
+-- | Greater than or equal to
+--
+-- > >>> run h $ [1] R.>= () :: IO (Maybe Bool)
+-- > Just False
+(>=) :: (Expr a, Expr b) => a -> b -> ReQL
+a >= b = op GE (a, b) ()
+
+-- | Lesser than or equal to
+--
+-- > >>> run h $ 2 R.<= 2 :: IO (Maybe Bool)
+-- > Just True
+(<=) :: (Expr a, Expr b) => a -> b -> ReQL
+a <= b = op LE (a, b) ()
+
 -- | Negation
+--
+-- > >>> run h $ R.not False :: IO (Maybe Bool)
+-- > Just True
+-- > >>> run h $ R.not () :: IO (Maybe Bool)
+-- > Just True
 not :: (Expr a) => a -> ReQL
 not a = op NOT [a] ()
 
 -- * Lists and Streams
 
 -- | The size of a sequence or an array.
+--
 -- Called /count/ in the official drivers
+--
+-- > >>> run h $ R.length (table "foo") :: IO (Maybe Int)
+-- > Just 17
 length :: (Expr a) => a -> ReQL
 length e = op COUNT [e] ()
 
 infixr 5 ++
+
 -- | Join two sequences.
+--
 -- Called /union/ in the official drivers
+--
+-- > >>> run h $ [1,2,3] R.++ ["a", "b", "c" :: Text] :: IO (Maybe [JSON])
+-- > Just [1.0,2.0,3.0,"a","b","c"]
 (++) :: (Expr a, Expr b) => a -> b -> ReQL
 a ++ b = op UNION (a, b) ()
 
 -- | Map a function over a sequence
+--
+-- > >>> run h $ R.map (!"a") [obj ["a" := 1], obj ["a" := 2]] :: IO (Maybe [Int])
+-- > Just [1,2]
 map :: (Expr a, Expr b) => (ReQL -> b) -> a -> ReQL
 map f a = op MAP (a, expr P.. f) ()
 
 -- | Filter a sequence given a predicate
+--
+-- > >>> run h $ R.filter (R.< 4) [3, 1, 4, 1, 5, 9, 2, 6] :: IO (Maybe [Int])
+-- > Just [3,1,1,2]
 filter :: (Expr predicate, Expr seq) => predicate -> seq -> ReQL
 filter f a = op FILTER (a, f) ()
 
 -- | Query all the documents whose value for the given index is in a given range
-between :: (Expr left, Expr right, Expr seq) => Key -> left -> right -> seq -> ReQL
-between i a b e = op BETWEEN [e] ["left_bound" := a, "right_bound" := b, "index" := i]
+--
+-- > >>> run h $ table "users" # between "id" (Closed $ str "a") (Open $ str "n") :: IO [JSON]
+-- > [{"post_count":4.0,"name":"bob","id":"b6a9df6a-b92c-46d1-ae43-1d2dd8ec293c"},{"post_count":4.0,"name":"bill","id":"b2908215-1d3c-4ff5-b9ee-1a003fa9690c"}]
+between :: (Expr left, Expr right, Expr seq) => Key -> Bound left -> Bound right -> seq -> ReQL
+between i a b e =
+  op BETWEEN [expr e, expr $ getBound a, expr $ getBound b]
+         ["left_bound" := closedOrOpen a, "right_bound" := closedOrOpen b, "index" := i]
 
 -- | Append a datum to a sequence
+--
+-- > >>> run h $ append 3 [1, 2] :: IO (Maybe [Int])
+-- > Just [1,2,3]
 append :: (Expr a, Expr b) => a -> b -> ReQL
 append a b = op APPEND (b, a) ()
 
 -- | Map a function of a sequence and concat the results
+--
+-- > >>> run h $ concatMap id [[1, 2], [3], [4, 5]] :: IO (Maybe [Int])
+-- > Just [1,2,3,4,5]
 concatMap :: (Expr a, Expr b) => (ReQL -> b) -> a -> ReQL
 concatMap f e = op CONCATMAP (e, expr P.. f) ()
 
--- | SQL-like join of two sequences. Returns each pair of rows that satisfy the 2-ary predicate.
-innerJoin, outerJoin :: (Expr a, Expr b, Expr c) => (ReQL -> ReQL -> c) -> a -> b -> ReQL
+-- | SQL-like inner join of two sequences
+--
+-- > >>> run' h $ innerJoin (\user post -> user!"id" R.== post!"author") (table "users") (table "posts") # mergeLeftRight # without ["id", "author"]
+-- > [[{"name":"bob","message":"lorem ipsum"},{"name":"bill","message":"hello"},{"name":"bill","message":"hi"}]]
+innerJoin :: (Expr a, Expr b, Expr c) => (ReQL -> ReQL -> c) -> a -> b -> ReQL
 innerJoin f a b = op INNER_JOIN (a, b, fmap expr P.. f) ()
+
+-- | SQL-like outer join of two sequences
+--
+-- > >>> run' h $ outerJoin (\user post -> user!"id" R.== post!"author") (table "users") (table "posts") # mergeLeftRight # without ["id", "author"]
+-- > [[{"name":"nancy"},{"name":"bill","message":"hello"},{"name":"bill","message":"hi"},{"name":"bob","message":"lorem ipsum"}]]
+outerJoin :: (Expr a, Expr b, Expr c) => (ReQL -> ReQL -> c) -> a -> b -> ReQL
 outerJoin f a b = op OUTER_JOIN (a, b, fmap expr P.. f) ()
 
--- | An efficient iner_join that uses a key for the first table and an index for the left table.
-eqJoin :: (Expr a, Expr b) => Key -> a -> Key -> b -> ReQL
-eqJoin a i k b = op EQ_JOIN (b, k, a) ["index" := i]
+-- | An efficient inner_join that uses a key for the left table and an index for the right table.
+--
+-- > >>> run' h $ table "posts" # eqJoin "author" (table "users") "id" # mergeLeftRight # without ["id", "author"]
+-- > [[{"name":"bill","message":"hi"},{"name":"bob","message":"lorem ipsum"},{"name":"bill","message":"hello"}]]
+eqJoin :: (Expr right, Expr left) => Key -> right -> Key -> left -> ReQL
+eqJoin key right index left = op EQ_JOIN (left, key, right) ["index" := index]
 
 -- | Drop elements from the head of a sequence.
+--
 -- Called /skip/ in the official drivers
+--
+-- > >>> run h $ R.drop 2 [1, 2, 3, 4] :: IO (Maybe [Int])
+-- > Just [3,4]
 drop :: (Expr a, Expr b) => a -> b -> ReQL
 drop a b = op SKIP (b, a) ()
 
 -- | Limit the size of a sequence.
+--
 -- Called /limit/ in the official drivers
+--
+-- > >>> run h $ R.take 2 [1, 2, 3, 4] :: IO (Maybe [Int])
+-- > Just [1,2]
 take :: (Expr n, Expr seq) => n -> seq -> ReQL
 take n s = op LIMIT (s, n) ()
 
 -- | Cut out part of a sequence
+--
+-- > >>> run h $ slice 2 4 [1, 2, 3, 4, 5] :: IO (Maybe [Int])
+-- > Just [3,4]
 slice :: (Expr a, Expr b, Expr c) => a -> b -> c -> ReQL
 slice n m s = op SLICE (s, n, m) ()
 
--- | Get the nth value of a sequence or array
 infixl 9 !!
+
+-- | Get the nth value of a sequence or array
+--
+-- > >>> run h $ [1, 2, 3] !! 0 :: IO (Maybe Int)
+-- > Just 1
 (!!) :: (Expr a) => a -> ReQL -> ReQL
 s !! n = op NTH (s, n) ()
 
 -- | Reduce a sequence to a single value
+--
+-- > >>> run h $ reduce (+) 0 [1, 2, 3] :: IO (Maybe Int)
+-- > Just 6
 reduce :: (Expr base, Expr seq, Expr a) => (ReQL -> ReQL -> a) -> base -> seq -> ReQL
 reduce f b s = op REDUCE (s, fmap expr P.. f) ["base" := b]
 
 -- | Reduce a non-empty sequence to a single value
+--
+-- > >>> run h $ reduce1 (+) [1, 2, 3] :: IO (Maybe Int)
+-- > Just 6
 reduce1 :: (Expr a, Expr s) => (ReQL -> ReQL -> a) -> s -> ReQL
 reduce1 f s = op REDUCE (s, fmap expr P.. f) ()
 
 -- | Filter out identical elements of the sequence
-distinct :: (Expr s) => s -> ReQL
-distinct s = op DISTINCT [s] ()
+--
+-- Called /distint/ in the official drivers
+--
+-- > >>> run h $ nub (table "posts" ! "flag") :: IO (Maybe [String])
+-- > Just ["pinned", "deleted"]
+nub :: (Expr s) => s -> ReQL
+nub s = op DISTINCT [s] ()
 
 -- | Like map but for write queries
+--
+-- > >>> run' h $ table "users" # replace (without ["post_count"])
+-- > >>> run' h $ forEach (table "posts") $ \post -> table "users" # get (post!"author") # update (\user -> obj ["post_count" := (handle 0 (user!"post_count") + 1)])
+-- > [{"skipped":0.0,"inserted":0.0,"unchanged":0.0,"deleted":0.0,"replaced":3.0,"errors":0.0}]
 forEach :: (Expr s, Expr a) => s -> (ReQL -> a) -> ReQL
 forEach s f = op FOREACH (s, expr P.. f) ()
 
 -- | Merge the "left" and "right" attributes of the objects in a sequence.
+--
 -- Called /zip/ in the official drivers
-mergeRightLeft :: (Expr a) => a -> ReQL
-mergeRightLeft a = op ZIP [a] ()
+--
+-- > >>> run' h $ table "posts" # eqJoin "author" (table "users") "id" # mergeLeftRight
+mergeLeftRight :: (Expr a) => a -> ReQL
+mergeLeftRight a = op ZIP [a] ()
 
--- | Oredering specification for orderBy
+-- | Ordering specification for orderBy
 data Order =
-  Asc { orderAttr :: Key } |
-  Desc { orderAttr :: Key }
+  Asc { orderAttr :: Key } -- ^ Ascending order
+  | Desc { orderAttr :: Key } -- ^ Descending order
 
 -- | Order a sequence by the given keys
+--
+-- > >>> run' h $ table "users" # orderBy [Desc "post_count", Asc "name"] # pluck ["name", "post_count"]
+-- > [[{"post_count":2.0,"name":"bill"},{"post_count":1.0,"name":"bob"},{"name":"nancy"}]]
 orderBy :: (Expr s) => [Order] -> s -> ReQL
 orderBy o s = ReQL $ do
   s' <- baseReQL (expr s)
@@ -155,19 +308,33 @@
     buildOrder (Desc k) = op DESC [k] ()
 
 -- | Turn a grouping function and a reduction function into a grouped map reduce operation
+--
+-- > >>> run' h $ table "posts" # groupBy (!"author") (reduce1 (\a b -> a + "\n" + b) . R.map (!"message"))
+    -- > [[{"group":"b2908215-1d3c-4ff5-b9ee-1a003fa9690c","reduction":"hi\nhello"},{"group":"b6a9df6a-b92c-46d1-ae43-1d2dd8ec293c","reduction":"lorem ipsum"}]]
+-- > >>> run' h $ table "users" # groupBy (!"level") (\users -> let pc = users!"post_count" in [avg pc, R.sum pc])
+-- > [[{"group":1,"reduction":[1.5,3.0]},{"group":2,"reduction":[0.0,0.0]}]]
 groupBy ::
   (Expr group, Expr reduction, Expr seq)
   => (ReQL -> group) -> (ReQL -> reduction) -> seq -> ReQL
 groupBy g mr s = ReQL $ do
-  (m, r, f) <- termToMapReduce (expr . mr)
-  baseReQL $
-    op GROUPED_MAP_REDUCE [expr s, expr $ expr P.. g, expr m, expr r] ()
+  (m, r, mf) <- termToMapReduce (expr . mr)
+  let gmr = op GROUPED_MAP_REDUCE [expr s, expr $ expr P.. g, expr m, expr r] ()
+  baseReQL $ case mf of
+    Nothing -> gmr
+    Just f -> op MAP [gmr, expr $ \x -> expr $
+                      obj ["group" := (x!"group"), "reduction" := f (x!"reduction")]] ()
 
 -- | The sum of a sequence
+--
+-- > >>> run h $ sum [1, 2, 3] :: IO (Maybe Int)
+-- > Just 6
 sum :: (Expr s) => s -> ReQL
 sum = reduce ((+) :: ReQL -> ReQL -> ReQL) (num 0)
 
 -- | The average of a sequence
+--
+-- > >>> run h $ avg [1, 2, 3, 4] :: IO (Maybe Double)
+-- > Just 2.5
 avg :: (Expr s) => s -> ReQL
 avg = (\x -> (x!!0) / (x!!1)) .
   reduce (\a b -> [(a!!0) + (b!!0), (a!!1) + (b!!1)]) [num 0, num 0] .
@@ -175,86 +342,142 @@
 
 -- * Accessors
 
--- | Get a single field form an object
 infixl 9 !
+
+-- | Get a single field from an object
+--
+-- > >>> run h $ (obj ["foo" := True]) ! "foo" :: IO (Maybe Bool)
+-- > Just True
+--
+-- Or a single field from each object in a sequence
+--
+-- > >>> run h $ [obj ["foo" := True], obj ["foo" := False]] ! "foo" :: IO (Maybe [Bool])
+-- > Just [True,False]
 (!) :: (Expr s) => s -> ReQL -> ReQL
 s ! k = op GET_FIELD (s, k) ()
 
 -- | Keep only the given attributes
+--
+-- > >>> run' h $ map obj [["a" := 1, "b" := 2], ["a" := 2, "c" := 7], ["b" := 4]] # pluck ["a"]
+-- > [[{"a":1.0},{"a":2.0},{}]]
 pluck :: (Expr o) => [ReQL] -> o -> ReQL
 pluck ks e = op PLUCK (cons e $ arr (P.map expr ks)) ()
 
 -- | Remove the given attributes from an object
+--
+-- > >>> run' h $ map obj [["a" := 1, "b" := 2], ["a" := 2, "c" := 7], ["b" := 4]] # without ["a"]
+-- > [[{"b":2.0},{"c":7.0},{"b":4.0}]]
 without :: (Expr o) => [ReQL] -> o -> ReQL
 without ks e = op WITHOUT (cons e $ arr (P.map expr ks)) ()
 
--- | Test if an object contains the given attribute.
--- Called /contains/ in the official drivers
-member :: (Expr o) => [ReQL] -> o -> ReQL
-member ks o = op CONTAINS (cons o $ arr (P.map expr ks)) ()
+-- | Test if a sequence contains a given element
+--
+-- > >>> run' h $ 1 `R.elem` [1,2,3]
+-- > [true]
+elem :: (Expr x, Expr seq) => x -> seq -> ReQL
+elem x s = op CONTAINS (s, x) ()
 
 -- | Merge two objects together
+--
+-- > >>> run' h $ merge (obj ["a" := 1, "b" := 1]) (obj ["b" := 2, "c" := 2])
+-- > [{"a":1.0,"b":2.0,"c":2.0}]
 merge :: (Expr a, Expr b) => a -> b -> ReQL
 merge a b = op MERGE (a, b) ()
 
--- | Create a javascript expression
-class Javascript r where
-  js :: P.String -> r
-
-instance Javascript ReQL where
-  js s = op JAVASCRIPT [str s] ()
-
-instance Javascript (ReQL -> ReQL) where
-  js s x = op FUNCALL (op JAVASCRIPT [str s] (), x) ()
-
-instance Javascript (ReQL -> ReQL -> ReQL) where
-  js s x y = op FUNCALL (op JAVASCRIPT [str s] (), x, y) ()
+-- | Evaluate a JavaScript expression
+--
+-- > >>> run h $ js "Math.random()" :: IO (Maybe Double)
+-- > Just 0.9119815775193274
+-- > >>> run h $ R.map (\x -> js "Math.sin" `apply` [x]) [pi, pi/2] :: IO (Maybe [Double])
+-- > Just [1.2246063538223773e-16,1.0]
+js :: ReQL -> ReQL
+js s = op JAVASCRIPT [s] ()
 
 -- | Called /branch/ in the official drivers
+--
+-- > >>> run h $ if' (1 R.< 2) 3 4 :: IO (Maybe Int)
+-- > Just 3
 if' :: (Expr a, Expr b, Expr c) => a -> b -> c -> ReQL
 if' a b c = op BRANCH (a, b, c) ()
 
 -- | Abort the query with an error
+--
+-- > >>> run' h $ R.error (str "haha") R./ 2 + 1
+-- > *** Exception: RethinkDBError {errorCode = runtime error, errorTerm = ADD(DIV(ERROR("haha"), 2.0), 1.0), errorMessage = "haha", errorBacktrace = [0,0]}
 error :: (Expr s) => s -> ReQL
 error m = op ERROR [m] ()
 
 -- | Create a Database reference
+--
+-- > >>> run' h $ db "test" # info
+-- > [{"name":"test","type":"DB"}]
 db :: Text -> O.Database
 db s = O.Database s
 
 -- | Create a database on the server
+--
+-- > >>> run' h $ dbCreate "dev"
+-- > [{"created":1.0}]
 dbCreate :: P.String -> ReQL
 dbCreate db_name = op DB_CREATE [str db_name] ()
 
 -- | Drop a database
+--
+-- > >>> run' h $ dbDrop (db "dev")
+-- > [{"dropped":1.0}]
 dbDrop :: Database -> ReQL
 dbDrop (O.Database name) = op DB_DROP [name] ()
 
 -- | List the databases on the server
+--
+-- > >>> run h $ dbList :: IO (Maybe [String])
+-- > Just ["test"]
 dbList :: ReQL
 dbList = op DB_LIST () ()
 
 -- | Create an index on the table from the given function
-indexCreate :: (Expr fun) => P.String -> fun -> Table -> ReQL
-indexCreate name f tbl = op INDEX_CREATE (tbl, str name, f) ()
+--
+-- > >>> run' h $ table "users" # indexCreate "name" (!"name") def
+-- > [{"created":1.0}]
+indexCreate :: (Expr fun) => P.String -> fun -> IndexCreateOptions -> Table -> ReQL
+indexCreate name f opts tbl = op INDEX_CREATE (tbl, str name, f) $ catMaybes [
+  ("multi" :=) <$> indexMulti opts]
 
 -- | Drop an index
+--
+-- > >>> run' h $ table "users" # indexDrop "name"
+-- > [{"dropped":1.0}]
 indexDrop :: Key -> Table -> ReQL
 indexDrop name tbl = op INDEX_DROP (tbl, name) ()
 
 -- | List the indexes on the table
+--
+-- > >>> run' h $ indexList (table "users")
+-- > [["name"]]
 indexList :: Table -> ReQL
 indexList tbl = op INDEX_LIST [tbl] ()
 
 -- | Retreive documents by their indexed value
+--
+-- > >>> run' h $ table "users" # getAll "name" ["bob"]
+-- > [{"post_count":1.0,"name":"bob","id":"b6a9df6a-b92c-46d1-ae43-1d2dd8ec293c"}]
 getAll :: (Expr value) => Key -> [value] -> Table -> ReQL
 getAll idx xs tbl = op GET_ALL (expr tbl : P.map expr xs) ["index" := idx]
 
--- | Create a simple table refence with no associated database
+-- | A table
+--
+-- > >>> (mapM_ print =<<) $ run' h $ table "users"
+-- > {"post_count":0.0,"name":"nancy","id":"8d674d7a-873c-4c0f-8a4a-32a4bd5bdee8"}
+-- > {"post_count":1.0,"name":"bob","id":"b6a9df6a-b92c-46d1-ae43-1d2dd8ec293c"}
+-- > {"post_count":2.0,"name":"bill","id":"b2908215-1d3c-4ff5-b9ee-1a003fa9690c"}
 table :: Text -> Table
 table n = O.Table Nothing n Nothing
 
 -- | Create a table on the server
+--
+-- > >>> run' h $ tableCreate (table "posts") def
+-- > >>> run' h $ tableCreate (table "users") def
+-- > >>> run' h $ tableCreate (Table (db "prod") "bar" (Just "name")) def{ tableDataCenter = Just "cloud", tableCacheSize = Just 10 }
 tableCreate :: Table -> TableCreateOptions -> ReQL
 tableCreate (O.Table mdb table_name pkey) opts =
   withQuerySettings $ \QuerySettings{ queryDefaultDatabase = ddb } ->
@@ -264,147 +487,273 @@
       ("primary_key" :=) <$> pkey ]
 
 -- | Drop a table
+--
+-- > >>> run' h $ tableDrop (table "bar")
+-- > [{"dropped":1.0}]
 tableDrop :: Table -> ReQL
 tableDrop (O.Table mdb table_name _) =
   withQuerySettings $ \QuerySettings{ queryDefaultDatabase = ddb } ->
     op TABLE_DROP (fromMaybe ddb mdb, table_name) ()
 
 -- | List the tables in a database
+--
+-- > >>> run h $ tableList (db "test") :: IO (Maybe [String])
+-- > Just ["foo","posts","users"]
 tableList :: Database -> ReQL
-tableList (O.Database name) = op TABLE_LIST [name] ()
+tableList name = op TABLE_LIST [name] ()
 
 -- | Get a document by primary key
-get :: (Expr s, Expr k) => k -> s -> ReQL
+--
+-- > >>> run' h $ table "users" # get "8d674d7a-873c-4c0f-8a4a-32a4bd5bdee8"
+-- > [{"post_count":0.0,"name":"nancy","id":"8d674d7a-873c-4c0f-8a4a-32a4bd5bdee8"}]
+get :: Expr s => ReQL -> s -> ReQL
 get k e = op GET (e, k) ()
 
 -- | Insert a document or a list of documents into a table
-insert :: (Expr table, Expr object) => object -> table -> ReQL
+--
+-- > >>> Just wr@WriteResponse{} <- run h $ table "users" # insert (map (\x -> obj ["name":=x]) ["bill", "bob", "nancy" :: Text])
+-- > >>> let Just [bill, bob, nancy] = writeResponseGeneratedKeys wr
+-- > >>> run' h $ table "posts" # insert (obj ["author" := bill, "message" := str "hi"])
+-- > >>> run' h $ table "posts" # insert (obj ["author" := bill, "message" := str "hello"])
+-- > >>> run' h $ table "posts" # insert (obj ["author" := bob, "message" := str "lorem ipsum"])
+insert :: (Expr object) => object -> Table -> ReQL
 insert a tb = canReturnVals $ op INSERT (tb, a) ()
 
 -- | Like insert, but update existing documents with the same primary key
+--
+-- > >>> run' h $ table "users" # upsert (obj ["id" := "79bfe377-9593-402a-ad47-f94c76c36a51", "name" := "rupert"])
+-- > [{"skipped":0.0,"inserted":0.0,"unchanged":0.0,"deleted":0.0,"replaced":1.0,"errors":0.0}]
 upsert :: (Expr table, Expr object) => object -> table -> ReQL
 upsert a tb = canReturnVals $ op INSERT (tb, a) ["upsert" := P.True]
 
 -- | Add to or modify the contents of a document
-update :: (Expr selection) => (ReQL -> ReQL) -> selection -> ReQL
-update f s = canReturnVals $ op UPDATE (s, f) ()
+--
+-- > >>> run' h $ table "users" # getAll "name" [str "bob"] # update (const $ obj ["name" := str "benjamin"])
+-- > [{"skipped":0.0,"inserted":0.0,"unchanged":0.0,"deleted":0.0,"replaced":1.0,"errors":0.0}]
+update :: (Expr selection, Expr a) => (ReQL -> a) -> selection -> ReQL
+update f s = canNonAtomic $ canReturnVals $ op UPDATE (s, expr . f) ()
 
 -- | Replace a document with another
-replace :: (Expr selection) => (ReQL -> ReQL) -> selection -> ReQL
-replace f s = canReturnVals $ op REPLACE (s, f) ()
+--
+-- > >>> run' h $ replace (\bill -> obj ["name" := str "stoyan", "id" := bill!"id"]) . R.filter ((R.== str "bill") . (!"name")) $ table "users"
+-- > [{"skipped":0.0,"inserted":0.0,"unchanged":0.0,"deleted":0.0,"replaced":1.0,"errors":0.0}]
+replace :: (Expr selection, Expr a) => (ReQL -> a) -> selection -> ReQL
+replace f s = canNonAtomic $ canReturnVals $ op REPLACE (s, expr . f) ()
 
 -- | Delete the documents
+--
+-- > >>> run' h $ delete . getAll "name" [str "bob"] $ table "users"
+-- > [{"skipped":0.0,"inserted":0.0,"unchanged":0.0,"deleted":1.0,"replaced":0.0,"errors":0.0}]
 delete :: (Expr selection) => selection -> ReQL
 delete s = canReturnVals $ op DELETE [s] ()
 
 -- | Convert a value to a different type
+--
+-- > >>> run h $ coerceTo "STRING" 1 :: IO (Maybe String)
+-- > Just "1"
 coerceTo :: (Expr x) => ReQL -> x -> ReQL
 coerceTo t a = op COERCE_TO (a, t) ()
 
--- | Convert a value to a different type
-asArray, asString, asNumber, asObject, asBool :: Expr x => x -> ReQL
+-- | Convert a value to an array
+--
+-- > >>> run h $ asArray $ obj ["a" := 1, "b" := 2] :: IO (Maybe [(String, Int)])
+-- > Just [("a",1),("b",2)]
+asArray :: Expr x => x -> ReQL
 asArray = coerceTo "ARRAY"
+
+-- | Convert a value to a string
+--
+-- > >>> run h $ asString $ obj ["a" := 1, "b" := 2] :: IO (Maybe String)
+-- > Just "{\n\t\"a\":\t1,\n\t\"b\":\t2\n}"
+asString :: Expr x => x -> ReQL
 asString = coerceTo "STRING"
+
+-- | Convert a value to a number
+--
+-- > >>> run h $ asNumber (str "34") :: IO (Maybe Int)
+-- > Just 34
+asNumber :: Expr x => x -> ReQL
 asNumber = coerceTo "NUMBER"
+
+-- | Convert a value to an object
+--
+-- > >>> run' h $ asObject $ [(str "a",1),("b",2)]
+-- > [{"a":1.0,"b":2.0}]
+asObject :: Expr x => x -> ReQL
 asObject = coerceTo "OBJECT"
+
+-- | Convert a value to a boolean
+asBool :: Expr x => x -> ReQL
 asBool = coerceTo "BOOL"
 
 -- | Like hasFields followed by pluck
-withFields :: (Expr paths, Expr seq) => [paths] -> seq -> ReQL
+--
+-- > >>> run' h $ map obj [["a" := 1, "b" := 2], ["a" := 2, "c" := 7], ["b" := 4]] # withFields ["a"]
+-- > [[{"a":1.0},{"a":2.0}]]
+withFields :: Expr seq => [ReQL] -> seq -> ReQL
 withFields p s = op WITH_FIELDS (s, p) ()
 
 -- | The position in the sequence of the elements that match the predicate
+--
+-- > >>> run h $ indexesOf (=~ "ba.") [str "foo", "bar", "baz"] :: IO (Maybe [Int])
+-- > Just [1,2]
 indexesOf :: (Expr fun, Expr seq) => fun -> seq -> ReQL
 indexesOf f s = op INDEXES_OF (s, f) ()
 
 -- | Test if a sequence is empty
+--
+-- > >>> run h $ isEmpty [1] :: IO (Maybe Bool)
+-- > Just False
 isEmpty :: Expr seq => seq -> ReQL
 isEmpty s = op IS_EMPTY [s] ()
 
 -- | Select a given number of elements from a sequence with uniform random distribution
+--
+-- > >>> run h $ sample 3 [0,1,2,3,4,5,6,7,8,9] :: IO (Maybe [Int])
+-- > Just [4,3,8]
 sample :: (Expr n, Expr seq) => n -> seq -> ReQL
 sample n s = op SAMPLE (s, n) ()
 
 -- | Prepend an element to an array
+--
+-- > >>> run h $ prepend 1 [2,3] :: IO (Maybe [Int])
+-- > Just [1,2,3]
 prepend :: (Expr datum, Expr array) => datum -> array -> ReQL
 prepend d a = op PREPEND (a, d) ()
 
--- | Called /difference/ in the official drivers
 infixl 9 \\ --
+
+-- | Called /difference/ in the official drivers
+--
+-- > >>> run h $ [1,2,3,4,5] \\ [2,5] :: IO (Maybe [Int])
+-- > Just [1,3,4]
 (\\) :: (Expr a, Expr b) => a -> b -> ReQL
 a \\ b = op DIFFERENCE (a, b) ()
 
 -- | Insert a datum into an array if it is not yet present
+--
+-- > >>> run h $ setInsert 3 [1,2,4,4,5] :: IO (Maybe [Int])
+-- > Just [1,2,4,5,3]
 setInsert :: (Expr datum, Expr array) => datum -> array -> ReQL
 setInsert d a = op SET_INSERT (a, d) ()
 
 -- | The union of two sets
+--
+-- > >>> run h $ [1,2] `setUnion` [2,3]  :: IO (Maybe [Int])
+-- > Just [2,3,1]
 setUnion :: (Expr a, Expr b) => a -> b -> ReQL
 setUnion a b = op SET_UNION (b, a) ()
 
 -- | The intersection of two sets
+--
+-- > >>> run h $ [1,2] `setIntersection` [2,3]  :: IO (Maybe [Int])
+-- > Just [2]
 setIntersection :: (Expr a, Expr b) => a -> b -> ReQL
 setIntersection a b = op SET_INTERSECTION (b, a) ()
 
 -- | The difference of two sets
+--
+-- > >>> run h $ [2,3] # setDifference [1,2]  :: IO (Maybe [Int])
+-- > Just [3]
 setDifference :: (Expr set, Expr remove) => remove -> set -> ReQL
 setDifference r s = op SET_DIFFERENCE (s, r) ()
 
 -- | Test if an object has the given fields
-hasFields :: (Expr obj, Expr paths) => paths -> obj -> ReQL
-hasFields p o = op HAS_FIELDS (o, p) ()
+--
+-- > >>> run h $ hasFields ["a"] $ obj ["a" := 1] :: IO (Maybe Bool)
+-- > Just True
+hasFields :: (Expr obj) => ReQL -> obj -> ReQL
+hasFields p o = op HAS_FIELDS (o, expr p) ()
 
 -- | Insert a datum at the given position in an array
+--
+-- > >>> run h $ insertAt 1 4 [1,2,3] :: IO (Maybe [Int])
+-- > Just [1,4,2,3]
 insertAt :: (Expr n, Expr datum, Expr array) => n -> datum -> array -> ReQL
 insertAt n d a = op INSERT_AT (a, n, d) ()
 
 -- | Splice an array at a given position inside another array
+--
+-- > >>> run h $ spliceAt 2 [4,5] [1,2,3] :: IO (Maybe [Int])
+-- > Just [1,2,4,5,3]
 spliceAt :: (Expr n, Expr replace, Expr array) => n -> replace -> array -> ReQL
 spliceAt n s a = op SPLICE_AT (a, n, s) ()
 
 -- | Delete an element from an array
+--
+-- > >>> run h $ deleteAt 1 [1,2,3] :: IO (Maybe [Int])
+-- > Just [1,3]
 deleteAt :: (Expr n, Expr array) => n -> array -> ReQL
 deleteAt n a = op DELETE_AT (a, n) ()
 
 -- | Change an element in an array
+--
+-- > >>> run h $ changeAt 1 4 [1,2,3] :: IO (Maybe [Int])
+-- > Just [1,4,3]
 changeAt :: (Expr n, Expr datum, Expr array) => n -> datum -> array -> ReQL
 changeAt n d a = op CHANGE_AT (a, n, d) ()
 
 -- | The list of keys of the given object
+--
+-- > >>> run h $ keys (obj ["a" := 1, "b" := 2]) :: IO (Maybe [String])
+-- > Just ["a","b"]
 keys :: Expr obj => obj -> ReQL
 keys o = op KEYS [o] ()
 
 -- | Match a string to a regular expression.
+--
 -- Called /match/ in the official drivers
+--
+-- > >>> run' h $ str "foobar" =~ "f(.)+[bc](.+)"
+-- > [{"groups":[{"start":2.0,"end":3.0,"str":"o"},{"start":4.0,"end":6.0,"str":"ar"}],"start":0.0,"end":6.0,"str":"foobar"}]
 (=~) :: (Expr string) => string -> ReQL -> ReQL
 s =~ r = op MATCH (s, r) ()
 
 -- | Apply a function to a list of arguments.
+--
 -- Called /do/ in the official drivers
+--
+-- > >>> run h $ (\x -> x R.* 2) `apply` [4] :: IO (Maybe Int)
+-- > Just 8
 apply :: (Expr fun, Expr arg) => fun -> [arg] -> ReQL
 f `apply` as = op FUNCALL (expr f : P.map expr as) ()
 
 -- | Catch some expections inside the query.
+--
 -- Called /default/ in the official drivers
+--
+-- > >>> run h $ handle 0 $ obj ["a" := 1] ! "b" :: IO (Maybe Int)
+-- > Just 0
+-- > >>> run h $ handle (expr . id) $ obj ["a" := 1] ! "b" :: IO (Maybe String)
+-- > Just "No attribute `b` in object:\n{\n\t\"a\":\t1\n}"
 handle :: (Expr handler, Expr reql) => handler -> reql -> ReQL
 handle h r = op DEFAULT (r, h) ()
 
 -- | A string representing the type of an expression
+--
+-- > >>> run h $ typeOf 1 :: IO (Maybe String)
+-- > Just "NUMBER"
 typeOf :: Expr a => a -> ReQL
 typeOf a = op TYPEOF [a] ()
 
 -- | Get information on a given expression. Useful for tables and databases.
+--
+-- > >>> run' h $ info $ table "foo"
+-- > [{"primary_key":"id","name":"foo","indexes":[],"type":"TABLE","db":{"name":"test","type":"DB"}}]
 info :: Expr a => a -> ReQL
 info a = op INFO [a] ()
 
 -- | Parse a json string into an object
-json :: Expr string => string -> ReQL
+--
+-- > >>> run' h $ json "{a:1}"
+-- > [{"a":1.0}]
+json :: ReQL -> ReQL
 json s = op JSON [s] ()
 
--- | Flipped function composition
+-- | Flipped function application
 infixl 8 #
-(#) :: (Expr a, Expr b) =>  a -> (ReQL -> b) -> ReQL
-x # f = expr (f (expr x))
+(#) :: (Expr a, Expr b) =>  a -> (a -> b) -> ReQL
+x # f = expr (f x)
 
 infixr 9 .
 -- | Specialised function composition
diff --git a/Database/RethinkDB/MapReduce.hs b/Database/RethinkDB/MapReduce.hs
--- a/Database/RethinkDB/MapReduce.hs
+++ b/Database/RethinkDB/MapReduce.hs
@@ -5,6 +5,7 @@
 import Control.Monad.State
 import Control.Monad.Writer
 import qualified Data.Text as T
+import Data.Maybe
 
 import Database.RethinkDB.Protobuf.Ql2.Term.TermType
 import qualified Database.RethinkDB.Protobuf.Ql2.Datum as Datum
@@ -13,16 +14,15 @@
 import Database.RethinkDB.Objects
 
 termToMapReduce ::
-  (ReQL -> ReQL) -> State QuerySettings (ReQL -> ReQL, ReQL -> ReQL -> ReQL, ReQL -> ReQL)
+  (ReQL -> ReQL) -> State QuerySettings (ReQL -> ReQL, ReQL -> ReQL -> ReQL, Maybe (ReQL -> ReQL))
 termToMapReduce f = do
   v <- newVarId
   body <- baseReQL $ f (op VAR [v] ())
-  let MapReduce map_ reduce finally = toMapReduce v body
-  return (map_, reduce, finally)
+  return . toReduce $ toMapReduce v body
 
-toReduce :: MapReduce -> (ReQL -> ReQL, ReQL -> ReQL -> ReQL, ReQL -> ReQL)
-toReduce (None t) = (\_ -> expr (), \_ _ -> expr (), const t)
-toReduce (Map m) = ((\x -> expr [x]) . m, unionReduce, id)
+toReduce :: MapReduce -> (ReQL -> ReQL, ReQL -> ReQL -> ReQL, Maybe (ReQL -> ReQL))
+toReduce (None t) = (\_ -> expr (), \_ _ -> expr (), Just $ const t)
+toReduce (Map m) = ((\x -> expr [x]) . m, unionReduce, Nothing)
 toReduce (MapReduce m r f) = (m, r, f)
 
 unionReduce :: ReQL -> ReQL -> ReQL
@@ -60,9 +60,9 @@
               case (type', args', optargs') of
                 (MAP, [Map m, None f], []) -> Map (toFun1 f . m)
                 (REDUCE, [Map m, None f], _) | Just mbase <- optargsToBase optargs ->
-                  MapReduce m (toFun2 f) (maybe id (toFun2 f) mbase)
+                  MapReduce m (toFun2 f) (fmap (toFun2 f) mbase)
                 (COUNT, [Map _], []) ->
-                  MapReduce (const (num 1)) (\a b -> op ADD (a, b) ()) id
+                  MapReduce (const (num 1)) (\a b -> op ADD (a, b) ()) Nothing
                 (tt, (Map m : _), _) | tt `elem` mappableTypes ->
                   (Map ((\x -> op tt (expr x : map expr (tail args)) (noRecurse : map baseAttrToAttr optargs)) . m))
                 _ -> rebuild
@@ -84,13 +84,13 @@
 data MapReduce =
     None ReQL |
     Map (ReQL -> ReQL) |
-    MapReduce (ReQL -> ReQL) (ReQL -> ReQL -> ReQL) (ReQL -> ReQL)
+    MapReduce (ReQL -> ReQL) (ReQL -> ReQL -> ReQL) (Maybe (ReQL -> ReQL))
 
 rebuild0 :: TermType -> [MapReduce] -> [(T.Text, MapReduce)] -> MapReduce
 rebuild0 ttype args optargs = MapReduce maps reduce finals where
   (finally2, [mr]) = extract Nothing ttype args optargs
   (maps, reduce, finally1) = toReduce mr
-  finals = finally2 . finally1
+  finals = Just $ maybe finally2 (finally2 .) finally1
 
 rebuildx :: TermType -> [MapReduce] -> [(Key, MapReduce)] -> MapReduce
 rebuildx ttype args optargs = MapReduce maps reduces finallys where
@@ -99,7 +99,11 @@
   triplets = map toReduce mrs
   maps x = expr $ map (($ x) . fst3) triplets
   reduces a b = expr $ map (uncurry $ mkReduce a b) . index $ map snd3 triplets
-  finallys x = finally $ expr $ map (uncurry $ mkFinally x) . index $ map thrd3 triplets
+  finallys = let fs = map thrd3 triplets in
+    if all isNothing fs
+       then Just finally
+       else Just $ \x -> finally $ expr $ map (uncurry $ mkFinally x) . index $
+                         map (fromMaybe id) fs
   mkReduce a b i f = f (op NTH (a, i) ()) (op NTH (b, i) ())
   mkFinally x i f = f (op NTH (x, i) ())
 
diff --git a/Database/RethinkDB/Network.hs b/Database/RethinkDB/Network.hs
--- a/Database/RethinkDB/Network.hs
+++ b/Database/RethinkDB/Network.hs
@@ -10,7 +10,6 @@
   makeCursor,
   next,
   collect,
-  stopResponse,
   nextResponse,
   Response(..),
   SuccessCode(..),
@@ -28,7 +27,7 @@
 import qualified Data.ByteString.UTF8 as BS (fromString)
 import qualified Data.Text as T
 import Control.Concurrent (
-  writeChan, MVar, Chan, modifyMVar, readMVar, forkIO, readChan,
+  writeChan, MVar, Chan, modifyMVar, takeMVar, forkIO, readChan,
   myThreadId, newMVar, ThreadId, newChan, killThread,
   newEmptyMVar, putMVar, mkWeakMVar)
 import Data.Bits (shiftL, (.|.), shiftR)
@@ -43,6 +42,7 @@
 import Control.Monad.Fix (fix)
 import Data.Int (Int64)
 import System.IO.Unsafe (unsafeInterleaveIO)
+import System.Mem.Weak (finalize)
 
 import Text.ProtocolBuffers.Basic (uToString)
 import Text.ProtocolBuffers (messagePut, defaultValue, messageGet)
@@ -68,7 +68,7 @@
   rdbWriteLock :: MVar (Maybe SomeException),
   rdbToken :: IORef Token, -- ^ The next token to use
   rdbDatabase :: Database,  -- ^ The default database
-  rdbWait :: IORef (Map Token (Chan Response, BaseReQL)),
+  rdbWait :: IORef (Map Token (Chan Response, BaseReQL, IO ())),
   rdbThread :: ThreadId
   }
 
@@ -130,7 +130,7 @@
 -- | Convert a 4-byte byestring to an int
 unpackUInt :: ByteString -> Maybe Int
 unpackUInt s = case unpack s of
-  [a,b,c,d] -> Just $ 
+  [a,b,c,d] -> Just $
                fromIntegral a .|.
                fromIntegral b `shiftL` 8 .|.
                fromIntegral c `shiftL` 16 .|.
@@ -205,7 +205,7 @@
   where
     bt = maybe [] convertBacktrace backtrace
     r = toList response
-    e = maybe "" uToString $ r_str =<< listToMaybe (toList response) 
+    e = maybe "" uToString $ r_str =<< listToMaybe (toList response)
         -- TODO: nicer backtrace
 
 runQLQuery :: RethinkDBHandle -> Query -> BaseReQL -> IO (MVar Response)
@@ -218,12 +218,13 @@
 addMBox :: RethinkDBHandle -> Token -> BaseReQL -> IO (MVar Response)
 addMBox h tok term = do
   chan <- newChan
-  atomicModifyIORef' (rdbWait h) $ \mboxes -> 
-    (M.insert tok (chan, term) mboxes, ())
   mbox <- newEmptyMVar
-  _ <- mkWeakMVar mbox $ do
-    atomicModifyIORef' (rdbWait h) $ \mboxes -> 
+  weak <- mkWeakMVar mbox $ do
+    closeToken h tok
+    atomicModifyIORef' (rdbWait h) $ \mboxes ->
       (M.delete tok mboxes, ())
+  atomicModifyIORef' (rdbWait h) $ \mboxes ->
+    (M.insert tok (chan, term, finalize weak) mboxes, ())
   _ <- forkIO $ fix $ \loop -> do
     response <- readChan chan
     putMVar mbox response
@@ -248,6 +249,7 @@
   tid <- myThreadId
   let h = h' tid
   let handler e@SomeException{} = do
+        hClose $ rdbHandle h
         modifyMVar (rdbWriteLock h) $ \_ -> return (Just e, ())
         writeIORef (rdbWait h) M.empty
   flip catch handler $ forever $ readSingleResponse h
@@ -264,7 +266,7 @@
     Left errMsg -> fail errMsg
     Right (response, rest)
       | B.null rest -> dispatch (Ql2.token response) response
-      | otherwise -> fail "readsingleResponse: invalid reply length"
+      | otherwise -> fail "readSingleResponse: invalid reply length"
 
   where
   dispatch Nothing _ = return ()
@@ -272,11 +274,10 @@
     mboxes <- readIORef $ rdbWait h
     case M.lookup tok mboxes of
       Nothing -> return ()
-      Just (mbox, term) -> do
+      Just (mbox, term, closetok) -> do
         let convertedResponse = convertResponse h term tok response
         writeChan mbox convertedResponse
-        when (isLastResponse convertedResponse) $
-          atomicModifyIORef' (rdbWait h) $ \m -> (M.delete tok m, ())
+        when (isLastResponse convertedResponse) $ closetok
 
 isLastResponse :: Response -> Bool
 isLastResponse ErrorResponse{} = True
@@ -309,11 +310,10 @@
 convertDatum Datum { type' = Just R_NUM, r_num = Just n } = toJSON n
 convertDatum d = error ("Invalid Datum: " ++ show d)
 
-stopResponse :: Response -> IO ()
-stopResponse SuccessResponse { successCode = SuccessPartial h tok } = do
+closeToken :: RethinkDBHandle -> Token -> IO ()
+closeToken h tok = do
   let query = defaultValue { Query.type' = Just STOP, Query.token = Just tok}
   sendQLQuery h query
-stopResponse _ = return ()
 
 nextResponse :: Response -> IO ()
 nextResponse SuccessResponse { successCode = SuccessPartial h tok } = do
@@ -338,7 +338,7 @@
 
 cursorFetchBatch :: Cursor a -> IO (Either RethinkDBError ([O.Datum], Bool))
 cursorFetchBatch c = do
-  response <- readMVar (cursorMBox c)
+  response <- takeMVar (cursorMBox c)
   case response of
     ErrorResponse e -> return $ Left e
     SuccessResponse Success datums -> return $ Right (datums, True)
diff --git a/Database/RethinkDB/NoClash.hs b/Database/RethinkDB/NoClash.hs
--- a/Database/RethinkDB/NoClash.hs
+++ b/Database/RethinkDB/NoClash.hs
@@ -6,10 +6,12 @@
   -- module Prelude, module Data.Time -- Uncomment to let GHC detect clashes
   ) where
 
-import Data.Time
+-- Uncomment imports to let GHC detect clashes
+--import Data.Time
 
 import Database.RethinkDB hiding (
   UTCTime, ZonedTime,
   (*), (+), (-), (/),
   sum, (++), (.), map, mod, (!!), concatMap, drop, length, take, (&&),
-  not, (||), (/=), (<), (<=), (>), (>=), error, (==), filter)
+  not, (||), (/=), (<), (<=), (>), (>=), error, (==), filter,
+  elem)
diff --git a/Database/RethinkDB/Objects.hs b/Database/RethinkDB/Objects.hs
--- a/Database/RethinkDB/Objects.hs
+++ b/Database/RethinkDB/Objects.hs
@@ -1,6 +1,7 @@
 module Database.RethinkDB.Objects (
   Database(..),
   TableCreateOptions(..),
+  IndexCreateOptions(..),
   Table(..),
   Datum,
   Key
@@ -29,6 +30,14 @@
 
 instance Default TableCreateOptions where
   def = TableCreateOptions Nothing Nothing
+
+-- | Options used to create an index
+data IndexCreateOptions = IndexCreateOptions {
+  indexMulti :: Maybe Bool
+  }
+
+instance Default IndexCreateOptions where
+  def = IndexCreateOptions Nothing
 
 -- | A table description
 data Table = Table {
diff --git a/Database/RethinkDB/ReQL.hs b/Database/RethinkDB/ReQL.hs
--- a/Database/RethinkDB/ReQL.hs
+++ b/Database/RethinkDB/ReQL.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE ExistentialQuantification, RecordWildCards, ScopedTypeVariables,
-             FlexibleInstances, OverloadedStrings, PatternGuards #-}
+             FlexibleInstances, OverloadedStrings, PatternGuards, GADTs #-}
 
 -- | Building RQL queries in Haskell
 module Database.RethinkDB.ReQL (
@@ -23,8 +23,12 @@
   Object(..),
   Obj(..),
   returnVals,
+  nonAtomic,
   canReturnVals,
-  reqlToProtobuf
+  canNonAtomic,
+  reqlToProtobuf,
+  Bound(..),
+  closedOrOpen
   ) where
 
 import qualified Data.Vector as V
@@ -76,11 +80,12 @@
   queryDefaultDatabase :: Database,
   queryVarIndex :: Int,
   queryUseOutdated :: Maybe Bool,
-  queryReturnVals :: Maybe Bool
+  queryReturnVals :: Maybe Bool,
+  queryAtomic :: Maybe Bool
   }
 
 instance Default QuerySettings where
-  def = QuerySettings 0 (Database "") 0 Nothing Nothing
+  def = QuerySettings 0 (Database "") 0 Nothing Nothing Nothing
 
 withQuerySettings :: (QuerySettings -> ReQL) -> ReQL
 withQuerySettings f = ReQL $ (baseReQL . f) =<< get
@@ -95,6 +100,16 @@
   put state'{ queryReturnVals = queryReturnVals state }
   return ret
 
+-- | Allow non-atomic replace
+nonAtomic :: ReQL -> ReQL
+nonAtomic (ReQL t) = ReQL $ do
+  state <- get
+  put state{ queryAtomic = Just False }
+  ret <- t
+  state' <- get
+  put state'{ queryAtomic = queryAtomic state }
+  return ret
+
 canReturnVals :: ReQL -> ReQL
 canReturnVals (ReQL t) = ReQL $ t >>= \ret -> do
   qs <- get
@@ -103,6 +118,14 @@
     Just rv -> return ret{
       termOptArgs = BaseAttribute "return_vals" (baseBool rv) : termOptArgs ret }
 
+canNonAtomic :: ReQL -> ReQL
+canNonAtomic (ReQL t) = ReQL $ t >>= \ret -> do
+  qs <- get
+  case queryAtomic qs of
+    Nothing -> return ret
+    Just atomic -> return ret{
+      termOptArgs = BaseAttribute "non_atomic" (baseBool $ not atomic) : termOptArgs ret }
+
 baseBool :: Bool -> BaseReQL
 baseBool b = BaseReQL DATUM (Just defaultValue{
                                 Datum.type' = Just R_BOOL, r_bool = Just b }) [] []
@@ -189,6 +212,8 @@
 -- | A list of key/value pairs
 data Object = Object { baseObject :: State QuerySettings [BaseAttribute] }
 
+infix 0 :=
+
 -- | A key/value pair used for building objects
 data Attribute = forall e . (Expr e) => T.Text := e
 
@@ -300,6 +325,8 @@
   fromInteger x = datumTerm R_NUM defaultValue { r_num = Just (fromInteger x) }
   a + b = op ADD (a, b) ()
   a * b = op MUL (a, b) ()
+  a - b = op SUB (a, b) ()
+  negate a = op SUB (0 :: Double, a) ()
   abs n = op BRANCH (op TermType.LT (n, 0 :: Double) (), negate n, n) ()
   signum n = op BRANCH (op TermType.LT (n, 0 :: Double) (),
                         -1 :: Double,
@@ -317,16 +344,16 @@
 instance IsString ReQL where
   fromString s = datumTerm R_STR defaultValue { r_str = Just (uFromString $ s) }
 
-instance Expr (ReQL -> ReQL) where
+instance (a ~ ReQL) => Expr (a -> ReQL) where
   expr f = ReQL $ do
     v <- newVarId
-    baseReQL $ op FUNC (datumNumberArray [v], f (op VAR [v] ())) ()
+    baseReQL $ op FUNC (datumNumberArray [v], expr $ f (op VAR [v] ())) ()
 
-instance Expr (ReQL -> ReQL -> ReQL) where
+instance (a ~ ReQL, b ~ ReQL) => Expr (a -> b -> ReQL) where
   expr f = ReQL $ do
     a <- newVarId
     b <- newVarId
-    baseReQL $ op FUNC (datumNumberArray [a, b], f (op VAR [a] ()) (op VAR [b] ())) ()
+    baseReQL $ op FUNC (datumNumberArray [a, b], expr $ f (op VAR [a] ()) (op VAR [b] ())) ()
 
 instance Expr Datum.Datum where
   expr d = ReQL $ return $ BaseReQL DATUM (Just d) [] []
@@ -431,3 +458,24 @@
 
 instance Expr BaseReQL where
   expr = ReQL . return
+
+-- | An upper or lower bound for between and during
+data Bound a =
+  Open { getBound :: a } -- ^ An inclusive bound
+  | Closed { getBound :: a } -- ^ An exclusive bound
+
+closedOrOpen :: Bound a -> T.Text
+closedOrOpen Open{} = "open"
+closedOrOpen Closed{} = "closed"
+
+instance (Expr a, Expr b) => Expr (a, b) where
+  expr (a, b) = expr [expr a, expr b]
+
+instance (Expr a, Expr b, Expr c) => Expr (a, b, c) where
+  expr (a, b, c) = expr [expr a, expr b, expr c]
+
+instance (Expr a, Expr b, Expr c, Expr d) => Expr (a, b, c, d) where
+  expr (a, b, c, d) = expr [expr a, expr b, expr c, expr d]
+
+instance (Expr a, Expr b, Expr c, Expr d, Expr e) => Expr (a, b, c, d, e) where
+  expr (a, b, c, d, e) = expr [expr a, expr b, expr c, expr d, expr e]
diff --git a/Database/RethinkDB/Time.hs b/Database/RethinkDB/Time.hs
--- a/Database/RethinkDB/Time.hs
+++ b/Database/RethinkDB/Time.hs
@@ -2,7 +2,6 @@
 
 module Database.RethinkDB.Time where
 
-import Data.Text (Text)
 import qualified  Data.Time as Time
 import qualified  Data.Time.Clock.POSIX as Time
 import Data.Aeson as JSON
@@ -15,37 +14,47 @@
 import Database.RethinkDB.Protobuf.Ql2.Term.TermType
 
 -- | The time and date when the query is executed
+--
+-- > >>> run h $ now :: IO (Maybe R.ZonedTime)
+-- > Just 2013-10-28 00:01:43.930000066757 +0000
 now :: ReQL
 now = op NOW () ()
 
 -- | Build a time object from the year, month, day, hour, minute, second and timezone fields
+--
+-- > >>> run h $ time 2011 12 24 23 59 59 "Z" :: IO (Maybe R.ZonedTime)
+-- > Just 2011-12-24 23:59:59 +0000
 time :: ReQL -> ReQL -> ReQL -> ReQL -> ReQL -> ReQL -> ReQL -> ReQL
 time y m d hh mm ss tz = op TIME [y, m, d, hh, mm, ss, tz] ()
 
 -- | Build a time object given the number of seconds since the unix epoch
+--
+-- > >>> run h $ epochTime 1147162826 :: IO (Maybe R.ZonedTime)
+-- > Just 2006-05-09 08:20:26 +0000
 epochTime :: ReQL -> ReQL
 epochTime t = op EPOCH_TIME [t] ()
 
 -- | Build a time object given an iso8601 string
+--
+-- > >>> run h $ iso8601 "2012-01-07T08:34:00-0700" :: IO (Maybe R.UTCTime)
+-- > Just 2012-01-07 15:34:00 UTC
 iso8601 :: ReQL -> ReQL
 iso8601 t = op ISO8601 [t] ()
 
 -- | The same time in a different timezone
+--
+-- > >>> run h $ inTimezone "+0800" now :: IO (Maybe R.ZonedTime)
+-- > Just 2013-10-28 08:16:39.22000002861 +0800
 inTimezone :: Expr time => ReQL -> time -> ReQL
 inTimezone tz t = op IN_TIMEZONE (t, tz) ()
 
-data Bound a =
-  Open { boundValue ::  a } |
-  Closed { boundValue :: a }
-
-boundString :: Bound a -> Text
-boundString Open{} = "open"
-boundString Closed{} = "closed"
-
 -- | Test if a time is between two other times
+--
+-- > >>> run h $ during (Open $ now - (60*60)) (Closed now) $ epochTime 1382919271 :: IO (Maybe Bool)
+-- > Just True
 during :: (Expr left, Expr right, Expr time) => Bound left -> Bound right -> time -> ReQL
-during l r t = op DURING (t, boundValue l, boundValue r) [
-  "left_bound" := boundString l, "right_bound" := boundString r]
+during l r t = op DURING (t, getBound l, getBound r) [
+  "left_bound" := closedOrOpen l, "right_bound" := closedOrOpen r]
 
 -- | Extract part of a time value
 timezone, date, timeOfDay, year, month, day, dayOfWeek, dayOfYear, hours, minutes, seconds ::
@@ -68,12 +77,20 @@
 toEpochTime t = op TO_EPOCH_TIME [t] ()
 
 -- | Time with no time zone
+--
 -- The default FromJSON instance for Data.Time.UTCTime is incompatible with ReQL's time type
 newtype UTCTime = UTCTime Time.UTCTime
 
+instance Show UTCTime where
+  show (UTCTime t) = show t
+
 -- | Time with a time zone
+--
 -- The default FromJSON instance for Data.Time.ZonedTime is incompatible with ReQL's time type
 newtype ZonedTime = ZonedTime Time.ZonedTime
+
+instance Show ZonedTime where
+  show (ZonedTime t) = show t
 
 instance FromJSON UTCTime where
   parseJSON (JSON.Object v) = UTCTime . Time.posixSecondsToUTCTime . fromRational <$> v .: "epoch_time"
diff --git a/rethinkdb.cabal b/rethinkdb.cabal
--- a/rethinkdb.cabal
+++ b/rethinkdb.cabal
@@ -1,5 +1,5 @@
 name:                rethinkdb
-version:             1.8.0.4
+version:             1.8.0.5
 description:         RethinkDB is a distributed document store with a powerful query language.
 synopsis:            RethinkDB driver for Haskell
 homepage:            http://github.com/atnnn/haskell-rethinkdb
