use crate::{Field, FieldRef, Meta, OrderItem, ValueExpr};
pub fn aggregate(
name: &'static str,
args: impl IntoIterator<Item = impl Into<ValueExpr>>,
distinct: bool,
) -> ValueExpr {
ValueExpr::aggregate(
name,
args.into_iter().map(Into::into).collect(),
distinct,
Vec::new(),
None,
None,
)
}
pub fn ordered_set_aggregate(
name: &'static str,
args: impl IntoIterator<Item = impl Into<ValueExpr>>,
within_group: impl IntoIterator<Item = OrderItem>,
) -> ValueExpr {
ValueExpr::ordered_set_aggregate(
name,
args.into_iter().map(Into::into).collect(),
within_group.into_iter().collect(),
None,
)
}
macro_rules! aggregate_fn {
($(#[$meta:meta])* $fn:ident => $name:literal) => {
$(#[$meta])*
pub fn $fn(expr: impl Into<ValueExpr>) -> ValueExpr {
aggregate($name, [expr], false)
}
};
($(#[$meta:meta])* $fn:ident => distinct $name:literal) => {
$(#[$meta])*
pub fn $fn(expr: impl Into<ValueExpr>) -> ValueExpr {
aggregate($name, [expr], true)
}
};
}
aggregate_fn!( count => "count");
pub fn count_all() -> ValueExpr {
aggregate("count", Vec::<ValueExpr>::new(), false)
}
aggregate_fn!( count_distinct => distinct "count");
aggregate_fn!( sum => "sum");
aggregate_fn!( sum_distinct => distinct "sum");
aggregate_fn!( avg => "avg");
aggregate_fn!( avg_distinct => distinct "avg");
aggregate_fn!( min => "min");
aggregate_fn!( max => "max");
aggregate_fn!( array_agg => "array_agg");
aggregate_fn!( array_agg_distinct => distinct "array_agg");
aggregate_fn!( json_agg => "json_agg");
aggregate_fn!( json_agg_strict => "json_agg_strict");
aggregate_fn!( jsonb_agg => "jsonb_agg");
aggregate_fn!( jsonb_agg_strict => "jsonb_agg_strict");
pub fn jsonb_agg_object<T>(items: impl IntoIterator<Item = T>) -> ValueExpr
where
T: JsonbObjectItem,
{
__jsonb_agg_object_from_pairs(
items
.into_iter()
.map(JsonbObjectItem::into_jsonb_object_pair),
)
}
#[doc(hidden)]
pub fn __jsonb_agg_object_from_pairs(
items: impl IntoIterator<Item = (String, ValueExpr)>,
) -> ValueExpr {
aggregate(
"jsonb_agg",
[ValueExpr::function(
"jsonb_build_object",
items
.into_iter()
.flat_map(|(key, expr)| [ValueExpr::from(key), expr])
.collect(),
)],
false,
)
}
#[doc(hidden)]
pub fn __jsonb_object_pair(item: impl JsonbObjectItem) -> (String, ValueExpr) {
item.into_jsonb_object_pair()
}
#[doc(hidden)]
pub trait JsonbObjectItem {
fn into_jsonb_object_pair(self) -> (String, ValueExpr);
}
impl<T> JsonbObjectItem for Field<T> {
fn into_jsonb_object_pair(self) -> (String, ValueExpr) {
(self.meta.api.to_owned(), self.expr())
}
}
impl<T> JsonbObjectItem for FieldRef<T> {
fn into_jsonb_object_pair(self) -> (String, ValueExpr) {
(self.meta.api.to_owned(), self.expr())
}
}
impl JsonbObjectItem for Meta {
fn into_jsonb_object_pair(self) -> (String, ValueExpr) {
(self.api.to_owned(), self.expr())
}
}
impl JsonbObjectItem for &Meta {
fn into_jsonb_object_pair(self) -> (String, ValueExpr) {
(self.api.to_owned(), self.expr())
}
}
impl<V> JsonbObjectItem for (&str, V)
where
V: Into<ValueExpr>,
{
fn into_jsonb_object_pair(self) -> (String, ValueExpr) {
(self.0.to_owned(), self.1.into())
}
}
impl<V> JsonbObjectItem for (String, V)
where
V: Into<ValueExpr>,
{
fn into_jsonb_object_pair(self) -> (String, ValueExpr) {
(self.0, self.1.into())
}
}
pub fn string_agg(expr: impl Into<ValueExpr>, delimiter: impl Into<ValueExpr>) -> ValueExpr {
aggregate("string_agg", [expr.into(), delimiter.into()], false)
}
pub fn json_object_agg(key: impl Into<ValueExpr>, value: impl Into<ValueExpr>) -> ValueExpr {
aggregate("json_object_agg", [key.into(), value.into()], false)
}
pub fn jsonb_object_agg(key: impl Into<ValueExpr>, value: impl Into<ValueExpr>) -> ValueExpr {
aggregate("jsonb_object_agg", [key.into(), value.into()], false)
}
pub fn json_object_agg_strict(key: impl Into<ValueExpr>, value: impl Into<ValueExpr>) -> ValueExpr {
aggregate("json_object_agg_strict", [key.into(), value.into()], false)
}
pub fn jsonb_object_agg_strict(
key: impl Into<ValueExpr>,
value: impl Into<ValueExpr>,
) -> ValueExpr {
aggregate("jsonb_object_agg_strict", [key.into(), value.into()], false)
}
pub fn json_object_agg_unique(key: impl Into<ValueExpr>, value: impl Into<ValueExpr>) -> ValueExpr {
aggregate("json_object_agg_unique", [key.into(), value.into()], false)
}
pub fn jsonb_object_agg_unique(
key: impl Into<ValueExpr>,
value: impl Into<ValueExpr>,
) -> ValueExpr {
aggregate("jsonb_object_agg_unique", [key.into(), value.into()], false)
}
pub fn json_object_agg_unique_strict(
key: impl Into<ValueExpr>,
value: impl Into<ValueExpr>,
) -> ValueExpr {
aggregate(
"json_object_agg_unique_strict",
[key.into(), value.into()],
false,
)
}
pub fn jsonb_object_agg_unique_strict(
key: impl Into<ValueExpr>,
value: impl Into<ValueExpr>,
) -> ValueExpr {
aggregate(
"jsonb_object_agg_unique_strict",
[key.into(), value.into()],
false,
)
}
aggregate_fn!( bool_and => "bool_and");
aggregate_fn!( bool_or => "bool_or");
aggregate_fn!( every => "every");
aggregate_fn!( any_value => "any_value");
aggregate_fn!( bit_and => "bit_and");
aggregate_fn!( bit_or => "bit_or");
aggregate_fn!( bit_xor => "bit_xor");
aggregate_fn!( range_agg => "range_agg");
aggregate_fn!( range_intersect_agg => "range_intersect_agg");
aggregate_fn!( stddev => "stddev");
aggregate_fn!( stddev_pop => "stddev_pop");
aggregate_fn!( stddev_samp => "stddev_samp");
aggregate_fn!( variance => "variance");
aggregate_fn!( var_pop => "var_pop");
aggregate_fn!( var_samp => "var_samp");
pub fn percentile_cont(
fraction: impl Into<ValueExpr>,
order_by: impl Into<ValueExpr>,
) -> ValueExpr {
ordered_set_aggregate("percentile_cont", [fraction], [OrderItem::asc(order_by)])
}
pub fn percentile_disc(
fraction: impl Into<ValueExpr>,
order_by: impl Into<ValueExpr>,
) -> ValueExpr {
ordered_set_aggregate("percentile_disc", [fraction], [OrderItem::asc(order_by)])
}
pub fn mode(order_by: impl Into<ValueExpr>) -> ValueExpr {
ordered_set_aggregate("mode", Vec::<ValueExpr>::new(), [OrderItem::asc(order_by)])
}
pub fn grouping(args: impl IntoIterator<Item = impl Into<ValueExpr>>) -> ValueExpr {
ValueExpr::function("GROUPING", args.into_iter().map(Into::into).collect())
}