ic_dbms_api/dbms/
query.rs1mod builder;
4mod delete;
5mod filter;
6
7use std::marker::PhantomData;
8
9use thiserror::Error;
10
11pub use self::builder::QueryBuilder;
12pub use self::delete::DeleteBehavior;
13pub use self::filter::Filter;
14use crate::dbms::table::TableSchema;
15use crate::dbms::value::Value;
16use crate::memory::MemoryError;
17
18pub type QueryResult<T> = Result<T, QueryError>;
20
21#[derive(Debug, Error)]
23pub enum QueryError {
24 #[error("Primary key conflict: record with the same primary key already exists")]
26 PrimaryKeyConflict,
27
28 #[error("Broken foreign key reference to table '{table}' with key '{key:?}'")]
30 BrokenForeignKeyReference { table: &'static str, key: Value },
31
32 #[error("Foreign key constraint violation on table '{referencing_table}' for field '{field}'")]
34 ForeignKeyConstraintViolation {
35 referencing_table: &'static str,
36 field: &'static str,
37 },
38
39 #[error("Unknown column: {0}")]
41 UnknownColumn(String),
42
43 #[error("Missing non-nullable field: {0}")]
45 MissingNonNullableField(&'static str),
46
47 #[error("Type mismatch: expected {expected}, found {found}")]
49 TypeMismatch {
50 column: &'static str,
51 expected: &'static str,
52 found: &'static str,
53 },
54
55 #[error("transaction not found")]
57 TransactionNotFound,
58
59 #[error("Invalid query: {0}")]
61 InvalidQuery(String),
62
63 #[error("Constraint violation: {0}")]
65 ConstraintViolation(String),
66
67 #[error("Memory error: {0}")]
69 MemoryError(MemoryError),
70
71 #[error("Table not found: {0}")]
73 TableNotFound(&'static str),
74
75 #[error("Record not found")]
77 RecordNotFound,
78
79 #[error("Serialization error: {0}")]
81 SerializationError(String),
82
83 #[error("Internal error: {0}")]
85 Internal(String),
86}
87
88#[derive(Debug, Default, Clone, PartialEq, Eq)]
90pub enum Select {
91 #[default]
92 All,
93 Columns(Vec<&'static str>),
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
98pub enum OrderDirection {
99 Ascending,
100 Descending,
101}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
105pub struct Query<T>
106where
107 T: TableSchema,
108{
109 columns: Select,
111 pub eager_relations: Vec<&'static str>,
113 pub filter: Option<Filter>,
115 pub order_by: Vec<(&'static str, OrderDirection)>,
117 pub limit: Option<usize>,
119 pub offset: Option<usize>,
121 _marker: PhantomData<T>,
123}
124
125impl<T> Default for Query<T>
126where
127 T: TableSchema,
128{
129 fn default() -> Self {
130 Self {
131 columns: Select::All,
132 eager_relations: Vec::new(),
133 filter: None,
134 order_by: Vec::new(),
135 limit: None,
136 offset: None,
137 _marker: PhantomData,
138 }
139 }
140}
141
142impl<T> Query<T>
143where
144 T: TableSchema,
145{
146 pub fn builder() -> QueryBuilder<T> {
148 QueryBuilder::default()
149 }
150
151 pub fn all_selected(&self) -> bool {
153 matches!(self.columns, Select::All)
154 }
155
156 pub fn columns(&self) -> Vec<&'static str> {
158 match &self.columns {
159 Select::All => T::columns().iter().map(|col| col.name).collect(),
160 Select::Columns(cols) => cols.clone(),
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167
168 use super::*;
169 use crate::tests::User;
170
171 #[test]
172 fn test_should_build_default_query() {
173 let query: Query<User> = Query::default();
174 assert!(matches!(query.columns, Select::All));
175 assert!(query.eager_relations.is_empty());
176 assert!(query.filter.is_none());
177 assert!(query.order_by.is_empty());
178 assert!(query.limit.is_none());
179 assert!(query.offset.is_none());
180 }
181
182 #[test]
183 fn test_should_get_columns() {
184 let query = Query::<User>::default();
185 let columns = query.columns();
186 assert_eq!(columns, vec!["id", "name",]);
187
188 let query = Query::<User> {
189 columns: Select::Columns(vec!["id"]),
190 ..Default::default()
191 };
192
193 let columns = query.columns();
194 assert_eq!(columns, vec!["id"]);
195 }
196
197 #[test]
198 fn test_should_check_all_selected() {
199 let query = Query::<User>::default();
200 assert!(query.all_selected());
201 }
202}