packages feed

clickhouse-haskell-0.1.2.3: src/Database/ClickHouseDriver/HTTP/Helpers.hs

-- Copyright (c) 2020-present, EMQX, Inc.
-- All rights reserved.
--
-- This source code is distributed under the terms of a MIT license,
-- found in the LICENSE file.
{-# LANGUAGE FlexibleInstances #-}

-- | Miscellaneous helper functions. User should not import it.
module Database.ClickHouseDriver.HTTP.Helpers
  ( extract,
    genURL,
    toString,
  )
where

import Control.Monad.Writer (WriterT (runWriterT))
import qualified Data.Aeson as JP
import Data.Attoparsec.ByteString (IResult (Done, Fail), parse)
import qualified Data.ByteString.Char8 as C8
import qualified Data.HashMap.Strict as HM
import Data.Maybe (fromMaybe)
import Data.Text (pack)
import Data.Vector (toList)
import Database.ClickHouseDriver.HTTP.Connection
  ( HttpConnection (HttpConnection, httpParams),
  )
import Database.ClickHouseDriver.HTTP.Types (Cmd, HttpParams (..), JSONResult)
import Database.ClickHouseDriver.IO.BufferedWriter (writeIn)
import Database.ClickHouseDriver.Types
  ( ClickhouseType (CKArray, CKInt32, CKNull, CKString, CKTuple),
  )
import qualified Network.URI.Encode as NE

-- | Trim JSON data
extract :: C8.ByteString -> JSONResult
extract val = getData $ parse JP.json val
  where
    getData (Fail e _ _) = Left e
    getData (Done _ (JP.Object x)) = Right $ getData' x
    getData _ = Right []

    getData' = map getObject . maybeArrToList . HM.lookup (pack "data")

    maybeArrToList Nothing = []
    maybeArrToList (Just x) = toList . getArray $ x

    getArray (JP.Array arr) = arr
    getObject (JP.Object x) = x

genURL :: HttpConnection -> Cmd -> IO String
genURL
  HttpConnection
    { httpParams =
        HttpParams
          { httpHost = host,
            httpPassword = pw,
            httpPort = port,
            httpUsername = usr,
            httpDatabase = db
          }
    }
  cmd = do
    (_, basicUrl) <- runWriterT $ do
      writeIn "http://"
      writeIn usr
      writeIn ":"
      writeIn pw
      writeIn "@"
      writeIn host
      writeIn ":"
      writeIn $ show port
      writeIn "/"
      if cmd == "ping" then return () else writeIn "?query="
      writeIn $ dbUrl db
    let res = basicUrl ++ NE.encode cmd
    return res

-- | serialize column type into sql string
toString :: [ClickhouseType] -> String
toString ck = "(" ++ toStr ck ++ ")"

toStr :: [ClickhouseType] -> String
toStr [] = ""
toStr (x : []) = toStr' x
toStr (x : xs) = toStr' x ++ "," ++ toStr xs

toStr' :: ClickhouseType -> String
toStr' (CKInt32 n) = show n
toStr' (CKString str) = "'" ++ C8.unpack str ++ "'"
toStr' (CKArray arr) = "[" ++ (toStr $ toList arr) ++ "]"
toStr' (CKTuple arr) = "(" ++ (toStr $ toList arr) ++ ")"
toStr' CKNull = "null"
toStr' _ = error "unsupported writing type"

dbUrl :: (Maybe String) -> String
dbUrl = fromMaybe "" . fmap ("?database=" ++)