1use crate::span::Span;
4use crate::types::{CqlType, Order};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum ColumnRole {
10 PartitionKey,
12 ClusteringKey,
14 Regular,
16}
17
18#[derive(Clone, Debug, PartialEq)]
20#[non_exhaustive]
21pub struct Column {
22 pub name: String,
24 pub cql_type: CqlType,
26 pub role: ColumnRole,
28 pub is_static: bool,
30 pub span: Span,
32}
33
34impl Column {
35 pub fn is_key(&self) -> bool {
37 self.role != ColumnRole::Regular
38 }
39
40 pub fn nullable(&self) -> bool {
42 !self.is_key()
43 }
44}
45
46#[derive(Clone, Debug, PartialEq)]
48#[non_exhaustive]
49pub struct ClusteringColumn {
50 pub name: String,
52 pub order: Order,
54}
55
56#[derive(Clone, Debug, PartialEq)]
58#[non_exhaustive]
59pub struct Table {
60 pub keyspace: Option<String>,
62 pub name: String,
64 pub columns: Vec<Column>,
66 pub partition_key: Vec<String>,
68 pub clustering: Vec<ClusteringColumn>,
70 pub span: Span,
72}
73
74impl Table {
75 pub fn column(&self, name: &str) -> Option<&Column> {
77 self.columns.iter().find(|c| c.name == name)
78 }
79
80 pub fn is_counter_table(&self) -> bool {
82 self.columns
83 .iter()
84 .any(|c| matches!(c.cql_type, CqlType::Counter))
85 }
86
87 pub fn qualified_name(&self) -> String {
89 match &self.keyspace {
90 Some(ks) => format!("{ks}.{}", self.name),
91 None => self.name.clone(),
92 }
93 }
94}
95
96#[derive(Clone, Debug, PartialEq)]
98#[non_exhaustive]
99pub struct Udt {
100 pub keyspace: Option<String>,
102 pub name: String,
104 pub fields: Vec<(String, CqlType)>,
106 pub span: Span,
108}
109
110#[derive(Clone, Debug, Default, PartialEq)]
112#[non_exhaustive]
113pub struct Schema {
114 pub tables: Vec<Table>,
116 pub udts: Vec<Udt>,
118}
119
120impl Schema {
121 pub fn udt(&self, name: &str) -> Option<&Udt> {
123 self.udts.iter().find(|u| u.name == name)
124 }
125}
126
127#[derive(Debug)]
129#[non_exhaustive]
130pub enum Lookup<'a> {
131 Found(&'a Table),
133 NotFound,
135 Ambiguous(Vec<&'a Table>),
137}
138
139impl Schema {
140 pub fn lookup_table(&self, keyspace: Option<&str>, name: &str) -> Lookup<'_> {
143 let matches: Vec<&Table> = self
144 .tables
145 .iter()
146 .filter(|t| {
147 t.name == name && keyspace.is_none_or(|ks| t.keyspace.as_deref() == Some(ks))
148 })
149 .collect();
150 match matches.len() {
151 0 => Lookup::NotFound,
152 1 => Lookup::Found(matches[0]),
153 _ => Lookup::Ambiguous(matches),
154 }
155 }
156}