Skip to content

Commit

Permalink
Add support for COUNT
Browse files Browse the repository at this point in the history
  • Loading branch information
timabdulla committed Sep 12, 2023
1 parent 4962bef commit f10c2c9
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 12 deletions.
18 changes: 13 additions & 5 deletions src/PostgREST/ApiRequest/QueryParams.hs
Original file line number Diff line number Diff line change
Expand Up @@ -453,10 +453,12 @@ pRelationSelect :: Parser SelectItem
pRelationSelect = lexeme $ do
alias <- optionMaybe ( try(pFieldName <* aliasSeparator) )
name <- pFieldName
guard (name /= "count")
(hint, jType) <- pEmbedParams
try (void $ lookAhead (string "("))
return $ SelectRelation name alias hint jType


-- |
-- Parse regular fields in select
--
Expand Down Expand Up @@ -497,11 +499,16 @@ pFieldSelect = lexeme $ try (do
s <- pStar
pEnd
return $ SelectField (s, []) Nothing Nothing Nothing)
<|> try (do
alias <- optionMaybe ( try(pFieldName <* aliasSeparator) )
_ <- string "count()"
pEnd
return $ SelectField ("*", []) (Just Count) Nothing alias)
<|> do
alias <- optionMaybe ( try(pFieldName <* aliasSeparator) )
fld <- pField
agg <- optionMaybe (try (char '.' *> pAggregation <* string "()"))
cast' <- optionMaybe (string "::" *> pIdentifier)
agg <- optionMaybe (try (char '.' *> pAggregation <* string "()"))
pEnd
return $ SelectField fld agg (toS <$> cast') alias
where
Expand All @@ -510,10 +517,11 @@ pFieldSelect = lexeme $ try (do
try eof
pStar = string "*" $> "*"
pAggregation = choice
[ string "sum" $> Sum
, string "avg" $> Avg
, string "max" $> Max
, string "min" $> Min
[ string "sum" $> Sum
, string "avg" $> Avg
, string "max" $> Max
, string "min" $> Min
, string "count" $> Count
]


Expand Down
2 changes: 1 addition & 1 deletion src/PostgREST/ApiRequest/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ type Cast = Text
type Alias = Text
type Hint = Text

data AggregateFunction = Sum | Avg | Max | Min
data AggregateFunction = Sum | Avg | Max | Min | Count
deriving (Show, Eq)

data EmbedParam
Expand Down
13 changes: 7 additions & 6 deletions src/PostgREST/Query/SqlFragment.hs
Original file line number Diff line number Diff line change
Expand Up @@ -263,19 +263,20 @@ pgFmtCoerceNamed CoercibleField{cfName=fn, cfTransform=(Just formatterProc)} = p
pgFmtCoerceNamed CoercibleField{cfName=fn} = pgFmtIdent fn

pgFmtSelectItem :: QualifiedIdentifier -> (CoercibleField, Maybe AggregateFunction, Maybe Cast, Maybe Alias) -> SQL.Snippet
pgFmtSelectItem table (fld, agg, Nothing, alias) = pgFmtApplyAggregate agg (pgFmtTableCoerce table fld <> pgFmtAs (cfName fld) (cfJsonPath fld) alias)
pgFmtSelectItem table (fld, agg, Nothing, alias) = pgFmtApplyAggregate agg (pgFmtTableCoerce table fld) <> pgFmtAs (cfName fld) (cfJsonPath fld) alias
-- Ideally we'd quote the cast with "pgFmtIdent cast". However, that would invalidate common casts such as "int", "bigint", etc.
-- Try doing: `select 1::"bigint"` - it'll err, using "int8" will work though. There's some parser magic that pg does that's invalidated when quoting.
-- Not quoting should be fine, we validate the input on Parsers.
pgFmtSelectItem table (fld, agg, Just cast, alias) = "CAST (" <> pgFmtTableCoerce table fld <> " AS " <> SQL.sql (encodeUtf8 cast) <> " )" <> pgFmtApplyAggregate agg (pgFmtAs (cfName fld) (cfJsonPath fld) alias)
pgFmtSelectItem table (fld, agg, Just cast, alias) = pgFmtApplyAggregate agg ("CAST (" <> pgFmtTableCoerce table fld <> " AS " <> SQL.sql (encodeUtf8 cast) <> " )") <> pgFmtAs (cfName fld) (cfJsonPath fld) alias

pgFmtApplyAggregate :: Maybe AggregateFunction -> SQL.Snippet -> SQL.Snippet
pgFmtApplyAggregate Nothing snippet = snippet
pgFmtApplyAggregate (Just agg) snippet = case agg of
Sum -> "SUM(" <> snippet <> ")"
Max -> "MAX(" <> snippet <> ")"
Min -> "MIN(" <> snippet <> ")"
Avg -> "AVG(" <> snippet <> ")"
Sum -> "SUM( " <> snippet <> " )"
Max -> "MAX( " <> snippet <> " )"
Min -> "MIN( " <> snippet <> " )"
Avg -> "AVG( " <> snippet <> " )"
Count -> "COUNT( " <> snippet <> " )"

-- TODO: At this stage there shouldn't be a Maybe since ApiRequest should ensure that an INSERT/UPDATE has a body
fromJsonBodyF :: Maybe LBS.ByteString -> [CoercibleField] -> Bool -> Bool -> Bool -> SQL.Snippet
Expand Down

0 comments on commit f10c2c9

Please sign in to comment.