From 6601d0ea949311d402b42d3fe9f2c2f1a1e335c1 Mon Sep 17 00:00:00 2001 From: Taimoor Zaeem Date: Wed, 12 Feb 2025 14:36:22 +0500 Subject: [PATCH] refactor: move ApiRequestError to Error module --- src/PostgREST/ApiRequest.hs | 4 +- src/PostgREST/ApiRequest/QueryParams.hs | 4 +- src/PostgREST/ApiRequest/Types.hs | 56 +----------------------- src/PostgREST/Error.hs | 57 ++++++++++++++++++++++--- src/PostgREST/Plan.hs | 3 +- src/PostgREST/Query.hs | 9 ++-- src/PostgREST/Response.hs | 15 +++---- 7 files changed, 70 insertions(+), 78 deletions(-) diff --git a/src/PostgREST/ApiRequest.hs b/src/PostgREST/ApiRequest.hs index 5b0c97cee1..081f163703 100644 --- a/src/PostgREST/ApiRequest.hs +++ b/src/PostgREST/ApiRequest.hs @@ -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, diff --git a/src/PostgREST/ApiRequest/QueryParams.hs b/src/PostgREST/ApiRequest/QueryParams.hs index a969bcade2..b8f21fd181 100644 --- a/src/PostgREST/ApiRequest/QueryParams.hs +++ b/src/PostgREST/ApiRequest/QueryParams.hs @@ -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 = diff --git a/src/PostgREST/ApiRequest/Types.hs b/src/PostgREST/ApiRequest/Types.hs index e1bdeea4d7..a53d008d42 100644 --- a/src/PostgREST/ApiRequest/Types.hs +++ b/src/PostgREST/ApiRequest/Types.hs @@ -5,7 +5,6 @@ module PostgREST.ApiRequest.Types , Cast , Depth , EmbedParam(..) - , ApiRequestError(..) , EmbedPath , Field , Filter(..) @@ -25,9 +24,6 @@ module PostgREST.ApiRequest.Types , OrderDirection(..) , OrderNulls(..) , OrderTerm(..) - , QPError(..) - , RaiseError(..) - , RangeError(..) , SingleVal , IsVal(..) , SimpleOperator(..) @@ -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 @@ -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 diff --git a/src/PostgREST/Error.hs b/src/PostgREST/Error.hs index 8f386a8000..d6eb992eca 100644 --- a/src/PostgREST/Error.hs +++ b/src/PostgREST/Error.hs @@ -8,6 +8,8 @@ Description : PostgREST error HTTP responses module PostgREST.Error ( errorResponseFor , ApiRequestError(..) + , QPError(..) + , RangeError(..) , PgError(..) , Error(..) , errorPayload @@ -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) @@ -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 + +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 + instance PgrstError ApiRequestError where status AggregatesNotAllowed{} = HTTP.status400 status AmbiguousRelBetween{} = HTTP.status300 diff --git a/src/PostgREST/Plan.hs b/src/PostgREST/Plan.hs index 23ca5aef94..b49e42114e 100644 --- a/src/PostgREST/Plan.hs +++ b/src/PostgREST/Plan.hs @@ -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, diff --git a/src/PostgREST/Query.hs b/src/PostgREST/Query.hs index 15ae7d6f84..f18d3b4922 100644 --- a/src/PostgREST/Query.hs +++ b/src/PostgREST/Query.hs @@ -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 @@ -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 @@ -251,14 +250,14 @@ 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 () @@ -266,7 +265,7 @@ 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 () diff --git a/src/PostgREST/Response.hs b/src/PostgREST/Response.hs index 68a68c4b8e..2666001de3 100644 --- a/src/PostgREST/Response.hs +++ b/src/PostgREST/Response.hs @@ -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) @@ -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 @@ -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 @@ -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 @@ -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{..} =