packages feed

influxdb 1.8.0 → 1.9.0

raw patch · 8 files changed

+137/−51 lines, 8 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

- Database.InfluxDB: newtype Tagged (s :: k) b
- Database.InfluxDB: parseResults :: QueryResults a => Precision 'QueryRequest -> Value -> Parser (Vector a)
- Database.InfluxDB.Format: instance (a GHC.Types.~ r) => Data.String.IsString (Database.InfluxDB.Format.Format a r)
- Database.InfluxDB.Query: newtype Tagged (s :: k) b
- Database.InfluxDB.Query: parseResults :: QueryResults a => Precision 'QueryRequest -> Value -> Parser (Vector a)
+ Database.InfluxDB: coerceDecoder :: QueryResults a => proxy a -> Maybe Decoder
+ Database.InfluxDB: data Empty
+ Database.InfluxDB: data Ignored
+ Database.InfluxDB: newtype Tagged (s :: k) b :: forall k. () => k -> Type -> Type
+ Database.InfluxDB.Format: instance (a Data.Type.Equality.~ r) => Data.String.IsString (Database.InfluxDB.Format.Format a r)
+ Database.InfluxDB.Query: coerceDecoder :: QueryResults a => proxy a -> Maybe Decoder
+ Database.InfluxDB.Query: data Empty
+ Database.InfluxDB.Query: data Ignored
+ Database.InfluxDB.Query: instance Database.InfluxDB.Query.QueryResults Database.InfluxDB.Query.Empty
+ Database.InfluxDB.Query: instance Database.InfluxDB.Query.QueryResults Database.InfluxDB.Query.Ignored
+ Database.InfluxDB.Query: instance GHC.Show.Show Database.InfluxDB.Query.Empty
+ Database.InfluxDB.Query: instance GHC.Show.Show Database.InfluxDB.Query.Ignored
+ Database.InfluxDB.Query: newtype Tagged (s :: k) b :: forall k. () => k -> Type -> Type
- Database.InfluxDB: Tagged :: b -> Tagged (s :: k) b
+ Database.InfluxDB: Tagged :: b -> Tagged b
- Database.InfluxDB: [FieldNull] :: Field 'Nullable
+ Database.InfluxDB: [FieldNull] :: Field 'Nullable
- Database.InfluxDB: [RFC3339] :: Precision 'QueryRequest
+ Database.InfluxDB: [RFC3339] :: Precision 'QueryRequest
- Database.InfluxDB: [unTagged] :: Tagged (s :: k) b -> b
+ Database.InfluxDB: [unTagged] :: Tagged b -> b
- Database.InfluxDB: parseMeasurement :: QueryResults a => Precision 'QueryRequest -> Maybe Text -> HashMap Text Text -> Vector Text -> Array -> Parser a
+ Database.InfluxDB: parseMeasurement :: QueryResults a => Precision 'QueryRequest -> Maybe Text -> HashMap Text Text -> Vector Text -> Array -> Parser a
- Database.InfluxDB: query :: QueryResults a => QueryParams -> Query -> IO (Vector a)
+ Database.InfluxDB: query :: forall a. QueryResults a => QueryParams -> Query -> IO (Vector a)
- Database.InfluxDB: roundTo :: Timestamp time => Precision 'WriteRequest -> time -> Int64
+ Database.InfluxDB: roundTo :: Timestamp time => Precision 'WriteRequest -> time -> Int64
- Database.InfluxDB: scaleTo :: Timestamp time => Precision 'WriteRequest -> time -> Int64
+ Database.InfluxDB: scaleTo :: Timestamp time => Precision 'WriteRequest -> time -> Int64
- Database.InfluxDB: type LineField = Field 'NonNullable
+ Database.InfluxDB: type LineField = Field 'NonNullable
- Database.InfluxDB: type QueryField = Field 'Nullable
+ Database.InfluxDB: type QueryField = Field 'Nullable
- Database.InfluxDB: untag :: forall k (s :: k) b. Tagged s b -> b
+ Database.InfluxDB: untag :: () => Tagged s b -> b
- Database.InfluxDB.Line: [FieldNull] :: Field 'Nullable
+ Database.InfluxDB.Line: [FieldNull] :: Field 'Nullable
- Database.InfluxDB.Line: [RFC3339] :: Precision 'QueryRequest
+ Database.InfluxDB.Line: [RFC3339] :: Precision 'QueryRequest
- Database.InfluxDB.Line: type LineField = Field 'NonNullable
+ Database.InfluxDB.Line: type LineField = Field 'NonNullable
- Database.InfluxDB.Query: Tagged :: b -> Tagged (s :: k) b
+ Database.InfluxDB.Query: Tagged :: b -> Tagged b
- Database.InfluxDB.Query: [unTagged] :: Tagged (s :: k) b -> b
+ Database.InfluxDB.Query: [unTagged] :: Tagged b -> b
- Database.InfluxDB.Query: parseMeasurement :: QueryResults a => Precision 'QueryRequest -> Maybe Text -> HashMap Text Text -> Vector Text -> Array -> Parser a
+ Database.InfluxDB.Query: parseMeasurement :: QueryResults a => Precision 'QueryRequest -> Maybe Text -> HashMap Text Text -> Vector Text -> Array -> Parser a
- Database.InfluxDB.Query: parseQueryResults :: QueryResults a => Precision 'QueryRequest -> Value -> Parser (Vector a)
+ Database.InfluxDB.Query: parseQueryResults :: forall a. QueryResults a => Precision 'QueryRequest -> Value -> Parser (Vector a)
- Database.InfluxDB.Query: parseQueryResultsWith :: QueryResults a => Decoder -> Precision 'QueryRequest -> Value -> Parser (Vector a)
+ Database.InfluxDB.Query: parseQueryResultsWith :: forall a. QueryResults a => Decoder -> Precision 'QueryRequest -> Value -> Parser (Vector a)
- Database.InfluxDB.Query: query :: QueryResults a => QueryParams -> Query -> IO (Vector a)
+ Database.InfluxDB.Query: query :: forall a. QueryResults a => QueryParams -> Query -> IO (Vector a)
- Database.InfluxDB.Query: untag :: forall k (s :: k) b. Tagged s b -> b
+ Database.InfluxDB.Query: untag :: () => Tagged s b -> b
- Database.InfluxDB.Types: [FieldNull] :: Field 'Nullable
+ Database.InfluxDB.Types: [FieldNull] :: Field 'Nullable
- Database.InfluxDB.Types: [RFC3339] :: Precision 'QueryRequest
+ Database.InfluxDB.Types: [RFC3339] :: Precision 'QueryRequest
- Database.InfluxDB.Types: roundTo :: Timestamp time => Precision 'WriteRequest -> time -> Int64
+ Database.InfluxDB.Types: roundTo :: Timestamp time => Precision 'WriteRequest -> time -> Int64
- Database.InfluxDB.Types: scaleTo :: Timestamp time => Precision 'WriteRequest -> time -> Int64
+ Database.InfluxDB.Types: scaleTo :: Timestamp time => Precision 'WriteRequest -> time -> Int64
- Database.InfluxDB.Types: type LineField = Field 'NonNullable
+ Database.InfluxDB.Types: type LineField = Field 'NonNullable
- Database.InfluxDB.Types: type QueryField = Field 'Nullable
+ Database.InfluxDB.Types: type QueryField = Field 'Nullable

