Skip to content

Commit

Permalink
refactor: move ApiRequestError to Error module
Browse files Browse the repository at this point in the history
  • Loading branch information
taimoorzaeem committed Feb 12, 2025
1 parent e4f3c2c commit 6601d0e
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 78 deletions.
4 changes: 2 additions & 2 deletions src/PostgREST/ApiRequest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ import Network.Wai.Parse (parseHttpAccept)
import Web.Cookie (parseCookies)

import PostgREST.ApiRequest.QueryParams (QueryParams (..))
import PostgREST.ApiRequest.Types (ApiRequestError (..),
RangeError (..))
import PostgREST.Config (AppConfig (..),
OpenAPIMode (..))
import PostgREST.Error (ApiRequestError (..),
RangeError (..))
import PostgREST.MediaType (MediaType (..))
import PostgREST.RangeQuery (NonnegRange, allRange,
convertToLimitZeroRange,
Expand Down
4 changes: 3 additions & 1 deletion src/PostgREST/ApiRequest/QueryParams.hs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ import PostgREST.ApiRequest.Types (AggregateFunction (..),
OpQuantifier (..), Operation (..),
OrderDirection (..),
OrderNulls (..), OrderTerm (..),
QPError (..), QuantOperator (..),
QuantOperator (..),
SelectItem (..),
SimpleOperator (..), SingleVal)

import PostgREST.Error (QPError (..))

import Protolude hiding (Sum, try)

data QueryParams =
Expand Down
56 changes: 1 addition & 55 deletions src/PostgREST/ApiRequest/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module PostgREST.ApiRequest.Types
, Cast
, Depth
, EmbedParam(..)
, ApiRequestError(..)
, EmbedPath
, Field
, Filter(..)
Expand All @@ -25,9 +24,6 @@ module PostgREST.ApiRequest.Types
, OrderDirection(..)
, OrderNulls(..)
, OrderTerm(..)
, QPError(..)
, RaiseError(..)
, RangeError(..)
, SingleVal
, IsVal(..)
, SimpleOperator(..)
Expand All @@ -36,12 +32,7 @@ module PostgREST.ApiRequest.Types
, SelectItem(..)
) where

import PostgREST.MediaType (MediaType (..))
import PostgREST.SchemaCache.Identifiers (FieldName,
QualifiedIdentifier)
import PostgREST.SchemaCache.Relationship (Relationship,
RelationshipsMap)
import PostgREST.SchemaCache.Routine (Routine (..))
import PostgREST.SchemaCache.Identifiers (FieldName)

import Protolude

Expand Down Expand Up @@ -69,51 +60,6 @@ data SelectItem
}
deriving (Eq, Show)

data ApiRequestError
= AggregatesNotAllowed
| AmbiguousRelBetween Text Text [Relationship]
| AmbiguousRpc [Routine]
| MediaTypeError [ByteString]
| InvalidBody ByteString
| InvalidFilters
| InvalidPreferences [ByteString]
| InvalidRange RangeError
| InvalidRpcMethod ByteString
| LimitNoOrderError
| NotFound
| NoRelBetween Text Text (Maybe Text) Text RelationshipsMap
| NoRpc Text Text [Text] MediaType Bool [QualifiedIdentifier] [Routine]
| NotEmbedded Text
| PutLimitNotAllowedError
| QueryParamError QPError
| RelatedOrderNotToOne Text Text
| SpreadNotToOne Text Text
| UnacceptableFilter Text
| UnacceptableSchema [Text]
| UnsupportedMethod ByteString
| ColumnNotFound Text Text
| GucHeadersError
| GucStatusError
| OffLimitsChangesError Int64 Integer
| PutMatchingPkError
| SingularityError Integer
| PGRSTParseError RaiseError
| MaxAffectedViolationError Integer
deriving Show

data QPError = QPError Text Text
deriving Show
data RaiseError
= MsgParseError ByteString
| DetParseError ByteString
| NoDetail
deriving Show
data RangeError
= NegativeLimit
| LowerGTUpper
| OutOfBounds Text Text
deriving Show

type NodeName = Text
type Depth = Integer

Expand Down
57 changes: 51 additions & 6 deletions src/PostgREST/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Description : PostgREST error HTTP responses
module PostgREST.Error
( errorResponseFor
, ApiRequestError(..)
, QPError(..)
, RangeError(..)
, PgError(..)
, Error(..)
, errorPayload
Expand All @@ -32,12 +34,8 @@ import Network.Wai (Response, responseLBS)

import Network.HTTP.Types.Header (Header)

import PostgREST.ApiRequest.Types (ApiRequestError (..),
QPError (..),
RaiseError (..),
RangeError (..))
import PostgREST.MediaType (MediaType (..))
import qualified PostgREST.MediaType as MediaType
import PostgREST.MediaType (MediaType (..))
import qualified PostgREST.MediaType as MediaType

import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
Schema)
Expand All @@ -62,6 +60,53 @@ class (JSON.ToJSON a) => PgrstError a where
let baseHeader = MediaType.toContentType MTApplicationJSON in
responseLBS (status err) (baseHeader : headers err) $ errorPayload err

