oxide_sql_core/schema/mod.rs
1//! Schema traits for type-safe table and column definitions.
2//!
3//! This module provides traits that are implemented by the `#[derive(Table)]`
4//! macro to enable compile-time checked SQL queries.
5
6/// Trait for table metadata.
7///
8/// Implemented by types generated from `#[derive(Table)]` to provide
9/// table-level information.
10pub trait Table {
11 /// The row type (the original struct).
12 type Row;
13
14 /// The SQL table name.
15 const NAME: &'static str;
16
17 /// List of all column names.
18 const COLUMNS: &'static [&'static str];
19
20 /// The primary key column name, if any.
21 const PRIMARY_KEY: Option<&'static str>;
22}
23
24/// Trait for column metadata.
25///
26/// Implemented by column types generated from `#[derive(Table)]` to provide
27/// column-level information and enable type-safe queries.
28pub trait Column {
29 /// The table this column belongs to.
30 type Table: Table;
31
32 /// The Rust type of this column.
33 type Type;
34
35 /// The SQL column name.
36 const NAME: &'static str;
37
38 /// Whether this column is nullable.
39 const NULLABLE: bool;
40
41 /// Whether this column is the primary key.
42 const PRIMARY_KEY: bool;
43}
44
45/// Marker trait for columns with a specific Rust type.
46///
47/// Used for compile-time type checking of values in queries.
48pub trait TypedColumn<T>: Column<Type = T> {}
49
50/// Trait for selecting specific columns from a table.
51///
52/// Implemented for tuples of column types to enable type-safe SELECT queries.
53pub trait Selectable<T: Table> {
54 /// Returns the column names to select.
55 fn column_names() -> &'static [&'static str];
56}
57
58// Implement Selectable for single columns
59impl<T: Table, C: Column<Table = T>> Selectable<T> for C {
60 fn column_names() -> &'static [&'static str] {
61 // Return as a slice containing just this column
62 // This is a compile-time constant
63 &[C::NAME]
64 }
65}
66
67/// Runtime column metadata (generated by derive macro).
68#[derive(Debug, Clone)]
69pub struct ColumnSchema {
70 /// The SQL column name.
71 pub name: &'static str,
72 /// The Rust type name as a canonical string (spaces stripped).
73 pub rust_type: &'static str,
74 /// Whether this column is nullable.
75 pub nullable: bool,
76 /// Whether this column is the primary key.
77 pub primary_key: bool,
78 /// Whether this column has a UNIQUE constraint.
79 pub unique: bool,
80 /// Whether this column auto-increments.
81 pub autoincrement: bool,
82 /// Raw SQL default expression, if any.
83 pub default_expr: Option<&'static str>,
84}
85
86/// Tables that provide full column schema for DDL generation.
87///
88/// Implemented by the `#[derive(Table)]` macro alongside the `Table`
89/// trait. While `Table` gives you column *names*, `TableSchema` gives
90/// you full column metadata (types, constraints, defaults) needed to
91/// generate CREATE TABLE statements.
92pub trait TableSchema: Table {
93 /// Complete schema for every column in declaration order.
94 const SCHEMA: &'static [ColumnSchema];
95}
96
97/// Maps Rust type names to SQL data types.
98///
99/// Each dialect implements this to provide its own mapping from the
100/// canonical Rust type string (e.g. `"String"`, `"i64"`) to a SQL
101/// [`DataType`](crate::ast::DataType).
102pub trait RustTypeMapping {
103 /// Maps a Rust type name to the dialect-specific SQL data type.
104 fn map_type(&self, rust_type: &str) -> crate::ast::DataType;
105}
106
107// Implement Selectable for tuples of columns (up to 12)
108macro_rules! impl_selectable_tuple {
109 ($($idx:tt: $col:ident),+) => {
110 impl<T: Table, $($col: Column<Table = T>),+> Selectable<T> for ($($col,)+) {
111 fn column_names() -> &'static [&'static str] {
112 &[$($col::NAME),+]
113 }
114 }
115 };
116}
117
118impl_selectable_tuple!(0: C0);
119impl_selectable_tuple!(0: C0, 1: C1);
120impl_selectable_tuple!(0: C0, 1: C1, 2: C2);
121impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3);
122impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4);
123impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5);
124impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6);
125impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7);
126impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7, 8: C8);
127impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7, 8: C8, 9: C9);
128impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7, 8: C8, 9: C9, 10: C10);
129impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7, 8: C8, 9: C9, 10: C10, 11: C11);