use async_trait::async_trait;
use ulid::Ulid;
use crate::error::GradatumError;
use crate::identity::NoteId;
use crate::index::{FileChecksumEntry, NoteRecord, TemporalEntry};
use crate::scope::{OverrideScope, VaultId};
use crate::status::NoteStatus;
#[derive(Debug, Clone)]
pub struct SearchHitRaw {
pub note_id: NoteId,
pub bm25: f64,
pub status: String,
pub snippet: String,
pub section: String,
pub title: Option<String>,
}
#[derive(Debug, Clone)]
pub struct LessonHitRaw {
pub note_id: NoteId,
pub title: Option<String>,
pub snippet: String,
pub tags: Vec<String>,
pub anchor_ms: i64,
}
#[derive(Debug, Clone)]
pub struct ReviewQueueRow {
pub note_id: NoteId,
pub title: Option<String>,
pub section: String,
pub locus: Option<String>,
pub status: String,
pub provenance: Option<String>,
pub created_ms: i64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AuthorRow {
pub name: String,
pub note_count: u64,
}
#[derive(Debug, Clone, Default)]
pub struct Lineage {
pub parents: Vec<String>,
pub children: Vec<String>,
}
#[derive(Debug, Clone)]
pub enum CodeSelector {
Query(String),
Path(String),
Symbol(String),
}
#[derive(Debug, Clone)]
pub struct CodeScopeEntryRaw {
pub note_id: NoteId,
pub source_path: String,
pub kind: String,
pub qualified_name: String,
pub signature: Option<String>,
pub deps: Vec<String>,
pub bm25: f64,
pub span: Option<(u32, u32)>,
}
#[async_trait]
pub trait IndexStore: Send + Sync {
async fn search_fts(
&self,
vault_id: &VaultId,
query: &str,
limit: usize,
) -> Result<Vec<NoteId>, GradatumError>;
async fn search_fts_scored(
&self,
vault_id: &VaultId,
query: &str,
limit: usize,
include_downgraded: bool,
) -> Result<Vec<(NoteId, f64, String)>, GradatumError>;
async fn upsert_override_raw(
&self,
note_id: NoteId,
scope: &OverrideScope,
override_type: &str,
schema_version: u32,
payload_toml: &str,
) -> Result<(), GradatumError>;
async fn get_override_raw(
&self,
note_id: NoteId,
scope: &OverrideScope,
override_type: &str,
) -> Result<Option<(u32, String)>, GradatumError>;
async fn upsert_file_checksum(&self, entry: &FileChecksumEntry) -> Result<(), GradatumError>;
async fn list_file_checksums(&self) -> Result<Vec<FileChecksumEntry>, GradatumError>;
async fn get_note_created_and_indegree(
&self,
vault_id: &str,
note_id: &str,
) -> Result<(i64, u64), GradatumError>;
#[expect(
clippy::too_many_arguments,
reason = "filtres de recherche orthogonaux (F-37 notes fix) — struct d'options sans gain"
)]
async fn search_fts_with_snippet(
&self,
vault_id: &VaultId,
query: &str,
limit: usize,
include_downgraded: bool,
section: Option<&str>,
locus: Option<&str>,
status: Option<&str>,
) -> Result<Vec<SearchHitRaw>, GradatumError>;
async fn recall_lessons(
&self,
vault_id: &VaultId,
class: &str,
limit: usize,
) -> Result<Vec<LessonHitRaw>, GradatumError>;
async fn list_review_queue(
&self,
vault_id: &VaultId,
cursor: Option<&str>,
limit: usize,
) -> Result<Vec<ReviewQueueRow>, GradatumError>;
async fn count_review_queue(&self, vault_id: &VaultId) -> Result<u64, GradatumError>;
async fn title_lookup(
&self,
vault_id: &str,
title: &str,
) -> Result<Option<String>, GradatumError>;
async fn id_lookup(
&self,
vault_id: &str,
note_id: &str,
) -> Result<Option<String>, GradatumError>;
async fn live_note_count(&self, vault_id: &str) -> Result<u64, GradatumError>;
async fn distinct_authors(&self, vault_id: &str) -> Result<Vec<AuthorRow>, GradatumError>;
async fn distinct_tags(&self, vault_id: &str) -> Result<Vec<(String, u64)>, GradatumError>;
async fn neighbors(
&self,
vault_id: &str,
note_id: &str,
depth: u8,
) -> Result<Vec<String>, GradatumError>;
async fn backlinks(&self, vault_id: &str, note_id: &str) -> Result<Vec<String>, GradatumError>;
async fn trace_lineage(&self, vault_id: &str, note_id: &str) -> Result<Lineage, GradatumError>;
async fn list_notes(
&self,
vault_id: &str,
section: Option<&str>,
limit: usize,
cursor: Option<&str>,
) -> Result<(Vec<NoteRecord>, u64), GradatumError>;
async fn total_body_size_bytes(&self, vault_id: &str) -> Result<u64, GradatumError>;
async fn upsert_link(
&self,
vault_id: &str,
src_note_id: &str,
dst_note_id: &str,
) -> Result<(), GradatumError>;
async fn get_titles_sections(
&self,
vault_id: &str,
ids: &[String],
) -> Result<std::collections::HashMap<String, (Option<String>, String)>, GradatumError>;
async fn get_statuses(
&self,
_vault_id: &str,
_ids: &[String],
) -> Result<std::collections::HashMap<String, String>, GradatumError> {
Ok(std::collections::HashMap::new())
}
async fn get_trust(&self, id: &NoteId) -> Result<Option<f32>, GradatumError>;
async fn get_trust_and_provenance(
&self,
_vault_id: &str,
_note_id: &str,
) -> Result<(Option<f32>, Option<String>), GradatumError> {
Ok((None, None))
}
async fn upsert_redirect(
&self,
slug: &str,
ulid: &Ulid,
renamed_at_ms: i64,
) -> Result<(), GradatumError>;
async fn resolve_redirect(&self, slug: &str) -> Result<Option<Ulid>, GradatumError>;
async fn search_fts_for_forget(
&self,
vault_id: &str,
query: &str,
limit: usize,
) -> Result<Vec<(String, String)>, GradatumError>;
async fn list_notes_by_locus_prefix(
&self,
vault_id: &str,
prefix: &str,
) -> Result<Vec<(String, String)>, GradatumError>;
async fn list_notes_by_agent(
&self,
agent_id: &str,
vaults: &[String],
) -> Result<Vec<(String, String)>, GradatumError>;
#[must_use = "le nombre de lignes affectées indique si la note existait"]
async fn set_note_trust(&self, _id: &NoteId, _trust: f32) -> Result<usize, GradatumError> {
Ok(0)
}
async fn write_temporal_entry(&self, _entry: &TemporalEntry) -> Result<(), GradatumError> {
Ok(())
}
async fn timeline(
&self,
vault_id: &VaultId,
filter: &crate::temporal_query::TimelineFilter,
) -> Result<Vec<crate::temporal_query::TimelineRow>, GradatumError>;
async fn delete_redirect_by_ulid(&self, _ulid_str: &str) -> Result<usize, GradatumError> {
Ok(0)
}
async fn delete_note_from_index(
&self,
_vault_id: &str,
_note_id: &str,
) -> Result<bool, GradatumError> {
Ok(false)
}
async fn list_garbage_older_than(
&self,
_vault_id: &str,
_cutoff_ms: i64,
) -> Result<Vec<NoteId>, GradatumError> {
Ok(vec![])
}
async fn get_note_status(
&self,
_vault_id: &str,
_note_id: &str,
) -> Result<Option<NoteStatus>, GradatumError> {
Ok(None)
}
async fn get_note_section(
&self,
_vault_id: &str,
_note_id: &str,
) -> Result<Option<String>, GradatumError> {
Ok(None)
}
async fn is_note_forgotten(
&self,
_vault_id: &str,
_note_id: &str,
) -> Result<bool, GradatumError> {
Ok(false)
}
async fn code_scope_query(
&self,
_vault_id: &str,
_selector: &CodeSelector,
_limit: usize,
) -> Result<Vec<CodeScopeEntryRaw>, GradatumError> {
Ok(Vec::new())
}
async fn code_scope_reverse_deps(
&self,
_vault_id: &str,
_qualified_name: &str,
_limit: usize,
) -> Result<Vec<CodeScopeEntryRaw>, GradatumError> {
Ok(Vec::new())
}
async fn code_scope_reverse_deps_batch(
&self,
_vault_id: &str,
_names: &[&str],
_limit: usize,
) -> Result<std::collections::HashMap<String, Vec<String>>, GradatumError> {
Ok(std::collections::HashMap::new())
}
async fn get_last_ingested_sha(
&self,
_vault_id: &str,
) -> Result<Option<String>, GradatumError> {
Ok(None)
}
async fn get_code_vault_repo_path(
&self,
_vault_id: &str,
) -> Result<Option<String>, GradatumError> {
Ok(None)
}
#[allow(clippy::too_many_arguments)]
async fn count_fts_matches(
&self,
_vault_id: &VaultId,
_query: &str,
_include_downgraded: bool,
_section: Option<&str>,
_locus: Option<&str>,
_status: Option<&str>,
) -> Result<(u64, bool), GradatumError> {
Ok((0, false))
}
async fn code_freshness_hashes(
&self,
_vault_id: &str,
_source_paths: &[String],
) -> Result<std::collections::HashMap<String, String>, GradatumError> {
Ok(std::collections::HashMap::new())
}
async fn persist_curated_index_atomic(
&self,
_note_id: &NoteId,
_title: &str,
_temporal: Option<&TemporalEntry>,
_links: &[(String, String)],
_trust: Option<f32>,
_vault_id: &str,
) -> Result<(), GradatumError> {
Ok(())
}
async fn backfill_ann_index(&self) -> Result<u64, GradatumError> {
Ok(0)
}
}