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