drizzle_postgres/builder/
update.rs

1use crate::common::PostgresSchemaType;
2use crate::values::PostgresValue;
3use drizzle_core::{SQLTable, ToSQL};
4use std::fmt::Debug;
5use std::marker::PhantomData;
6
7// Import the ExecutableState trait
8use super::ExecutableState;
9
10//------------------------------------------------------------------------------
11// Type State Markers
12//------------------------------------------------------------------------------
13
14/// Marker for the initial state of UpdateBuilder
15#[derive(Debug, Clone, Copy, Default)]
16pub struct UpdateInitial;
17
18/// Marker for the state after SET clause
19#[derive(Debug, Clone, Copy, Default)]
20pub struct UpdateSetClauseSet;
21
22/// Marker for the state after FROM clause
23#[derive(Debug, Clone, Copy, Default)]
24pub struct UpdateFromSet;
25
26/// Marker for the state after WHERE clause
27#[derive(Debug, Clone, Copy, Default)]
28pub struct UpdateWhereSet;
29
30/// Marker for the state after RETURNING clause
31#[derive(Debug, Clone, Copy, Default)]
32pub struct UpdateReturningSet;
33
34// Mark states that can execute update queries
35impl ExecutableState for UpdateSetClauseSet {}
36impl ExecutableState for UpdateFromSet {}
37impl ExecutableState for UpdateWhereSet {}
38impl ExecutableState for UpdateReturningSet {}
39
40//------------------------------------------------------------------------------
41// UpdateBuilder Definition
42//------------------------------------------------------------------------------
43
44/// Builds an UPDATE query specifically for PostgreSQL
45pub type UpdateBuilder<'a, Schema, State, Table> = super::QueryBuilder<'a, Schema, State, Table>;
46
47//------------------------------------------------------------------------------
48// Initial State Implementation
49//------------------------------------------------------------------------------
50
51impl<'a, Schema, Table> UpdateBuilder<'a, Schema, UpdateInitial, Table>
52where
53    Table: SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>,
54{
55    /// Sets the values to update and transitions to the SetClauseSet state
56    #[inline]
57    pub fn set(
58        self,
59        values: Table::Update,
60    ) -> UpdateBuilder<'a, Schema, UpdateSetClauseSet, Table> {
61        let sql = crate::helpers::set::<'a, Table, PostgresSchemaType, PostgresValue<'a>>(values);
62        UpdateBuilder {
63            sql: self.sql.append(sql),
64            schema: PhantomData,
65            state: PhantomData,
66            table: PhantomData,
67        }
68    }
69}
70
71//------------------------------------------------------------------------------
72// Post-SET Implementation
73//------------------------------------------------------------------------------
74
75impl<'a, S, T> UpdateBuilder<'a, S, UpdateSetClauseSet, T> {
76    /// Adds a FROM clause and transitions to the FromSet state
77    #[inline]
78    pub fn from(
79        self,
80        source: impl ToSQL<'a, PostgresValue<'a>>,
81    ) -> UpdateBuilder<'a, S, UpdateFromSet, T> {
82        let from_sql = crate::helpers::from(source);
83        UpdateBuilder {
84            sql: self.sql.append(from_sql),
85            schema: PhantomData,
86            state: PhantomData,
87            table: PhantomData,
88        }
89    }
90
91    /// Adds a WHERE condition and transitions to the WhereSet state
92    #[inline]
93    pub fn r#where(
94        self,
95        condition: impl ToSQL<'a, PostgresValue<'a>>,
96    ) -> UpdateBuilder<'a, S, UpdateWhereSet, T> {
97        let where_sql = crate::helpers::r#where(condition);
98        UpdateBuilder {
99            sql: self.sql.append(where_sql),
100            schema: PhantomData,
101            state: PhantomData,
102            table: PhantomData,
103        }
104    }
105
106    /// Adds a RETURNING clause and transitions to the ReturningSet state
107    #[inline]
108    pub fn returning(
109        self,
110        columns: impl ToSQL<'a, PostgresValue<'a>>,
111    ) -> UpdateBuilder<'a, S, UpdateReturningSet, T> {
112        let returning_sql = crate::helpers::returning(columns);
113        UpdateBuilder {
114            sql: self.sql.append(returning_sql),
115            schema: PhantomData,
116            state: PhantomData,
117            table: PhantomData,
118        }
119    }
120}
121
122//------------------------------------------------------------------------------
123// Post-FROM Implementation
124//------------------------------------------------------------------------------
125
126impl<'a, S, T> UpdateBuilder<'a, S, UpdateFromSet, T> {
127    /// Adds a WHERE condition after FROM
128    #[inline]
129    pub fn r#where(
130        self,
131        condition: impl ToSQL<'a, PostgresValue<'a>>,
132    ) -> UpdateBuilder<'a, S, UpdateWhereSet, T> {
133        let where_sql = crate::helpers::r#where(condition);
134        UpdateBuilder {
135            sql: self.sql.append(where_sql),
136            schema: PhantomData,
137            state: PhantomData,
138            table: PhantomData,
139        }
140    }
141
142    /// Adds a RETURNING clause after FROM
143    #[inline]
144    pub fn returning(
145        self,
146        columns: impl ToSQL<'a, PostgresValue<'a>>,
147    ) -> UpdateBuilder<'a, S, UpdateReturningSet, T> {
148        let returning_sql = crate::helpers::returning(columns);
149        UpdateBuilder {
150            sql: self.sql.append(returning_sql),
151            schema: PhantomData,
152            state: PhantomData,
153            table: PhantomData,
154        }
155    }
156}
157
158//------------------------------------------------------------------------------
159// Post-WHERE Implementation
160//------------------------------------------------------------------------------
161
162impl<'a, S, T> UpdateBuilder<'a, S, UpdateWhereSet, T> {
163    /// Adds a RETURNING clause after WHERE
164    #[inline]
165    pub fn returning(
166        self,
167        columns: impl ToSQL<'a, PostgresValue<'a>>,
168    ) -> UpdateBuilder<'a, S, UpdateReturningSet, T> {
169        let returning_sql = crate::helpers::returning(columns);
170        UpdateBuilder {
171            sql: self.sql.append(returning_sql),
172            schema: PhantomData,
173            state: PhantomData,
174            table: PhantomData,
175        }
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182    use drizzle_core::{SQL, ToSQL};
183
184    #[test]
185    fn test_update_builder_creation() {
186        let builder = UpdateBuilder::<(), UpdateInitial, ()> {
187            sql: SQL::raw("UPDATE test"),
188            schema: PhantomData,
189            state: PhantomData,
190            table: PhantomData,
191        };
192
193        assert_eq!(builder.to_sql().sql(), "UPDATE test");
194    }
195}