rqb 0.1.7

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

impl Renderer {
    pub(super) fn render_insert(&mut self, insert: &Insert) {
        self.render_ctes(&insert.ctes);
        self.sql.push_str("INSERT INTO ");
        self.render_write_target(&insert.target);
        match &insert.body {
            InsertBody::DefaultValues => self.sql.push_str(" DEFAULT VALUES"),
            InsertBody::Values(assignments) => {
                self.sql.push(' ');
                self.render_parenthesized_idents(
                    assignments.iter().map(|assignment| assignment.field.db),
                );
                self.sql.push_str(" VALUES (");
                for (idx, assignment) in assignments.iter().enumerate() {
                    if idx > 0 {
                        self.sql.push_str(", ");
                    }
                    self.render_assignment_value(&assignment.value);
                }
                self.sql.push(')');
            }
            InsertBody::Select { columns, select } => {
                self.sql.push(' ');
                self.render_parenthesized_idents(columns.iter().map(|field| field.db));
                self.sql.push(' ');
                self.render_select(select);
            }
        }
        if let Some(conflict) = &insert.conflict {
            self.render_conflict(conflict);
        }
        self.render_returning(&insert.returning);
    }

    pub(super) fn render_update(&mut self, update: &crate::Update) {
        self.render_ctes(&update.ctes);
        self.sql.push_str("UPDATE ");
        self.render_write_target(&update.target);
        self.sql.push_str(" SET ");
        self.render_assignments(&update.assignments);
        self.render_update_from(&update.from);
        if let Some(filter) = &update.filter {
            self.sql.push_str(" WHERE ");
            self.render_bool(filter);
        }
        self.render_returning(&update.returning);
    }

    pub(super) fn render_delete(&mut self, delete: &Delete) {
        self.render_ctes(&delete.ctes);
        self.sql.push_str("DELETE FROM ");
        self.render_write_target(&delete.target);
        self.render_delete_using(&delete.using);
        if let Some(filter) = &delete.filter {
            self.sql.push_str(" WHERE ");
            self.render_bool(filter);
        }
        self.render_returning(&delete.returning);
    }

    pub(super) fn render_merge(&mut self, merge: &Merge) {
        self.render_ctes(&merge.ctes);
        self.sql.push_str("MERGE INTO ");
        self.render_write_target(&merge.target);
        self.sql.push_str(" USING ");
        self.render_source(&merge.using);
        self.sql.push_str(" ON ");
        self.render_bool(&merge.on);
        for action in &merge.actions {
            self.render_merge_action(action);
        }
        self.render_returning(&merge.returning);
    }

    pub(super) fn render_merge_action(&mut self, action: &MergeAction) {
        match action {
            MergeAction::DoNothing { when, condition } => {
                self.render_merge_when(*when, condition.as_deref());
                self.sql.push_str(" THEN DO NOTHING");
            }
            MergeAction::Insert {
                when,
                condition,
                assignments,
            } => {
                self.render_merge_when(*when, condition.as_deref());
                self.sql.push_str(" THEN INSERT ");
                self.render_parenthesized_idents(
                    assignments.iter().map(|assignment| assignment.field.db),
                );
                self.sql.push_str(" VALUES (");
                for (idx, assignment) in assignments.iter().enumerate() {
                    if idx > 0 {
                        self.sql.push_str(", ");
                    }
                    self.render_assignment_value(&assignment.value);
                }
                self.sql.push(')');
            }
            MergeAction::Update {
                when,
                condition,
                assignments,
            } => {
                self.render_merge_when(*when, condition.as_deref());
                self.sql.push_str(" THEN UPDATE SET ");
                self.render_assignments(assignments)
            }
            MergeAction::Delete { when, condition } => {
                self.render_merge_when(*when, condition.as_deref());
                self.sql.push_str(" THEN DELETE");
            }
        }
    }

    pub(super) fn render_merge_when(&mut self, when: MergeWhen, condition: Option<&BoolExpr>) {
        self.sql.push_str(" WHEN ");
        self.sql.push_str(when.as_sql());
        if let Some(condition) = condition {
            self.sql.push_str(" AND ");
            self.render_bool(condition);
        }
    }

    pub(super) fn render_update_from(&mut self, sources: &[Source]) {
        if sources.is_empty() {
            return;
        }
        self.sql.push_str(" FROM ");
        self.render_source_list(sources)
    }

    pub(super) fn render_delete_using(&mut self, sources: &[Source]) {
        if sources.is_empty() {
            return;
        }
        self.sql.push_str(" USING ");
        self.render_source_list(sources)
    }

    pub(super) fn render_source_list(&mut self, sources: &[Source]) {
        for (idx, source) in sources.iter().enumerate() {
            if idx > 0 {
                self.sql.push_str(", ");
            }
            self.render_source(source);
        }
    }
    pub(super) fn render_assignments(&mut self, assignments: &[Assignment]) {
        for (idx, assignment) in assignments.iter().enumerate() {
            if idx > 0 {
                self.sql.push_str(", ");
            }
            write_quoted_ident(&mut self.sql, assignment.field.db);
            self.sql.push_str(" = ");
            self.render_assignment_value(&assignment.value);
        }
    }

    pub(super) fn render_assignment_value(&mut self, value: &AssignmentValue) {
        match value {
            AssignmentValue::Expr(expr) => self.render_value(expr),
            AssignmentValue::Default => {
                self.sql.push_str("DEFAULT");
            }
        }
    }

    pub(super) fn render_returning(&mut self, returning: &[SelectItem]) {
        if returning.is_empty() {
            return;
        }
        self.sql.push_str(" RETURNING ");
        for (idx, item) in returning.iter().enumerate() {
            if idx > 0 {
                self.sql.push_str(", ");
            }
            self.render_select_item(item);
        }
    }

    pub(super) fn render_conflict(&mut self, conflict: &ConflictClause) {
        self.sql.push_str(" ON CONFLICT ");
        match &conflict.target {
            ConflictTarget::Columns { fields, predicate } => {
                self.render_parenthesized_idents(fields.iter().map(|field| field.db));
                if let Some(predicate) = predicate {
                    self.sql.push_str(" WHERE ");
                    self.render_bool(predicate);
                }
            }
            ConflictTarget::Constraint(constraint) => {
                self.sql.push_str("ON CONSTRAINT ");
                write_quoted_ident(&mut self.sql, constraint);
            }
        }
        match &conflict.action {
            ConflictAction::DoNothing => {
                self.sql.push_str(" DO NOTHING");
            }
            ConflictAction::DoUpdate {
                assignments,
                filter,
            } => {
                self.sql.push_str(" DO UPDATE SET ");
                self.render_assignments(assignments);
                if let Some(filter) = filter {
                    self.sql.push_str(" WHERE ");
                    self.render_bool(filter);
                }
            }
        }
    }

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