rethinkdb 1.8.0.0 → 1.8.0.1
raw patch · 6 files changed
+95/−45 lines, 6 files
Files
- Database/RethinkDB.hs +3/−2
- Database/RethinkDB/Functions.hs +25/−12
- Database/RethinkDB/MapReduce.hs +27/−8
- Database/RethinkDB/Network.hs +29/−18
- Database/RethinkDB/ReQL.hs +10/−4
- rethinkdb.cabal +1/−1
Database/RethinkDB.hs view
@@ -5,7 +5,7 @@ -- /How to use/ -- -- >>> {-# LANGUAGE OverloadedStrings #-}--- >>> import Database.RethinkDB as R+-- >>> import qualified Database.RethinkDB as R module Database.RethinkDB ( -- * Accessing RethinkDB@@ -22,6 +22,7 @@ RethinkDBError(..), SuccessCode(..), ErrorCode(..),+ ReQL, -- * Manipulating databases @@ -75,7 +76,7 @@ -- * Math and logic (+), (-), (*), (/), mod, (&&), (||),- (==), (!=), (>), (<), (<=), (>=), not,+ (==), (/=), (>), (<), (<=), (>=), not, -- * String manipulation
Database/RethinkDB/Functions.hs view
@@ -21,6 +21,8 @@ import qualified Prelude as P -- | Arithmetic Operator+infixl 6 +, -+infixl 7 *, / (+), (-), (*), (/), mod :: (Expr a, Expr b) => a -> b -> ReQL (+) a b = op ADD (a, b) ()@@ -30,15 +32,19 @@ mod a b = op MOD (a, b) () -- | Boolean operator+infixr 2 ||+infixr 3 && (||), (&&) :: (Expr a, Expr b) => a -> b -> ReQL a || b = op ANY (a, b) () a && b = op ALL (a, b) () -- | Comparison operator-(==), (!=) :: (Expr a, Expr b) => a -> b -> ReQL+infix 4 ==, /=+(==), (/=) :: (Expr a, Expr b) => a -> b -> ReQL a == b = op EQ (a, b) ()-a != b = op NE (a, b) ()+a /= b = op NE (a, b) () +infix 4 >, <, <=, >= -- | Comparison operator (>), (>=), (<), (<=) :: (Expr a, Expr b) => a -> b -> ReQL@@ -53,11 +59,12 @@ -- * Lists and Streams --- | The size of a sequence or an array+-- | The size of a sequence or an array. -- Called /count/ in the official drivers length :: (Expr a) => a -> ReQL length e = op COUNT [e] () +infixr 5 ++ -- | Join two sequences. -- Called /union/ in the official drivers (++) :: (Expr a, Expr b) => a -> b -> ReQL@@ -92,12 +99,12 @@ eqJoin :: (Expr a, Expr b) => Key -> a -> Key -> b -> ReQL eqJoin a i k b = op EQ_JOIN (b, k, a) ["index" := i] --- | Drop elements from the head of a sequence+-- | Drop elements from the head of a sequence. -- Called /skip/ in the official drivers drop :: (Expr a, Expr b) => a -> b -> ReQL drop a b = op SKIP (b, a) () --- | Limit the size of a sequence+-- | Limit the size of a sequence. -- Called /limit/ in the official drivers take :: (Expr a, Expr b) => a -> b -> ReQL take a b = op LIMIT (a, b) ()@@ -107,6 +114,7 @@ slice n m s = op SLICE (s, n, m) () -- | Get the nth value of a sequence or array+infixl 9 !! (!!) :: (Expr a) => a -> ReQL -> ReQL s !! n = op NTH (s, n) () @@ -126,7 +134,7 @@ 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+-- | 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] ()@@ -152,7 +160,7 @@ => (ReQL -> group) -> (ReQL -> reduction) -> seq -> ReQL groupBy g mr s = ReQL $ do (m, r, f) <- termToMapReduce (expr . mr)- baseReQL $ map (f . (!"reduction")) $+ baseReQL $ op GROUPED_MAP_REDUCE [expr s, expr $ expr P.. g, expr m, expr r] () -- | The sum of a sequence@@ -168,6 +176,7 @@ -- * Accessors -- | Get a single field form an object+infixl 9 ! (!) :: (Expr s) => s -> ReQL -> ReQL s ! k = op GET_FIELD (s, k) () @@ -179,7 +188,7 @@ 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+-- | 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)) ()@@ -205,6 +214,7 @@ 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 error :: (Expr s) => s -> ReQL error m = op ERROR [m] () @@ -320,6 +330,7 @@ prepend d a = op PREPEND (a, d) () -- | Called /difference/ in the official drivers+infixl 9 \\ -- (\\) :: (Expr a, Expr b) => a -> b -> ReQL a \\ b = op DIFFERENCE (a, b) () @@ -363,12 +374,12 @@ keys :: Expr obj => obj -> ReQL keys o = op KEYS [o] () --- | Match a string to a regulr expression+-- | Match a string to a regulr expression. -- Called /match/ in the official drivers (=~) :: (Expr string, Expr regex) => string -> regex -> ReQL s =~ r = op MATCH (s, r) () --- | Apply a function to a list of arguments+-- | Apply a function to a list of arguments. -- Called /do/ in the official drivers apply :: (Expr fun, Expr arg) => fun -> [arg] -> ReQL f `apply` as = op FUNCALL (expr f : P.map expr as) ()@@ -391,9 +402,11 @@ json s = op JSON [s] () -- | Flipped function composition-(#) :: (Expr a, Expr b, Expr c) => (ReQL -> a) -> (ReQL -> b) -> c -> ReQL-(f # g) x = expr (g (expr (f (expr x))))+infixl 8 #+(#) :: (Expr a, Expr b) => a -> (ReQL -> b) -> ReQL+x # f = expr (f (expr x)) +infixr 9 . -- | Specialised function composition (.) :: (Expr a, Expr b, Expr c) => (ReQL -> b) -> (ReQL -> a) -> c -> ReQL (f . g) x = expr (f (expr (g (expr x))))
Database/RethinkDB/MapReduce.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings, PatternGuards #-}+ module Database.RethinkDB.MapReduce where import Control.Monad.State@@ -15,8 +17,8 @@ termToMapReduce f = do v <- newVarId body <- baseReQL $ f (op VAR [v] ())- let MapReduce map reduce finally = toMapReduce v body- return (map, reduce, finally)+ let MapReduce map_ reduce finally = toMapReduce v body+ return (map_, reduce, finally) toReduce :: MapReduce -> (ReQL -> ReQL, ReQL -> ReQL -> ReQL, ReQL -> ReQL) toReduce (None t) = (\_ -> expr (), \_ _ -> expr (), const t)@@ -55,13 +57,30 @@ in if count == 0 then None $ wrap t else if not $ count == 1 then rebuild else- case (type', args') of- (MAP, [Map m, None f]) -> Map (toFun1 f . m)- (REDUCE, [Map m, None f]) -> MapReduce m (toFun2 f) id- (COUNT, [Map _]) -> MapReduce (const 1)- (\a b -> op ADD (a, b) ()) id+ 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)+ (COUNT, [Map _], []) ->+ MapReduce (const 1) (\a b -> op ADD (a, b) ()) id+ (tt, (Map m : _), _) | tt `elem` mappableTypes ->+ (Map ((\x -> op tt (expr x : map expr (tail args)) (noRecurse : map baseAttrToAttr optargs)) . m)) _ -> rebuild +optargsToBase :: [BaseAttribute] -> Maybe (Maybe ReQL)+optargsToBase [] = Just Nothing+optargsToBase [BaseAttribute "base" b] = Just (Just $ ReQL $ return b)+optargsToBase _ = Nothing++baseAttrToAttr :: BaseAttribute -> Attribute+baseAttrToAttr (BaseAttribute k v) = k := v++noRecurse :: Attribute+noRecurse = "_NO_RECURSE_" := True++mappableTypes :: [TermType]+mappableTypes = [GET_FIELD, PLUCK, WITHOUT, MERGE, HAS_FIELDS]+ data MapReduce = None ReQL | Map (ReQL -> ReQL) |@@ -96,7 +115,7 @@ extract :: Maybe Int -> TermType -> [MapReduce] -> [(Key, MapReduce)] -> (ReQL -> ReQL, [MapReduce])-extract state tt args optargs = fst $ flip runState state $ runWriterT $ do+extract st tt args optargs = fst $ flip runState st $ runWriterT $ do args' <- sequence $ map extractOne args optargvs' <- sequence $ map extractOne (map snd optargs) let optargks = map fst optargs
Database/RethinkDB/Network.hs view
@@ -29,14 +29,14 @@ import qualified Data.Text as T import Control.Concurrent ( writeChan, MVar, Chan, modifyMVar, readMVar, forkIO, readChan,- myThreadId, newMVar, ThreadId, withMVar, newChan,+ myThreadId, newMVar, ThreadId, newChan, killThread, newEmptyMVar, putMVar, mkWeakMVar) import Data.Bits (shiftL, (.|.), shiftR) import Data.Monoid ((<>)) import Data.Foldable hiding (forM_)-import Control.Exception (catches, Exception, throwIO)+import Control.Exception (catch, Exception, throwIO, SomeException(..)) import Data.Aeson (toJSON, object, (.=), Value(Null, Bool))-import Data.IORef (IORef, newIORef, atomicModifyIORef', readIORef)+import Data.IORef (IORef, newIORef, atomicModifyIORef', readIORef, writeIORef) import Data.Map (Map) import qualified Data.Map as M import Data.Maybe (fromMaybe, listToMaybe)@@ -65,7 +65,7 @@ -- | A connection to the database server data RethinkDBHandle = RethinkDBHandle { rdbHandle :: Handle,- rdbWriteLock :: MVar (),+ rdbWriteLock :: MVar (Maybe SomeException), rdbToken :: IORef Token, -- ^ The next token to use rdbDatabase :: Database, -- ^ The default database rdbWait :: IORef (Map Token (Chan Response, BaseReQL)),@@ -109,7 +109,7 @@ when (res /= "SUCCESS") $ throwIO (RethinkDBConnectionError res) r <- newIORef 1 let db' = Database "test"- wlock <- newMVar ()+ wlock <- newMVar Nothing waits <- newIORef M.empty let rdb = RethinkDBHandle h wlock r db' waits tid <- forkIO $ readResponses rdb@@ -128,13 +128,14 @@ magicNumber = packUInt $ fromEnum V0_2 -- | Convert a 4-byte byestring to an int-unpackUInt :: ByteString -> Int+unpackUInt :: ByteString -> Maybe Int unpackUInt s = case unpack s of- [a,b,c,d] -> fromIntegral a .|.+ [a,b,c,d] -> Just $ + fromIntegral a .|. fromIntegral b `shiftL` 8 .|. fromIntegral c `shiftL` 16 .|. fromIntegral d `shiftL` 24- _ -> error "unpackUInt: lengh is not 4"+ _ -> Nothing -- | Convert an int to a 4-byte bytestring packUInt :: Int -> B.ByteString@@ -144,7 +145,12 @@ withHandle :: RethinkDBHandle -> (Handle -> IO a) -> IO a withHandle RethinkDBHandle{ rdbHandle, rdbWriteLock } f =- withMVar rdbWriteLock $ \_ -> f rdbHandle+ modifyMVar rdbWriteLock $ \mex ->+ case mex of+ Nothing -> do+ a <- f rdbHandle+ return (Nothing, a)+ Just ex -> throwIO ex data RethinkDBError = RethinkDBError { errorCode :: ErrorCode,@@ -233,7 +239,7 @@ hPut s $ packUInt (fromIntegral $ B.length queryS) <> queryS data RethinkDBReadError =- RethinkDBReadError String+ RethinkDBReadError SomeException deriving (Show, Typeable) instance Exception RethinkDBReadError @@ -241,21 +247,24 @@ readResponses h' = do tid <- myThreadId let h = h' tid- forever $ flip catches handlers $- readSingleResponse h- where- handlers = []+ let handler e@SomeException{} = do+ modifyMVar (rdbWriteLock h) $ \_ -> return (Just e, ())+ writeIORef (rdbWait h) M.empty+ flip catch handler $ forever $ readSingleResponse h readSingleResponse :: RethinkDBHandle -> IO () readSingleResponse h = do header <- hGet (rdbHandle h) 4- rawResponse <- hGet (rdbHandle h) (unpackUInt header)+ replyLength <-+ maybe (fail "Connection closed by remote server")+ return (unpackUInt header)+ rawResponse <- hGet (rdbHandle h) replyLength let parsedResponse = messageGet rawResponse case parsedResponse of- Left errMsg -> throwIO $ RethinkDBReadError errMsg+ Left errMsg -> fail errMsg Right (response, rest) | B.null rest -> dispatch (Ql2.token response) response- | otherwise -> throwIO $ RethinkDBReadError "RethinkDB: readResponses: invalid reply length"+ | otherwise -> fail "readsingleResponse: invalid reply length" where dispatch Nothing _ = return ()@@ -283,7 +292,9 @@ -- | Close an open connection close :: RethinkDBHandle -> IO ()-close RethinkDBHandle{ rdbHandle } = hClose rdbHandle+close RethinkDBHandle{ rdbHandle, rdbThread } = do+ killThread rdbThread+ hClose rdbHandle convertDatum :: Datum.Datum -> O.Datum convertDatum Datum { type' = Just R_NULL } = Null
Database/RethinkDB/ReQL.hs view
@@ -119,9 +119,9 @@ show (BaseReQL MAKE_ARRAY _ x []) = "[" ++ (concat $ intersperse ", " $ map show x) ++ "]" show (BaseReQL MAKE_OBJ _ [] x) = "{" ++ (concat $ intersperse ", " $ map show x) ++ "}" show (BaseReQL VAR _ [BaseReQL DATUM (Just d) [] []] []) | Just x <- toDouble d =- "x" ++ show (round x)+ "x" ++ show (round x :: Int) show (BaseReQL FUNC _ [BaseReQL DATUM (Just d) [] [], body] []) | Just vars <- toDoubles d =- "(\\" ++ (concat $ intersperse " " $ map (("x"++) . show . round) $ vars)+ "(\\" ++ (concat $ intersperse " " $ map (("x"++) . show . (round :: Double -> Int)) $ vars) ++ " -> " ++ show body ++ ")" show (BaseReQL GET_FIELD _ [o, k] []) = show o ++ "!" ++ show k show (BaseReQL fun _ args optargs) =@@ -208,6 +208,9 @@ obj = Object . mapM base where base (k := e) = BaseAttribute k <$> baseReQL (expr e) +instance Obj [BaseAttribute] where+ obj = Object . return+ instance Obj Object where obj = id @@ -231,8 +234,8 @@ toDoubles :: Datum.Datum -> Maybe [Double] toDoubles Datum.Datum{ Datum.type' = Just R_ARRAY,- r_array = seq } =- sequence . map toDouble . toList $ seq+ r_array = s } =+ sequence . map toDouble . toList $ s toDoubles _ = Nothing toDouble :: Datum.Datum -> Maybe Double@@ -425,3 +428,6 @@ in op TIME [ expr year, expr month, expr day, expr hour, expr minute, expr (toRational seconds), str $ timeZoneOffsetString timezone] ()++instance Expr BaseReQL where+ expr = ReQL . return
rethinkdb.cabal view
@@ -1,5 +1,5 @@ name: rethinkdb-version: 1.8.0.0+version: 1.8.0.1 description: RethinkDB is a distributed document store with a powerful query language. synopsis: RethinkDB driver for Haskell homepage: http://github.com/atnnn/haskell-rethinkdb