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/// Trait exposing column definition and reference.
10pub trait ColumnTrait {
11    /// Logical definition (column metadata).
12    fn column_def(&self) -> &ColumnDef;
13    /// Column reference.
14    fn column_ref(&self) -> &ColumnRef;
15}
16
17/// Reference to a column.
18#[derive(Default, Debug, Clone, PartialEq, Eq)]
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    pub fn new(name: Cow<'static, str>) -> Self {
30        Self {
31            name,
32            ..Default::default()
33        }
34    }
35    /// Get the table reference for this column.
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/// Primary key participation.
46#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
47pub enum PrimaryKeyType {
48    /// Full primary key.
49    PrimaryKey,
50    /// Part of a composite key.
51    PartOfPrimaryKey,
52    /// Not in 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 action.
72    #[default]
73    NoAction,
74    /// Reject operation.
75    Restrict,
76    /// Propagate change.
77    Cascade,
78    /// Set to NULL.
79    SetNull,
80    /// Set to 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 types.
102    pub column_type: BTreeMap<&'static str, &'static str>,
103    /// Type descriptor.
104    pub value: Value,
105    /// Is nullable.
106    pub nullable: bool,
107    /// Default expression.
108    pub default: DefaultValueType,
109    /// Primary key role.
110    pub primary_key: PrimaryKeyType,
111    /// Clustering key (relevant for ScyllaDB / Cassandra).
112    pub clustering_key: bool,
113    /// Single-column unique constraint.
114    pub unique: bool,
115    /// Foreign key target.
116    pub references: Option<ColumnRef>,
117    /// On delete action.
118    pub on_delete: Option<Action>,
119    /// On update action.
120    pub on_update: Option<Action>,
121    /// Exclude from INSERTs.
122    pub passive: bool,
123    /// Comment.
124    pub comment: &'static str,
125}
126
127impl ColumnDef {
128    /// Column name.
129    pub fn name(&self) -> &str {
130        &self.column_ref.name
131    }
132    /// Table name.
133    pub fn table(&self) -> &str {
134        &self.column_ref.table
135    }
136    /// Schema name.
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}