1use alloc::rc::Rc;
4use alloc::string::String;
5use alloc::sync::Arc;
6use alloc::vec::Vec;
7use cynos_core::{Row, RowId, Value};
8
9pub type SharedTables = Arc<[String]>;
11
12#[derive(Clone, Debug)]
14enum TablesStorage {
15 Owned(Vec<String>),
17 Shared(SharedTables),
19}
20
21impl TablesStorage {
22 #[inline]
23 fn as_slice(&self) -> &[String] {
24 match self {
25 TablesStorage::Owned(v) => v,
26 TablesStorage::Shared(arc) => arc,
27 }
28 }
29
30 #[inline]
31 #[allow(dead_code)]
32 fn to_vec(&self) -> Vec<String> {
33 match self {
34 TablesStorage::Owned(v) => v.clone(),
35 TablesStorage::Shared(arc) => arc.to_vec(),
36 }
37 }
38
39 #[inline]
40 #[allow(dead_code)]
41 fn len(&self) -> usize {
42 match self {
43 TablesStorage::Owned(v) => v.len(),
44 TablesStorage::Shared(arc) => arc.len(),
45 }
46 }
47}
48
49#[derive(Clone, Debug)]
51pub struct RelationEntry {
52 pub row: Rc<Row>,
54 pub is_combined: bool,
56 tables: TablesStorage,
58}
59
60impl RelationEntry {
61 #[inline]
63 pub fn new_shared(row: Rc<Row>, shared_tables: SharedTables) -> Self {
64 Self {
65 row,
66 is_combined: shared_tables.len() > 1,
67 tables: TablesStorage::Shared(shared_tables),
68 }
69 }
70
71 pub fn new(row: Rc<Row>, tables: Vec<String>) -> Self {
73 Self {
74 row,
75 is_combined: tables.len() > 1,
76 tables: TablesStorage::Owned(tables),
77 }
78 }
79
80 pub fn new_owned(row: Row, tables: Vec<String>) -> Self {
82 Self {
83 row: Rc::new(row),
84 is_combined: tables.len() > 1,
85 tables: TablesStorage::Owned(tables),
86 }
87 }
88
89 #[inline]
92 pub fn new_combined(row: Rc<Row>, shared_tables: SharedTables) -> Self {
93 Self {
94 row,
95 is_combined: true,
96 tables: TablesStorage::Shared(shared_tables),
97 }
98 }
99
100 pub fn from_row(row: Rc<Row>, table: impl Into<String>) -> Self {
102 Self {
103 row,
104 is_combined: false,
105 tables: TablesStorage::Owned(alloc::vec![table.into()]),
106 }
107 }
108
109 pub fn from_row_owned(row: Row, table: impl Into<String>) -> Self {
111 Self {
112 row: Rc::new(row),
113 is_combined: false,
114 tables: TablesStorage::Owned(alloc::vec![table.into()]),
115 }
116 }
117
118 pub fn id(&self) -> RowId {
120 self.row.id()
121 }
122
123 pub fn tables(&self) -> &[String] {
125 self.tables.as_slice()
126 }
127
128 pub fn get_field(&self, index: usize) -> Option<&Value> {
130 self.row.get(index)
131 }
132
133 pub fn combine(
136 left: &RelationEntry,
137 left_tables: &[String],
138 right: &RelationEntry,
139 right_tables: &[String],
140 ) -> Self {
141 let left_values = left.row.values();
142 let right_values = right.row.values();
143 let total_len = left_values.len() + right_values.len();
144
145 let mut values = Vec::with_capacity(total_len);
146 values.extend(left_values.iter().cloned());
147 values.extend(right_values.iter().cloned());
148
149 let mut tables = Vec::with_capacity(left_tables.len() + right_tables.len());
150 tables.extend(left_tables.iter().cloned());
151 tables.extend(right_tables.iter().cloned());
152
153 let combined_version = left.row.version().wrapping_add(right.row.version());
155
156 Self {
157 row: Rc::new(Row::dummy_with_version(combined_version, values)),
158 is_combined: true,
159 tables: TablesStorage::Owned(tables),
160 }
161 }
162
163 pub fn combine_with_null(
166 left: &RelationEntry,
167 left_tables: &[String],
168 right_column_count: usize,
169 right_tables: &[String],
170 ) -> Self {
171 let left_values = left.row.values();
172 let total_len = left_values.len() + right_column_count;
173
174 let mut values = Vec::with_capacity(total_len);
175 values.extend(left_values.iter().cloned());
176 values.resize(total_len, Value::Null);
177
178 let mut tables = Vec::with_capacity(left_tables.len() + right_tables.len());
179 tables.extend(left_tables.iter().cloned());
180 tables.extend(right_tables.iter().cloned());
181
182 let combined_version = left.row.version();
184
185 Self {
186 row: Rc::new(Row::dummy_with_version(combined_version, values)),
187 is_combined: true,
188 tables: TablesStorage::Owned(tables),
189 }
190 }
191
192 #[inline]
195 pub fn combine_fast(
196 left: &RelationEntry,
197 right: &RelationEntry,
198 combined_tables: SharedTables,
199 ) -> Self {
200 let left_values = left.row.values();
201 let right_values = right.row.values();
202 let total_len = left_values.len() + right_values.len();
203
204 let mut values = Vec::with_capacity(total_len);
205 values.extend(left_values.iter().cloned());
206 values.extend(right_values.iter().cloned());
207
208 let combined_version = left.row.version().wrapping_add(right.row.version());
210
211 Self {
212 row: Rc::new(Row::dummy_with_version(combined_version, values)),
213 is_combined: true,
214 tables: TablesStorage::Shared(combined_tables),
215 }
216 }
217
218 #[inline]
221 pub fn combine_with_null_fast(
222 left: &RelationEntry,
223 right_column_count: usize,
224 combined_tables: SharedTables,
225 ) -> Self {
226 let left_values = left.row.values();
227 let total_len = left_values.len() + right_column_count;
228
229 let mut values = Vec::with_capacity(total_len);
230 values.extend(left_values.iter().cloned());
231 values.resize(total_len, Value::Null);
232
233 let combined_version = left.row.version();
235
236 Self {
237 row: Rc::new(Row::dummy_with_version(combined_version, values)),
238 is_combined: true,
239 tables: TablesStorage::Shared(combined_tables),
240 }
241 }
242}
243
244#[derive(Clone, Debug)]
246pub struct Relation {
247 pub entries: Vec<RelationEntry>,
249 pub tables: Vec<String>,
251 pub table_column_counts: Vec<usize>,
254}
255
256impl Relation {
257 pub fn new(tables: Vec<String>) -> Self {
259 let table_count = tables.len();
260 Self {
261 entries: Vec::new(),
262 tables,
263 table_column_counts: alloc::vec![0; table_count],
264 }
265 }
266
267 pub fn new_with_column_counts(tables: Vec<String>, column_counts: Vec<usize>) -> Self {
269 Self {
270 entries: Vec::new(),
271 tables,
272 table_column_counts: column_counts,
273 }
274 }
275
276 pub fn empty() -> Self {
278 Self {
279 entries: Vec::new(),
280 tables: Vec::new(),
281 table_column_counts: Vec::new(),
282 }
283 }
284
285 pub fn from_rows(rows: Vec<Rc<Row>>, tables: Vec<String>) -> Self {
288 let shared_tables: SharedTables = Arc::from(tables.as_slice());
289 let column_count = rows.first().map(|r| r.len()).unwrap_or(0);
291 let table_column_counts = if tables.len() == 1 {
292 alloc::vec![column_count]
293 } else {
294 alloc::vec![0; tables.len()]
295 };
296 let entries = rows
297 .into_iter()
298 .map(|row| RelationEntry::new_shared(row, shared_tables.clone()))
299 .collect();
300 Self { entries, tables, table_column_counts }
301 }
302
303 pub fn from_rows_with_column_count(rows: Vec<Rc<Row>>, tables: Vec<String>, column_count: usize) -> Self {
305 let shared_tables: SharedTables = Arc::from(tables.as_slice());
306 let table_column_counts = alloc::vec![column_count];
307 let entries = rows
308 .into_iter()
309 .map(|row| RelationEntry::new_shared(row, shared_tables.clone()))
310 .collect();
311 Self { entries, tables, table_column_counts }
312 }
313
314 pub fn from_rows_owned(rows: Vec<Row>, tables: Vec<String>) -> Self {
317 let shared_tables: SharedTables = Arc::from(tables.as_slice());
318 let column_count = rows.first().map(|r| r.len()).unwrap_or(0);
320 let table_column_counts = if tables.len() == 1 {
321 alloc::vec![column_count]
322 } else {
323 alloc::vec![0; tables.len()]
324 };
325 let entries = rows
326 .into_iter()
327 .map(|row| RelationEntry {
328 row: Rc::new(row),
329 is_combined: shared_tables.len() > 1,
330 tables: TablesStorage::Shared(shared_tables.clone()),
331 })
332 .collect();
333 Self { entries, tables, table_column_counts }
334 }
335
336 pub fn tables(&self) -> &[String] {
338 &self.tables
339 }
340
341 pub fn table_column_counts(&self) -> &[usize] {
343 &self.table_column_counts
344 }
345
346 pub fn get_table_offset(&self, table_name: &str) -> Option<usize> {
349 let mut offset = 0;
350 for (i, t) in self.tables.iter().enumerate() {
351 if t == table_name {
352 return Some(offset);
353 }
354 offset += self.table_column_counts.get(i).copied().unwrap_or(0);
355 }
356 None
357 }
358
359 pub fn len(&self) -> usize {
361 self.entries.len()
362 }
363
364 pub fn is_empty(&self) -> bool {
366 self.entries.is_empty()
367 }
368
369 pub fn push(&mut self, entry: RelationEntry) {
371 self.entries.push(entry);
372 }
373
374 pub fn iter(&self) -> impl Iterator<Item = &RelationEntry> {
376 self.entries.iter()
377 }
378}
379
380impl IntoIterator for Relation {
381 type Item = RelationEntry;
382 type IntoIter = alloc::vec::IntoIter<RelationEntry>;
383
384 fn into_iter(self) -> Self::IntoIter {
385 self.entries.into_iter()
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392 use alloc::vec;
393
394 #[test]
395 fn test_relation_entry() {
396 let row = Rc::new(Row::new(1, vec![Value::Int64(42), Value::String("test".into())]));
397 let entry = RelationEntry::from_row(row, "users");
398
399 assert_eq!(entry.id(), 1);
400 assert_eq!(entry.tables(), &["users"]);
401 assert_eq!(entry.get_field(0), Some(&Value::Int64(42)));
402 assert!(!entry.is_combined);
403 }
404
405 #[test]
406 fn test_relation_entry_combine() {
407 let left_row = Rc::new(Row::new(1, vec![Value::Int64(1)]));
408 let right_row = Rc::new(Row::new(2, vec![Value::Int64(2)]));
409
410 let left_entry = RelationEntry::from_row(left_row, "a");
411 let right_entry = RelationEntry::from_row(right_row, "b");
412
413 let combined = RelationEntry::combine(
414 &left_entry,
415 &["a".into()],
416 &right_entry,
417 &["b".into()],
418 );
419
420 assert!(combined.is_combined);
421 assert_eq!(combined.tables(), &["a", "b"]);
422 assert_eq!(combined.get_field(0), Some(&Value::Int64(1)));
423 assert_eq!(combined.get_field(1), Some(&Value::Int64(2)));
424 }
425
426 #[test]
427 fn test_relation_from_rows() {
428 let rows = vec![
429 Rc::new(Row::new(1, vec![Value::Int64(1)])),
430 Rc::new(Row::new(2, vec![Value::Int64(2)])),
431 ];
432 let relation = Relation::from_rows(rows, vec!["users".into()]);
433
434 assert_eq!(relation.len(), 2);
435 assert_eq!(relation.tables(), &["users"]);
436 }
437}