{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Database.InfluxDB.Format
(
Format
, makeFormat
, (%)
, formatQuery
, formatDatabase
, formatMeasurement
, formatKey
, database
, key
, keys
, measurement
, measurements
, field
, decimal
, realFloat
, text
, string
, byteString8
, time
, fromQuery
) where
import Control.Category
import Data.Monoid
import Data.String
import Prelude hiding ((.), id)
import Data.Time
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Builder as BB
import qualified Data.List as L
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TL
import qualified Data.Text.Lazy.Builder.Int as TL
import qualified Data.Text.Lazy.Builder.RealFloat as TL
import Database.InfluxDB.Internal.Text
import Database.InfluxDB.Types hiding (database)
fromQuery :: Query -> B.ByteString
fromQuery :: Query -> ByteString
fromQuery (Query Text
q) =
ByteString -> ByteString
BL.toStrict (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Builder -> ByteString
BB.toLazyByteString (Builder -> ByteString) -> Builder -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> Builder
T.encodeUtf8Builder Text
q
newtype Format a r = Format { Format a r -> (Builder -> a) -> r
runFormat :: (TL.Builder -> a) -> r }
instance Category Format where
id :: Format a a
id = ((Builder -> a) -> a) -> Format a a
forall a r. ((Builder -> a) -> r) -> Format a r
Format (\Builder -> a
k -> Builder -> a
k Builder
"")
Format b c
fmt1 . :: Format b c -> Format a b -> Format a c
. Format a b
fmt2 = ((Builder -> a) -> c) -> Format a c
forall a r. ((Builder -> a) -> r) -> Format a r
Format (((Builder -> a) -> c) -> Format a c)
-> ((Builder -> a) -> c) -> Format a c
forall a b. (a -> b) -> a -> b
$ \Builder -> a
k ->
Format b c -> (Builder -> b) -> c
forall a r. Format a r -> (Builder -> a) -> r
runFormat Format b c
fmt1 ((Builder -> b) -> c) -> (Builder -> b) -> c
forall a b. (a -> b) -> a -> b
$ \Builder
a ->
Format a b -> (Builder -> a) -> b
forall a r. Format a r -> (Builder -> a) -> r
runFormat Format a b
fmt2 ((Builder -> a) -> b) -> (Builder -> a) -> b
forall a b. (a -> b) -> a -> b
$ \Builder
b ->
Builder -> a
k (Builder
a Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
b)
instance a ~ r => IsString (Format a r) where
fromString :: String -> Format a r
fromString String
xs = ((Builder -> a) -> a) -> Format a a
forall a r. ((Builder -> a) -> r) -> Format a r
Format (((Builder -> a) -> a) -> Format a a)
-> ((Builder -> a) -> a) -> Format a a
forall a b. (a -> b) -> a -> b
$ \Builder -> a
k -> Builder -> a
k (Builder -> a) -> Builder -> a
forall a b. (a -> b) -> a -> b
$ String -> Builder
forall a. IsString a => String -> a
fromString String
xs
(%) :: Format b c -> Format a b -> Format a c
% :: Format b c -> Format a b -> Format a c
(%) = Format b c -> Format a b -> Format a c
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
(.)
runFormatWith :: (T.Text -> a) -> Format a r -> r
runFormatWith :: (Text -> a) -> Format a r -> r
runFormatWith Text -> a
f Format a r
fmt = Format a r -> (Builder -> a) -> r
forall a r. Format a r -> (Builder -> a) -> r
runFormat Format a r
fmt (Text -> a
f (Text -> a) -> (Builder -> Text) -> Builder -> a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> Text
TL.toStrict (Text -> Text) -> (Builder -> Text) -> Builder -> Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Builder -> Text
TL.toLazyText)
formatQuery :: Format Query r -> r
formatQuery :: Format Query r -> r
formatQuery = (Text -> Query) -> Format Query r -> r
forall a r. (Text -> a) -> Format a r -> r
runFormatWith Text -> Query
Query
formatDatabase :: Format Database r -> r
formatDatabase :: Format Database r -> r
formatDatabase = (Text -> Database) -> Format Database r -> r
forall a r. (Text -> a) -> Format a r -> r
runFormatWith Text -> Database
Database
formatMeasurement :: Format Measurement r -> r
formatMeasurement :: Format Measurement r -> r
formatMeasurement = (Text -> Measurement) -> Format Measurement r -> r
forall a r. (Text -> a) -> Format a r -> r
runFormatWith Text -> Measurement
Measurement
formatKey :: Format Key r -> r
formatKey :: Format Key r -> r
formatKey Format Key r
fmt = Format Key r -> (Builder -> Key) -> r
forall a r. Format a r -> (Builder -> a) -> r
runFormat Format Key r
fmt (Text -> Key
Key (Text -> Key) -> (Builder -> Text) -> Builder -> Key
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> Text
TL.toStrict (Text -> Text) -> (Builder -> Text) -> Builder -> Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Builder -> Text
TL.toLazyText)
makeFormat :: (a -> TL.Builder) -> Format r (a -> r)
makeFormat :: (a -> Builder) -> Format r (a -> r)
makeFormat a -> Builder
build = ((Builder -> r) -> a -> r) -> Format r (a -> r)
forall a r. ((Builder -> a) -> r) -> Format a r
Format (((Builder -> r) -> a -> r) -> Format r (a -> r))
-> ((Builder -> r) -> a -> r) -> Format r (a -> r)
forall a b. (a -> b) -> a -> b
$ \Builder -> r
k a
a -> Builder -> r
k (Builder -> r) -> Builder -> r
forall a b. (a -> b) -> a -> b
$ a -> Builder
build a
a
doubleQuote :: T.Text -> TL.Builder
doubleQuote :: Text -> Builder
doubleQuote Text
name = Builder
"\"" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
TL.fromText Text
name Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\""
singleQuote :: T.Text -> TL.Builder
singleQuote :: Text -> Builder
singleQuote Text
name = Builder
"'" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
TL.fromText Text
name Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"'"
identifierBuilder :: T.Text -> TL.Builder
identifierBuilder :: Text -> Builder
identifierBuilder = Text -> Builder
doubleQuote (Text -> Builder) -> (Text -> Text) -> Text -> Builder
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> Text
escapeDoubleQuotes
stringBuilder :: T.Text -> TL.Builder
stringBuilder :: Text -> Builder
stringBuilder = Text -> Builder
singleQuote (Text -> Builder) -> (Text -> Text) -> Text -> Builder
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> Text
escapeSingleQuotes
database :: Format r (Database -> r)
database :: Format r (Database -> r)
database = (Database -> Builder) -> Format r (Database -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat ((Database -> Builder) -> Format r (Database -> r))
-> (Database -> Builder) -> Format r (Database -> r)
forall a b. (a -> b) -> a -> b
$ \(Database Text
name) -> Text -> Builder
identifierBuilder Text
name
key :: Format r (Key -> r)
key :: Format r (Key -> r)
key = (Key -> Builder) -> Format r (Key -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat ((Key -> Builder) -> Format r (Key -> r))
-> (Key -> Builder) -> Format r (Key -> r)
forall a b. (a -> b) -> a -> b
$ \(Key Text
name) -> Text -> Builder
identifierBuilder Text
name
keys :: Format r ([Key] -> r)
keys :: Format r ([Key] -> r)
keys = ([Key] -> Builder) -> Format r ([Key] -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat (([Key] -> Builder) -> Format r ([Key] -> r))
-> ([Key] -> Builder) -> Format r ([Key] -> r)
forall a b. (a -> b) -> a -> b
$
[Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder) -> ([Key] -> [Builder]) -> [Key] -> Builder
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
L.intersperse Builder
"," ([Builder] -> [Builder])
-> ([Key] -> [Builder]) -> [Key] -> [Builder]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Key -> Builder) -> [Key] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (\(Key Text
name) -> Text -> Builder
identifierBuilder Text
name)
measurement :: Format r (Measurement -> r)
measurement :: Format r (Measurement -> r)
measurement = (Measurement -> Builder) -> Format r (Measurement -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat ((Measurement -> Builder) -> Format r (Measurement -> r))
-> (Measurement -> Builder) -> Format r (Measurement -> r)
forall a b. (a -> b) -> a -> b
$ \(Measurement Text
name) -> Text -> Builder
identifierBuilder Text
name
measurements :: Format r ([Measurement] -> r)
measurements :: Format r ([Measurement] -> r)
measurements = ([Measurement] -> Builder) -> Format r ([Measurement] -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat (([Measurement] -> Builder) -> Format r ([Measurement] -> r))
-> ([Measurement] -> Builder) -> Format r ([Measurement] -> r)
forall a b. (a -> b) -> a -> b
$
[Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder)
-> ([Measurement] -> [Builder]) -> [Measurement] -> Builder
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
L.intersperse Builder
","
([Builder] -> [Builder])
-> ([Measurement] -> [Builder]) -> [Measurement] -> [Builder]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Measurement -> Builder) -> [Measurement] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (\(Measurement Text
name) -> Text -> Builder
identifierBuilder Text
name)
field :: Format r (QueryField -> r)
field :: Format r (QueryField -> r)
field = (QueryField -> Builder) -> Format r (QueryField -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat ((QueryField -> Builder) -> Format r (QueryField -> r))
-> (QueryField -> Builder) -> Format r (QueryField -> r)
forall a b. (a -> b) -> a -> b
$ \case
FieldInt Int64
n -> Int64 -> Builder
forall a. Integral a => a -> Builder
TL.decimal Int64
n
FieldFloat Double
d -> Double -> Builder
forall a. RealFloat a => a -> Builder
TL.realFloat Double
d
FieldString Text
s -> Text -> Builder
stringBuilder Text
s
FieldBool Bool
b -> if Bool
b then Builder
"true" else Builder
"false"
QueryField
FieldNull -> Builder
"null"
decimal :: Integral a => Format r (a -> r)
decimal :: Format r (a -> r)
decimal = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat a -> Builder
forall a. Integral a => a -> Builder
TL.decimal
realFloat :: RealFloat a => Format r (a -> r)
realFloat :: Format r (a -> r)
realFloat = (a -> Builder) -> Format r (a -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat a -> Builder
forall a. RealFloat a => a -> Builder
TL.realFloat
text :: Format r (T.Text -> r)
text :: Format r (Text -> r)
text = (Text -> Builder) -> Format r (Text -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat Text -> Builder
TL.fromText
string :: Format r (String -> r)
string :: Format r (String -> r)
string = (String -> Builder) -> Format r (String -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat String -> Builder
TL.fromString
byteString8 :: Format r (B.ByteString -> r)
byteString8 :: Format r (ByteString -> r)
byteString8 = (ByteString -> Builder) -> Format r (ByteString -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat ((ByteString -> Builder) -> Format r (ByteString -> r))
-> (ByteString -> Builder) -> Format r (ByteString -> r)
forall a b. (a -> b) -> a -> b
$ Text -> Builder
TL.fromText (Text -> Builder) -> (ByteString -> Text) -> ByteString -> Builder
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ByteString -> Text
T.decodeUtf8
time :: FormatTime time => Format r (time -> r)
time :: Format r (time -> r)
time = (time -> Builder) -> Format r (time -> r)
forall a r. (a -> Builder) -> Format r (a -> r)
makeFormat ((time -> Builder) -> Format r (time -> r))
-> (time -> Builder) -> Format r (time -> r)
forall a b. (a -> b) -> a -> b
$ \time
t ->
Builder
"'" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> String -> Builder
TL.fromString (TimeLocale -> String -> time -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
fmt time
t) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"'"
where
fmt :: String
fmt = String
"%F %X%Q"