drizzle_types/sqlite/ddl/mod.rs
1//! `SQLite` schema objects (tables, columns, indexes, constraints, views) for
2//! migrations.
3//!
4//! Each object comes in two forms:
5//!
6//! - **`*Def` types** ([`TableDef`], [`ColumnDef`], ...) hold only `Copy`
7//! data (`&'static str`, `bool`, slices) so they can be built in `const`
8//! items. The schema macros generate these.
9//! - **Runtime types** ([`Table`], [`Column`], ...) hold `Cow<'static, str>`
10//! and can be serialized with the `serde` feature. Migration snapshots
11//! store these, as a list of [`SqliteEntity`] values.
12//!
13//! Convert a definition with its `into_*` method or `From`. [`TableSql`]
14//! renders `CREATE TABLE` and related statements.
15//!
16//! # Examples
17//!
18//! Const definitions:
19//!
20//! ```
21//! use drizzle_types::sqlite::ddl::{ColumnDef, TableDef};
22//!
23//! const USERS_TABLE: TableDef = TableDef::new("users").strict();
24//!
25//! const USERS_COLUMNS: &[ColumnDef] = &[
26//! ColumnDef::new("users", "id", "INTEGER").primary_key().autoincrement(),
27//! ColumnDef::new("users", "name", "TEXT").not_null(),
28//! ColumnDef::new("users", "email", "TEXT").unique(),
29//! ];
30//! # let _ = (USERS_TABLE, USERS_COLUMNS);
31//! ```
32//!
33//! Converting to the runtime type:
34//!
35//! ```
36//! use drizzle_types::sqlite::ddl::{Table, TableDef};
37//!
38//! const DEF: TableDef = TableDef::new("users").strict();
39//!
40//! let table: Table = DEF.into_table();
41//! assert_eq!(table.name(), "users");
42//! ```
43//!
44//! Deserializing (with the `serde` feature):
45//!
46//! ```
47//! # #[cfg(feature = "serde")]
48//! # {
49//! use drizzle_types::sqlite::ddl::Table;
50//!
51//! let table: Table = serde_json::from_str(r#"{"name": "users", "strict": true}"#).unwrap();
52//! assert!(table.strict);
53//! # }
54//! ```
55
56use crate::alloc_prelude::*;
57
58mod check_constraint;
59mod column;
60mod foreign_key;
61mod index;
62mod primary_key;
63pub mod sql;
64mod table;
65mod unique_constraint;
66mod view;
67
68// Const-friendly definition types
69pub use check_constraint::CheckConstraintDef;
70pub use column::{ColumnDef, GeneratedDef, GeneratedType};
71pub use foreign_key::{ForeignKeyDef, ReferentialAction};
72pub use index::{IndexColumn, IndexColumnDef, IndexDef, IndexOrigin};
73pub use primary_key::PrimaryKeyDef;
74pub use table::TableDef;
75pub use unique_constraint::UniqueConstraintDef;
76pub use view::ViewDef;
77
78// Runtime types for serde
79pub use check_constraint::CheckConstraint;
80pub use column::{Column, Generated};
81pub use foreign_key::ForeignKey;
82pub use index::Index;
83pub use primary_key::PrimaryKey;
84pub use table::Table;
85pub use unique_constraint::UniqueConstraint;
86pub use view::View;
87
88// SQL generation
89pub use sql::TableSql;
90
91#[cfg(feature = "serde")]
92pub use crate::serde_helpers::{cow_from_string, cow_option_from_string};
93
94// =============================================================================
95// Entity Type Constants (for compatibility with migrations)
96// =============================================================================
97
98/// Entity type discriminator for tables
99pub const ENTITY_TYPE_TABLES: &str = "tables";
100/// Entity type discriminator for columns
101pub const ENTITY_TYPE_COLUMNS: &str = "columns";
102/// Entity type discriminator for indexes
103pub const ENTITY_TYPE_INDEXES: &str = "indexes";
104/// Entity type discriminator for foreign keys
105pub const ENTITY_TYPE_FKS: &str = "fks";
106/// Entity type discriminator for primary keys
107pub const ENTITY_TYPE_PKS: &str = "pks";
108/// Entity type discriminator for unique constraints
109pub const ENTITY_TYPE_UNIQUES: &str = "uniques";
110/// Entity type discriminator for check constraints
111pub const ENTITY_TYPE_CHECKS: &str = "checks";
112/// Entity type discriminator for views
113pub const ENTITY_TYPE_VIEWS: &str = "views";
114
115// =============================================================================
116// Unified Entity Enum
117// =============================================================================
118
119/// Any `SQLite` schema object: one element of a snapshot's `ddl` array.
120///
121/// With `serde`, the variant is stored in an `entityType` field, using the
122/// `ENTITY_TYPE_*` names (`"tables"`, `"columns"`, `"indexes"`, `"fks"`,
123/// `"pks"`, `"uniques"`, `"checks"`, `"views"`).
124#[derive(Clone, Debug, PartialEq, Eq)]
125#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126#[cfg_attr(feature = "serde", serde(tag = "entityType"))]
127pub enum SqliteEntity {
128 #[cfg_attr(feature = "serde", serde(rename = "tables"))]
129 Table(Table),
130 #[cfg_attr(feature = "serde", serde(rename = "columns"))]
131 Column(Column),
132 #[cfg_attr(feature = "serde", serde(rename = "indexes"))]
133 Index(Index),
134 #[cfg_attr(feature = "serde", serde(rename = "fks"))]
135 ForeignKey(ForeignKey),
136 #[cfg_attr(feature = "serde", serde(rename = "pks"))]
137 PrimaryKey(PrimaryKey),
138 #[cfg_attr(feature = "serde", serde(rename = "uniques"))]
139 UniqueConstraint(UniqueConstraint),
140 #[cfg_attr(feature = "serde", serde(rename = "checks"))]
141 CheckConstraint(CheckConstraint),
142 #[cfg_attr(feature = "serde", serde(rename = "views"))]
143 View(View),
144}
145
146// =============================================================================
147// Naming Helpers (matching drizzle-kit grammar.ts patterns)
148// =============================================================================
149
150/// Returns the default foreign key name:
151/// `fk_{table}_{columns}_{table_to}_{columns_to}_fk`, with columns joined by `_`.
152#[must_use]
153pub fn name_for_fk(table: &str, columns: &[&str], table_to: &str, columns_to: &[&str]) -> String {
154 format!(
155 "fk_{}_{}_{}_{}_fk",
156 table,
157 columns.join("_"),
158 table_to,
159 columns_to.join("_")
160 )
161}
162
163/// Returns the default unique constraint name: `{table}_{columns}_unique`.
164///
165/// # Examples
166///
167/// ```
168/// use drizzle_types::sqlite::ddl::name_for_unique;
169///
170/// assert_eq!(name_for_unique("users", &["org_id", "email"]), "users_org_id_email_unique");
171/// ```
172#[must_use]
173pub fn name_for_unique(table: &str, columns: &[&str]) -> String {
174 format!("{}_{}_unique", table, columns.join("_"))
175}
176
177/// Returns the default primary key name: `{table}_pk`.
178#[must_use]
179pub fn name_for_pk(table: &str) -> String {
180 format!("{table}_pk")
181}
182
183/// Returns the default index name: `{table}_{columns}_idx`.
184#[must_use]
185pub fn name_for_index(table: &str, columns: &[&str]) -> String {
186 format!("{}_{}_idx", table, columns.join("_"))
187}
188
189/// Returns the default name of the `index`-th check constraint:
190/// `{table}_check_{index}`.
191#[must_use]
192pub fn name_for_check(table: &str, index: usize) -> String {
193 format!("{table}_check_{index}")
194}