1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! RETURNING clause support
//!
//! This module provides the `ReturningClause` type for specifying columns to return
//! from INSERT, UPDATE, and DELETE statements (PostgreSQL, SQLite 3.35+).
use crate::types::{ColumnRef, IntoColumnRef};
/// RETURNING clause for INSERT/UPDATE/DELETE statements
///
/// Specifies which columns should be returned after the modification operation.
/// Supported by PostgreSQL and SQLite 3.35+.
///
/// # Examples
///
/// ```rust,ignore
/// use reinhardt_query::prelude::*;
///
/// // Return all columns
/// let returning = ReturningClause::all();
///
/// // Return specific columns
/// let returning = ReturningClause::columns(["id", "created_at"]);
/// ```
#[derive(Debug, Clone, Default)]
pub enum ReturningClause {
/// Return all columns (RETURNING *)
#[default]
All,
/// Return specific columns
Columns(Vec<ColumnRef>),
}
impl ReturningClause {
/// Create a RETURNING * clause
///
/// # Examples
///
/// ```rust,ignore
/// use reinhardt_query::prelude::*;
///
/// let query = Query::insert()
/// .into_table("users")
/// .columns(["name", "email"])
/// .values_panic(["Alice", "alice@example.com"])
/// .returning_all();
/// ```
pub fn all() -> Self {
Self::All
}
/// Create a RETURNING clause with specific columns
///
/// # Examples
///
/// ```rust,ignore
/// use reinhardt_query::prelude::*;
///
/// let query = Query::insert()
/// .into_table("users")
/// .columns(["name", "email"])
/// .values_panic(["Alice", "alice@example.com"])
/// .returning(["id", "created_at"]);
/// ```
pub fn columns<I, C>(cols: I) -> Self
where
I: IntoIterator<Item = C>,
C: IntoColumnRef,
{
let columns: Vec<ColumnRef> = cols.into_iter().map(|c| c.into_column_ref()).collect();
Self::Columns(columns)
}
/// Add a column to the RETURNING clause
///
/// If this is a `ReturningClause::All`, it will be converted to a specific column list.
pub fn add_column<C>(&mut self, col: C)
where
C: IntoColumnRef,
{
match self {
Self::All => {
// Convert ALL to specific columns
*self = Self::Columns(vec![col.into_column_ref()]);
}
Self::Columns(cols) => {
cols.push(col.into_column_ref());
}
}
}
/// Check if this clause returns all columns
pub fn is_all(&self) -> bool {
matches!(self, Self::All)
}
/// Get the columns list if this is a specific column clause
pub fn get_columns(&self) -> Option<&[ColumnRef]> {
match self {
Self::All => None,
Self::Columns(cols) => Some(cols),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_returning_all() {
let returning = ReturningClause::all();
assert!(returning.is_all());
assert!(returning.get_columns().is_none());
}
#[test]
fn test_returning_columns() {
let returning = ReturningClause::columns(["id", "name"]);
assert!(!returning.is_all());
let cols = returning.get_columns().unwrap();
assert_eq!(cols.len(), 2);
}
#[test]
fn test_add_column() {
let mut returning = ReturningClause::all();
returning.add_column("id");
assert!(!returning.is_all());
let cols = returning.get_columns().unwrap();
assert_eq!(cols.len(), 1);
}
#[test]
fn test_default() {
let returning = ReturningClause::default();
assert!(returning.is_all());
}
}