Skip to main content

toolu_orm_core/
table.rs

1use serde::{Deserialize, Serialize};
2
3use crate::column::ColumnDef;
4use crate::index::IndexDef;
5
6/// How the database creates the table.
7///
8/// `Virtual` covers every `CREATE VIRTUAL TABLE … USING <module>(<args>)`
9/// form — `fts5`, `vec0`, `rtree`, or a module the application registered
10/// itself. `args` are already-rendered SQL arguments, joined with `", "`
11/// inside the module parentheses, so the schema layer stays module-agnostic
12/// and each module gets its own builder (see [`crate::fts5`]).
13#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum TableKind {
16  #[default]
17  Ordinary,
18  Virtual {
19    module: String,
20    args: Vec<String>,
21  },
22}
23
24impl TableKind {
25  /// Builds a virtual-table kind from a module name and rendered arguments.
26  pub fn virtual_table(module: impl Into<String>, args: Vec<String>) -> Self {
27    Self::Virtual {
28      module: module.into(),
29      args,
30    }
31  }
32
33  #[must_use]
34  pub fn is_ordinary(&self) -> bool {
35    matches!(self, Self::Ordinary)
36  }
37
38  /// The module name for a virtual table, `None` for an ordinary one.
39  #[must_use]
40  pub fn module(&self) -> Option<&str> {
41    match self {
42      Self::Ordinary => None,
43      Self::Virtual { module, .. } => Some(module),
44    }
45  }
46
47  /// The rendered module arguments; empty for an ordinary table.
48  #[must_use]
49  pub fn args(&self) -> &[String] {
50    match self {
51      Self::Ordinary => &[],
52      Self::Virtual { args, .. } => args,
53    }
54  }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
58pub struct TableDef {
59  pub name: String,
60  pub columns: Vec<ColumnDef>,
61  #[serde(default)]
62  pub indexes: Vec<IndexDef>,
63  #[serde(default)]
64  pub strict: bool,
65  /// Defaults to [`TableKind::Ordinary`], so snapshots written before virtual
66  /// tables existed still deserialize.
67  #[serde(default, skip_serializing_if = "TableKind::is_ordinary")]
68  pub kind: TableKind,
69}
70
71impl TableDef {
72  pub fn find_column(&self, name: &str) -> Option<&ColumnDef> {
73    self.columns.iter().find(|c| c.name == name)
74  }
75
76  #[must_use]
77  pub fn is_virtual(&self) -> bool {
78    !self.kind.is_ordinary()
79  }
80}
81
82pub trait TableSchema {
83  fn table_def() -> TableDef;
84}