postrust_core/schema_cache/
table.rs1use crate::api_request::QualifiedIdentifier;
4use indexmap::IndexMap;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Clone, Debug, Serialize, Deserialize)]
10pub struct Table {
11 pub schema: String,
13 pub name: String,
15 pub description: Option<String>,
17 pub is_view: bool,
19 pub insertable: bool,
21 pub updatable: bool,
23 pub deletable: bool,
25 pub pk_cols: Vec<String>,
27 pub columns: ColumnMap,
29}
30
31impl Table {
32 pub fn get_column(&self, name: &str) -> Option<&Column> {
34 self.columns.get(name)
35 }
36
37 pub fn has_column(&self, name: &str) -> bool {
39 self.columns.contains_key(name)
40 }
41
42 pub fn qualified_identifier(&self) -> QualifiedIdentifier {
44 QualifiedIdentifier::new(&self.schema, &self.name)
45 }
46
47 pub fn column_names(&self) -> impl Iterator<Item = &str> {
49 self.columns.keys().map(|s| s.as_str())
50 }
51
52 pub fn is_readonly(&self) -> bool {
54 !self.insertable && !self.updatable && !self.deletable
55 }
56}
57
58#[derive(Clone, Debug, Serialize, Deserialize)]
60pub struct Column {
61 pub name: String,
63 pub description: Option<String>,
65 pub nullable: bool,
67 pub data_type: String,
69 pub nominal_type: String,
71 pub max_len: Option<i32>,
73 pub default: Option<String>,
75 pub enum_values: Vec<String>,
77 pub is_pk: bool,
79 pub position: i32,
81}
82
83impl Column {
84 pub fn has_default(&self) -> bool {
86 self.default.is_some()
87 }
88
89 pub fn is_auto(&self) -> bool {
91 self.default
92 .as_ref()
93 .map(|d| d.contains("nextval(") || d.contains("gen_random_uuid()"))
94 .unwrap_or(false)
95 }
96
97 pub fn is_json(&self) -> bool {
99 self.data_type == "json" || self.data_type == "jsonb"
100 }
101
102 pub fn is_array(&self) -> bool {
104 self.data_type.starts_with('_') || self.data_type.ends_with("[]")
105 }
106
107 pub fn is_range(&self) -> bool {
109 self.data_type.ends_with("range")
110 }
111}
112
113pub type ColumnMap = IndexMap<String, Column>;
115
116pub type TablesMap = HashMap<QualifiedIdentifier, Table>;
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_table_qualified_identifier() {
125 let table = Table {
126 schema: "public".into(),
127 name: "users".into(),
128 description: None,
129 is_view: false,
130 insertable: true,
131 updatable: true,
132 deletable: true,
133 pk_cols: vec!["id".into()],
134 columns: IndexMap::new(),
135 };
136
137 let qi = table.qualified_identifier();
138 assert_eq!(qi.schema, "public");
139 assert_eq!(qi.name, "users");
140 }
141
142 #[test]
143 fn test_column_is_auto() {
144 let col1 = Column {
145 name: "id".into(),
146 description: None,
147 nullable: false,
148 data_type: "integer".into(),
149 nominal_type: "integer".into(),
150 max_len: None,
151 default: Some("nextval('users_id_seq'::regclass)".into()),
152 enum_values: vec![],
153 is_pk: true,
154 position: 1,
155 };
156 assert!(col1.is_auto());
157
158 let col2 = Column {
159 name: "uuid".into(),
160 description: None,
161 nullable: false,
162 data_type: "uuid".into(),
163 nominal_type: "uuid".into(),
164 max_len: None,
165 default: Some("gen_random_uuid()".into()),
166 enum_values: vec![],
167 is_pk: false,
168 position: 2,
169 };
170 assert!(col2.is_auto());
171
172 let col3 = Column {
173 name: "name".into(),
174 description: None,
175 nullable: false,
176 data_type: "text".into(),
177 nominal_type: "text".into(),
178 max_len: None,
179 default: None,
180 enum_values: vec![],
181 is_pk: false,
182 position: 3,
183 };
184 assert!(!col3.is_auto());
185 }
186}