Function to convert parsed CSV to array of JSON objects

This commit is contained in:
Joe Nelson
2015-11-18 20:21:21 -08:00
parent a0af096ff4
commit ed18f2b1e8
+39 -12
View File
@@ -1,15 +1,20 @@
module PostgREST.RequestIntent where
import qualified Data.Aeson as JSON
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.List (find)
import Data.Maybe (fromMaybe, isJust, isNothing,
listToMaybe)
import Network.Wai (Request (..))
import Network.Wai.Parse (parseHttpAccept)
import PostgREST.RangeQuery (NonnegRange, rangeRequested)
import PostgREST.Types (QualifiedIdentifier (..), Schema)
import qualified Data.Aeson as JSON
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import qualified Data.Csv as CSV
import Data.List (find)
import qualified Data.HashMap.Strict as M
import Data.Maybe (fromMaybe, isJust, isNothing,
listToMaybe)
import Data.String.Conversions (cs)
import qualified Data.Text as T
import qualified Data.Vector as V
import Network.Wai (Request (..))
import Network.Wai.Parse (parseHttpAccept)
import PostgREST.RangeQuery (NonnegRange, rangeRequested)
import PostgREST.Types (QualifiedIdentifier (..), Schema)
type RequestBody = BL.ByteString
@@ -25,8 +30,9 @@ data Target = TargetIdent QualifiedIdentifier
data ContentType = ApplicationJSON | TextCSV
-- | When Hasql supports the COPY command then we can
-- have a special payload just for CSV, but until
-- then CSV is converted to a JSON array
-- then CSV is converted to a JSON array.
data Payload = PayloadJSON JSON.Array
| PayloadParseError BS.ByteString
-- | Describes what the user wants to do. This data type is a
-- translation of the raw elements of an HTTP request into domain
@@ -42,7 +48,7 @@ data Intent = Intent {
, iTarget :: Maybe Target
-- | The content type the client most desires (or JSON if undecided)
, iAccepts :: Either BS.ByteString ContentType
-- | {foo} becomes [{foo}] and CSV is converted to JSON
-- | Set to Nothing when client sends no data
, iPayload :: Maybe Payload
-- | Taken from JSON Web Token
, iTrustedClaims :: Maybe JSON.Object
@@ -88,6 +94,8 @@ userIntent schema req _ =
lookupHeader = flip lookup hdrs
hasPrefer val = any (\(h,v) -> h == "Prefer" && v == val) hdrs
-- PRIVATE ---------------------------------------------------------------
-- | Chooses a payload from the items in an accept header.
-- When possible it picks JSON.
pickContentType :: Maybe BS.ByteString -> Either BS.ByteString ContentType
@@ -102,3 +110,22 @@ pickContentType accept
Just acceptH = accept
findInAccept = flip find $ parseHttpAccept acceptH
has = isJust . findInAccept . BS.isPrefixOf
type CsvData = V.Vector (V.Vector BL.ByteString)
-- | Convert
-- a,b
-- 1,2
-- 3,4
--
-- into
-- [ {"a": 1, "b": 2}, {"a": 3, "b": 4} ]
csvToJson :: (CSV.Header, CsvData) -> JSON.Array
csvToJson (cols, vals) =
V.map rowToJson vals
where
cols' = V.map cs cols :: V.Vector T.Text
rowToJson :: V.Vector BL.ByteString -> JSON.Value
rowToJson val = JSON.Object $
let val' = V.map (JSON.String . cs) val in
M.fromList . V.toList $ V.zip cols' val'