data ApiRequestError
= AggregatesNotAllowed
| AmbiguousRelBetween Text Text [Relationship]
| AmbiguousRpc [Routine]
| MediaTypeError [ByteString]
| InvalidBody ByteString
| InvalidFilters
| InvalidPreferences [ByteString]
| InvalidRange RangeError
| InvalidRpcMethod ByteString
| LimitNoOrderError
| NotFound
| NoRelBetween Text Text (Maybe Text) Text RelationshipsMap
| NoRpc Text Text [Text] MediaType Bool [QualifiedIdentifier] [Routine]
| NotEmbedded Text
| PutLimitNotAllowedError
| QueryParamError QPError
| RelatedOrderNotToOne Text Text
| SpreadNotToOne Text Text
| UnacceptableFilter Text
| UnacceptableSchema [Text]
| UnsupportedMethod ByteString
| ColumnNotFound Text Text
| GucHeadersError
| GucStatusError
| OffLimitsChangesError Int64 Integer
| PutMatchingPkError
| SingularityError Integer
| PGRSTParseError RaiseError
| MaxAffectedViolationError Integer
deriving Show

Check warning on line 93 in src/PostgREST/Error.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/Error.hs#L93

Added line #L93 was not covered by tests

data QPError = QPError Text Text
deriving Show

Check warning on line 96 in src/PostgREST/Error.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/Error.hs#L96

Added line #L96 was not covered by tests

data RaiseError
= MsgParseError ByteString
| DetParseError ByteString
| NoDetail
deriving Show

Check warning on line 102 in src/PostgREST/Error.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/Error.hs#L102

Added line #L102 was not covered by tests

data RangeError
= NegativeLimit
| LowerGTUpper
| OutOfBounds Text Text
deriving Show

Check warning on line 108 in src/PostgREST/Error.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/Error.hs#L108

Added line #L108 was not covered by tests