Files

CHANGELOG.md view
@@ -1,5 +1,13 @@ # Revision history for influxdb +## v1.9.0 - 2020-07-18++* Fix `Ignore` and `Empty` to replace the `QueryResults` instance for `Void`. The instance has been deprecated.+* Remove the deprecated `parseResults` method in `QueryResults`.+* Add the `coerceDecoder` method in `QueryResults`.+* Drop support for GHC 8.2 and older because of the use of `EmptyDataDeriving`.+* Update doctest comments with `TypeApplications`.+ ## v1.8.0 - 2020-06-19  This release reworked the `QueryResuls` type class. There are some breaking changes:
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2014-2015, Mitsutoshi Aoe+Copyright (c) 2014-2020, Mitsutoshi Aoe  All rights reserved. 
influxdb.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.24 name: influxdb-version: 1.8.0+version: 1.9.0 synopsis: Haskell client library for InfluxDB description:   @influxdb@ is an InfluxDB client library for Haskell.@@ -15,8 +15,6 @@ category: Database build-type: Custom tested-with:-  GHC == 8.0.2-  GHC == 8.2.2   GHC == 8.4.4   GHC == 8.6.5   GHC == 8.8.3@@ -75,7 +73,7 @@     ViewPatterns   ghc-options: -Wall   build-depends:-      base >= 4.9 && < 4.15+      base >= 4.11 && < 4.15     , aeson >= 0.7 && < 1.6     , attoparsec < 0.14     , bytestring >= 0.10 && < 0.11
src/Database/InfluxDB.hs view
@@ -52,15 +52,19 @@   , Decoder   , lenientDecoder   , strictDecoder++  -- ** Helper types and functions+  , Ignored+  , Empty+  , Tagged(..)+  , untag+   , getField   , getTag   , parseJSON   , parseUTCTime   , parsePOSIXTime -  -- *** Re-exports from tagged-  , Tagged(..)-  , untag    -- * Database management   , manage@@ -110,6 +114,7 @@  >>> :set -XOverloadedStrings >>> :set -XRecordWildCards+>>> :set -XTypeApplications >>> import Database.InfluxDB >>> import qualified Database.InfluxDB.Format as F >>> import Control.Lens@@ -146,7 +151,7 @@ >>> let cpuUsage = "cpu_usage" >>> :{ writeBatch wp-  [ Line cpuUsage (Map.singleton "cpu" "cpu-total")+  [ Line @UTCTime cpuUsage (Map.singleton "cpu" "cpu-total")     (Map.fromList       [ ("idle",   FieldFloat 10.1)       , ("system", FieldFloat 53.3)@@ -154,7 +159,7 @@       ])     (Just $ parseTimeOrError False defaultTimeLocale       "%F %T%Q %Z"-      "2017-06-17 15:41:40.42659044 UTC") :: Line UTCTime+      "2017-06-17 15:41:40.42659044 UTC")   ] :} @@ -168,9 +173,9 @@ If all the field types are an instance of 'Data.Aeson.FromJSON', we can use a tuple to store the results. ->>> :set -XDataKinds -XOverloadedStrings+>>> :set -XDataKinds -XOverloadedStrings -XTypeOperators >>> type CPUUsage = (Tagged "time" UTCTime, Tagged "idle" Double, Tagged "system" Double, Tagged "user" Double)->>> v <- query p $ formatQuery ("SELECT * FROM "%F.measurement) cpuUsage :: IO (V.Vector CPUUsage)+>>> v <- query @CPUUsage p $ formatQuery ("SELECT * FROM "%F.measurement) cpuUsage >>> v [(Tagged 2017-06-17 15:41:40 UTC,Tagged 10.1,Tagged 53.3,Tagged 46.6)] @@ -206,7 +211,7 @@     return CPUUsage {..} :} ->>> query p $ formatQuery ("SELECT * FROM "%F.measurement) cpuUsage :: IO (V.Vector CPUUsage)+>>> query @CPUUsage p $ formatQuery ("SELECT * FROM "%F.measurement) cpuUsage [CPUUsage {time = 2017-06-17 15:41:40 UTC, cpuIdle = 10.1, cpuSystem = 53.3, cpuUser = 46.6}] -} 
src/Database/InfluxDB/Manage.hs view
@@ -43,7 +43,6 @@ import Data.Scientific (toBoundedInteger) import Data.Text (Text) import Data.Time.Clock-import Data.Void import qualified Data.Aeson.Types as A import qualified Data.Attoparsec.Combinator as AC import qualified Data.Attoparsec.Text as AT@@ -76,9 +75,11 @@     Left message ->       throwIO $ UnexpectedResponse message request body     Right val -> do-      let parser = parseQueryResultsWith (params^.decoder) (params^.precision)+      let parser = parseQueryResultsWith+            (params ^. decoder)+            (params ^. precision)       case A.parse parser val of-        A.Success (_ :: V.Vector Void) -> return ()+        A.Success (_ :: V.Vector Empty) -> return ()         A.Error message -> do           let status = HC.responseStatus response           when (HT.statusIsServerError status) $@@ -107,7 +108,7 @@     Server {..} = params^.server  -- |--- >>> v <- query (queryParams "_internal") "SHOW QUERIES" :: IO (V.Vector ShowQuery)+-- >>> v <- query @ShowQuery (queryParams "_internal") "SHOW QUERIES" data ShowQuery = ShowQuery   { showQueryQid :: !Int   , showQueryText :: !Query@@ -163,20 +164,20 @@  -- | Query ID ----- >>> v <- query (queryParams "_internal") "SHOW QUERIES" :: IO (V.Vector ShowQuery)+-- >>> v <- query @ShowQuery (queryParams "_internal") "SHOW QUERIES" -- >>> v ^.. each.qid -- ... qid :: Lens' ShowQuery Int  -- | Query text ----- >>> v <- query (queryParams "_internal") "SHOW QUERIES" :: IO (V.Vector ShowQuery)+-- >>> v <- query @ShowQuery (queryParams "_internal") "SHOW QUERIES" -- >>> v ^.. each.queryText -- ... queryText :: Lens' ShowQuery Query  -- |--- >>> v <- query (queryParams "_internal") "SHOW QUERIES" :: IO (V.Vector ShowQuery)+-- >>> v <- query @ShowQuery (queryParams "_internal") "SHOW QUERIES" -- >>> v ^.. each.database -- ... instance HasDatabase ShowQuery where@@ -184,7 +185,7 @@  -- | Duration of the query ----- >>> v <- query (queryParams "_internal") "SHOW QUERIES" :: IO (V.Vector ShowQuery)+-- >>> v <- query @ShowQuery (queryParams "_internal") "SHOW QUERIES" -- >>> v ^.. each.duration -- ... duration :: Lens' ShowQuery NominalDiffTime@@ -193,7 +194,7 @@  -- | Series name ----- >>> v <- query (queryParams "_internal") "SHOW SERIES" :: IO (V.Vector ShowSeries)+-- >>> v <- query @ShowSeries (queryParams "_internal") "SHOW SERIES" -- >>> length $ v ^.. each.key -- ... key :: Lens' ShowSeries Key
src/Database/InfluxDB/Query.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE EmptyDataDeriving #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-}@@ -36,7 +37,9 @@   -- * Low-level functions   , withQueryResponse -  -- * Re-exports from tagged+  -- * Helper types+  , Ignored+  , Empty   , Tagged(..)   , untag   ) where@@ -44,6 +47,7 @@ import Control.Monad import Data.Char import Data.List+import Data.Maybe (fromMaybe) import Data.Proxy import GHC.TypeLits @@ -62,8 +66,9 @@ import qualified Data.ByteString as B import qualified Data.ByteString.Builder as BB import qualified Data.ByteString.Lazy as BL-import qualified Data.Text.Encoding as TE import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import qualified Data.Vector as V import qualified Network.HTTP.Client as HC import qualified Network.HTTP.Types as HT @@ -72,8 +77,10 @@ import qualified Database.InfluxDB.Format as F  -- $setup+-- >>> :set -XDataKinds -- >>> :set -XOverloadedStrings -- >>> :set -XRecordWildCards+-- >>> :set -XTypeApplications -- >>> import Data.Time (UTCTime) -- >>> import qualified Data.Vector as V @@ -99,14 +106,7 @@ --     return H2OFeet {..} -- :} class QueryResults a where-  -- | Parse a JSON object as an array of values of expected type.-  parseResults-    :: Precision 'QueryRequest-    -> Value-    -> A.Parser (Vector a)-  parseResults = parseQueryResultsWith strictDecoder--  -- | Parse a measurement in a JSON object.+  -- | Parse a single measurement in a JSON object.   parseMeasurement     :: Precision 'QueryRequest     -- ^ Timestamp precision@@ -120,38 +120,88 @@     -- ^ Field values     -> A.Parser a -{-# DEPRECATED parseResults-  "Use 'parseQueryResults' or 'parseQueryResultsWith' " #-}+  -- | Always use this 'Decoder' when decoding this type.+  --+  -- @'Just' dec@ means 'decoder' in 'QueryParams' will be ignored and be+  -- replaced with the @dec@. 'Nothing' means 'decoder' in 'QueryParams' will+  -- be used.+  coerceDecoder :: proxy a -> Maybe Decoder+  coerceDecoder _ = Nothing  -- | Parse a JSON object as an array of values of expected type. parseQueryResults-  :: QueryResults a+  :: forall a. QueryResults a   => Precision 'QueryRequest   -> Value   -> A.Parser (Vector a)-parseQueryResults = parseQueryResultsWith strictDecoder+parseQueryResults =+  parseQueryResultsWith $+    fromMaybe strictDecoder (coerceDecoder (Proxy :: Proxy a))  parseQueryResultsWith-  :: QueryResults a+  :: forall a. QueryResults a   => Decoder   -> Precision 'QueryRequest   -> Value   -> A.Parser (Vector a) parseQueryResultsWith decoder prec =-  parseResultsWithDecoder decoder (parseMeasurement prec)+  parseResultsWithDecoder+    (fromMaybe decoder (coerceDecoder (Proxy :: Proxy a)))+    (parseMeasurement prec)  -- | 'QueryResults' instance for empty results. Used by -- 'Database.InfluxDB.Manage.manage'.+--+-- NOTE: This instance is deprecated because it's unclear from the name whether+-- it can be used to ignore results. Use 'Empty' when expecting an empty result.+-- Use 'Ignored' if you want to ignore any results. instance QueryResults Void where-  parseMeasurement _ _ _ _ _ = parseJSON A.emptyArray+  parseMeasurement _ _ _ _ _ = fail "parseMeasurement for Void"+  coerceDecoder _ = Just $ Decoder $ SomeDecoder+    { decodeEach = id+    , decodeFold = const $ pure V.empty+    } +-- | 'Ignored' can be used in the result type of 'query' when the result values+-- are not needed.+--+-- >>> v <- query @Ignored (queryParams "dummy") "SHOW DATABASES"+-- >>> v+-- []+data Ignored deriving Show++-- | 'QueryResults' instance for ignoring results.+instance QueryResults Ignored where+  parseMeasurement _ _ _ _ _ = fail "parseMeasurement for Ignored"+  coerceDecoder _ = Just $ Decoder $ SomeDecoder+    { decodeEach = id -- doesn't matter+    , decodeFold = const $ pure V.empty -- always succeeds with an empty vector+    }++-- | 'Empty' can be used in the result type of 'query' when the expected results+-- are always empty. Note that if the results are not empty, the decoding+-- process will fail:+--+-- >>> let p = queryParams "empty"+-- >>> Database.InfluxDB.Manage.manage p "CREATE DATABASE empty"+-- >>> v <- query @Empty p "SELECT * FROM empty" -- query an empty series+-- >>> v+-- []+data Empty deriving Show++-- | 'QueryResults' instance for empty results. Used by+-- 'Database.InfluxDB.Manage.manage'.+instance QueryResults Empty where+  parseMeasurement _ _ _ _ _ = fail "parseMeasurement for Empty"+  coerceDecoder _ = Just strictDecoder -- fail when the results are not empty+ fieldName :: KnownSymbol k => proxy k -> T.Text fieldName = T.pack . symbolVal  -- | One-off type for non-timestamped measurements -- -- >>> let p = queryParams "_internal"--- >>> dbs <- query p "SHOW DATABASES" :: IO (V.Vector (Tagged "name" T.Text))+-- >>> dbs <- query @(Tagged "name" T.Text) p "SHOW DATABASES" -- >>> find ((== "_internal") . untag) dbs -- Just (Tagged "_internal") instance (KnownSymbol k, FromJSON v) => QueryResults (Tagged k v) where@@ -368,7 +418,7 @@ -- -- If you need a lower-level interface (e.g. to bypass the 'QueryResults' -- constraint etc), see 'withQueryResponse'.-query :: QueryResults a => QueryParams -> Query -> IO (Vector a)+query :: forall a. QueryResults a => QueryParams -> Query -> IO (Vector a) query params q = withQueryResponse params Nothing q go   where     go request response = do@@ -378,7 +428,9 @@         Left message -> throwIO $ UnexpectedResponse message request body         Right val -> do           let parser = parseQueryResultsWith-                (queryDecoder params)+                (fromMaybe+                  (queryDecoder params)+                  (coerceDecoder (Proxy :: Proxy a)))                 (queryPrecision params)           case A.parse parser val of             A.Success vec -> return vec@@ -441,7 +493,7 @@               chunk' <- HC.responseBody response               loop x k' chunk'             AB.Done leftover val ->-              case A.parse (parseResults (queryPrecision params)) val of+              case A.parse (parseQueryResults (queryPrecision params)) val of                 A.Success vec -> do                   x' <- step x vec                   loop x' k0 leftover
src/Database/InfluxDB/Write.hs view
@@ -46,7 +46,7 @@ import Database.InfluxDB.JSON  -- $setup--- >>> :set -XOverloadedStrings -XNoOverloadedLists+-- >>> :set -XOverloadedStrings -XNoOverloadedLists -XTypeApplications -- >>> import qualified Data.Map as Map -- >>> import Data.Time -- >>> import Database.InfluxDB@@ -109,7 +109,7 @@ -- | Write a 'Line'. -- -- >>> let p = writeParams "test-db"--- >>> write p $ Line "room_temp" Map.empty (Map.fromList [("temp", FieldFloat 25.0)]) (Nothing :: Maybe UTCTime)+-- >>> write p $ Line @UTCTime "room_temp" Map.empty (Map.fromList [("temp", FieldFloat 25.0)]) Nothing write   :: Timestamp time   => WriteParams@@ -125,8 +125,8 @@ -- >>> let p = writeParams "test-db" -- >>> :{ -- writeBatch p---   [ Line "temp" (Map.singleton "city" "tokyo") (Map.fromList [("temp", FieldFloat 25.0)]) (Nothing :: Maybe UTCTime)---   , Line "temp" (Map.singleton "city" "osaka") (Map.fromList [("temp", FieldFloat 25.2)]) (Nothing :: Maybe UTCTime)+--   [ Line @UTCTime "temp" (Map.singleton "city" "tokyo") (Map.fromList [("temp", FieldFloat 25.0)]) Nothing+--   , Line @UTCTime "temp" (Map.singleton "city" "osaka") (Map.fromList [("temp", FieldFloat 25.2)]) Nothing --   ] -- :} writeBatch
tests/regressions.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}@@ -23,14 +24,15 @@   [ testCase "issue #64" case_issue64   , testCase "issue #66" case_issue66   , testCaseSteps "issue #75" case_issue75+  , testCaseSteps "issue #79" case_issue79   ]  -- https://github.com/maoe/influxdb-haskell/issues/64 case_issue64 :: Assertion case_issue64 = withDatabase dbName $ do-  write wp $ Line "count" Map.empty+  write wp $ Line @UTCTime "count" Map.empty     (Map.fromList [("value", FieldInt 1)])-    (Nothing :: Maybe UTCTime)+    Nothing   r <- try $ query qp "SELECT value FROM count"   case r of     Left err -> case err of@@ -70,9 +72,9 @@   step "Checking encoded value"   let string = [Raw.r|bl\"a|]   let encoded = encodeLine (scaleTo Nanosecond)-        $ Line "testing" mempty+        $ Line @UTCTime "testing" mempty           (M.singleton "test" $ FieldString string)-          (Nothing :: Maybe UTCTime)+          Nothing   encoded @?= [Raw.r|testing test="bl\\\"a"|]    step "Preparing a test database"@@ -84,6 +86,26 @@   step "Checking server response"   let wp = writeParams db   writeByteString wp encoded++case_issue79 :: (String -> IO ()) -> Assertion+case_issue79 step = withDatabase db $ do+  let w = writeParams db+  let q = queryParams db+  step "Querying an empty series with two fields expected"+  _ <- query @(Tagged "time" UTCTime, Tagged "value" Int) q "SELECT * FROM foo"+  step "Querying an empty series with the results ignored"+  _ <- query @Ignored q "SELECT * FROM foo"+  step "Querying an empty series expecting an empty result"+  _ <- query @Empty q "SELECT * FROM foo"+  step "Writing a data point"+  write w $ Line @UTCTime "foo" mempty (Map.fromList [("value", FieldInt 42)]) Nothing+  step "Querying a non-empty series with two fields expected"+  _ <- query @(Tagged "time" UTCTime, Tagged "value" Int) q "SELECT * FROM foo"+  step "Querying a non-empty series with the results ignored"+  _ <- query @Ignored q "SELECT * FROM foo"+  return ()+  where+    db = "case_issue79"  withDatabase :: Database -> IO a -> IO a withDatabase dbName f = bracket_