Skip to main content

tank_core/
column.rs

1use crate::{
2    DefaultValueType, DynQuery, Expression, ExpressionVisitor, OpPrecedence, SqlWriter, TableRef,
3    Value, writer::Context,
4};
5use proc_macro2::TokenStream;
6use quote::{ToTokens, TokenStreamExt, quote};
7use std::{borrow::Cow, collections::BTreeMap, hash::Hash};
8
9/// Trait exposing column definition and reference.
10pub trait ColumnTrait {
11    /// Returns the column definition, including metadata like type and constraints.
12    fn column_def(&self) -> &ColumnDef;
13    /// Returns the reference identifying the column (name, table, schema).
14    fn column_ref(&self) -> &ColumnRef;
15}
16
17/// Reference to a column.
18#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
19pub struct ColumnRef {
20    /// Name of the column.
21    pub name: Cow<'static, str>,
22    /// Name of the table.
23    pub table: Cow<'static, str>,
24    /// Name of the schema.
25    pub schema: Cow<'static, str>,
26}
27
28impl ColumnRef {
29    /// Create a column reference from just a name.
30    pub fn new(name: Cow<'static, str>) -> Self {
31        Self {
32            name,
33            ..Default::default()
34        }
35    }
36    /// Get the table reference for this column.
37    pub fn table(&self) -> TableRef {
38        TableRef {
39            name: self.table.clone(),
40            schema: self.schema.clone(),
41            ..Default::default()
42        }
43    }
44}
45
46/// Primary key participation.
47#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
48pub enum PrimaryKeyType {
49    /// Full primary key.
50    PrimaryKey,
51    /// Part of a composite key.
52    PartOfPrimaryKey,
53    /// Not in primary key.
54    #[default]
55    None,
56}
57
58impl ToTokens for PrimaryKeyType {
59    fn to_tokens(&self, tokens: &mut TokenStream) {
60        use PrimaryKeyType::*;
61        tokens.append_all(match self {
62            PrimaryKey => quote!(::tank::PrimaryKeyType::PrimaryKey),
63            PartOfPrimaryKey => quote!(::tank::PrimaryKeyType::PartOfPrimaryKey),
64            None => quote!(::tank::PrimaryKeyType::None),
65        });
66    }
67}
68
69/// Referential action for foreign key updates or deletes.
70#[derive(Default, Debug, PartialEq, Eq)]
71pub enum Action {
72    /// No action.
73    #[default]
74    NoAction,
75    /// Reject operation.
76    Restrict,
77    /// Propagate change.
78    Cascade,
79    /// Set to NULL.
80    SetNull,
81    /// Set to DEFAULT.
82    SetDefault,
83}
84
85impl ToTokens for Action {
86    fn to_tokens(&self, tokens: &mut TokenStream) {
87        tokens.append_all(match self {
88            Action::NoAction => quote! { ::tank::Action::NoAction },
89            Action::Restrict => quote! { ::tank::Action::Restrict },
90            Action::Cascade => quote! { ::tank::Action::Cascade },
91            Action::SetNull => quote! { ::tank::Action::SetNull },
92            Action::SetDefault => quote! { ::tank::Action::SetDefault },
93        });
94    }
95}
96
97/// Column specification.
98#[derive(Default, Debug)]
99pub struct ColumnDef {
100    /// Column identity.
101    pub column_ref: ColumnRef,
102    /// Explicit SQL types.
103    pub column_type: BTreeMap<&'static str, &'static str>,
104    /// Type descriptor.
105    pub value: Value,
106    /// Is nullable.
107    pub nullable: bool,
108    /// Default expression.
109    pub default: DefaultValueType,
110    /// Primary key role.
111    pub primary_key: PrimaryKeyType,
112    /// Clustering key (relevant for ScyllaDB/Cassandra).
113    pub clustering_key: bool,
114    /// Single-column unique constraint.
115    pub unique: bool,
116    /// Foreign key target.
117    pub references: Option<ColumnRef>,
118    /// On delete action.
119    pub on_delete: Option<Action>,
120    /// On update action.
121    pub on_update: Option<Action>,
122    /// Exclude from INSERTs.
123    pub passive: bool,
124    /// Comment.
125    pub comment: &'static str,
126}
127
128impl ColumnDef {
129    /// Column name.
130    pub fn name(&self) -> &str {
131        &self.column_ref.name
132    }
133    /// Table name.
134    pub fn table(&self) -> &str {
135        &self.column_ref.table
136    }
137    /// Schema name.
138    pub fn schema(&self) -> &str {
139        &self.column_ref.schema
140    }
141}
142
143impl<'a> From<&'a ColumnDef> for &'a ColumnRef {
144    fn from(value: &'a ColumnDef) -> Self {
145        &value.column_ref
146    }
147}
148
149impl OpPrecedence for ColumnRef {
150    fn precedence(&self, _writer: &dyn SqlWriter) -> i32 {
151        1_000_000
152    }
153}
154
155impl Expression for ColumnRef {
156    fn write_query(&self, writer: &dyn SqlWriter, context: &mut Context, out: &mut DynQuery) {
157        writer.write_column_ref(context, out, self);
158    }
159    fn accept_visitor(
160        &self,
161        matcher: &mut dyn ExpressionVisitor,
162        writer: &dyn SqlWriter,
163        context: &mut Context,
164        out: &mut DynQuery,
165    ) -> bool {
166        matcher.visit_column(writer, context, out, self)
167    }
168}
169
170impl OpPrecedence for ColumnDef {
171    fn precedence(&self, _writer: &dyn SqlWriter) -> i32 {
172        1_000_000
173    }
174}
175
176impl Expression for ColumnDef {
177    fn write_query(&self, writer: &dyn SqlWriter, context: &mut Context, out: &mut DynQuery) {
178        writer.write_column_ref(context, out, &self.column_ref);
179    }
180
181    fn accept_visitor(
182        &self,
183        matcher: &mut dyn ExpressionVisitor,
184        writer: &dyn SqlWriter,
185        context: &mut Context,
186        out: &mut DynQuery,
187    ) -> bool {
188        matcher.visit_column(writer, context, out, &self.column_ref)
189    }
190}
191
192impl PartialEq for ColumnDef {
193    fn eq(&self, other: &Self) -> bool {
194        self.column_ref == other.column_ref
195    }
196}
197
198impl Eq for ColumnDef {}
199
200impl Hash for ColumnDef {
201    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
202        self.column_ref.hash(state)
203    }
204}