use lunaris_core::Hlc;
use lunaris_core::storage::types::Filter;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SourceOp {
Vector,
Keyword,
Fused,
Reranked,
Graph,
Tree,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RawHit {
pub id: Vec<u8>,
pub score: f32,
pub rerank_applied: bool,
#[serde(default)]
pub degraded: bool,
#[serde(default)]
pub metadata: serde_json::Value,
pub source_op: SourceOp,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Hit {
pub id: Vec<u8>,
#[serde(skip)]
pub episode_id: Vec<u8>,
pub score: f32,
pub text: String,
pub source: String,
#[serde(default)]
pub heading_path: Vec<String>,
pub valid_from: Hlc,
pub valid_to: Option<Hlc>,
pub degraded: bool,
pub rerank_applied: bool,
pub source_op: SourceOp,
}
#[derive(Clone, Debug, Default)]
pub struct Query {
pub text: String,
pub k: usize,
pub filter: Option<Filter>,
pub as_of: Option<Hlc>,
}
impl Query {
pub fn text(t: impl Into<String>) -> Self {
Self { text: t.into(), k: 30, filter: None, as_of: None }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn query_text_defaults() {
let q = Query::text("hello");
assert_eq!(q.text, "hello");
assert_eq!(q.k, 30);
assert!(q.filter.is_none());
assert!(q.as_of.is_none());
}
#[test]
fn source_op_is_hashable_and_eq() {
use std::collections::HashSet;
let mut s = HashSet::new();
s.insert(SourceOp::Vector);
s.insert(SourceOp::Vector);
s.insert(SourceOp::Keyword);
s.insert(SourceOp::Graph); assert_eq!(s.len(), 3);
}
#[test]
fn source_op_graph_is_distinct_from_other_variants() {
assert_ne!(SourceOp::Graph, SourceOp::Vector);
assert_ne!(SourceOp::Graph, SourceOp::Keyword);
assert_ne!(SourceOp::Graph, SourceOp::Fused);
assert_ne!(SourceOp::Graph, SourceOp::Reranked);
}
}