drizzle_types/postgres/ddl/
table.rs

1//! PostgreSQL Table DDL types
2//!
3//! This module provides two complementary types:
4//! - [`TableDef`] - A const-friendly definition type for compile-time schema definitions
5//! - [`Table`] - A runtime type for serde serialization/deserialization
6
7#[cfg(feature = "std")]
8use std::borrow::Cow;
9
10#[cfg(all(feature = "alloc", not(feature = "std")))]
11use alloc::borrow::Cow;
12
13#[cfg(feature = "serde")]
14use crate::serde_helpers::cow_from_string;
15
16// =============================================================================
17// Const-friendly Definition Type
18// =============================================================================
19
20/// Const-friendly table definition for compile-time schema definitions.
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
22pub struct TableDef {
23    /// Schema name
24    pub schema: &'static str,
25    /// Table name
26    pub name: &'static str,
27    /// Is Row-Level Security enabled?
28    pub is_rls_enabled: bool,
29}
30
31impl TableDef {
32    /// Create a new table definition
33    #[must_use]
34    pub const fn new(schema: &'static str, name: &'static str) -> Self {
35        Self {
36            schema,
37            name,
38            is_rls_enabled: false,
39        }
40    }
41
42    /// Set Row-Level Security enabled
43    #[must_use]
44    pub const fn rls_enabled(self) -> Self {
45        Self {
46            schema: self.schema,
47            name: self.name,
48            is_rls_enabled: true,
49        }
50    }
51
52    /// Convert to runtime [`Table`] type
53    #[must_use]
54    pub const fn into_table(self) -> Table {
55        Table {
56            schema: Cow::Borrowed(self.schema),
57            name: Cow::Borrowed(self.name),
58            is_rls_enabled: if self.is_rls_enabled {
59                Some(true)
60            } else {
61                None
62            },
63        }
64    }
65}
66
67impl Default for TableDef {
68    fn default() -> Self {
69        Self::new("public", "")
70    }
71}
72
73// =============================================================================
74// Runtime Type for Serde
75// =============================================================================
76
77/// Runtime table entity for serde serialization.
78#[derive(Clone, Debug, PartialEq, Eq)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
81pub struct Table {
82    /// Schema name
83    #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
84    pub schema: Cow<'static, str>,
85
86    /// Table name
87    #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
88    pub name: Cow<'static, str>,
89
90    /// Is Row-Level Security enabled?
91    #[cfg_attr(
92        feature = "serde",
93        serde(default, skip_serializing_if = "Option::is_none")
94    )]
95    pub is_rls_enabled: Option<bool>,
96}
97
98impl Table {
99    /// Create a new table (runtime)
100    #[must_use]
101    pub fn new(schema: impl Into<Cow<'static, str>>, name: impl Into<Cow<'static, str>>) -> Self {
102        Self {
103            schema: schema.into(),
104            name: name.into(),
105            is_rls_enabled: None,
106        }
107    }
108
109    /// Set Row-Level Security enabled
110    #[must_use]
111    pub fn rls_enabled(mut self) -> Self {
112        self.is_rls_enabled = Some(true);
113        self
114    }
115
116    /// Get the schema name
117    #[inline]
118    #[must_use]
119    pub fn schema(&self) -> &str {
120        &self.schema
121    }
122
123    /// Get the table name
124    #[inline]
125    #[must_use]
126    pub fn name(&self) -> &str {
127        &self.name
128    }
129}
130
131impl Default for Table {
132    fn default() -> Self {
133        Self::new("public", "")
134    }
135}
136
137impl From<TableDef> for Table {
138    fn from(def: TableDef) -> Self {
139        def.into_table()
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    #[test]
148    fn test_const_table_def() {
149        const TABLE: TableDef = TableDef::new("public", "users").rls_enabled();
150
151        assert_eq!(TABLE.schema, "public");
152        assert_eq!(TABLE.name, "users");
153        assert!(TABLE.is_rls_enabled);
154    }
155
156    #[test]
157    fn test_table_def_to_table() {
158        const DEF: TableDef = TableDef::new("public", "users");
159        let table = DEF.into_table();
160        assert_eq!(table.schema(), "public");
161        assert_eq!(table.name(), "users");
162    }
163}