Skip to main content

keelson_mysql/statement/
replace.rs

1use keelson_core::clause::{HasSet, HasTableRef, HasValues, Set, TableRef, Values};
2use keelson_core::expr::{Expr, IntoExpr, IntoExprList};
3use keelson_core::{Dialect, Error, Expression, Mod, Query, QueryExtensions, QueryType, SqlWriter};
4
5use super::insert::write_target_and_row_source;
6use super::write_hints_and_modifiers;
7use crate::Mysql;
8use crate::extras::{HasHints, HasModifiers, Hints, Modifiers};
9
10/// A MySQL `REPLACE`.
11///
12/// From <https://dev.mysql.com/doc/refman/8.4/en/replace.html>:
13///
14/// ```text
15/// REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name
16///     [PARTITION (partition_name [, partition_name] ...)]
17///     [(col_name [, col_name] ...)]
18///     { {VALUES | VALUE} (value_list) [, (value_list)] ...
19///     | SET assignment_list
20///     | [(col_name [, col_name] ...)] SELECT ... }
21/// ```
22///
23/// A statement type of its own rather than a flag on
24/// [`InsertQuery`](super::InsertQuery), because the differences are exactly the
25/// things a flag would leave reachable: `REPLACE` has **no `HIGH_PRIORITY`**, **no
26/// `IGNORE`**, **no row alias** and **no `ON DUPLICATE KEY UPDATE`** — the last two
27/// being meaningless when a duplicate key is what the statement is for. Not
28/// implementing the traits is how that is said, so `replace::ignore()` and
29/// `replace::on_duplicate_key_update(..)` simply do not exist.
30///
31/// Its [`query_type`](Query::query_type) is [`QueryType::Insert`]: `REPLACE` is a
32/// `DELETE`-then-`INSERT`, and the layers above care only that it writes rows.
33#[derive(Debug, Clone, Default)]
34pub struct ReplaceQuery {
35    /// `/*+ … */`.
36    pub hints: Hints,
37    /// `LOW_PRIORITY` or `DELAYED`, and nothing else.
38    pub modifiers: Modifiers,
39    /// The target: table, partitions, and the column list.
40    pub table: TableRef,
41    /// The rows, or the query to insert the results of.
42    pub values: Values,
43    /// `SET a = 1, b = 2`, the assignment-list row source.
44    pub set: Set,
45}
46
47impl ReplaceQuery {
48    /// A `REPLACE` with nothing set yet.
49    pub fn new() -> ReplaceQuery {
50        ReplaceQuery::default()
51    }
52
53    /// Apply more mods to an existing query.
54    pub fn apply(&mut self, mods: impl Mod<ReplaceQuery>) {
55        mods.apply(self);
56    }
57}
58
59impl Expression for ReplaceQuery {
60    fn write_sql(&self, w: &mut SqlWriter<'_>) {
61        if self.table.is_empty() {
62            w.record_error(Error::Incomplete("the target table of a REPLACE"));
63            return;
64        }
65
66        w.push_str("REPLACE ");
67        write_hints_and_modifiers(w, &self.hints, &self.modifiers);
68        w.push_str("INTO ");
69        write_target_and_row_source(w, &self.table, &self.set, &self.values);
70    }
71}
72
73impl Query for ReplaceQuery {
74    fn query_type(&self) -> QueryType {
75        QueryType::Insert
76    }
77
78    fn dialect(&self) -> &dyn Dialect {
79        &Mysql
80    }
81}
82
83impl<H, L, M> QueryExtensions<H, L, M> for ReplaceQuery {}
84
85impl IntoExpr for ReplaceQuery {
86    fn into_expr(self) -> Expr {
87        crate::query(self)
88    }
89}
90
91impl IntoExprList for ReplaceQuery {
92    fn into_expr_list(self) -> Vec<Expr> {
93        vec![self.into_expr()]
94    }
95}
96
97impl HasHints for ReplaceQuery {
98    fn hints_mut(&mut self) -> &mut Hints {
99        &mut self.hints
100    }
101}
102
103impl HasModifiers for ReplaceQuery {
104    fn modifiers_mut(&mut self) -> &mut Modifiers {
105        &mut self.modifiers
106    }
107}
108
109impl HasTableRef for ReplaceQuery {
110    fn table_ref_mut(&mut self) -> &mut TableRef {
111        &mut self.table
112    }
113}
114
115impl HasValues for ReplaceQuery {
116    fn values_mut(&mut self) -> &mut Values {
117        &mut self.values
118    }
119}
120
121impl HasSet for ReplaceQuery {
122    fn set_mut(&mut self) -> &mut Set {
123        &mut self.set
124    }
125}