use super::*;
impl Select {
pub(crate) fn from(source: impl Into<Source>) -> Self {
Self {
ctes: Vec::new(),
source: source.into(),
joins: Vec::new(),
distinct: false,
distinct_on: Vec::new(),
projection: Vec::new(),
filter: None,
group_by: Vec::new(),
having: None,
order: Vec::new(),
row_limit: None,
offset: None,
lock: None,
}
}
#[inline]
pub fn with(mut self, cte: Cte) -> Self {
self.ctes.push(cte);
self
}
pub fn infer_source(self, alias: impl Into<String>) -> crate::Result<Source> {
let fields = self.inferred_source_fields()?;
Ok(subquery(self, alias, fields))
}
pub fn into_source(self, alias: impl Into<String>, fields: impl IntoFieldMetas) -> Source {
subquery(self, alias, fields)
}
pub fn infer_cte(self, name: impl Into<String>) -> crate::Result<Cte> {
let fields = self.inferred_source_fields()?;
Ok(cte(name, self, fields))
}
pub fn into_cte(self, name: impl Into<String>, fields: impl IntoFieldMetas) -> Cte {
cte(name, self, fields)
}
pub fn column(mut self, field: impl IntoColumn) -> Self {
let mut columns = ColumnList {
items: self.projection,
};
field.push_column(&mut columns);
self.projection = columns.items;
self
}
pub fn columns(mut self, fields: impl IntoColumns) -> Self {
self.projection.extend(fields.into_columns().items);
self
}
pub fn default_columns(mut self) -> Self {
let qualifier = self.source.explicit_alias();
self.source.for_each_field(|meta| {
self.projection
.push(select_item_for_source_meta(*meta, qualifier));
});
self
}
pub fn expr(mut self, expr: impl Into<ValueExpr>) -> Self {
self.projection.push(SelectItem {
expr: expr.into(),
alias: None,
});
self
}
pub fn expr_as(mut self, expr: impl Into<ValueExpr>, alias: impl Into<String>) -> Self {
self.projection.push(SelectItem {
expr: expr.into(),
alias: Some(alias.into()),
});
self
}
pub fn apply(self, f: impl FnOnce(Self) -> Self) -> Self {
f(self)
}
#[inline]
pub fn distinct(mut self) -> Self {
self.distinct = true;
self
}
pub fn distinct_on(mut self, expr: impl Into<ValueExpr>) -> Self {
self.distinct_on.push(expr.into());
self
}
pub fn join(mut self, source: impl Into<Source>, on: BoolExpr) -> Self {
self.joins.push(Join::new(JoinKind::Inner, source, on));
self
}
pub fn left_join(mut self, source: impl Into<Source>, on: BoolExpr) -> Self {
self.joins.push(Join::new(JoinKind::Left, source, on));
self
}
pub fn right_join(mut self, source: impl Into<Source>, on: BoolExpr) -> Self {
self.joins.push(Join::new(JoinKind::Right, source, on));
self
}
pub fn full_join(mut self, source: impl Into<Source>, on: BoolExpr) -> Self {
self.joins.push(Join::new(JoinKind::Full, source, on));
self
}
pub fn join_lateral(mut self, source: impl Into<Source>, on: BoolExpr) -> Self {
self.joins.push(Join::lateral(JoinKind::Inner, source, on));
self
}
pub fn left_join_lateral(mut self, source: impl Into<Source>, on: BoolExpr) -> Self {
self.joins.push(Join::lateral(JoinKind::Left, source, on));
self
}
pub fn cross_join(mut self, source: impl Into<Source>) -> Self {
self.joins.push(Join::cross(source));
self
}
pub fn cross_join_lateral(mut self, source: impl Into<Source>) -> Self {
self.joins.push(Join::cross_lateral(source));
self
}
#[inline]
pub fn order_by(mut self, item: OrderItem) -> Self {
self.order.push(item);
self
}
pub fn group_by(mut self, expr: impl Into<ValueExpr>) -> Self {
self.group_by.push(GroupByItem::expr(expr));
self
}
pub fn rollup<I, E>(mut self, exprs: I) -> Self
where
I: IntoIterator<Item = E>,
E: Into<ValueExpr>,
{
self.group_by
.push(GroupByItem::rollup(exprs.into_iter().map(Into::into)));
self
}
pub fn cube<I, E>(mut self, exprs: I) -> Self
where
I: IntoIterator<Item = E>,
E: Into<ValueExpr>,
{
self.group_by
.push(GroupByItem::cube(exprs.into_iter().map(Into::into)));
self
}
pub fn grouping_sets<I, S, E>(mut self, sets: I) -> Self
where
I: IntoIterator<Item = S>,
S: IntoIterator<Item = E>,
E: Into<ValueExpr>,
{
self.group_by.push(GroupByItem::grouping_sets(
sets.into_iter()
.map(|set| set.into_iter().map(Into::into).collect()),
));
self
}
#[inline]
pub fn having(mut self, having: BoolExpr) -> Self {
self.having = Some(BoolExpr::and_option(self.having, having));
self
}
pub fn order_asc(mut self, expr: impl Into<ValueExpr>) -> Self {
self.order.push(OrderItem::asc(expr));
self
}
pub fn order_desc(mut self, expr: impl Into<ValueExpr>) -> Self {
self.order.push(OrderItem::desc(expr));
self
}
pub fn order_asc_nulls_first(mut self, expr: impl Into<ValueExpr>) -> Self {
self.order.push(OrderItem::asc_nulls_first(expr));
self
}
pub fn order_asc_nulls_last(mut self, expr: impl Into<ValueExpr>) -> Self {
self.order.push(OrderItem::asc_nulls_last(expr));
self
}
pub fn order_desc_nulls_first(mut self, expr: impl Into<ValueExpr>) -> Self {
self.order.push(OrderItem::desc_nulls_first(expr));
self
}
pub fn order_desc_nulls_last(mut self, expr: impl Into<ValueExpr>) -> Self {
self.order.push(OrderItem::desc_nulls_last(expr));
self
}
#[inline]
pub fn limit(mut self, limit: u32) -> Self {
self.row_limit = Some(RowLimit::Limit(Param::typed(i64::from(limit))));
self
}
pub fn fetch_first(mut self, count: impl Into<ValueExpr>) -> Self {
self.row_limit = Some(RowLimit::Fetch(FetchClause {
count: count.into(),
with_ties: false,
}));
self
}
pub fn fetch_first_with_ties(mut self, count: impl Into<ValueExpr>) -> Self {
self.row_limit = Some(RowLimit::Fetch(FetchClause {
count: count.into(),
with_ties: true,
}));
self
}
#[inline]
pub fn offset(mut self, offset: u32) -> Self {
self.offset = Some(Param::typed(i64::from(offset)));
self
}
#[inline]
pub fn lock(mut self, mode: LockMode) -> Self {
self.lock.get_or_insert_with(|| RowLock::new(mode)).mode = mode;
self
}
pub fn lock_of(mut self, mode: LockMode, relation: impl Into<String>) -> Self {
let lock = self.lock.get_or_insert_with(|| RowLock::new(mode));
lock.mode = mode;
let relation = relation.into();
if !lock.of.contains(&relation) {
lock.of.push(relation);
}
self
}
#[inline]
pub fn for_update(self) -> Self {
self.lock(LockMode::Update)
}
pub fn for_update_of(self, relation: impl Into<String>) -> Self {
self.lock_of(LockMode::Update, relation)
}
#[inline]
pub fn for_no_key_update(self) -> Self {
self.lock(LockMode::NoKeyUpdate)
}
pub fn for_no_key_update_of(self, relation: impl Into<String>) -> Self {
self.lock_of(LockMode::NoKeyUpdate, relation)
}
#[inline]
pub fn for_share(self) -> Self {
self.lock(LockMode::Share)
}
pub fn for_share_of(self, relation: impl Into<String>) -> Self {
self.lock_of(LockMode::Share, relation)
}
#[inline]
pub fn for_key_share(self) -> Self {
self.lock(LockMode::KeyShare)
}
pub fn for_key_share_of(self, relation: impl Into<String>) -> Self {
self.lock_of(LockMode::KeyShare, relation)
}
#[inline]
pub fn nowait(mut self) -> Self {
self.lock = Some(self.lock.unwrap_or_default().nowait());
self
}
#[inline]
pub fn skip_locked(mut self) -> Self {
self.lock = Some(self.lock.unwrap_or_default().skip_locked());
self
}
pub(crate) fn inferred_source_fields(&self) -> crate::Result<Vec<Meta>> {
let mut fields = Vec::with_capacity(self.projection.len());
if self.projection.is_empty() {
self.source.for_each_field(|field| fields.push(*field));
}
for item in &self.projection {
let ValueExpr::Field { meta, qualifier } = &item.expr else {
return Err(crate::Error::InvalidSelectShape {
message: "infer_source cannot infer fields from computed projection; use into_source",
});
};
let generated_alias = field_ref_alias(meta, qualifier.as_deref());
if item
.alias
.as_deref()
.is_some_and(|alias| alias != meta.db && Some(alias) != generated_alias.as_deref())
{
return Err(crate::Error::InvalidSelectShape {
message: "infer_source cannot infer fields from aliased projection; use into_source",
});
}
fields.push(*meta);
}
for (index, field) in fields.iter().enumerate() {
if fields[..index]
.iter()
.any(|other| other.db == field.db || other.api == field.api)
{
return Err(crate::Error::InvalidSelectShape {
message: "inferred fields must have unique database and API names; use into_source or into_cte with distinct metadata",
});
}
}
Ok(fields)
}
}
impl_filter_methods!(Select);