packages feed

classy-influxdb-simple (empty) → 0.1.0.1

raw patch · 6 files changed

+278/−0 lines, 6 filesdep +aesondep +async-io-eitherdep +basesetup-changed

Dependencies added: aeson, async-io-either, base, bytestring, lens, mtl, text, wreq

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Sean Chalmers (c) 2017++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Sean Chalmers nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,8 @@+Classy InfluxDB Simple+======================++A simple, stupid, classy-mtl style, wrapper for interacting with [InfluxDB](https://www.influxdata.com/)+via the HTTP API.++It doesn't do a lot to protect you from yourself, however it does wire in nicely with an application+structured using the Classy Lenses/MTL style. Can/Has/As et al.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ classy-influxdb-simple.cabal view
@@ -0,0 +1,32 @@+name:                classy-influxdb-simple+version:             0.1.0.1+synopsis:            Super simple InfluxDB package in Classy-MTL style+-- description:+homepage:            https://github.com/mankyKitty/classy-influxdb-simple#readme+license:             BSD3+license-file:        LICENSE+author:              Sean Chalmers+maintainer:          sclhiannan@gmail.com.au+copyright:           2017 Sean Chalmers+category:            Database+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Database.InfluxDB.Simple.Classy+                     , Database.InfluxDB.Simple.Classy.Types+  build-depends:       base >= 4.7 && < 5+                     , wreq+                     , lens+                     , aeson+                     , mtl+                     , bytestring+                     , text+                     , async-io-either+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/mankyKitty/classy-influxdb-simple
+ src/Database/InfluxDB/Simple/Classy.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE TemplateHaskell       #-}+module Database.InfluxDB.Simple.Classy+  ( writeData+  , queryData+  , queryDataToCSV+  ) where+++import           Control.Lens                          (to, view, (.~), (^.))+import           Control.Monad.Error.Lens              (throwing)++import qualified Data.ByteString.Char8                 as BS8+import           Data.ByteString.Lazy                  (ByteString)+import           Data.ByteString.Lens                  (unpackedChars)++import           Data.Function                         ((&))+import           Data.Monoid                           ((<>))++import qualified Data.Text.Encoding                    as Text++import qualified Network.Wreq                          as W++import           Database.InfluxDB.Simple.Classy.Types (AsInfluxDbError (..),+                                                        CanInflux,+                                                        HasInfluxDBConfig (..),+                                                        InfluxDBConfig,+                                                        InfluxDbError (..),+                                                        InfluxQuery (..),+                                                        InfluxRqType (..),+                                                        IsDb (..), ToLine (..),+                                                        basicInfluxOpts,+                                                        rqWinCode)++import           Data.Aeson                            (Value)+import qualified Data.Aeson                            as A++import           Control.Concurrent.Async.Either (runAsyncToE)++writeUrl,queryUrl,baseUrl :: HasInfluxDBConfig c => c -> String+baseUrl c  = c ^. idbHost . unpackedChars <> ":" <> c ^. idbPort . to show+writeUrl c = baseUrl c <> "/" <> "write"+queryUrl c = baseUrl c <> "/" <> "query"++handleSuccess+  :: CanInflux m e+  => InfluxRqType+  -> (W.Response ByteString -> m a)+  -> W.Response ByteString+  -> m a+handleSuccess rqT f r+  | r ^. W.responseStatus . W.statusCode . to (== rqWinCode rqT)+    = f r+  | otherwise+    = throwing _CommsOrInfluxError $ r ^. W.responseStatus . W.statusMessage++runInflux+  :: CanInflux m e+  => IO (W.Response ByteString)+  -> InfluxRqType+  -> (W.Response ByteString -> m a)+  -> m a+runInflux act rq resFn = do+  r <- runAsyncToE act (UnknownError rq)+  either (throwing _InfluxDbError) (handleSuccess rq resFn) r++writeData+  :: ( CanInflux m e+     , IsDb db+     , ToLine l+     )+  => InfluxDBConfig+  -> db+  -> l+  -> m ()+writeData c db l =+  runInflux (W.postWith o (writeUrl c) (toLine l)) Write win+  where+    win = pure . const ()+    o = basicInfluxOpts W.defaults c db++queryDataToCSV+  :: ( CanInflux m e+     , IsDb db+     )+  => InfluxDBConfig+  -> db+  -> InfluxQuery+  -> m ByteString+queryDataToCSV c db (InfluxQuery q) =+  runInflux (W.getWith o (queryUrl c)) QueryCSV (pure . view W.responseBody)+  where+    o = basicInfluxOpts W.defaults c db+      & W.param "q" .~ [Text.decodeUtf8 q]+      & W.header "Accept" .~ ["application/csv"]++queryData+  :: ( CanInflux m e+     , IsDb db+     )+  => InfluxDBConfig+  -> db+  -> InfluxQuery+  -> m Value+queryData c db (InfluxQuery q) =+  runInflux (W.getWith o (queryUrl c)) Query success+  where+    success r = either (throwing _ParseError . BS8.pack)+      pure $ r ^. W.responseBody . to A.eitherDecode++    o = basicInfluxOpts W.defaults c db+      & W.param "q" .~ [Text.decodeUtf8 q]
+ src/Database/InfluxDB/Simple/Classy/Types.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE ConstraintKinds            #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE TemplateHaskell            #-}+{-# LANGUAGE CPP #-}+module Database.InfluxDB.Simple.Classy.Types where++import           Control.Exception      (SomeException)+import           Control.Lens           (makeClassy, makeClassyPrisms, (.~),+                                         (?~), (^.))+import           Control.Monad.Except   (MonadError)+import           Control.Monad.IO.Class (MonadIO)++import           Data.ByteString        (ByteString)+import qualified Data.ByteString.Char8  as BS8++import           Data.Function          ((&))++import           Data.Text              (Text)++#if VERSION_vector+import           Data.Vector            (Vector)+import qualified Data.Vector            as V+#endif++import           GHC.Word               (Word32)++import           Network.Wreq           (Options)+import qualified Network.Wreq           as W++data InfluxRqType+  = Write+  | Query+  | QueryCSV+  deriving Show++rqWinCode :: InfluxRqType -> Int+rqWinCode Write    = 204+rqWinCode Query    = 200+rqWinCode QueryCSV = 200++class ToLine a where+  toLine :: a -> ByteString++instance ToLine a => ToLine [a] where+  toLine = BS8.unlines . fmap toLine++#if VERSION_vector+instance ToLine a => ToLine (Vector a) where+  toLine = BS8.unlines . V.toList . fmap toLine+#endif++class IsDb a where+  toDbName :: a -> Text++newtype Count = Count Word32+  deriving (Eq, Show, Ord, Num)++newtype InfluxQuery = InfluxQuery ByteString+  deriving (Eq, Show)++data InfluxDBConfig = InfluxDBConfig+  { _idbUser :: ByteString+  , _idbPass :: ByteString+  , _idbHost :: ByteString+  , _idbPort :: Int+  }+makeClassy ''InfluxDBConfig++data InfluxDbError+  = CommsOrInfluxError ByteString+  | ParseError ByteString+  | UnknownError InfluxRqType SomeException+  deriving Show+makeClassyPrisms ''InfluxDbError++type CanInflux m e =+  ( AsInfluxDbError e+  , MonadError e m+  , MonadIO m+  )++basicInfluxOpts+  :: IsDb a+  => Options+  -> InfluxDBConfig+  -> a+  -> Options+basicInfluxOpts o env db = o+  & W.param "db" .~ [toDbName db]+  & W.auth ?~ W.basicAuth user' pass'+  where+    user' = env ^. idbUser+    pass' = env ^. idbPass