rqb 0.1.7

sqlx-first typed Postgres query builder.
Documentation
use super::*;

impl Renderer {
    pub(super) fn render_ctes(&mut self, ctes: &[Cte]) {
        if ctes.is_empty() {
            return;
        }
        self.sql.push_str(if ctes.iter().any(|cte| cte.recursive) {
            "WITH RECURSIVE "
        } else {
            "WITH "
        });
        for (idx, cte) in ctes.iter().enumerate() {
            if idx > 0 {
                self.sql.push_str(", ");
            }
            write_quoted_ident(&mut self.sql, &cte.name);
            if !cte.fields.is_empty() {
                self.render_paren_column_list(cte.fields.iter().map(|field| field.db));
            }
            self.sql.push_str(" AS");
            if let Some(materialization) = cte.materialization {
                self.sql.push(' ');
                self.sql.push_str(materialization.as_sql());
            }
            self.sql.push_str(" (");
            self.render_stmt(&cte.stmt);
            self.sql.push(')');
        }
        self.sql.push(' ');
    }

    fn render_paren_column_list<'a>(&mut self, columns: impl IntoIterator<Item = &'a str>) {
        self.sql.push_str(" (");
        for (column_idx, column) in columns.into_iter().enumerate() {
            if column_idx > 0 {
                self.sql.push_str(", ");
            }
            write_quoted_ident(&mut self.sql, column);
        }
        self.sql.push(')');
    }

    pub(super) fn render_source_fields(&mut self, source: &Source) {
        let mut rendered = 0usize;
        let qualifier = source.explicit_alias();
        source.for_each_field(|field| {
            if rendered > 0 {
                self.sql.push_str(", ");
            }
            self.render_field(field, qualifier);
            if field.api != field.db {
                self.sql.push_str(" AS ");
                write_quoted_ident(&mut self.sql, field.api);
            }
            rendered += 1;
        });
        if rendered == 0 {
            match source {
                Source::Table {
                    name, alias: None, ..
                }
                | Source::View {
                    name, alias: None, ..
                } => {
                    write_quoted_qualified(&mut self.sql, name);
                }
                Source::Table {
                    alias: Some(alias), ..
                }
                | Source::View {
                    alias: Some(alias), ..
                }
                | Source::Cte {
                    alias: Some(alias), ..
                }
                | Source::Subquery { alias, .. }
                | Source::Raw { alias, .. }
                | Source::Function { alias, .. }
                | Source::Values { alias, .. } => write_quoted_ident(&mut self.sql, alias),
                Source::Cte {
                    name, alias: None, ..
                } => write_quoted_ident(&mut self.sql, name),
            }
            self.sql.push('.');
            self.sql.push('*');
        }
    }

    pub(super) fn render_source(&mut self, source: &Source) {
        match source {
            Source::Table { name, alias, .. } | Source::View { name, alias, .. } => {
                write_quoted_qualified(&mut self.sql, name);
                self.render_optional_alias(alias.as_deref());
            }
            Source::Cte { name, alias, .. } => {
                write_quoted_ident(&mut self.sql, name);
                self.render_optional_alias(alias.as_deref());
            }
            Source::Subquery {
                stmt,
                alias,
                fields,
            } => {
                self.sql.push('(');
                self.render_stmt(stmt);
                self.sql.push_str(") AS ");
                write_quoted_ident(&mut self.sql, alias);
                if !fields.is_empty() {
                    self.render_paren_column_list(fields.iter().map(|field| field.db));
                }
            }
            Source::Raw {
                sql,
                alias,
                params,
                fields,
            } => {
                self.sql.push('(');
                self.render_raw(sql, params);
                self.sql.push_str(") AS ");
                write_quoted_ident(&mut self.sql, alias);
                if !fields.is_empty() {
                    self.render_paren_column_list(fields.iter().map(|field| field.db));
                }
            }
            Source::Function {
                name,
                args,
                alias,
                ordinality,
                fields,
                ..
            } => {
                self.render_call(name, args);
                if *ordinality {
                    self.sql.push_str(" WITH ORDINALITY");
                }
                self.sql.push_str(" AS ");
                write_quoted_ident(&mut self.sql, alias);
                if !fields.is_empty() {
                    self.render_paren_column_list(fields.iter().map(|field| field.db));
                }
            }
            Source::Values {
                rows,
                alias,
                fields,
            } => {
                self.sql.push_str("(VALUES ");
                for (row_idx, row) in rows.iter().enumerate() {
                    if row_idx > 0 {
                        self.sql.push_str(", ");
                    }
                    self.sql.push('(');
                    for (value_idx, value) in row.iter().enumerate() {
                        if value_idx > 0 {
                            self.sql.push_str(", ");
                        }
                        self.render_value(value);
                    }
                    self.sql.push(')');
                }
                self.sql.push_str(") AS ");
                write_quoted_ident(&mut self.sql, alias);
                if !fields.is_empty() {
                    self.render_paren_column_list(fields.iter().map(|field| field.db));
                }
            }
        }
    }

    pub(super) fn render_join(&mut self, join: &crate::source::Join) {
        self.sql.push(' ');
        self.sql.push_str(join.kind.as_sql());
        self.sql.push(' ');
        if join.lateral {
            self.sql.push_str("LATERAL ");
        }
        self.render_source(&join.source);
        if let Some(on) = &join.on {
            self.sql.push_str(" ON ");
            self.render_bool(on);
        }
    }

    pub(super) fn render_optional_alias(&mut self, alias: Option<&str>) {
        if let Some(alias) = alias {
            self.sql.push_str(" AS ");
            write_quoted_ident(&mut self.sql, alias);
        }
    }

    pub(super) fn render_write_target(&mut self, source: &Source) {
        match source {
            Source::Table { name, alias, .. } | Source::View { name, alias, .. } => {
                write_quoted_qualified(&mut self.sql, name);
                self.render_optional_alias(alias.as_deref());
            }
            Source::Cte { .. }
            | Source::Subquery { .. }
            | Source::Raw { .. }
            | Source::Function { .. }
            | Source::Values { .. } => {
                unreachable!("write target validated as table")
            }
        }
    }

    pub(super) fn render_field(&mut self, field: &crate::Meta, qualifier: Option<&str>) {
        if let Some(qualifier) = qualifier {
            write_quoted_ident(&mut self.sql, qualifier);
            self.sql.push('.');
        }
        write_quoted_ident(&mut self.sql, field.db);
    }
}