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};
8
9/// Helper trait for types that expose an underlying column definition and reference.
10pub trait ColumnTrait {
11    /// Logical definition (column metadata).
12    fn column_def(&self) -> &ColumnDef;
13    /// Column reference to be used in expressions.
14    fn column_ref(&self) -> &ColumnRef;
15}
16
17/// Reference to a table column.
18#[derive(Default, Debug, Clone, PartialEq, Eq)]
19pub struct ColumnRef {
20    /// Column name.
21    pub name: Cow<'static, str>,
22    /// Table name.
23    pub table: Cow<'static, str>,
24    /// Schema name (may be empty).
25    pub schema: Cow<'static, str>,
26}
27
28impl ColumnRef {
29    pub fn new(name: Cow<'static, str>) -> Self {
30        Self {
31            name,
32            ..Default::default()
33        }
34    }
35    /// Return a `TableRef` referencing the column's table and schema.
36    pub fn table(&self) -> TableRef {
37        TableRef {
38            name: self.table.clone(),
39            schema: self.schema.clone(),
40            ..Default::default()
41        }
42    }
43}
44
45/// Indicates if and how a column participates in the primary key.
46#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
47pub enum PrimaryKeyType {
48    /// Single-column primary key.
49    PrimaryKey,
50    /// Member of a composite primary key.
51    PartOfPrimaryKey,
52    /// Not part of the primary key.
53    #[default]
54    None,
55}
56
57impl ToTokens for PrimaryKeyType {
58    fn to_tokens(&self, tokens: &mut TokenStream) {
59        use PrimaryKeyType::*;
60        tokens.append_all(match self {
61            PrimaryKey => quote!(::tank::PrimaryKeyType::PrimaryKey),
62            PartOfPrimaryKey => quote!(::tank::PrimaryKeyType::PartOfPrimaryKey),
63            None => quote!(::tank::PrimaryKeyType::None),
64        });
65    }
66}
67
68/// Referential action for foreign key updates or deletes.
69#[derive(Default, Debug, PartialEq, Eq)]
70pub enum Action {
71    /// No special action.
72    #[default]
73    NoAction,
74    /// Reject the operation.
75    Restrict,
76    /// Propagate delete, update...
77    Cascade,
78    /// Set referencing columns to NULL.
79    SetNull,
80    /// Apply column DEFAULT.
81    SetDefault,
82}
83
84impl ToTokens for Action {
85    fn to_tokens(&self, tokens: &mut TokenStream) {
86        tokens.append_all(match self {
87            Action::NoAction => quote! { ::tank::Action::NoAction },
88            Action::Restrict => quote! { ::tank::Action::Restrict },
89            Action::Cascade => quote! { ::tank::Action::Cascade },
90            Action::SetNull => quote! { ::tank::Action::SetNull },
91            Action::SetDefault => quote! { ::tank::Action::SetDefault },
92        });
93    }
94}
95
96/// Column specification.
97#[derive(Default, Debug)]
98pub struct ColumnDef {
99    /// Column identity.
100    pub column_ref: ColumnRef,
101    /// Explicit SQL type override (empty means infer from `value`).
102    pub column_type: BTreeMap<&'static str, &'static str>,
103    /// `Value` describing column type and parameters.
104    pub value: Value,
105    /// Nullability flag.
106    pub nullable: bool,
107    /// Default value (expression rendered by `SqlWriter`).
108    pub default: DefaultValueType,
109    /// Primary key participation.
110    pub primary_key: PrimaryKeyType,
111    /// Defines the ordering of the rows.
112    pub clustering_key: bool,
113    /// Unique constraint (single column only, composite handled in the `TableDef`).
114    pub unique: bool,
115    /// Foreign key target column.
116    pub references: Option<ColumnRef>,
117    /// Action for deletes.
118    pub on_delete: Option<Action>,
119    /// Action for updates.
120    pub on_update: Option<Action>,
121    /// Passive columns are skipped when generating `INSERT` value lists (DEFAULT used).
122    pub passive: bool,
123    /// Optional human-readable comment.
124    pub comment: &'static str,
125}
126
127impl ColumnDef {
128    /// Column name (as declared in the table definition).
129    pub fn name(&self) -> &str {
130        &self.column_ref.name
131    }
132    /// Table name owning this column.
133    pub fn table(&self) -> &str {
134        &self.column_ref.table
135    }
136    /// Schema name owning this column (may be empty).
137    pub fn schema(&self) -> &str {
138        &self.column_ref.schema
139    }
140}
141
142impl<'a> From<&'a ColumnDef> for &'a ColumnRef {
143    fn from(value: &'a ColumnDef) -> Self {
144        &value.column_ref
145    }
146}
147
148impl OpPrecedence for ColumnRef {
149    fn precedence(&self, _writer: &dyn SqlWriter) -> i32 {
150        1_000_000
151    }
152}
153
154impl Expression for ColumnRef {
155    fn write_query(&self, writer: &dyn SqlWriter, context: &mut Context, out: &mut DynQuery) {
156        writer.write_column_ref(context, out, self);
157    }
158    fn accept_visitor(
159        &self,
160        matcher: &mut dyn ExpressionVisitor,
161        writer: &dyn SqlWriter,
162        context: &mut Context,
163        out: &mut DynQuery,
164    ) -> bool {
165        matcher.visit_column(writer, context, out, self)
166    }
167}
168
169impl OpPrecedence for ColumnDef {
170    fn precedence(&self, _writer: &dyn SqlWriter) -> i32 {
171        1_000_000
172    }
173}
174
175impl Expression for ColumnDef {
176    fn write_query(&self, writer: &dyn SqlWriter, context: &mut Context, out: &mut DynQuery) {
177        writer.write_column_ref(context, out, &self.column_ref);
178    }
179
180    fn accept_visitor(
181        &self,
182        matcher: &mut dyn ExpressionVisitor,
183        writer: &dyn SqlWriter,
184        context: &mut Context,
185        out: &mut DynQuery,
186    ) -> bool {
187        matcher.visit_column(writer, context, out, &self.column_ref)
188    }
189}