use rudb_common::{Error, Result, Value};
use rudb_functions::strategy_fields;
use rudb_pipeline::{Morsel, Progress, Source};
use rudb_plan::{Plan, Slice};
use rudb_seam::{SeamId, StrategyRow};
use rudb_vector::{Chunk, VECTOR_SIZE, Vector};
use crate::register::registries;
use crate::schema::Schema;
use crate::source::{Handout, position};
#[derive(Debug)]
pub(crate) struct Strategies {
schema: Schema,
chunks: Vec<Chunk>,
handout: Handout,
}
impl Strategies {
pub(crate) fn new(plan: &Plan, index: u32, columns: Slice) -> Result<Self> {
let all = strategy_fields();
let wanted = plan.field_list(columns).to_vec();
let mut positions = Vec::with_capacity(wanted.len());
for field in &wanted {
let position =
all.iter().position(|held| held.name == field.name).ok_or_else(|| {
Error::internal(format!("rudb_strategies() has no column named {}", field.name))
})?;
positions.push(position);
}
let schema = Schema::numbered(wanted, index);
let registered = registries().rows();
let mut rows = Vec::new();
for seam in SeamId::ALL.iter().copied() {
let mut any = false;
for row in registered.iter().filter(|row| row.seam == seam) {
rows.push(implemented(row));
any = true;
}
if !any {
rows.push(planned(seam));
}
}
let types = schema.types();
let mut chunks = Vec::new();
let mut start = 0;
while start < rows.len() {
let end = (start + VECTOR_SIZE).min(rows.len());
let mut built = Vec::with_capacity(types.len());
for (wanted, ty) in positions.iter().zip(&types) {
let column: Vec<Value> =
rows[start..end].iter().map(|row| row[*wanted].clone()).collect();
built.push(Vector::from_values(ty.clone(), &column)?);
}
chunks.push(Chunk::with_rows(built, end - start)?);
start = end;
}
let handout = Handout::new(chunks.len());
Ok(Self { schema, chunks, handout })
}
pub(crate) fn schema(&self) -> &Schema {
&self.schema
}
}
impl Source for Strategies {
fn morsel(&self) -> Option<Morsel> {
self.handout.take()
}
fn read(&self, morsel: &mut Morsel, out: &mut Chunk) -> Result<Progress> {
*out = match self.chunks.get(position(morsel)) {
Some(chunk) => chunk.clone(),
None => Chunk::empty(&self.schema.types()),
};
morsel.advance(1);
Ok(Progress::Done)
}
}
fn implemented(row: &StrategyRow) -> Vec<Value> {
vec![
text(row.seam.name()),
text(row.seam.milestone()),
text(row.seam.describe()),
text(row.name),
text(row.describe),
text(&row.provenance.to_string()),
text(&row.determinism.to_string()),
Value::Boolean(row.is_reference),
Value::Boolean(row.is_default),
]
}
fn planned(seam: SeamId) -> Vec<Value> {
vec![
text(seam.name()),
text(seam.milestone()),
text(seam.describe()),
Value::Null,
Value::Null,
Value::Null,
Value::Null,
Value::Null,
Value::Null,
]
}
fn text(value: &str) -> Value {
Value::Varchar(value.to_string())
}