Skip to content

Commit a9766ec

Browse files
authored
feat: support aggregation function helpers (#22)
1 parent a35f5f0 commit a9766ec

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

lib/supabase/postgrest/query_builder.ex

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,39 @@ defmodule Supabase.PostgREST.QueryBuilder do
182182
|> Request.with_headers(%{"prefer" => prefer})
183183
|> Request.with_body(data)
184184
end
185+
186+
# aggregation helpers
187+
188+
defguardp is_column(c) when is_binary(c) or is_atom(c)
189+
190+
@aggregators [:sum, :avg, :min, :max, :count]
191+
192+
for agg <- @aggregators do
193+
@doc """
194+
Hleper function to apply aggregation of #{agg} function to a specified
195+
column name. This should be used on `select/3`.
196+
197+
## Parameters
198+
- `column`: The `Supabase.Fetcher.Request` to use.
199+
- `opts.as`: If specifying more than one aggregate function for the same column, you may need to rename it, so you can pass an optional `:as` value for it.
200+
201+
## Examples
202+
iex> alias Supabase.PostgREST, as: Q
203+
iex> Q.select(builder, [Q.avg("amount")])
204+
205+
iex> alias Supabase.PostgREST, as: Q
206+
iex> Q.select(builder, [Q.avg("amount", as: "avg_amount"), Q.sum("amount", as: "total_amount")])
207+
208+
## See also
209+
- PostgREST official docs about aggregation functions: https://docs.postgrest.org/en/stable/references/api/aggregate_functions.html
210+
"""
211+
@impl true
212+
def unquote(agg)(column, opts \\ []) when is_column(column) do
213+
if as = Keyword.get(opts, :as) do
214+
"#{as}:#{column}.#{to_string(unquote(agg))}()"
215+
else
216+
"#{column}.#{to_string(unquote(agg))}()"
217+
end
218+
end
219+
end
185220
end

lib/supabase/postgrest/query_builder/behaviour.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ defmodule Supabase.PostgREST.QueryBuilder.Behaviour do
33

44
alias Supabase.Fetcher.Request
55

6+
@type column :: String.t() | atom
7+
@type agg_opt :: {:as, column}
68
@type options :: [count: :exact, returning: boolean | :representation]
79
@type insert_options :: [count: :exact, returning: boolean | :representation, on_conflict: any]
810

@@ -16,4 +18,11 @@ defmodule Supabase.PostgREST.QueryBuilder.Behaviour do
1618
@callback delete(Request.t(), options) :: Request.t()
1719
@callback update(Request.t(), map) :: Request.t()
1820
@callback update(Request.t(), map, options) :: Request.t()
21+
22+
# aggregate functions helpers
23+
@callback sum(column, list(agg_opt)) :: String.t()
24+
@callback max(column, list(agg_opt)) :: String.t()
25+
@callback min(column, list(agg_opt)) :: String.t()
26+
@callback avg(column, list(agg_opt)) :: String.t()
27+
@callback count(column, list(agg_opt)) :: String.t()
1928
end

test/supabase/postgrest/query_builder_test.exs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,27 @@ defmodule Supabase.PostgREST.QueryBuilderTest do
260260
assert is_list(body)
261261
end
262262
end
263+
264+
describe "select with aggregations" do
265+
test "it should support single column with aggregation", %{request: req} do
266+
result = QueryBuilder.select(req, [QueryBuilder.sum("amount")])
267+
assert {"select", "amount.sum()"} = List.keyfind(result.query, "select", 0)
268+
end
269+
270+
test "it should support multiple different column with aggregation", %{request: req} do
271+
result = QueryBuilder.select(req, [QueryBuilder.sum("amount"), QueryBuilder.avg("sales")])
272+
assert {"select", "amount.sum(),sales.avg()"} = List.keyfind(result.query, "select", 0)
273+
end
274+
275+
test "it should support multiple column with aggregation", %{request: req} do
276+
result =
277+
QueryBuilder.select(req, [
278+
QueryBuilder.sum("amount", as: "total_amount"),
279+
QueryBuilder.avg("amount", as: "avg_amount")
280+
])
281+
282+
assert {"select", "total_amount:amount.sum(),avg_amount:amount.avg()"} =
283+
List.keyfind(result.query, "select", 0)
284+
end
285+
end
263286
end

0 commit comments

Comments
 (0)