romance_core/addon/
search.rs1use crate::addon::Addon;
2use anyhow::Result;
3use std::path::Path;
4
5pub struct SearchAddon;
6
7impl Addon for SearchAddon {
8 fn name(&self) -> &str {
9 "search"
10 }
11
12 fn check_prerequisites(&self, project_root: &Path) -> Result<()> {
13 super::check_romance_project(project_root)
14 }
15
16 fn is_already_installed(&self, project_root: &Path) -> bool {
17 project_root.join("backend/src/search.rs").exists()
18 }
19
20 fn install(&self, project_root: &Path) -> Result<()> {
21 install_search(project_root)
22 }
23
24 fn uninstall(&self, project_root: &Path) -> Result<()> {
25 use colored::Colorize;
26
27 println!("{}", "Uninstalling full-text search...".bold());
28
29 if super::remove_file_if_exists(&project_root.join("backend/src/search.rs"))? {
31 println!(" {} backend/src/search.rs", "delete".red());
32 }
33 if super::remove_file_if_exists(&project_root.join("backend/src/handlers/search.rs"))? {
34 println!(" {} backend/src/handlers/search.rs", "delete".red());
35 }
36 if super::remove_file_if_exists(
37 &project_root.join("frontend/src/components/SearchBar.tsx"),
38 )? {
39 println!(
40 " {} frontend/src/components/SearchBar.tsx",
41 "delete".red()
42 );
43 }
44
45 super::remove_mod_from_main(project_root, "search")?;
47
48 super::remove_line_from_file(
50 &project_root.join("backend/src/handlers/mod.rs"),
51 "pub mod search;",
52 )?;
53
54 super::remove_feature_flag(project_root, "search")?;
56
57 crate::ai_context::regenerate(project_root).ok();
59
60 println!();
61 println!(
62 "{}",
63 "Full-text search uninstalled successfully.".green().bold()
64 );
65
66 Ok(())
67 }
68}
69
70fn install_search(project_root: &Path) -> Result<()> {
71 use crate::template::TemplateEngine;
72 use crate::utils;
73 use colored::Colorize;
74 use tera::Context;
75
76 println!("{}", "Installing full-text search...".bold());
77
78 let engine = TemplateEngine::new()?;
79 let ctx = Context::new();
80
81 let content = engine.render("addon/search/search.rs.tera", &ctx)?;
83 utils::write_file(&project_root.join("backend/src/search.rs"), &content)?;
84 println!(" {} backend/src/search.rs", "create".green());
85
86 let content = engine.render("addon/search/search_handler.rs.tera", &ctx)?;
88 utils::write_file(
89 &project_root.join("backend/src/handlers/search.rs"),
90 &content,
91 )?;
92 println!(" {} backend/src/handlers/search.rs", "create".green());
93
94 let content = engine.render("addon/search/SearchBar.tsx.tera", &ctx)?;
96 utils::write_file(
97 &project_root.join("frontend/src/components/SearchBar.tsx"),
98 &content,
99 )?;
100 println!(
101 " {} frontend/src/components/SearchBar.tsx",
102 "create".green()
103 );
104
105 super::add_mod_to_main(project_root, "search")?;
107
108 let mods_marker = "// === ROMANCE:MODS ===";
110 utils::insert_at_marker(
111 &project_root.join("backend/src/handlers/mod.rs"),
112 mods_marker,
113 "pub mod search;",
114 )?;
115
116 super::update_feature_flag(project_root, "search", true)?;
118
119 println!();
120 println!(
121 "{}",
122 "Full-text search installed successfully!".green().bold()
123 );
124 println!(" Use [searchable] annotation on fields: title:string[searchable]");
125 println!(" Search endpoint: GET /api/{{entities}}/search?q=term");
126
127 Ok(())
128}