alopex_sql/executor/query/
scan.rs

1use alopex_core::KVTransaction;
2use alopex_core::kv::KVStore;
3
4use crate::catalog::TableMetadata;
5use crate::executor::Result;
6use crate::storage::{KeyEncoder, SqlTxn, TableScanIterator};
7
8use super::Row;
9use super::iterator::ScanIterator;
10
11/// Execute a table scan and return rows with RowIDs.
12pub fn execute_scan<'txn, S: KVStore + 'txn>(
13    txn: &mut impl SqlTxn<'txn, S>,
14    table_meta: &crate::catalog::TableMetadata,
15) -> Result<Vec<Row>> {
16    Ok(txn.with_table(table_meta, |storage| {
17        let iter = storage.range_scan(0, u64::MAX)?;
18        let mut rows = Vec::new();
19        for entry in iter {
20            let (row_id, values) = entry?;
21            rows.push(Row::new(row_id, values));
22        }
23        Ok(rows)
24    })?)
25}
26
27/// Create a streaming scan iterator for FR-7 compliance.
28///
29/// This function creates a `ScanIterator` that streams rows directly from
30/// the underlying storage without materializing all rows upfront.
31///
32/// # Lifetime
33///
34/// The returned iterator borrows from the transaction (`'a`), so the
35/// transaction must remain valid while the iterator is in use.
36pub fn create_scan_iterator<'a, 'txn: 'a, S: KVStore + 'txn, T: SqlTxn<'txn, S>>(
37    txn: &'a mut T,
38    table_meta: &TableMetadata,
39) -> Result<ScanIterator<'a>> {
40    let table_id = table_meta.table_id;
41    let prefix = KeyEncoder::table_prefix(table_id);
42    let inner = txn.inner_mut().scan_prefix(&prefix)?;
43    let table_scan_iter = TableScanIterator::new(inner, table_id);
44    Ok(ScanIterator::new(table_scan_iter, table_meta))
45}