1pub mod models;
2pub mod pocketbase;
3pub mod schema;
4pub mod sqlite;
5
6use crate::config::DatabaseConfig;
7use crate::error::Result;
8use models::{Asset, Finding, Observation, Relationship, Report, ScanRun, Service};
9
10pub mod collections {
12 pub const ASSETS: &str = "Assets";
13 pub const SERVICES: &str = "Services";
14 pub const FINDINGS: &str = "Findings";
15 pub const OBSERVATIONS: &str = "Observations";
16 pub const RELATIONSHIPS: &str = "Relationships";
17 pub const SCAN_RUNS: &str = "ScanRuns";
18 pub const REPORTS: &str = "Reports";
19
20 pub const ALL: [&str; 7] = [
21 ASSETS,
22 SERVICES,
23 FINDINGS,
24 OBSERVATIONS,
25 RELATIONSHIPS,
26 SCAN_RUNS,
27 REPORTS,
28 ];
29}
30
31pub trait Storage: Send {
38 fn kind(&self) -> &str;
39
40 fn ping(&mut self) -> Result<bool>;
42
43 fn ensure_schema(&mut self) -> Result<()>;
45
46 fn upsert_scan_run(&mut self, run: &ScanRun) -> Result<()>;
49 fn get_scan_run(&mut self, run_id: &str) -> Result<Option<ScanRun>>;
50 fn list_scan_runs(&mut self) -> Result<Vec<ScanRun>>;
51
52 fn upsert_asset(&mut self, asset: &Asset) -> Result<()>;
55 fn get_asset(&mut self, asset_id: &str) -> Result<Option<Asset>>;
56 fn list_assets(&mut self) -> Result<Vec<Asset>>;
57
58 fn upsert_service(&mut self, service: &Service) -> Result<()>;
61 fn get_service(&mut self, service_id: &str) -> Result<Option<Service>>;
62 fn list_services_for_asset(&mut self, asset_id: &str) -> Result<Vec<Service>>;
63 fn list_all_services(&mut self) -> Result<Vec<Service>>;
64
65 fn upsert_finding(&mut self, finding: &Finding) -> Result<()>;
68 fn get_finding(&mut self, finding_id: &str) -> Result<Option<Finding>>;
69 fn list_findings_for_asset(&mut self, asset_id: &str) -> Result<Vec<Finding>>;
70 fn list_all_findings(&mut self) -> Result<Vec<Finding>>;
71
72 fn add_observation(&mut self, observation: &Observation) -> Result<()>;
75 fn get_observation(&mut self, obs_id: &str) -> Result<Option<Observation>>;
76 fn list_observations_for(
77 &mut self,
78 subject_type: &str,
79 subject_id: &str,
80 ) -> Result<Vec<Observation>>;
81 fn list_all_observations(&mut self) -> Result<Vec<Observation>>;
82
83 fn upsert_relationship(&mut self, relationship: &Relationship) -> Result<()>;
86 fn get_relationship(&mut self, rel_id: &str) -> Result<Option<Relationship>>;
87 fn list_relationships_for(
88 &mut self,
89 subject_type: &str,
90 subject_id: &str,
91 ) -> Result<Vec<Relationship>>;
92
93 fn upsert_report(&mut self, report: &Report) -> Result<()>;
96 fn get_report(&mut self, report_id: &str) -> Result<Option<Report>>;
97 fn list_reports_for_run(&mut self, run_id: &str) -> Result<Vec<Report>>;
98}
99
100pub fn open_storage(config: &DatabaseConfig) -> Result<Box<dyn Storage>> {
102 if config.backend == "sqlite" {
103 Ok(Box::new(sqlite::SqliteStorage::open(&config.sqlite_path)?))
104 } else {
105 Ok(Box::new(pocketbase::PocketBaseStorage::new(config)?))
106 }
107}
108
109pub fn open_storage_with(
111 config: &DatabaseConfig,
112 backend: &str,
113 pocketbase_url: Option<&str>,
114 sqlite_path: Option<&str>,
115) -> Result<Box<dyn Storage>> {
116 if backend == "sqlite" {
117 let path = sqlite_path
118 .map(str::to_string)
119 .unwrap_or_else(|| config.sqlite_path.clone());
120 Ok(Box::new(sqlite::SqliteStorage::open(&path)?))
121 } else {
122 let mut override_config = config.clone();
123 if let Some(url) = pocketbase_url {
124 override_config.pocketbase_url = url.to_string();
125 }
126 Ok(Box::new(pocketbase::PocketBaseStorage::new(
127 &override_config,
128 )?))
129 }
130}