sqlx_core_oldapi/odbc/
row.rs1use crate::column::ColumnIndex;
2use crate::database::HasValueRef;
3use crate::error::Error;
4use crate::odbc::{Odbc, OdbcColumn, OdbcValue};
5use crate::row::Row;
6use crate::value::Value;
7
8#[derive(Debug, Clone)]
9pub struct OdbcRow {
10 pub(crate) columns: Vec<OdbcColumn>,
11 pub(crate) values: Vec<OdbcValue>,
12}
13
14impl Row for OdbcRow {
15 type Database = Odbc;
16
17 fn columns(&self) -> &[OdbcColumn] {
18 &self.columns
19 }
20
21 fn try_get_raw<I>(
22 &self,
23 index: I,
24 ) -> Result<<Self::Database as HasValueRef<'_>>::ValueRef, Error>
25 where
26 I: ColumnIndex<Self>,
27 {
28 let idx = index.index(self)?;
29 let value = &self.values[idx];
30 Ok(value.as_ref())
31 }
32}
33
34impl ColumnIndex<OdbcRow> for &str {
35 fn index(&self, row: &OdbcRow) -> Result<usize, Error> {
36 if let Some(pos) = row.columns.iter().position(|col| col.name == *self) {
38 return Ok(pos);
39 }
40
41 row.columns
43 .iter()
44 .position(|col| col.name.eq_ignore_ascii_case(self))
45 .ok_or_else(|| Error::ColumnNotFound((*self).into()))
46 }
47}
48
49mod private {
50 use super::OdbcRow;
51 use crate::row::private_row::Sealed;
52 impl Sealed for OdbcRow {}
53}
54
55#[cfg(feature = "any")]
56impl From<OdbcRow> for crate::any::AnyRow {
57 fn from(row: OdbcRow) -> Self {
58 let columns = row
59 .columns
60 .iter()
61 .map(|col| crate::any::AnyColumn {
62 kind: crate::any::column::AnyColumnKind::Odbc(col.clone()),
63 type_info: crate::any::AnyTypeInfo::from(col.type_info.clone()),
64 })
65 .collect();
66
67 crate::any::AnyRow {
68 kind: crate::any::row::AnyRowKind::Odbc(row),
69 columns,
70 }
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use crate::odbc::{OdbcColumn, OdbcTypeInfo};
78 use crate::type_info::TypeInfo;
79 use odbc_api::DataType;
80
81 fn create_test_row() -> OdbcRow {
82 use crate::odbc::OdbcValue;
83
84 OdbcRow {
85 columns: vec![
86 OdbcColumn {
87 name: "lowercase_col".to_string(),
88 type_info: OdbcTypeInfo::new(DataType::Integer),
89 ordinal: 0,
90 },
91 OdbcColumn {
92 name: "UPPERCASE_COL".to_string(),
93 type_info: OdbcTypeInfo::new(DataType::Varchar { length: None }),
94 ordinal: 1,
95 },
96 OdbcColumn {
97 name: "MixedCase_Col".to_string(),
98 type_info: OdbcTypeInfo::new(DataType::Double),
99 ordinal: 2,
100 },
101 ],
102 values: vec![
103 OdbcValue {
104 type_info: OdbcTypeInfo::new(DataType::Integer),
105 is_null: false,
106 text: None,
107 blob: None,
108 int: Some(42),
109 float: None,
110 },
111 OdbcValue {
112 type_info: OdbcTypeInfo::new(DataType::Varchar { length: None }),
113 is_null: false,
114 text: Some("test".to_string()),
115 blob: None,
116 int: None,
117 float: None,
118 },
119 OdbcValue {
120 type_info: OdbcTypeInfo::new(DataType::Double),
121 is_null: false,
122 text: None,
123 blob: None,
124 int: None,
125 float: Some(std::f64::consts::PI),
126 },
127 ],
128 }
129 }
130
131 #[test]
132 fn test_exact_column_match() {
133 let row = create_test_row();
134
135 assert_eq!("lowercase_col".index(&row).unwrap(), 0);
137 assert_eq!("UPPERCASE_COL".index(&row).unwrap(), 1);
138 assert_eq!("MixedCase_Col".index(&row).unwrap(), 2);
139 }
140
141 #[test]
142 fn test_case_insensitive_column_match() {
143 let row = create_test_row();
144
145 assert_eq!("LOWERCASE_COL".index(&row).unwrap(), 0);
147 assert_eq!("lowercase_col".index(&row).unwrap(), 0);
148 assert_eq!("uppercase_col".index(&row).unwrap(), 1);
149 assert_eq!("UPPERCASE_COL".index(&row).unwrap(), 1);
150 assert_eq!("mixedcase_col".index(&row).unwrap(), 2);
151 assert_eq!("MIXEDCASE_COL".index(&row).unwrap(), 2);
152 assert_eq!("MixedCase_Col".index(&row).unwrap(), 2);
153 }
154
155 #[test]
156 fn test_column_not_found() {
157 let row = create_test_row();
158
159 let result = "nonexistent_column".index(&row);
160 assert!(result.is_err());
161 if let Err(Error::ColumnNotFound(name)) = result {
162 assert_eq!(name, "nonexistent_column");
163 } else {
164 panic!("Expected ColumnNotFound error");
165 }
166 }
167
168 #[test]
169 fn test_try_get_raw() {
170 let row = create_test_row();
171
172 let value = row.try_get_raw("lowercase_col").unwrap();
174 assert!(!value.is_null);
175 assert_eq!(value.type_info.name(), "INTEGER");
176
177 let value = row.try_get_raw("LOWERCASE_COL").unwrap();
179 assert!(!value.is_null);
180 assert_eq!(value.type_info.name(), "INTEGER");
181
182 let value = row.try_get_raw("uppercase_col").unwrap();
184 assert!(!value.is_null);
185 assert_eq!(value.type_info.name(), "VARCHAR");
186 }
187
188 #[test]
189 fn test_columns_method() {
190 let row = create_test_row();
191 let columns = row.columns();
192
193 assert_eq!(columns.len(), 3);
194 assert_eq!(columns[0].name, "lowercase_col");
195 assert_eq!(columns[1].name, "UPPERCASE_COL");
196 assert_eq!(columns[2].name, "MixedCase_Col");
197 }
198}