refactor: untangle query logic from response logic

* untangle failNotSingular
* untangle failsChangesOffLimits
* untangle readTotal
This commit is contained in:
steve-chavez
2022-09-25 13:53:11 -05:00
committed by Steve Chavez
parent c27e7be028
commit 92e28bd902
2 changed files with 46 additions and 46 deletions
+44 -44
View File
@@ -30,7 +30,7 @@ import Network.Wai.Handler.Warp (defaultSettings, setHost, setPort,
setServerName) setServerName)
import System.Posix.Types (FileMode) import System.Posix.Types (FileMode)
import qualified Data.Aeson as JSON import qualified Data.Aeson as JSON
import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Lazy as LBS
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
@@ -280,9 +280,11 @@ handleRead headersOnly identifier context@RequestContext{..} = do
bField bField
configDbPreparedStatements configDbPreparedStatements
failNotSingular iAcceptMediaType resultSet
total <- readTotal ctxConfig ctxApiRequest resultSet countQuery
case resultSet of case resultSet of
RSStandard{..} -> do RSStandard{..} -> do
total <- readTotal ctxConfig ctxApiRequest rsTableTotal countQuery
let let
(status, contentRange) = RangeQuery.rangeStatusHeader iTopLevelRange rsQueryTotal total (status, contentRange) = RangeQuery.rangeStatusHeader iTopLevelRange rsQueryTotal total
@@ -301,14 +303,14 @@ handleRead headersOnly identifier context@RequestContext{..} = do
$ ApiRequestTypes.OutOfBounds (show $ RangeQuery.rangeOffset iTopLevelRange) (maybe "0" show total) $ ApiRequestTypes.OutOfBounds (show $ RangeQuery.rangeOffset iTopLevelRange) (maybe "0" show total)
else LBS.fromStrict rsBody else LBS.fromStrict rsBody
failNotSingular iAcceptMediaType rsQueryTotal . response status headers $ pure $ response status headers $ if headersOnly then mempty else rsOrErrBody
if headersOnly then mempty else rsOrErrBody
RSPlan plan -> RSPlan plan ->
pure $ Wai.responseLBS HTTP.status200 (contentTypeHeaders context) $ LBS.fromStrict plan pure $ Wai.responseLBS HTTP.status200 (contentTypeHeaders context) $ LBS.fromStrict plan
readTotal :: AppConfig -> ApiRequest -> Maybe Int64 -> SQL.Snippet -> DbHandler (Maybe Int64) readTotal :: AppConfig -> ApiRequest -> ResultSet -> SQL.Snippet -> DbHandler (Maybe Int64)
readTotal AppConfig{..} ApiRequest{..} tableTotal countQuery = readTotal _ _ RSPlan{} _ = pure Nothing
readTotal AppConfig{..} ApiRequest{..} RSStandard{rsTableTotal=tableTotal} countQuery =
case iPreferCount of case iPreferCount of
Just PlannedCount -> Just PlannedCount ->
explain explain
@@ -334,6 +336,8 @@ handleCreate identifier@QualifiedIdentifier{..} context@RequestContext{..} = do
resultSet <- writeQuery MutationCreate identifier True pkCols context resultSet <- writeQuery MutationCreate identifier True pkCols context
failNotSingular iAcceptMediaType resultSet
case resultSet of case resultSet of
RSStandard{..} -> do RSStandard{..} -> do
let let
@@ -357,11 +361,10 @@ handleCreate identifier@QualifiedIdentifier{..} context@RequestContext{..} = do
toAppliedHeader <$> iPreferResolution toAppliedHeader <$> iPreferResolution
] ]
failNotSingular iAcceptMediaType rsQueryTotal $ pure $ if iPreferRepresentation == Full then
if iPreferRepresentation == Full then response HTTP.status201 (headers ++ contentTypeHeaders context) (LBS.fromStrict rsBody)
response HTTP.status201 (headers ++ contentTypeHeaders context) (LBS.fromStrict rsBody) else
else response HTTP.status201 headers mempty
response HTTP.status201 headers mempty
RSPlan plan -> RSPlan plan ->
pure $ Wai.responseLBS HTTP.status200 (contentTypeHeaders context) $ LBS.fromStrict plan pure $ Wai.responseLBS HTTP.status200 (contentTypeHeaders context) $ LBS.fromStrict plan
@@ -369,6 +372,8 @@ handleCreate identifier@QualifiedIdentifier{..} context@RequestContext{..} = do
handleUpdate :: QualifiedIdentifier -> RequestContext -> DbHandler Wai.Response handleUpdate :: QualifiedIdentifier -> RequestContext -> DbHandler Wai.Response
handleUpdate identifier context@(RequestContext _ _ ApiRequest{..} _) = do handleUpdate identifier context@(RequestContext _ _ ApiRequest{..} _) = do
resultSet <- writeQuery MutationUpdate identifier False mempty context resultSet <- writeQuery MutationUpdate identifier False mempty context
failNotSingular iAcceptMediaType resultSet
failsChangesOffLimits (RangeQuery.rangeLimit iTopLevelRange) resultSet
case resultSet of case resultSet of
RSStandard{..} -> do RSStandard{..} -> do
@@ -384,12 +389,10 @@ handleUpdate identifier context@(RequestContext _ _ ApiRequest{..} _) = do
RangeQuery.contentRangeH 0 (rsQueryTotal - 1) $ RangeQuery.contentRangeH 0 (rsQueryTotal - 1) $
if shouldCount iPreferCount then Just rsQueryTotal else Nothing if shouldCount iPreferCount then Just rsQueryTotal else Nothing
failChangesOffLimits (RangeQuery.rangeLimit iTopLevelRange) rsQueryTotal =<< pure $ if fullRepr then
failNotSingular iAcceptMediaType rsQueryTotal ( response status (contentTypeHeaders context ++ [contentRangeHeader]) (LBS.fromStrict rsBody)
if fullRepr then else
response status (contentTypeHeaders context ++ [contentRangeHeader]) (LBS.fromStrict rsBody) response status [contentRangeHeader] mempty
else
response status [contentRangeHeader] mempty)
RSPlan plan -> RSPlan plan ->
pure $ Wai.responseLBS HTTP.status200 (contentTypeHeaders context) $ LBS.fromStrict plan pure $ Wai.responseLBS HTTP.status200 (contentTypeHeaders context) $ LBS.fromStrict plan
@@ -426,6 +429,8 @@ handleSingleUpsert identifier context@(RequestContext _ ctxDbStructure ApiReques
handleDelete :: QualifiedIdentifier -> RequestContext -> DbHandler Wai.Response handleDelete :: QualifiedIdentifier -> RequestContext -> DbHandler Wai.Response
handleDelete identifier context@(RequestContext _ _ ApiRequest{..} _) = do handleDelete identifier context@(RequestContext _ _ ApiRequest{..} _) = do
resultSet <- writeQuery MutationDelete identifier False mempty context resultSet <- writeQuery MutationDelete identifier False mempty context
failNotSingular iAcceptMediaType resultSet
failsChangesOffLimits (RangeQuery.rangeLimit iTopLevelRange) resultSet
case resultSet of case resultSet of
RSStandard {..} -> do RSStandard {..} -> do
@@ -435,14 +440,12 @@ handleDelete identifier context@(RequestContext _ _ ApiRequest{..} _) = do
RangeQuery.contentRangeH 1 0 $ RangeQuery.contentRangeH 1 0 $
if shouldCount iPreferCount then Just rsQueryTotal else Nothing if shouldCount iPreferCount then Just rsQueryTotal else Nothing
failChangesOffLimits (RangeQuery.rangeLimit iTopLevelRange) rsQueryTotal =<< pure $ if iPreferRepresentation == Full then
failNotSingular iAcceptMediaType rsQueryTotal ( response HTTP.status200
if iPreferRepresentation == Full then (contentTypeHeaders context ++ [contentRangeHeader])
response HTTP.status200 (LBS.fromStrict rsBody)
(contentTypeHeaders context ++ [contentRangeHeader]) else
(LBS.fromStrict rsBody) response HTTP.status204 [contentRangeHeader] mempty
else
response HTTP.status204 [contentRangeHeader] mempty)
RSPlan plan -> RSPlan plan ->
pure $ Wai.responseLBS HTTP.status200 (contentTypeHeaders context) $ LBS.fromStrict plan pure $ Wai.responseLBS HTTP.status200 (contentTypeHeaders context) $ LBS.fromStrict plan
@@ -499,6 +502,8 @@ handleInvoke invMethod proc context@RequestContext{..} = do
bField bField
(configDbPreparedStatements ctxConfig) (configDbPreparedStatements ctxConfig)
failNotSingular iAcceptMediaType resultSet
case resultSet of case resultSet of
RSStandard {..} -> do RSStandard {..} -> do
let let
@@ -510,8 +515,7 @@ handleInvoke invMethod proc context@RequestContext{..} = do
$ ApiRequestTypes.OutOfBounds (show $ RangeQuery.rangeOffset iTopLevelRange) (maybe "0" show rsTableTotal) $ ApiRequestTypes.OutOfBounds (show $ RangeQuery.rangeOffset iTopLevelRange) (maybe "0" show rsTableTotal)
else LBS.fromStrict rsBody else LBS.fromStrict rsBody
failNotSingular iAcceptMediaType rsQueryTotal $ pure $ if Proc.procReturnsVoid proc then
if Proc.procReturnsVoid proc then
response HTTP.status204 [contentRange] mempty response HTTP.status204 [contentRange] mempty
else else
response status response status
@@ -608,24 +612,20 @@ decodeGucStatus =
-- | -- |
-- Fail a response if a single JSON object was requested and not exactly one -- Fail a response if a single JSON object was requested and not exactly one
-- was found. -- was found.
failNotSingular :: MediaType -> Int64 -> Wai.Response -> DbHandler Wai.Response failNotSingular :: MediaType -> ResultSet -> DbHandler ()
failNotSingular mediaType queryTotal response = failNotSingular _ RSPlan{} = pure ()
if mediaType == MTSingularJSON && queryTotal /= 1 then failNotSingular mediaType RSStandard{rsQueryTotal=queryTotal} =
do when (mediaType == MTSingularJSON && queryTotal /= 1) $ do
lift SQL.condemn lift SQL.condemn
throwError $ Error.singularityError queryTotal throwError $ Error.singularityError queryTotal
else
return response
failChangesOffLimits :: Maybe Integer -> Int64 -> Wai.Response -> DbHandler Wai.Response failsChangesOffLimits :: Maybe Integer -> ResultSet -> DbHandler ()
failChangesOffLimits (Just maxChanges) queryTotal response = failsChangesOffLimits _ RSPlan{} = pure ()
if queryTotal > fromIntegral maxChanges failsChangesOffLimits Nothing _ = pure ()
then do failsChangesOffLimits (Just maxChanges) RSStandard{rsQueryTotal=queryTotal} =
lift SQL.condemn when (queryTotal > fromIntegral maxChanges) $ do
throwError $ Error.OffLimitsChangesError queryTotal maxChanges lift SQL.condemn
else throwError $ Error.OffLimitsChangesError queryTotal maxChanges
return response
failChangesOffLimits _ _ response = return response
shouldCount :: Maybe PreferCount -> Bool shouldCount :: Maybe PreferCount -> Bool
shouldCount preferCount = shouldCount preferCount =
+2 -2
View File
@@ -22,8 +22,8 @@ import qualified Hasql.DynamicStatements.Snippet as SQL
import qualified Hasql.DynamicStatements.Statement as SQL import qualified Hasql.DynamicStatements.Statement as SQL
import qualified Hasql.Statement as SQL import qualified Hasql.Statement as SQL
import Control.Lens ((^?)) import Control.Lens ((^?))
import Data.Maybe (fromJust) import Data.Maybe (fromJust)
import PostgREST.DbStructure.Identifiers (FieldName) import PostgREST.DbStructure.Identifiers (FieldName)
import PostgREST.MediaType (MTPlanAttrs (..), import PostgREST.MediaType (MTPlanAttrs (..),