Skip to main content

drizzle_types/sqlite/ddl/
view.rs

1//! `SQLite` View DDL types
2//!
3//! See: <https://github.com/drizzle-team/drizzle-orm/blob/beta/drizzle-kit/src/dialects/sqlite/ddl.ts>
4
5use crate::alloc_prelude::*;
6
7#[cfg(feature = "serde")]
8use crate::serde_helpers::{cow_from_string, cow_option_from_string};
9
10// =============================================================================
11// Const-friendly Definition Type
12// =============================================================================
13
14/// Const-friendly view definition
15///
16/// # Examples
17///
18/// ```
19/// use drizzle_types::sqlite::ddl::ViewDef;
20///
21/// const VIEW: ViewDef = ViewDef::new("active_users")
22///     .definition("SELECT * FROM users WHERE active = 1");
23/// ```
24#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
25pub struct ViewDef {
26    /// View name
27    pub name: &'static str,
28    /// View definition (AS SELECT ...)
29    pub definition: Option<&'static str>,
30    /// Whether this is an existing view (not managed by drizzle)
31    pub is_existing: bool,
32    /// Error message if the view failed to parse/validate
33    pub error: Option<&'static str>,
34}
35
36impl ViewDef {
37    /// Create a new view definition
38    #[must_use]
39    pub const fn new(name: &'static str) -> Self {
40        Self {
41            name,
42            definition: None,
43            is_existing: false,
44            error: None,
45        }
46    }
47
48    /// Set the view definition
49    #[must_use]
50    pub const fn definition(self, sql: &'static str) -> Self {
51        Self {
52            definition: Some(sql),
53            ..self
54        }
55    }
56
57    /// Mark as existing (not managed by drizzle)
58    #[must_use]
59    pub const fn existing(self) -> Self {
60        Self {
61            is_existing: true,
62            ..self
63        }
64    }
65
66    /// Set an error message
67    #[must_use]
68    pub const fn error(self, error: &'static str) -> Self {
69        Self {
70            error: Some(error),
71            ..self
72        }
73    }
74
75    /// Convert to runtime [`View`] type
76    #[must_use]
77    pub const fn into_view(self) -> View {
78        View {
79            name: Cow::Borrowed(self.name),
80            definition: match self.definition {
81                Some(d) => Some(Cow::Borrowed(d)),
82                None => None,
83            },
84            is_existing: self.is_existing,
85            error: match self.error {
86                Some(e) => Some(Cow::Borrowed(e)),
87                None => None,
88            },
89        }
90    }
91}
92
93impl Default for ViewDef {
94    fn default() -> Self {
95        Self::new("")
96    }
97}
98
99// =============================================================================
100// Runtime Type for Serde
101// =============================================================================
102
103/// Runtime view entity
104#[derive(Clone, Debug, PartialEq, Eq)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
106#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
107pub struct View {
108    /// View name
109    #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
110    pub name: Cow<'static, str>,
111
112    /// View definition (AS SELECT ...)
113    #[cfg_attr(
114        feature = "serde",
115        serde(
116            default,
117            skip_serializing_if = "Option::is_none",
118            deserialize_with = "cow_option_from_string"
119        )
120    )]
121    pub definition: Option<Cow<'static, str>>,
122
123    /// Whether this is an existing view (not managed by drizzle)
124    #[cfg_attr(feature = "serde", serde(default))]
125    pub is_existing: bool,
126
127    /// Error message if the view failed to parse/validate
128    #[cfg_attr(
129        feature = "serde",
130        serde(
131            default,
132            skip_serializing_if = "Option::is_none",
133            deserialize_with = "cow_option_from_string"
134        )
135    )]
136    pub error: Option<Cow<'static, str>>,
137}
138
139impl View {
140    /// Create a new view
141    #[must_use]
142    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
143        Self {
144            name: name.into(),
145            definition: None,
146            is_existing: false,
147            error: None,
148        }
149    }
150
151    /// Get the view name
152    #[inline]
153    #[must_use]
154    pub fn name(&self) -> &str {
155        &self.name
156    }
157}
158
159impl Default for View {
160    fn default() -> Self {
161        Self::new("")
162    }
163}
164
165impl From<ViewDef> for View {
166    fn from(def: ViewDef) -> Self {
167        def.into_view()
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn test_const_view_def() {
177        const VIEW: ViewDef =
178            ViewDef::new("active_users").definition("SELECT * FROM users WHERE active = 1");
179
180        assert_eq!(VIEW.name, "active_users");
181        assert!(VIEW.definition.is_some());
182        const {
183            assert!(!VIEW.is_existing);
184        }
185    }
186
187    #[test]
188    fn test_view_def_to_view() {
189        const DEF: ViewDef = ViewDef::new("active_users").existing();
190
191        let view = DEF.into_view();
192        assert_eq!(view.name(), "active_users");
193        assert!(view.is_existing);
194    }
195}