mod from;
pub use from::*;
mod group;
pub use group::*;
mod order;
pub use order::*;
mod project;
pub use project::*;
mod query;
pub use query::*;
mod join;
pub use join::*;
mod having;
pub use having::*;
mod filter;
pub use filter::*;
use crate::{
HasDialect, TypeMeta,
alias::Aliased,
cte::{Cte, IntoCtes},
emitter::Emitter,
expression::Scalar,
lower::LowerCtx,
};
#[derive(Debug, Clone, Copy)]
pub struct Select<P> {
project: P,
}
#[derive(Debug, Clone)]
pub struct WithSelect<P> {
project: P,
ctes: Vec<Cte>,
}
impl<P: LowerProject> Select<P> {
pub fn from<F>(self, v: F) -> Query
where
F: LowerFrom,
{
Query::from(v).select(self.project)
}
pub fn into_query(self) -> Query {
let mut query = Query::default();
let mut ctx = LowerCtx {
instrs: &mut query.project,
params: &mut query.params,
data: &mut query.data,
};
self.project.lower_project(&mut ctx);
query
}
pub fn scalar<T: TypeMeta>(self) -> Scalar<T> {
Scalar {
inner: self.into_query(),
marker: std::marker::PhantomData,
}
}
pub fn with<C>(self, ctes: C) -> WithSelect<P>
where
C: IntoCtes,
{
let ctes = ctes.into_ctes(false);
WithSelect {
project: self.project,
ctes,
}
}
pub fn with_recursive<C>(self, ctes: C) -> WithSelect<P>
where
C: IntoCtes,
{
let ctes = ctes.into_ctes(true);
WithSelect {
project: self.project,
ctes,
}
}
pub fn into_sql<D: HasDialect>(self) -> String {
let mut buf = String::new();
let mut directives = Vec::new();
let mut params = Vec::new();
let query = self.into_query();
let mut emitter = Emitter::new(
&mut buf,
&query.data,
D::DIALECT,
&mut directives,
&mut params,
);
emitter.emit_query(&query).unwrap();
buf
}
}
impl<P: LowerProject> WithSelect<P> {
pub fn with<C>(mut self, ctes: C) -> Self
where
C: IntoCtes,
{
self.ctes.extend(ctes.into_ctes(false));
self
}
pub fn with_recursive<C>(mut self, ctes: C) -> Self
where
C: IntoCtes,
{
self.ctes.extend(ctes.into_ctes(true));
self
}
pub fn from<F>(self, v: F) -> Query
where
F: LowerFrom,
{
Query::from(v).select(self.project).with_many(self.ctes)
}
pub fn into_query(self) -> Query {
let mut query = Query::default();
let mut ctx = LowerCtx {
instrs: &mut query.project,
params: &mut query.params,
data: &mut query.data,
};
self.project.lower_project(&mut ctx);
query.with_many(self.ctes)
}
pub fn scalar<T: TypeMeta>(self) -> Scalar<T> {
Scalar {
inner: self.into_query(),
marker: std::marker::PhantomData,
}
}
pub fn into_sql<D: HasDialect>(self) -> String {
self.into_query().to_sql::<D>()
}
}
pub fn select<P>(project: P) -> Select<P>
where
P: LowerProject,
{
Select { project }
}
pub fn select_all() -> Select<Star> {
Select { project: star() }
}
impl<P: LowerProject> LowerProject for Select<P> {
fn lower_project(self, ctx: &mut LowerCtx) {
let query = self.into_query();
let _ = ctx.lower_subquery_ref(&query);
}
}
impl<P: LowerProject> LowerProject for Aliased<Select<P>> {
fn lower_project(self, ctx: &mut LowerCtx) {
let query = self.inner.into_query();
let inner = ctx.lower_subquery_ref(&query);
let _ = ctx.lower_alias(self.alias, inner);
}
}