use super::{write_file, Scaffold, ScaffoldArgs, ScaffoldResult};
use anyhow::Result;
pub struct SearchScaffold;
impl Scaffold for SearchScaffold {
fn name(&self) -> &'static str {
"search"
}
fn description(&self) -> &'static str {
"Search endpoint: FTS, filters, facets, autocomplete, rok-search driver integration"
}
fn generate(&self, args: &ScaffoldArgs) -> Result<ScaffoldResult> {
let mut r = ScaffoldResult::default();
let d = args.dry_run;
write_file(
&mut r,
"src/app/controllers/search_controller.rs",
CONTROLLER,
d,
)?;
write_file(
&mut r,
"src/app/observers/search_index_observer.rs",
OBSERVER,
d,
)?;
r.warnings
.push("Set SEARCH_DRIVER=meilisearch|typesense|postgres in .env".into());
r.warnings
.push("Register GET /search, GET /search/autocomplete routes".into());
Ok(r)
}
}
const CONTROLLER: &str = r#"use axum::{extract::Query, response::IntoResponse};
use rok_auth::axum::Response;
use serde::Deserialize;
#[derive(Deserialize)]
pub struct SearchQuery {
pub q: Option<String>,
pub page: Option<i64>,
pub per_page: Option<i64>,
pub filter: Option<String>,
pub facets: Option<String>,
}
pub async fn search(Query(q): Query<SearchQuery>) -> impl IntoResponse {
let query = q.q.unwrap_or_default();
// TODO: call rok-search driver with query + filters
Response::json(serde_json::json!({
"data": [],
"meta": { "query": query, "total": 0 },
"facets": {}
}))
}
pub async fn autocomplete(Query(q): Query<SearchQuery>) -> impl IntoResponse {
let query = q.q.unwrap_or_default();
// TODO: return top-N suggestions from search engine
Response::json(serde_json::json!({ "suggestions": [] }))
}
"#;
const OBSERVER: &str = r#"use rok_events::Listener;
pub struct SearchIndexObserver;
#[async_trait::async_trait]
impl Listener for SearchIndexObserver {
async fn on_created(&self, model: &serde_json::Value) -> anyhow::Result<()> {
// TODO: index model in search engine via rok-search
Ok(())
}
async fn on_updated(&self, model: &serde_json::Value) -> anyhow::Result<()> {
// TODO: update document in search engine
Ok(())
}
async fn on_deleted(&self, id: i64) -> anyhow::Result<()> {
// TODO: remove document from search engine
Ok(())
}
}
"#;