1use std::collections::HashMap;
2use std::sync::Arc;
3
4use bytes::Bytes;
5
6use crate::error::{Error, Result};
7use crate::protocol::backend::{DataRowColumns, FieldDescription};
8use crate::types::FromSql;
9
10#[derive(Debug, Clone)]
14pub struct RowDescription {
15 fields: Vec<FieldDescription>,
16 name_index: HashMap<String, usize>,
17}
18
19impl RowDescription {
20 pub fn new(fields: Vec<FieldDescription>) -> Self {
21 let name_index = fields
22 .iter()
23 .enumerate()
24 .map(|(i, f)| (f.name.clone(), i))
25 .collect();
26
27 Self { fields, name_index }
28 }
29
30 pub fn len(&self) -> usize {
32 self.fields.len()
33 }
34
35 pub fn is_empty(&self) -> bool {
36 self.fields.is_empty()
37 }
38
39 pub fn field(&self, idx: usize) -> Option<&FieldDescription> {
41 self.fields.get(idx)
42 }
43
44 pub fn column_index(&self, name: &str) -> Option<usize> {
46 self.name_index.get(name).copied()
47 }
48
49 pub fn fields(&self) -> &[FieldDescription] {
51 &self.fields
52 }
53}
54
55#[derive(Debug)]
60pub struct Row {
61 columns: DataRowColumns,
62 description: Arc<RowDescription>,
63}
64
65impl Row {
66 pub fn new(columns: DataRowColumns, description: Arc<RowDescription>) -> Self {
67 Self {
68 columns,
69 description,
70 }
71 }
72
73 pub fn get<T: FromSql>(&self, idx: usize) -> T {
80 self.try_get(idx)
81 .unwrap_or_else(|e| panic!("error getting column {idx}: {e}"))
82 }
83
84 pub fn get_by_name<T: FromSql>(&self, name: &str) -> T {
90 self.try_get_by_name(name)
91 .unwrap_or_else(|e| panic!("error getting column '{name}': {e}"))
92 }
93
94 pub fn try_get<T: FromSql>(&self, idx: usize) -> Result<T> {
96 if idx >= self.columns.len() {
97 return Err(Error::ColumnIndex {
98 index: idx,
99 count: self.columns.len(),
100 });
101 }
102
103 let raw = self.columns.get(idx);
104 T::from_sql_nullable(raw.as_deref())
105 }
106
107 pub fn try_get_by_name<T: FromSql>(&self, name: &str) -> Result<T> {
109 let idx = self
110 .description
111 .column_index(name)
112 .ok_or_else(|| Error::ColumnNotFound(name.to_string()))?;
113 self.try_get(idx)
114 }
115
116 pub fn get_raw(&self, idx: usize) -> Option<Bytes> {
118 self.columns.get(idx)
119 }
120
121 pub fn is_null(&self, idx: usize) -> bool {
123 self.columns.is_null(idx)
124 }
125
126 pub fn len(&self) -> usize {
128 self.columns.len()
129 }
130
131 pub fn is_empty(&self) -> bool {
132 self.columns.is_empty()
133 }
134
135 pub fn description(&self) -> &RowDescription {
137 &self.description
138 }
139}
140
141pub fn parse_command_tag(tag: &str) -> CommandResult {
145 let parts: Vec<&str> = tag.split_whitespace().collect();
146 let command = parts.first().copied().unwrap_or("");
147
148 let rows_affected = match command {
149 "INSERT" => parts.get(2).and_then(|s| s.parse().ok()).unwrap_or(0),
150 "SELECT" | "UPDATE" | "DELETE" | "COPY" | "MERGE" | "MOVE" | "FETCH" => {
151 parts.last().and_then(|s| s.parse().ok()).unwrap_or(0)
152 }
153 _ => 0,
154 };
155
156 CommandResult {
157 command: command.to_string(),
158 rows_affected,
159 }
160}
161
162#[derive(Debug, Clone)]
164pub struct CommandResult {
165 pub command: String,
166 pub rows_affected: u64,
167}
168
169#[derive(Debug, Clone)]
174pub enum SimpleQueryMessage {
175 Row(SimpleQueryRow),
177 CommandComplete(u64),
179}
180
181#[derive(Debug, Clone)]
186pub struct SimpleQueryRow {
187 columns: Vec<Option<String>>,
188}
189
190impl SimpleQueryRow {
191 pub fn new(columns: Vec<Option<String>>) -> Self {
192 Self { columns }
193 }
194
195 pub fn get(&self, idx: usize) -> Option<&str> {
197 self.columns.get(idx).and_then(|c| c.as_deref())
198 }
199
200 pub fn try_get(&self, idx: usize) -> Result<&str> {
203 if idx >= self.columns.len() {
204 return Err(Error::ColumnIndex {
205 index: idx,
206 count: self.columns.len(),
207 });
208 }
209 self.columns[idx]
210 .as_deref()
211 .ok_or_else(|| Error::Decode("unexpected NULL in simple query row".into()))
212 }
213
214 pub fn len(&self) -> usize {
216 self.columns.len()
217 }
218
219 pub fn is_empty(&self) -> bool {
221 self.columns.is_empty()
222 }
223}