Skip to main content

sochdb_query/executor/
types.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3//! Core types for the Volcano executor.
4
5use crate::soch_ql::SochValue;
6
7/// A single row: positional values matching the schema column order.
8pub type Row = Vec<SochValue>;
9
10/// Column metadata.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct ColumnMeta {
13    /// Column name.
14    pub name: String,
15    /// Source table (if known).
16    pub table: Option<String>,
17}
18
19impl ColumnMeta {
20    pub fn new(name: impl Into<String>) -> Self {
21        Self { name: name.into(), table: None }
22    }
23
24    pub fn qualified(table: impl Into<String>, name: impl Into<String>) -> Self {
25        Self { name: name.into(), table: Some(table.into()) }
26    }
27}
28
29/// Schema: ordered list of columns defining the row layout.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct Schema {
32    pub columns: Vec<ColumnMeta>,
33}
34
35impl Schema {
36    pub fn new(columns: Vec<ColumnMeta>) -> Self {
37        Self { columns }
38    }
39
40    pub fn empty() -> Self {
41        Self { columns: vec![] }
42    }
43
44    /// Number of columns.
45    pub fn len(&self) -> usize {
46        self.columns.len()
47    }
48
49    pub fn is_empty(&self) -> bool {
50        self.columns.is_empty()
51    }
52
53    /// Find column index by name (unqualified lookup).
54    pub fn index_of(&self, name: &str) -> Option<usize> {
55        self.columns.iter().position(|c| c.name == name)
56    }
57
58    /// Find column index by qualified name (table.column).
59    pub fn index_of_qualified(&self, table: Option<&str>, name: &str) -> Option<usize> {
60        match table {
61            Some(t) => self.columns.iter().position(|c| {
62                c.name == name && c.table.as_deref() == Some(t)
63            }),
64            None => self.index_of(name),
65        }
66    }
67
68    /// Column names as strings.
69    pub fn column_names(&self) -> Vec<String> {
70        self.columns.iter().map(|c| c.name.clone()).collect()
71    }
72
73    /// Merge two schemas (for joins).
74    pub fn merge(&self, other: &Schema) -> Schema {
75        let mut cols = self.columns.clone();
76        cols.extend(other.columns.iter().cloned());
77        Schema::new(cols)
78    }
79}