google_cloud_spanner/
error.rs1use google_cloud_gax::error::rpc::Status;
16use std::error::Error;
17
18pub use crate::from_value::ConvertError;
19pub use wkt::{DurationError, TimestampError};
20
21#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
32#[non_exhaustive]
33pub enum SpannerInternalError {
34 #[error("unexpected data received from Spanner: {0}")]
38 UnexpectedData(String),
39}
40
41impl SpannerInternalError {
42 pub(crate) fn new(message: impl Into<String>) -> Self {
43 Self::UnexpectedData(message.into())
44 }
45}
46
47pub(crate) fn internal_error(message: impl Into<String>) -> crate::Error {
48 crate::Error::deser(SpannerInternalError::new(message))
49}
50
51#[derive(thiserror::Error, Debug)]
63#[error("{status}")]
64#[non_exhaustive]
65pub struct BatchUpdateError {
66 pub update_counts: Vec<i64>,
68 #[source]
70 pub status: crate::Error,
71}
72
73impl BatchUpdateError {
74 pub fn extract(err: &crate::Error) -> Option<&Self> {
76 err.source()
77 .and_then(|source| source.downcast_ref::<BatchUpdateError>())
78 }
79
80 pub(crate) fn build_error(update_counts: Vec<i64>, grpc_status: Status) -> crate::Error {
81 let status = crate::Error::service(grpc_status.clone());
82 let err = Self {
83 update_counts,
84 status,
85 };
86 crate::Error::service_full(grpc_status, None, None, Some(Box::new(err)))
87 }
88}
89
90pub(crate) fn aborted_due_to_failed_initial_statement() -> crate::Error {
91 crate::Error::service(
92 google_cloud_gax::error::rpc::Status::default()
93 .set_code(google_cloud_gax::error::rpc::Code::Aborted)
94 .set_message("Aborted due to failed initial statement"),
95 )
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use google_cloud_gax::error::rpc::Code;
102 use static_assertions::assert_impl_all;
103
104 #[test]
105 fn auto_traits() {
106 assert_impl_all!(BatchUpdateError: Send, Sync, std::fmt::Debug);
107 }
108
109 #[test]
110 fn extract_success() {
111 let update_counts = vec![1, 2, 3];
112 let grpc_status = Status::default()
113 .set_code(Code::Aborted)
114 .set_message("Batch failed");
115
116 let err = BatchUpdateError::build_error(update_counts.clone(), grpc_status);
117
118 let extracted = BatchUpdateError::extract(&err).expect("should extract BatchUpdateError");
119 assert_eq!(extracted.update_counts, update_counts);
120 assert_eq!(
121 extracted
122 .status
123 .status()
124 .expect("status should be populated")
125 .code,
126 Code::Aborted
127 );
128 }
129
130 #[test]
131 fn extract_failure() {
132 let grpc_status = Status::default()
133 .set_code(Code::Unknown)
134 .set_message("Regular error");
135 let err = crate::Error::service(grpc_status);
136
137 let extracted = BatchUpdateError::extract(&err);
138 assert!(
139 extracted.is_none(),
140 "should not extract BatchUpdateError from standard service error"
141 );
142 }
143}