1use miette::Diagnostic;
8use sqlx::QueryBuilder;
9use thiserror::Error;
10
11use crate::{Bind, Result, Table, runtime::sql::Bindings};
12
13#[derive(Debug, Diagnostic, Error)]
19#[non_exhaustive]
20pub enum QueryError {
21 #[error("IO")]
23 #[diagnostic(code(atmosphere::query::io))]
24 Io(#[source] sqlx::Error),
25
26 #[error("not found")]
28 #[diagnostic(code(atmosphere::query::not_found))]
29 NotFound(#[source] sqlx::Error),
30
31 #[error("sql")]
33 #[diagnostic(transparent)]
34 Sql(#[source] SqlError),
35
36 #[error("violation")]
38 #[diagnostic(transparent)]
39 Violation(#[source] ViolationError),
40
41 #[error("sqlx")]
43 #[diagnostic(code(atmosphere::query::sqlx))]
44 Other(#[source] sqlx::Error),
45
46 #[error("internal error")]
48 #[diagnostic(code(atmosphere::query::internal))]
49 InternalError(#[source] sqlx::Error),
50}
51
52#[derive(Debug, Diagnostic, Error)]
58#[non_exhaustive]
59pub enum ViolationError {
60 #[error("uniqueness violation")]
62 #[diagnostic(code(atmosphere::violation::uniqueness))]
63 Unique(#[source] sqlx::Error),
64
65 #[error("foreign key violation")]
67 #[diagnostic(code(atmosphere::violation::foreign_key))]
68 ForeignKey(#[source] sqlx::Error),
69
70 #[error("integrity check")]
72 #[diagnostic(code(atmosphere::violation::integrity))]
73 Check(#[source] sqlx::Error),
74}
75
76#[derive(Debug, Diagnostic, Error)]
81#[non_exhaustive]
82pub enum SqlError {
83 #[error("data exception")]
85 #[diagnostic(code(atmosphere::sqlstate::data))]
86 DataException(#[source] sqlx::Error),
87
88 #[error("integrity constraint")]
90 #[diagnostic(code(atmosphere::sqlstate::integrity))]
91 IntegrityConstraint(#[source] sqlx::Error),
92
93 #[error("syntax")]
95 #[diagnostic(code(atmosphere::sqlstate::syntax))]
96 Syntax(#[source] sqlx::Error),
97
98 #[error("other")]
100 #[diagnostic(code(atmosphere::sqlstate::other))]
101 Other(#[source] sqlx::Error),
102}
103
104impl From<sqlx::Error> for QueryError {
105 fn from(err: sqlx::Error) -> Self {
106 use sqlx::Error as E;
107
108 match err {
109 E::RowNotFound => Self::NotFound(err),
110 E::Io(_)
111 | E::Protocol(_)
112 | E::Tls(_)
113 | E::Configuration(_)
114 | E::PoolTimedOut
115 | E::PoolClosed
116 | E::WorkerCrashed => Self::Io(err),
117 E::Database(ref e) => {
118 if e.is_unique_violation() {
119 return Self::Violation(ViolationError::Unique(err));
120 }
121
122 if e.is_foreign_key_violation() {
123 return Self::Violation(ViolationError::ForeignKey(err));
124 }
125
126 if e.is_check_violation() {
127 return Self::Violation(ViolationError::Check(err));
128 }
129
130 if let Some(c) = e.code() {
134 if c.len() < 5 {
135 return Self::InternalError(err);
136 }
137
138 return match &c.as_ref()[0..1] {
139 "22" => Self::Sql(SqlError::DataException(err)),
140 "23" => Self::Sql(SqlError::IntegrityConstraint(err)),
141 "42" => Self::Sql(SqlError::Syntax(err)),
142 _ => Self::Sql(SqlError::Other(err)),
143 };
144 }
145
146 Self::Other(err)
147 }
148 _ => Self::Other(err),
149 }
150 }
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq)]
155pub enum Cardinality {
156 None,
157 One,
158 Many,
159}
160
161#[derive(Clone, Copy, Debug, PartialEq, Eq)]
163pub enum Operation {
164 Select,
165 Insert,
166 Update,
167 Upsert,
168 Delete,
169 Other,
170}
171
172pub struct Query<T: Bind> {
174 pub op: Operation,
175 pub cardinality: Cardinality,
176 pub(crate) builder: QueryBuilder<'static, crate::Driver>,
177 pub(crate) bindings: Bindings<T>,
178}
179
180impl<T: Bind> Query<T> {
181 pub(crate) fn new(
182 op: Operation,
183 cardinality: Cardinality,
184 builder: QueryBuilder<'static, crate::Driver>,
185 bindings: Bindings<T>,
186 ) -> Self {
187 Self {
188 op,
189 cardinality,
190 builder,
191 bindings,
192 }
193 }
194
195 pub fn sql(&self) -> &str {
197 self.builder.sql()
198 }
199
200 pub const fn bindings(&self) -> &Bindings<T> {
202 &self.bindings
203 }
204}
205
206pub enum QueryResult<'t, T: Table + Bind> {
208 Execution(&'t Result<<crate::Driver as sqlx::Database>::QueryResult>),
209 Optional(&'t Result<Option<T>>),
210 One(&'t Result<T>),
211 Many(&'t Result<Vec<T>>),
212}