1use crate::constants::FetchOrientation;
28use crate::row::Row;
29use crate::statement::ColumnInfo;
30
31#[derive(Debug)]
37pub struct ScrollableCursor {
38 pub(crate) cursor_id: u16,
40 pub(crate) columns: Vec<ColumnInfo>,
42 pub(crate) is_open: bool,
44 pub(crate) position: i64,
46 pub(crate) row_count: Option<u64>,
48}
49
50impl ScrollableCursor {
51 pub(crate) fn new(cursor_id: u16, columns: Vec<ColumnInfo>) -> Self {
53 Self {
54 cursor_id,
55 columns,
56 is_open: true,
57 position: 0,
58 row_count: None,
59 }
60 }
61
62 pub fn cursor_id(&self) -> u16 {
64 self.cursor_id
65 }
66
67 pub fn columns(&self) -> &[ColumnInfo] {
69 &self.columns
70 }
71
72 pub fn is_open(&self) -> bool {
74 self.is_open
75 }
76
77 pub fn position(&self) -> i64 {
79 self.position
80 }
81
82 pub fn row_count(&self) -> Option<u64> {
84 self.row_count
85 }
86
87 pub(crate) fn mark_closed(&mut self) {
89 self.is_open = false;
90 }
91
92 pub(crate) fn update_position(&mut self, new_position: i64) {
94 self.position = new_position;
95 }
96}
97
98#[derive(Debug, Clone, Default)]
100pub struct ScrollableCursorOptions {
101 pub array_size: u32,
103}
104
105impl ScrollableCursorOptions {
106 pub fn new() -> Self {
108 Self::default()
109 }
110
111 pub fn with_array_size(mut self, size: u32) -> Self {
113 self.array_size = size;
114 self
115 }
116}
117
118#[derive(Debug)]
120pub struct ScrollResult {
121 pub rows: Vec<Row>,
123 pub position: i64,
125 pub at_beginning: bool,
127 pub at_end: bool,
129}
130
131impl ScrollResult {
132 pub fn new(rows: Vec<Row>, position: i64) -> Self {
134 Self {
135 rows,
136 position,
137 at_beginning: false,
138 at_end: false,
139 }
140 }
141
142 pub fn first(&self) -> Option<&Row> {
144 self.rows.first()
145 }
146
147 pub fn is_empty(&self) -> bool {
149 self.rows.is_empty()
150 }
151
152 pub fn len(&self) -> usize {
154 self.rows.len()
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub enum ScrollMode {
161 First,
163 Last,
165 Relative,
167 Absolute,
169}
170
171impl Default for ScrollMode {
172 fn default() -> Self {
173 Self::Relative
174 }
175}
176
177impl From<ScrollMode> for FetchOrientation {
178 fn from(mode: ScrollMode) -> Self {
179 match mode {
180 ScrollMode::First => FetchOrientation::First,
181 ScrollMode::Last => FetchOrientation::Last,
182 ScrollMode::Relative => FetchOrientation::Relative,
183 ScrollMode::Absolute => FetchOrientation::Absolute,
184 }
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use crate::constants::OracleType;
192
193 #[test]
194 fn test_scrollable_cursor_creation() {
195 let columns = vec![
196 ColumnInfo::new("ID", OracleType::Number),
197 ColumnInfo::new("NAME", OracleType::Varchar),
198 ];
199 let cursor = ScrollableCursor::new(123, columns);
200
201 assert_eq!(cursor.cursor_id(), 123);
202 assert_eq!(cursor.columns().len(), 2);
203 assert!(cursor.is_open());
204 assert_eq!(cursor.position(), 0);
205 }
206
207 #[test]
208 fn test_scrollable_cursor_close() {
209 let mut cursor = ScrollableCursor::new(1, Vec::new());
210 assert!(cursor.is_open());
211 cursor.mark_closed();
212 assert!(!cursor.is_open());
213 }
214
215 #[test]
216 fn test_scroll_result() {
217 let rows = vec![Row::new(vec![crate::row::Value::Integer(1)])];
218 let result = ScrollResult::new(rows, 5);
219
220 assert_eq!(result.len(), 1);
221 assert!(!result.is_empty());
222 assert_eq!(result.position, 5);
223 assert!(result.first().is_some());
224 }
225
226 #[test]
227 fn test_scroll_mode_conversion() {
228 assert_eq!(FetchOrientation::from(ScrollMode::First), FetchOrientation::First);
229 assert_eq!(FetchOrientation::from(ScrollMode::Last), FetchOrientation::Last);
230 assert_eq!(FetchOrientation::from(ScrollMode::Relative), FetchOrientation::Relative);
231 assert_eq!(FetchOrientation::from(ScrollMode::Absolute), FetchOrientation::Absolute);
232 }
233
234 #[test]
235 fn test_scrollable_cursor_options() {
236 let opts = ScrollableCursorOptions::new()
237 .with_array_size(50);
238 assert_eq!(opts.array_size, 50);
239 }
240}