packages feed

hascas 1.0.0 → 1.1.0

raw patch · 5 files changed

+95/−67 lines, 5 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

+ CQL: LongStr :: ByteString -> LongStr
+ CQL: RetryInterval :: Int -> RetryInterval
+ CQL: ShortStr :: ByteString -> ShortStr
+ CQL: data BatchQuery
+ CQL: data Candle
+ CQL: data LoggedBatch
+ CQL: data Prepared
+ CQL: newtype LongStr
+ CQL: newtype RetryInterval
+ CQL: newtype ShortStr
- CQL: init :: HostName -> PortID -> ExceptT ShortStr IO Candle
+ CQL: init :: HostName -> PortID -> RetryInterval -> ExceptT ShortStr IO Candle

Files

hascas.cabal view
@@ -1,5 +1,5 @@ name:                hascas-version:             1.0.0+version:             1.1.0 synopsis:            Cassandra driver for haskell description:         This is a cassandra driver. homepage:            https://github.com/eklavya/hascas#readme
src/CQL.hs view
@@ -22,13 +22,13 @@ Initialize the driver by calling  @-  CQL.init host port+  CQL.init host port retryInterval @  for example  @-  CQL.init "127.0.0.1" (PortNumber 9042)+  CQL.init "127.0.0.1" (PortNumber 9042) (RetryInterval 1000000) @  Example:@@ -51,7 +51,7 @@  main :: IO () main = do-    candle <- CQL.init "127.0.0.1" (PortNumber 9042)+    candle <- CQL.init "127.0.0.1" (PortNumber 9042) (RetryInterval 1000000)      res <- flip runReaderT candle $ runExceptT $ do       let q = create "keyspace demodb WITH REPLICATION = {'class' : 'SimpleStrategy','replication_factor': 1}"@@ -121,6 +121,8 @@ module CQL (            Driver.init,            Consistency(..),+           Candle,+           Driver.RetryInterval(..),            -- ** Data Types            Rows,            Row,@@ -130,6 +132,8 @@            CQLMap(..),            CQLSet(..),            CQLList(..),+           ShortStr(..),+           LongStr(..),            -- ** Auto derive conversion for record types            deriveBuildRec,            fromRow,@@ -145,10 +149,13 @@            where',            and',            -- ** Prepare and run queries+           Prepared,            runCQL,            prepare,            execCQL,            -- ** Batching+           LoggedBatch,+           BatchQuery,            batch,            prepBatch,            runBatch) where
src/Driver.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE ScopedTypeVariables #-}  -module Driver (Driver.init, Driver.allConnections) where+module Driver (Driver.init, Driver.allConnections, Driver.RetryInterval(..)) where   import           Codec@@ -14,7 +14,7 @@ import           Control.Concurrent.MVar import           Control.Concurrent.STM import           Control.Concurrent.STM.TBQueue-import           Control.Exception              (bracket, catch, mask)+import           Control.Exception.Safe         (bracket, catchAny, mask) import           Control.Monad                  (forM_, forever, replicateM) import           Control.Monad.Except import           Data.Binary@@ -33,6 +33,7 @@ import           Data.Maybe import           Data.Monoid                    as DM import           Data.Set+import           Data.Traversable import           Data.UUID import           Debug.Trace import           Encoding@@ -72,38 +73,43 @@   return mvar  -receiveThread :: Handle -> MVar [Int16] -> MVar(IM.IntMap (MVar (Either ShortStr Result))) -> IO ()-receiveThread h streams streamMap = do-  forkIO $ forever $ do-        header <- hGet h 9-        he <- pure $ runGet (get :: Get Header) $ DBL.fromStrict header-        p <- hGet h (fromIntegral $ len he)-        case opcode he of-          0 -> do-            let (erCode, erMsg) = runGet getErr (DBL.fromStrict p)-            mvar <- getResHolder he streams streamMap-            putMVar mvar (Left erMsg)-          8 -> do-            let resultType = runGet (get :: Get Int32) (DBL.fromStrict p)+receiveThread :: HostName -> PortID -> RetryInterval -> Handle -> MVar [Int16] -> MVar(IM.IntMap (MVar (Either ShortStr Result))) -> IO ()+receiveThread host port ri h streams streamMap = do+  forkIO $ catchAny (forever $ do+                                header <- hGet h 9+                                he <- pure $ runGet (get :: Get Header) $ DBL.fromStrict header+                                p <- hGet h (fromIntegral $ len he)+                                case opcode he of+                                  0 -> do+                                    let (erCode, erMsg) = runGet getErr (DBL.fromStrict p)+                                    mvar <- getResHolder he streams streamMap+                                    putMVar mvar (Left erMsg)+                                  8 -> do+                                    let resultType = runGet (get :: Get Int32) (DBL.fromStrict p) -            case resultType of-              1 -> do-                mvar <- getResHolder he streams streamMap-                putMVar mvar (Right $ RRows [])+                                    case resultType of+                                      1 -> do+                                        mvar <- getResHolder he streams streamMap+                                        putMVar mvar (Right $ RRows []) -              2 -> do-                let rows = content $ runGet getRows (DBL.fromStrict $ C8.drop 4 p)-                mvar <- getResHolder he streams streamMap-                putMVar mvar (Right $ RRows rows)+                                      2 -> do+                                        let rows = content $ runGet getRows (DBL.fromStrict $ C8.drop 4 p)+                                        mvar <- getResHolder he streams streamMap+                                        putMVar mvar (Right $ RRows rows) -              4 -> do-                let prep = runGet (get :: Get ShortBytes) (DBL.fromStrict $ C8.drop 4 p)-                mvar <- getResHolder he streams streamMap-                putMVar mvar (Right $ RPrepared prep)+                                      4 -> do+                                        let prep = runGet (get :: Get ShortBytes) (DBL.fromStrict $ C8.drop 4 p)+                                        mvar <- getResHolder he streams streamMap+                                        putMVar mvar (Right $ RPrepared prep) -              5 -> do-                mvar <- getResHolder he streams streamMap-                putMVar mvar (Right $ RRows [])+                                      5 -> do+                                        mvar <- getResHolder he streams streamMap+                                        putMVar mvar (Right $ RRows [])) (\e -> do+                                                                                  print "error in receiving"+                                                                                  sm <- takeMVar streamMap+                                                                                  nm <- sequence $ fmap (\mvar -> tryPutMVar mvar (Left $ ShortStr $ DBL.fromStrict $ C8.pack $ "connection to node " <> show host <> " was lost")) sm+                                                                                  putMVar streamMap sm)+           -- 12 -> do           --   print "something happened"           --   print $ runGet (get :: Get ShortStr) (DBL.fromStrict p)@@ -122,8 +128,8 @@           return mvar  -someDef :: Handle -> MVar [Int16] -> MVar (IM.IntMap (MVar (Either ShortStr Result))) -> (LongStr, Word8, MVar (Either ShortStr Result)) -> IO ()-someDef h streams streamMap (bs, opc, mvar) = do+writeQuery :: Handle -> MVar [Int16] -> MVar (IM.IntMap (MVar (Either ShortStr Result))) -> (LongStr, Word8, MVar (Either ShortStr Result)) -> IO ()+writeQuery h streams streamMap (bs, opc, mvar) = do       strs <- takeMVar streams       case Data.List.uncons strs of         Just (i, strsTail) -> do@@ -137,26 +143,32 @@          Nothing -> do           putMVar streams strs-          someDef h streams streamMap (bs, opc, mvar)+          writeQuery h streams streamMap (bs, opc, mvar)  -sendThread :: Handle -> MVar [Int16] -> MVar(IM.IntMap (MVar (Either ShortStr Result))) -> TBQueue (LongStr, Word8, MVar (Either ShortStr Result)) -> IO ()-sendThread h streams streamMap driverQ = do-  forkIO $ forever $ do+sendThread :: HostName -> PortID -> RetryInterval -> Handle -> MVar [Int16] -> MVar(IM.IntMap (MVar (Either ShortStr Result))) -> TBQueue (LongStr, Word8, MVar (Either ShortStr Result)) -> IO ()+sendThread host port ri h streams streamMap driverQ = do+  forkIO $ catchAny (forever $ do           (bs, opc, mvar) <- atomically $ readTBQueue driverQ           when (opc == 9) $ do              pq <- takeMVar prepareQueries              putMVar prepareQueries (Data.Set.insert bs pq)              cons <- readMVar allConnections-             mvars <- forM cons $ \(_, h', str, strMap) -> do+             mvars <- forM cons $ \(_, _, h', str, strMap) -> do                mv <- newEmptyMVar-               someDef h' str strMap (bs, opc, mv)+               writeQuery h' str strMap (bs, opc, mv)                return mv              forkIO $ do                ls <- sequence $ fmap (\mva -> do {a <- takeMVar mva; return a}) mvars                putMVar mvar $ Data.List.foldl' (\b a -> if isLeft a then a else b) (Data.List.head ls) (Data.List.tail ls)              return ()-          when (opc /= 9) $ someDef h streams streamMap (bs, opc, mvar)+          when (opc /= 9) $ writeQuery h streams streamMap (bs, opc, mvar)) (\e -> do+                                                                                  sm <- takeMVar streamMap+                                                                                  nm <- sequence $ fmap (\mvar -> tryPutMVar mvar (Left $ ShortStr $ DBL.fromStrict $ C8.pack $ "connection to node " <> show host <> " was lost")) sm+                                                                                  putMVar streamMap sm+                                                                                  (host, port, h, streams, streamMap) <- setupNode host port ri+                                                                                  sendThread host port ri h streams streamMap driverQ+                                                                                  receiveThread host port ri h streams streamMap)   return ()  @@ -186,14 +198,29 @@   {-# NOINLINE allConnections #-}-allConnections :: MVar [(HostName, Handle, MVar [Int16], MVar(IM.IntMap (MVar (Either ShortStr Result))))]+allConnections :: MVar [(HostName, PortID, Handle, MVar [Int16], MVar(IM.IntMap (MVar (Either ShortStr Result))))] allConnections = unsafePerformIO $ newMVar []  +setupNode peer port rInt@(RetryInterval ri) = catchAny (do+  streams <- newMVar ([0..32767] :: [Int16])+  streamMap <- newMVar (IM.empty :: (IM.IntMap (MVar (Either ShortStr Result))))+  h <- connectTo peer port+  startUp h+  return (peer, port, h, streams, streamMap)) (\e -> do+                                                  threadDelay ri+                                                  setupNode peer port rInt)++++newtype RetryInterval = RetryInterval Int++ -- | The first function you need to call. It initializes the driver and connects to the cluster. -- You only need to specify one node from your cluster here.-init :: HostName -> PortID -> ExceptT ShortStr IO Candle-init host port = do+-- Retryinterval is the interval with which connection to a node will be retried in case of disconnection.+init :: HostName -> PortID -> RetryInterval -> ExceptT ShortStr IO Candle+init host port ri = do     streamNum <- liftIO $ newMVar 0     streams <- liftIO $ newMVar ([0..32767] :: [Int16])     streamMap <- liftIO $ newMVar (IM.empty :: (IM.IntMap (MVar (Either ShortStr Result))))@@ -208,18 +235,11 @@       Left err -> throwError err       Right rows -> do         let peers = (\(CQLString p) -> Data.List.concat <$> Data.List.intersperse "." $ fmap show (unpack p)) <$> catMaybes (fmap (\r -> fromCQL r (CQLString "peer")::Maybe CQLString) rows)-        oCons <- liftIO $ sequence $ fmap (\peer -> do-                        streams <- newMVar ([0..32767] :: [Int16])-                        streamMap <- newMVar (IM.empty :: (IM.IntMap (MVar (Either ShortStr Result))))-                        h <- connectTo peer port-                        startUp h-                        -- registerForEvents h-                        return (peer, h, streams, streamMap)-                    ) peers-        let connections = (host, h, streams, streamMap) : oCons+        oCons <- liftIO $ sequence $ fmap (\peer -> setupNode peer port ri) peers+        let connections = (host, port, h, streams, streamMap) : oCons         allCon <- liftIO $ takeMVar allConnections         liftIO $ putMVar allConnections connections-        forM_ connections (\(_, h, streams, streamMap) -> do-          liftIO $ receiveThread h streams streamMap-          liftIO $ sendThread h streams streamMap driverQ)+        forM_ connections (\(host, port, h, streams, streamMap) -> do+          liftIO $ receiveThread host port ri h streams streamMap+          liftIO $ sendThread host port ri h streams streamMap driverQ)         return $ Candle driverQ
src/Query.hs view
@@ -40,6 +40,7 @@ import           Network  + create :: String -> Q create s = Query (ShortStr $ DBL.fromStrict $ C8.pack "create " <> C8.pack s <> " ") [] @@ -70,7 +71,7 @@  -- | Prepare a query, returns a prepared query which can be fed to execCQL for execution. prepare :: ByteString -> ExceptT ShortStr (ReaderT Candle IO) Prepared-prepare q = do+prepare q  = do   (Candle driverQ) <- ask   mvar <- liftIO newEmptyMVar   let len = fromIntegral (C8.length q)::Int32@@ -78,7 +79,7 @@   liftIO $ atomically $ writeTBQueue driverQ (LongStr hd, 9, mvar)   res <- liftIO $ takeMVar mvar   case res of-      Left e -> throwError e+      Left e               -> throwError e       Right (RPrepared sb) -> return $ Prepared sb  @@ -94,7 +95,7 @@   liftIO $ atomically $ writeTBQueue driverQ (LongStr hd, 7, mvar)   res <- liftIO $ takeMVar mvar   case res of-    Left e -> throwError e+    Left e             -> throwError e     Right (RRows rows) -> return rows  @@ -108,7 +109,7 @@   liftIO $ atomically $ writeTBQueue driverQ (LongStr q, 10, mvar)   res <- liftIO $ takeMVar mvar   case res of-    Left e -> throwError e+    Left e             -> throwError e     Right (RRows rows) -> return rows  
test/Spec.hs view
@@ -60,7 +60,7 @@  main :: IO () main = do-    conRes <- runExceptT $ CQL.init "127.0.0.1" (PortNumber 9042)+    conRes <- runExceptT $ CQL.init "127.0.0.1" (PortNumber 9042) (RetryInterval 1000000)     case conRes of       Right ch ->         hspec $ before (threadDelay 1000000) (describe "driver should be able to" $ do@@ -83,7 +83,7 @@               case prep of                 Left e -> print e                 Right p -> do-                  res <- (runReaderT . runExceptT) (execCQL QUORUM p [+                  res <- (runReaderT . runExceptT) (execCQL ALL p [                     put (104::Int64),                     put (15::Int32),                     put True,@@ -100,14 +100,14 @@               case prep of                 Left e -> print e                 Right p -> do-                  res <- (runReaderT . runExceptT) (execCQL QUORUM p [+                  res <- (runReaderT . runExceptT) (execCQL ALL p [                     put (104::Int64),                     put (15::Int32)]) ch                   fmap fromRow <$> res `shouldBe` Right [Just (Emp {empID = 104, deptID = 15, alive = True, Main.id = fromJust $ fromString $ "38d0ceb1-9e3e-427c-bc36-0106398f672b", name = CQLString "Hot Shot", salary = CQLDouble 100000.0, someList = CQLList [1,2,3,4,5,6], someSet = CQLSet (fromList [CQLDouble 1.0e-3,CQLDouble 1000.0]), someMap = CQLMap $ DMS.fromList [(CQLString "some",CQLString "Things")]})]              it "select rows from table" $ do               let q = select "demodb.emp" # where' "empID" (104::Int64) # and' "deptID" (15::Int32)-              res <- (runReaderT . runExceptT) (runCQL QUORUM q) ch+              res <- (runReaderT . runExceptT) (runCQL ALL q) ch               fmap fromRow <$> res `shouldBe` Right [Just (Emp {empID = 104, deptID = 15, alive = True, Main.id = fromJust $ fromString $ "38d0ceb1-9e3e-427c-bc36-0106398f672b", name = CQLString "Hot Shot", salary = CQLDouble 100000.0, someList = CQLList [1,2,3,4,5,6], someSet = CQLSet (fromList [CQLDouble 1.0e-3,CQLDouble 1000.0]), someMap = CQLMap $ DMS.fromList [(CQLString "some",CQLString "Things")]})]              it "batch queries" $ do@@ -127,7 +127,7 @@                   res <- (runReaderT . runExceptT) (runBatch q) ch                   res `shouldBe` Right []                   let q = select "demodb.emp" # where' "empID" (101::Int64) # and' "deptID" (13::Int32)-                  res <- (runReaderT . runExceptT) (runCQL QUORUM q) ch+                  res <- (runReaderT . runExceptT) (runCQL ALL q) ch                   fmap fromRow <$> res `shouldBe` Right [Just (Emp {empID = 101, deptID = 13, alive = True, Main.id = fromJust $ fromString $ "48d0ceb1-9e3e-427c-bc36-0106398f672b", name = CQLString "Hot1 Shot1", salary = CQLDouble 10000.0, someList = CQLList [], someSet = CQLSet Data.Set.empty, someMap = CQLMap DMS.empty})]              it "drop a table" $ do