refactor: remove MTPlanAttrs to doctest
This commit is contained in:
committed by
Steve Chavez
parent
77cd9387d4
commit
aa15f4782e
@@ -51,9 +51,7 @@ import PostgREST.ApiRequest.Types (ApiRequestError (..),
|
|||||||
RangeError (..))
|
RangeError (..))
|
||||||
import PostgREST.Config (AppConfig (..),
|
import PostgREST.Config (AppConfig (..),
|
||||||
OpenAPIMode (..))
|
OpenAPIMode (..))
|
||||||
import PostgREST.MediaType (MTPlanAttrs (..),
|
import PostgREST.MediaType (MediaType (..))
|
||||||
MTPlanFormat (..),
|
|
||||||
MediaType (..))
|
|
||||||
import PostgREST.RangeQuery (NonnegRange, allRange,
|
import PostgREST.RangeQuery (NonnegRange, allRange,
|
||||||
convertToLimitZeroRange,
|
convertToLimitZeroRange,
|
||||||
hasLimitZero,
|
hasLimitZero,
|
||||||
@@ -375,5 +373,5 @@ producedMediaTypes conf action path =
|
|||||||
++ [MTOpenAPI | pathIsRootSpec path]
|
++ [MTOpenAPI | pathIsRootSpec path]
|
||||||
defaultMediaTypes =
|
defaultMediaTypes =
|
||||||
[MTApplicationJSON, MTSingularJSON, MTGeoJSON, MTTextCSV] ++
|
[MTApplicationJSON, MTSingularJSON, MTGeoJSON, MTTextCSV] ++
|
||||||
[MTPlan $ MTPlanAttrs Nothing PlanJSON mempty | configDbPlanEnabled conf] ++ [MTAny]
|
[MTPlan Nothing Nothing mempty | configDbPlanEnabled conf] ++ [MTAny]
|
||||||
rawMediaTypes = configRawMediaTypes conf `union` [MTOctetStream, MTTextPlain, MTTextXML]
|
rawMediaTypes = configRawMediaTypes conf `union` [MTOctetStream, MTTextPlain, MTTextXML]
|
||||||
|
|||||||
+45
-17
@@ -4,7 +4,6 @@ module PostgREST.MediaType
|
|||||||
( MediaType(..)
|
( MediaType(..)
|
||||||
, MTPlanOption (..)
|
, MTPlanOption (..)
|
||||||
, MTPlanFormat (..)
|
, MTPlanFormat (..)
|
||||||
, MTPlanAttrs(..)
|
|
||||||
, toContentType
|
, toContentType
|
||||||
, toMime
|
, toMime
|
||||||
, decodeMediaType
|
, decodeMediaType
|
||||||
@@ -19,6 +18,14 @@ import Network.HTTP.Types.Header (Header, hContentType)
|
|||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
|
--
|
||||||
|
-- $setup
|
||||||
|
-- Setup for doctests
|
||||||
|
-- >>> import Text.Pretty.Simple (pPrint)
|
||||||
|
-- >>> deriving instance Show MTPlanFormat
|
||||||
|
-- >>> deriving instance Show MTPlanOption
|
||||||
|
-- >>> deriving instance Show MediaType
|
||||||
|
|
||||||
-- | Enumeration of currently supported media types
|
-- | Enumeration of currently supported media types
|
||||||
data MediaType
|
data MediaType
|
||||||
= MTApplicationJSON
|
= MTApplicationJSON
|
||||||
@@ -32,12 +39,21 @@ data MediaType
|
|||||||
| MTOctetStream
|
| MTOctetStream
|
||||||
| MTAny
|
| MTAny
|
||||||
| MTOther ByteString
|
| MTOther ByteString
|
||||||
| MTPlan MTPlanAttrs
|
| MTPlan (Maybe MediaType) (Maybe MTPlanFormat) [MTPlanOption]
|
||||||
deriving Eq
|
instance Eq MediaType where
|
||||||
|
MTApplicationJSON == MTApplicationJSON = True
|
||||||
data MTPlanAttrs = MTPlanAttrs (Maybe MediaType) MTPlanFormat [MTPlanOption]
|
MTSingularJSON == MTSingularJSON = True
|
||||||
instance Eq MTPlanAttrs where
|
MTGeoJSON == MTGeoJSON = True
|
||||||
MTPlanAttrs {} == MTPlanAttrs {} = True -- we don't care about the attributes when comparing two MTPlan media types
|
MTTextCSV == MTTextCSV = True
|
||||||
|
MTTextPlain == MTTextPlain = True
|
||||||
|
MTTextXML == MTTextXML = True
|
||||||
|
MTOpenAPI == MTOpenAPI = True
|
||||||
|
MTUrlEncoded == MTUrlEncoded = True
|
||||||
|
MTOctetStream == MTOctetStream = True
|
||||||
|
MTAny == MTAny = True
|
||||||
|
MTOther x == MTOther y = x == y
|
||||||
|
MTPlan{} == MTPlan{} = True
|
||||||
|
_ == _ = False
|
||||||
|
|
||||||
data MTPlanOption
|
data MTPlanOption
|
||||||
= PlanAnalyze | PlanVerbose | PlanSettings | PlanBuffers | PlanWAL
|
= PlanAnalyze | PlanVerbose | PlanSettings | PlanBuffers | PlanWAL
|
||||||
@@ -67,8 +83,8 @@ toMime MTUrlEncoded = "application/x-www-form-urlencoded"
|
|||||||
toMime MTOctetStream = "application/octet-stream"
|
toMime MTOctetStream = "application/octet-stream"
|
||||||
toMime MTAny = "*/*"
|
toMime MTAny = "*/*"
|
||||||
toMime (MTOther ct) = ct
|
toMime (MTOther ct) = ct
|
||||||
toMime (MTPlan (MTPlanAttrs mt fmt opts)) =
|
toMime (MTPlan mt fmt opts) =
|
||||||
"application/vnd.pgrst.plan+" <> toMimePlanFormat fmt <>
|
"application/vnd.pgrst.plan" <> maybe mempty (\x -> "+" <> toMimePlanFormat x) fmt <>
|
||||||
(if isNothing mt then mempty else "; for=\"" <> toMime (fromJust mt) <> "\"") <>
|
(if isNothing mt then mempty else "; for=\"" <> toMime (fromJust mt) <> "\"") <>
|
||||||
(if null opts then mempty else "; options=" <> BS.intercalate "|" (toMimePlanOption <$> opts))
|
(if null opts then mempty else "; options=" <> BS.intercalate "|" (toMimePlanOption <$> opts))
|
||||||
|
|
||||||
@@ -83,7 +99,19 @@ toMimePlanFormat :: MTPlanFormat -> ByteString
|
|||||||
toMimePlanFormat PlanJSON = "json"
|
toMimePlanFormat PlanJSON = "json"
|
||||||
toMimePlanFormat PlanText = "text"
|
toMimePlanFormat PlanText = "text"
|
||||||
|
|
||||||
-- | Convert from ByteString to MediaType. Warning: discards MIME parameters
|
-- | Convert from ByteString to MediaType.
|
||||||
|
--
|
||||||
|
-- >>> decodeMediaType "application/json"
|
||||||
|
-- MTApplicationJSON
|
||||||
|
--
|
||||||
|
-- >>> decodeMediaType "application/vnd.pgrst.plan;"
|
||||||
|
-- MTPlan Nothing Nothing []
|
||||||
|
--
|
||||||
|
-- >>> decodeMediaType "application/vnd.pgrst.plan;for=\"application/json\""
|
||||||
|
-- MTPlan (Just MTApplicationJSON) Nothing []
|
||||||
|
--
|
||||||
|
-- >>> decodeMediaType "application/vnd.pgrst.plan+text;for=\"text/csv\""
|
||||||
|
-- MTPlan (Just MTTextCSV) (Just PlanText) []
|
||||||
decodeMediaType :: BS.ByteString -> MediaType
|
decodeMediaType :: BS.ByteString -> MediaType
|
||||||
decodeMediaType mt =
|
decodeMediaType mt =
|
||||||
case BS.split (BS.c2w ';') mt of
|
case BS.split (BS.c2w ';') mt of
|
||||||
@@ -97,9 +125,9 @@ decodeMediaType mt =
|
|||||||
"application/vnd.pgrst.object":_ -> MTSingularJSON
|
"application/vnd.pgrst.object":_ -> MTSingularJSON
|
||||||
"application/x-www-form-urlencoded":_ -> MTUrlEncoded
|
"application/x-www-form-urlencoded":_ -> MTUrlEncoded
|
||||||
"application/octet-stream":_ -> MTOctetStream
|
"application/octet-stream":_ -> MTOctetStream
|
||||||
"application/vnd.pgrst.plan":rest -> getPlan PlanText rest
|
"application/vnd.pgrst.plan":rest -> getPlan Nothing rest
|
||||||
"application/vnd.pgrst.plan+text":rest -> getPlan PlanText rest
|
"application/vnd.pgrst.plan+text":rest -> getPlan (Just PlanText) rest
|
||||||
"application/vnd.pgrst.plan+json":rest -> getPlan PlanJSON rest
|
"application/vnd.pgrst.plan+json":rest -> getPlan (Just PlanJSON) rest
|
||||||
"*/*":_ -> MTAny
|
"*/*":_ -> MTAny
|
||||||
other:_ -> MTOther other
|
other:_ -> MTOther other
|
||||||
_ -> MTAny
|
_ -> MTAny
|
||||||
@@ -110,7 +138,7 @@ decodeMediaType mt =
|
|||||||
inOpts str = str `elem` opts
|
inOpts str = str `elem` opts
|
||||||
mtFor = decodeMediaType . dropAround (== BS.c2w '"') <$> (BS.stripPrefix "for=" =<< find (BS.isPrefixOf "for=") rest)
|
mtFor = decodeMediaType . dropAround (== BS.c2w '"') <$> (BS.stripPrefix "for=" =<< find (BS.isPrefixOf "for=") rest)
|
||||||
dropAround p = BS.dropWhile p . BS.dropWhileEnd p in
|
dropAround p = BS.dropWhile p . BS.dropWhileEnd p in
|
||||||
MTPlan $ MTPlanAttrs mtFor fmt $
|
MTPlan mtFor fmt $
|
||||||
[PlanAnalyze | inOpts "analyze" ] ++
|
[PlanAnalyze | inOpts "analyze" ] ++
|
||||||
[PlanVerbose | inOpts "verbose" ] ++
|
[PlanVerbose | inOpts "verbose" ] ++
|
||||||
[PlanSettings | inOpts "settings"] ++
|
[PlanSettings | inOpts "settings"] ++
|
||||||
@@ -119,6 +147,6 @@ decodeMediaType mt =
|
|||||||
|
|
||||||
getMediaType :: MediaType -> MediaType
|
getMediaType :: MediaType -> MediaType
|
||||||
getMediaType mt = case mt of
|
getMediaType mt = case mt of
|
||||||
MTPlan (MTPlanAttrs (Just mType) _ _) -> mType
|
MTPlan (Just mType) _ _ -> mType
|
||||||
MTPlan (MTPlanAttrs Nothing _ _) -> MTApplicationJSON
|
MTPlan Nothing _ _ -> MTApplicationJSON
|
||||||
other -> other
|
other -> other
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ import PostgREST.ApiRequest (Action (..),
|
|||||||
Payload (..))
|
Payload (..))
|
||||||
import PostgREST.Config (AppConfig (..))
|
import PostgREST.Config (AppConfig (..))
|
||||||
import PostgREST.Error (Error (..))
|
import PostgREST.Error (Error (..))
|
||||||
import PostgREST.MediaType (MTPlanAttrs (..),
|
import PostgREST.MediaType (MediaType (..))
|
||||||
MediaType (..))
|
|
||||||
import PostgREST.Query.SqlFragment (sourceCTEName)
|
import PostgREST.Query.SqlFragment (sourceCTEName)
|
||||||
import PostgREST.RangeQuery (NonnegRange, allRange,
|
import PostgREST.RangeQuery (NonnegRange, allRange,
|
||||||
convertToLimitZeroRange,
|
convertToLimitZeroRange,
|
||||||
@@ -634,10 +633,10 @@ binaryField AppConfig{configRawMediaTypes} acceptMediaType proc rpTree
|
|||||||
where
|
where
|
||||||
isRawMediaType = acceptMediaType `elem` configRawMediaTypes `L.union` [MTOctetStream, MTTextPlain, MTTextXML] || isRawPlan acceptMediaType
|
isRawMediaType = acceptMediaType `elem` configRawMediaTypes `L.union` [MTOctetStream, MTTextPlain, MTTextXML] || isRawPlan acceptMediaType
|
||||||
isRawPlan mt = case mt of
|
isRawPlan mt = case mt of
|
||||||
MTPlan (MTPlanAttrs (Just MTOctetStream) _ _) -> True
|
MTPlan (Just MTOctetStream) _ _ -> True
|
||||||
MTPlan (MTPlanAttrs (Just MTTextPlain) _ _) -> True
|
MTPlan (Just MTTextPlain) _ _ -> True
|
||||||
MTPlan (MTPlanAttrs (Just MTTextXML) _ _) -> True
|
MTPlan (Just MTTextXML) _ _ -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
|
|
||||||
fstFieldName :: ReadPlanTree -> Maybe FieldName
|
fstFieldName :: ReadPlanTree -> Maybe FieldName
|
||||||
fstFieldName (Node ReadPlan{select=(("*", []), _, _):_} []) = Nothing
|
fstFieldName (Node ReadPlan{select=(("*", []), _, _):_} []) = Nothing
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ intercalateSnippet :: ByteString -> [SQL.Snippet] -> SQL.Snippet
|
|||||||
intercalateSnippet _ [] = mempty
|
intercalateSnippet _ [] = mempty
|
||||||
intercalateSnippet frag snippets = foldr1 (\a b -> a <> SQL.sql frag <> b) snippets
|
intercalateSnippet frag snippets = foldr1 (\a b -> a <> SQL.sql frag <> b) snippets
|
||||||
|
|
||||||
explainF :: MTPlanFormat -> [MTPlanOption] -> SQL.Snippet -> SQL.Snippet
|
explainF :: Maybe MTPlanFormat -> [MTPlanOption] -> SQL.Snippet -> SQL.Snippet
|
||||||
explainF fmt opts snip =
|
explainF fmt opts snip =
|
||||||
"EXPLAIN (" <>
|
"EXPLAIN (" <>
|
||||||
SQL.sql (BS.intercalate ", " (fmtPlanFmt fmt : (fmtPlanOpt <$> opts))) <>
|
SQL.sql (BS.intercalate ", " (fmtPlanFmt fmt : (fmtPlanOpt <$> opts))) <>
|
||||||
@@ -444,8 +444,9 @@ explainF fmt opts snip =
|
|||||||
fmtPlanOpt PlanBuffers = "BUFFERS"
|
fmtPlanOpt PlanBuffers = "BUFFERS"
|
||||||
fmtPlanOpt PlanWAL = "WAL"
|
fmtPlanOpt PlanWAL = "WAL"
|
||||||
|
|
||||||
fmtPlanFmt PlanJSON = "FORMAT JSON"
|
fmtPlanFmt Nothing = "FORMAT TEXT"
|
||||||
fmtPlanFmt PlanText = "FORMAT TEXT"
|
fmtPlanFmt (Just PlanJSON) = "FORMAT JSON"
|
||||||
|
fmtPlanFmt (Just PlanText) = "FORMAT TEXT"
|
||||||
|
|
||||||
-- | Do a pg set_config(setting, value, true) call. This is equivalent to a SET LOCAL.
|
-- | Do a pg set_config(setting, value, true) call. This is equivalent to a SET LOCAL.
|
||||||
setConfigLocal :: ByteString -> (ByteString, ByteString) -> SQL.Snippet
|
setConfigLocal :: ByteString -> (ByteString, ByteString) -> SQL.Snippet
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ import Control.Lens ((^?))
|
|||||||
import Data.Maybe (fromJust)
|
import Data.Maybe (fromJust)
|
||||||
|
|
||||||
import PostgREST.ApiRequest.Preferences
|
import PostgREST.ApiRequest.Preferences
|
||||||
import PostgREST.MediaType (MTPlanAttrs (..),
|
import PostgREST.MediaType (MTPlanFormat (..),
|
||||||
MTPlanFormat (..),
|
|
||||||
MediaType (..),
|
MediaType (..),
|
||||||
getMediaType)
|
getMediaType)
|
||||||
import PostgREST.Query.SqlFragment
|
import PostgREST.Query.SqlFragment
|
||||||
@@ -168,7 +167,7 @@ preparePlanRows :: SQL.Snippet -> Bool -> SQL.Statement () (Maybe Int64)
|
|||||||
preparePlanRows countQuery =
|
preparePlanRows countQuery =
|
||||||
SQL.dynamicallyParameterized snippet decodeIt
|
SQL.dynamicallyParameterized snippet decodeIt
|
||||||
where
|
where
|
||||||
snippet = explainF PlanJSON mempty countQuery
|
snippet = explainF (Just PlanJSON) mempty countQuery
|
||||||
decodeIt :: HD.Result (Maybe Int64)
|
decodeIt :: HD.Result (Maybe Int64)
|
||||||
decodeIt =
|
decodeIt =
|
||||||
let row = HD.singleRow $ column HD.bytea in
|
let row = HD.singleRow $ column HD.bytea in
|
||||||
@@ -188,8 +187,8 @@ standardRow noLocation =
|
|||||||
|
|
||||||
mtSnippet :: MediaType -> SQL.Snippet -> SQL.Snippet
|
mtSnippet :: MediaType -> SQL.Snippet -> SQL.Snippet
|
||||||
mtSnippet mediaType snippet = case mediaType of
|
mtSnippet mediaType snippet = case mediaType of
|
||||||
MTPlan (MTPlanAttrs _ fmt opts) -> explainF fmt opts snippet
|
MTPlan _ fmt opts -> explainF fmt opts snippet
|
||||||
_ -> snippet
|
_ -> snippet
|
||||||
|
|
||||||
-- | We use rowList because when doing EXPLAIN (FORMAT TEXT), the result comes as many rows. FORMAT JSON comes as one.
|
-- | We use rowList because when doing EXPLAIN (FORMAT TEXT), the result comes as many rows. FORMAT JSON comes as one.
|
||||||
planRow :: HD.Result ResultSet
|
planRow :: HD.Result ResultSet
|
||||||
|
|||||||
@@ -16,4 +16,5 @@ main =
|
|||||||
, "src/PostgREST/ApiRequest/Preferences.hs"
|
, "src/PostgREST/ApiRequest/Preferences.hs"
|
||||||
, "src/PostgREST/ApiRequest/QueryParams.hs"
|
, "src/PostgREST/ApiRequest/QueryParams.hs"
|
||||||
, "src/PostgREST/Error.hs"
|
, "src/PostgREST/Error.hs"
|
||||||
|
, "src/PostgREST/MediaType.hs"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ spec actualPgVersion = do
|
|||||||
resStatus = simpleStatus r
|
resStatus = simpleStatus r
|
||||||
|
|
||||||
liftIO $ do
|
liftIO $ do
|
||||||
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+text; charset=utf-8")
|
resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan; charset=utf-8")
|
||||||
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
|
resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" }
|
||||||
resBody `shouldSatisfy` (\t -> LBS.take 9 t == "Aggregate")
|
resBody `shouldSatisfy` (\t -> LBS.take 9 t == "Aggregate")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user