instance PgrstError ApiRequestError where
status AggregatesNotAllowed{} = HTTP.status400
status AmbiguousRelBetween{} = HTTP.status300
Expand Down
3 changes: 2 additions & 1 deletion src/PostgREST/Plan.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ import PostgREST.ApiRequest (Action (..),
Mutation (..),
Payload (..))
import PostgREST.Config (AppConfig (..))
import PostgREST.Error (Error (..))
import PostgREST.Error (ApiRequestError (..),
Error (..))
import PostgREST.MediaType (MediaType (..))
import PostgREST.Query.SqlFragment (sourceCTEName)
import PostgREST.RangeQuery (NonnegRange, allRange,
Expand Down
9 changes: 4 additions & 5 deletions src/PostgREST/Query.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import qualified Hasql.DynamicStatements.Statement as SQL
import qualified Hasql.Transaction as SQL
import qualified Hasql.Transaction.Sessions as SQL

import qualified PostgREST.ApiRequest.Types as ApiRequestTypes
import qualified PostgREST.AppState as AppState
import qualified PostgREST.Error as Error
import qualified PostgREST.Query.QueryBuilder as QueryBuilder
Expand Down Expand Up @@ -219,7 +218,7 @@ failPut RSPlan{} = pure ()
failPut RSStandard{rsQueryTotal=queryTotal} =
when (queryTotal /= 1) $ do
lift SQL.condemn
throwError $ Error.ApiRequestError ApiRequestTypes.PutMatchingPkError
throwError $ Error.ApiRequestError Error.PutMatchingPkError

resultSetWTotal :: AppConfig -> ApiRequest -> ResultSet -> SQL.Snippet -> DbHandler ResultSet
resultSetWTotal _ _ rs@RSPlan{} _ = return rs
Expand Down Expand Up @@ -251,22 +250,22 @@ failNotSingular _ RSPlan{} = pure ()
failNotSingular mediaType RSStandard{rsQueryTotal=queryTotal} =
when (elem mediaType [MTVndSingularJSON True, MTVndSingularJSON False] && queryTotal /= 1) $ do
lift SQL.condemn
throwError $ Error.ApiRequestError . ApiRequestTypes.SingularityError $ toInteger queryTotal
throwError $ Error.ApiRequestError . Error.SingularityError $ toInteger queryTotal

failExceedsMaxAffectedPref :: (Maybe PreferMaxAffected, Maybe PreferHandling) -> ResultSet -> DbHandler ()
failExceedsMaxAffectedPref (Nothing,_) _ = pure ()
failExceedsMaxAffectedPref _ RSPlan{} = pure ()
failExceedsMaxAffectedPref (Just (PreferMaxAffected n), handling) RSStandard{rsQueryTotal=queryTotal} = when ((queryTotal > n) && (handling == Just Strict)) $ do
lift SQL.condemn
throwError $ Error.ApiRequestError . ApiRequestTypes.MaxAffectedViolationError $ toInteger queryTotal
throwError $ Error.ApiRequestError . Error.MaxAffectedViolationError $ toInteger queryTotal

failsChangesOffLimits :: Maybe Integer -> ResultSet -> DbHandler ()
failsChangesOffLimits _ RSPlan{} = pure ()
failsChangesOffLimits Nothing _ = pure ()
failsChangesOffLimits (Just maxChanges) RSStandard{rsQueryTotal=queryTotal} =
when (queryTotal > fromIntegral maxChanges) $ do
lift SQL.condemn
throwError $ Error.ApiRequestError $ ApiRequestTypes.OffLimitsChangesError queryTotal maxChanges
throwError $ Error.ApiRequestError $ Error.OffLimitsChangesError queryTotal maxChanges

-- | Set a transaction to roll back if requested
optionalRollback :: AppConfig -> ApiRequest -> DbHandler ()
Expand Down
15 changes: 7 additions & 8 deletions src/PostgREST/Response.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import PostgREST.SchemaCache.Routine (FuncVolatility (..),
Routine (..))
import PostgREST.SchemaCache.Table (Table (..))

import qualified PostgREST.ApiRequest.Types as ApiRequestTypes
import qualified PostgREST.SchemaCache.Routine as Routine

import Protolude hiding (Handler, toS)
Expand Down Expand Up @@ -83,8 +82,8 @@ actionResponse (DbCrudResult WrappedReadPlan{wrMedia, wrHdrsOnly=headersOnly, cr

(ovStatus, ovHeaders) <- overrideStatusHeaders rsGucStatus rsGucHeaders status headers

let bod | status == HTTP.status416 = Error.errorPayload $ Error.ApiRequestError $ ApiRequestTypes.InvalidRange $
ApiRequestTypes.OutOfBounds (show $ RangeQuery.rangeOffset iTopLevelRange) (maybe "0" show rsTableTotal)
let bod | status == HTTP.status416 = Error.errorPayload $ Error.ApiRequestError $ Error.InvalidRange $
Error.OutOfBounds (show $ RangeQuery.rangeOffset iTopLevelRange) (maybe "0" show rsTableTotal)
| headersOnly = mempty
| otherwise = LBS.fromStrict rsBody

Expand Down Expand Up @@ -203,8 +202,8 @@ actionResponse (DbCallResult CallReadPlan{crMedia, crInvMthd=invMethod, crProc=p
(status, contentRange) =
RangeQuery.rangeStatusHeader iTopLevelRange rsQueryTotal rsTableTotal
rsOrErrBody = if status == HTTP.status416
then Error.errorPayload $ Error.ApiRequestError $ ApiRequestTypes.InvalidRange
$ ApiRequestTypes.OutOfBounds (show $ RangeQuery.rangeOffset iTopLevelRange) (maybe "0" show rsTableTotal)
then Error.errorPayload $ Error.ApiRequestError $ Error.InvalidRange
$ Error.OutOfBounds (show $ RangeQuery.rangeOffset iTopLevelRange) (maybe "0" show rsTableTotal)
else LBS.fromStrict rsBody
prefHeader = maybeToList . prefAppliedHeader $ Preferences Nothing Nothing preferCount preferTransaction Nothing preferHandling preferTimezone preferMaxAffected []
headers = contentRange : prefHeader
Expand Down Expand Up @@ -232,7 +231,7 @@ actionResponse (MaybeDbResult InspectPlan{ipHdrsOnly=headersOnly} body) _ versio
actionResponse (NoDbResult (RelInfoPlan identifier)) _ _ _ sCache _ _ =
case HM.lookup identifier (dbTables sCache) of
Just tbl -> respondInfo $ allowH tbl
Nothing -> Left $ Error.ApiRequestError ApiRequestTypes.NotFound
Nothing -> Left $ Error.ApiRequestError Error.NotFound
where
allowH table =
let hasPK = not . null $ tablePKCols table in
Expand Down Expand Up @@ -263,11 +262,11 @@ overrideStatusHeaders rsGucStatus rsGucHeaders pgrstStatus pgrstHeaders = do

decodeGucHeaders :: Maybe BS.ByteString -> Either Error.Error [GucHeader]
decodeGucHeaders =
maybe (Right []) $ first (const . Error.ApiRequestError $ ApiRequestTypes.GucHeadersError) . JSON.eitherDecode . LBS.fromStrict
maybe (Right []) $ first (const . Error.ApiRequestError $ Error.GucHeadersError) . JSON.eitherDecode . LBS.fromStrict

decodeGucStatus :: Maybe Text -> Either Error.Error (Maybe HTTP.Status)
decodeGucStatus =
maybe (Right Nothing) $ first (const . Error.ApiRequestError $ ApiRequestTypes.GucStatusError) . fmap (Just . toEnum . fst) . decimal
maybe (Right Nothing) $ first (const . Error.ApiRequestError $ Error.GucStatusError) . fmap (Just . toEnum . fst) . decimal

contentTypeHeaders :: MediaType -> ApiRequest -> [HTTP.Header]
contentTypeHeaders mediaType ApiRequest{..} =
Expand Down

0 comments on commit 6601d0e

Please sign in to comment.