Skip to content

Commit

Permalink
Allow alias and hint for columns in query string
Browse files Browse the repository at this point in the history
  • Loading branch information
laurenceisla committed Apr 2, 2024
1 parent 89206b1 commit 15568e4
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 20 deletions.
12 changes: 6 additions & 6 deletions src/PostgREST/ApiRequest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import Web.Cookie (parseCookies)

import PostgREST.ApiRequest.QueryParams (QueryParams (..))
import PostgREST.ApiRequest.Types (ApiRequestError (..),
ColumnItem (..),
RangeError (..))
import PostgREST.Config (AppConfig (..),
OpenAPIMode (..))
Expand All @@ -55,8 +56,7 @@ import PostgREST.RangeQuery (NonnegRange, allRange,
hasLimitZero,
rangeRequested)
import PostgREST.SchemaCache (SchemaCache (..))
import PostgREST.SchemaCache.Identifiers (FieldName,
QualifiedIdentifier (..),
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..),
Schema)

import qualified PostgREST.ApiRequest.Preferences as Preferences
Expand Down Expand Up @@ -117,7 +117,7 @@ data ApiRequest = ApiRequest {
, iPayload :: Maybe Payload -- ^ Data sent by client and used for mutation actions
, iPreferences :: Preferences.Preferences -- ^ Prefer header values
, iQueryParams :: QueryParams.QueryParams
, iColumns :: S.Set (Tree FieldName) -- ^ parsed colums from &columns parameter and payload
, iColumns :: S.Set (Tree ColumnItem) -- ^ parsed colums from &columns parameter and payload

Check warning on line 120 in src/PostgREST/ApiRequest.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/ApiRequest.hs#L120

Added line #L120 was not covered by tests
, iHeaders :: [(ByteString, ByteString)] -- ^ HTTP request headers
, iCookies :: [(ByteString, ByteString)] -- ^ Request Cookies
, iPath :: ByteString -- ^ Raw request path
Expand Down Expand Up @@ -237,12 +237,12 @@ getRanges method QueryParams{qsOrder,qsRanges} hdrs
isInvalidRange = topLevelRange == emptyRange && not (hasLimitZero limitRange)
topLevelRange = fromMaybe allRange $ HM.lookup "limit" ranges -- if no limit is specified, get all the request rows

getPayload :: RequestBody -> MediaType -> QueryParams.QueryParams -> Action -> Either ApiRequestError (Maybe Payload, S.Set (Tree FieldName))
getPayload :: RequestBody -> MediaType -> QueryParams.QueryParams -> Action -> Either ApiRequestError (Maybe Payload, S.Set (Tree ColumnItem))
getPayload reqBody contentMediaType QueryParams{qsColumns} action = do
checkedPayload <- if shouldParsePayload then payload else Right Nothing
let cols = case (checkedPayload, columns) of
(Just ProcessedJSON{payKeys}, _) -> S.map (`Node` []) payKeys
(Just ProcessedUrlEncoded{payKeys}, _) -> S.map (`Node` []) payKeys
(Just ProcessedJSON{payKeys}, _) -> S.map ((`Node` []) . ColumnField) payKeys
(Just ProcessedUrlEncoded{payKeys}, _) -> S.map ((`Node` []) . ColumnField) payKeys
(Just RawJSON{}, Just cls) -> S.fromList cls
_ -> S.empty
return (checkedPayload, cols)
Expand Down
26 changes: 14 additions & 12 deletions src/PostgREST/ApiRequest/QueryParams.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ import PostgREST.RangeQuery (NonnegRange, allRange,
import PostgREST.SchemaCache.Identifiers (FieldName)

import PostgREST.ApiRequest.Types (AggregateFunction (..),
EmbedParam (..), EmbedPath, Field,
Filter (..), FtsOperator (..),
Hint, JoinType (..),
JsonOperand (..),
ColumnItem (..), EmbedParam (..),
EmbedPath, Field, Filter (..),
FtsOperator (..), Hint,
JoinType (..), JsonOperand (..),
JsonOperation (..), JsonPath,
ListVal, LogicOperator (..),
LogicTree (..), OpExpr (..),
Expand All @@ -73,7 +73,7 @@ data QueryParams =
-- ^ &order parameters for each level
, qsLogic :: [(EmbedPath, LogicTree)]
-- ^ &and and &or parameters used for complex boolean logic
, qsColumns :: Maybe [Tree FieldName]
, qsColumns :: Maybe [Tree ColumnItem]

Check warning on line 76 in src/PostgREST/ApiRequest/QueryParams.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/ApiRequest/QueryParams.hs#L76

Added line #L76 was not covered by tests
-- ^ &columns parameter and payload
, qsSelect :: [Tree SelectItem]
-- ^ &select parameter used to shape the response
Expand Down Expand Up @@ -261,8 +261,8 @@ pRequestLogicTree (k, v) = mapError $ (,) <$> embedPath <*> logicTree
P.parse pLogicTree ("failed to parse logic tree (" ++ toS v ++ ")") $ toS (op <> v)


-- Satisfies the form: /products?columns=name,suppliers(name)
pRequestColumns :: Maybe Text -> Either QPError (Maybe [Tree FieldName])
-- Satisfies the form: /products?columns=name,sup:suppliers!fk(name)
pRequestColumns :: Maybe Text -> Either QPError (Maybe [Tree ColumnItem])
pRequestColumns colStr =
case colStr of
Just str ->
Expand Down Expand Up @@ -479,11 +479,13 @@ pRelationSelect = lexeme $ do
try (void $ lookAhead (string "("))
return $ SelectRelation name alias hint jType

pRelationColumn :: Parser FieldName
pRelationColumn :: Parser ColumnItem
pRelationColumn = lexeme $ do
alias <- optionMaybe ( try(pFieldName <* aliasSeparator) )
name <- pFieldName
(hint, _) <- pEmbedParams
try (void $ lookAhead (string "("))
return name
return $ ColumnRelation name alias hint

Check warning on line 488 in src/PostgREST/ApiRequest/QueryParams.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/ApiRequest/QueryParams.hs#L488

Added line #L488 was not covered by tests

-- |
-- Parse regular fields in select
Expand Down Expand Up @@ -852,17 +854,17 @@ pLogicPath = do
pColumns :: Parser [FieldName]
pColumns = pFieldName `sepBy1` lexeme (char ',')

pColumnForest :: Parser [Tree FieldName]
pColumnForest :: Parser [Tree ColumnItem]
pColumnForest = pColumnTree `sepBy1` lexeme (char ',')
where
pColumnTree = Node <$> try pRelationColumn <*> between (char '(') (char ')') pColumnForest <|>
Node <$> pColumnName <*> pure []

pColumnName :: Parser FieldName
pColumnName :: Parser ColumnItem
pColumnName = lexeme $ do
fld <- pFieldName
pEnd
return fld
return $ ColumnField fld
where
pEnd = try (void $ lookAhead (string ")")) <|>
try (void $ lookAhead (string ",")) <|>
Expand Down
10 changes: 10 additions & 0 deletions src/PostgREST/ApiRequest/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module PostgREST.ApiRequest.Types
, QuantOperator(..)
, FtsOperator(..)
, SelectItem(..)
, ColumnItem(..)
) where

import PostgREST.MediaType (MediaType (..))
Expand Down Expand Up @@ -67,6 +68,15 @@ data SelectItem
}
deriving (Eq, Show)

data ColumnItem
= ColumnField FieldName
| ColumnRelation
{ colRelation :: FieldName
, colAlias :: Maybe Alias
, colHint :: Maybe Hint

Check warning on line 76 in src/PostgREST/ApiRequest/Types.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/ApiRequest/Types.hs#L74-L76

Added lines #L74 - L76 were not covered by tests
}
deriving (Eq, Show, Ord)

data ApiRequestError
= AggregatesNotAllowed
| AmbiguousRelBetween Text Text [Relationship]
Expand Down
10 changes: 8 additions & 2 deletions src/PostgREST/Plan.hs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ callReadPlan :: QualifiedIdentifier -> AppConfig -> SchemaCache -> ApiRequest ->
callReadPlan identifier conf sCache apiRequest@ApiRequest{iPreferences=Preferences{..},..} invMethod = do
let paramKeys = case invMethod of
InvRead _ -> S.fromList $ fst <$> qsParams'
Inv -> S.map rootLabel iColumns
Inv -> S.map (getColumnAsText . rootLabel) iColumns
proc@Function{..} <- mapLeft ApiRequestError $
findProc identifier paramKeys (preferParameters == Just SingleObject) (dbRoutines sCache) iContentMediaType (invMethod == Inv)
let relIdentifier = QualifiedIdentifier pdSchema (fromMaybe pdName $ Routine.funcTableName proc) -- done so a set returning function can embed other relations
Expand Down Expand Up @@ -923,7 +923,7 @@ mutatePlan mutation qi ApiRequest{iPreferences=Preferences{..}, ..} SchemaCache{
combinedLogic = foldr (addFilterToLogicForest . resolveFilter ctx) logic qsFiltersRoot
body = payRaw <$> iPayload -- the body is assumed to be json at this stage(ApiRequest validates)
applyDefaults = preferMissing == Just ApplyDefaults
typedColumnsOrError = resolveOrError ctx tbl `traverse` S.toList (S.map rootLabel iColumns)
typedColumnsOrError = resolveOrError ctx tbl `traverse` S.toList (S.map (getColumnAsText . rootLabel) iColumns)

resolveOrError :: ResolverContext -> Maybe Table -> FieldName -> Either ApiRequestError CoercibleField
resolveOrError _ Nothing _ = Left NotFound
Expand Down Expand Up @@ -1032,3 +1032,9 @@ negotiateContent conf ApiRequest{iAction=act, iPreferences=Preferences{preferRep
when' :: Bool -> Maybe a -> Maybe a
when' True (Just a) = Just a
when' _ _ = Nothing

getColumnAsText :: ColumnItem -> Text
getColumnAsText colItem =
case colItem of
ColumnField col -> col
ColumnRelation{colRelation} -> colRelation

Check warning on line 1040 in src/PostgREST/Plan.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/Plan.hs#L1040

Added line #L1040 was not covered by tests

0 comments on commit 15568e4

Please sign in to comment.