pub mod column; pub mod db; pub mod table; use crate::generator::DatabaseUrl; use super::{Module, ModulesContext}; use color_eyre::Result; use db::DbType; use serde::Deserialize; use serde_inline_default::serde_inline_default; use table::Table; #[derive(Debug, Clone, Deserialize)] #[serde(default)] pub struct DiscoveryConfig { pub enable: bool, pub database_schema: Option, pub max_connections: u32, pub acquire_timeout: u64, pub filter: DiscoveryFilterConfig, } impl Default for DiscoveryConfig { fn default() -> Self { Self { enable: false, database_schema: None, max_connections: 10, acquire_timeout: 30, filter: DiscoveryFilterConfig::default(), } } } #[derive(Debug, Clone, Deserialize)] #[serde(default)] pub struct DiscoveryFilterConfig { pub include_hidden: bool, pub skip_seaql_migrations: bool, #[serde(flatten)] pub table: Option, } impl Default for DiscoveryFilterConfig { fn default() -> Self { Self { include_hidden: false, skip_seaql_migrations: true, table: None, } } } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "snake_case")] #[serde(untagged)] pub enum TableConfig { Specific { only: Vec }, Exclude { exclude: Vec }, } impl DiscoveryFilterConfig { pub fn get_filter(&self) -> Box bool + Send> { let include_hidden = self.include_hidden; if let Some(table) = &self.table { match table { TableConfig::Specific { only } => { let specific = only.clone(); Box::new(move |table: &String| { (include_hidden || !table.starts_with('_')) && specific.contains(table) }) } TableConfig::Exclude { exclude } => { let exclude = exclude.clone(); Box::new(move |table: &String| { (include_hidden || !table.starts_with('_')) && !exclude.contains(table) }) } } } else if self.skip_seaql_migrations { Box::new(move |table: &String| { (include_hidden || !table.starts_with('_')) && !table.starts_with("seaql_migrations") }) } else { Box::new(move |table: &String| (include_hidden || !table.starts_with('_'))) } } } #[derive(Debug, Clone)] pub struct DiscoveredSchema { pub tables: Vec, pub database_type: DbType, } #[derive(Debug)] pub struct DiscoveryModule; #[async_trait::async_trait] impl Module for DiscoveryModule { fn init(&mut self, ctx: &mut ModulesContext) -> Result<()> { ctx.get_config_auto::("modules.discovery")?; Ok(()) } async fn validate(&mut self, ctx: &mut ModulesContext) -> Result { let map = ctx.get_anymap(); if let (Some(config), Some(_)) = (map.get::(), map.get::()) { Ok(config.enable) } else { // One or both keys are missing Ok(false) } } async fn execute(&mut self, ctx: &mut ModulesContext) -> Result<()> { if let (Some(config), Some(url)) = ( ctx.get_anymap().get::(), ctx.get_anymap().get::(), ) { let url = url.clone(); let (stmts, db_type) = db::get_tables(url.0, config).await?; let tables = stmts .into_iter() .map(Table::new) .collect::>>()?; tracing::info!(?tables, ?db_type); let discovered = DiscoveredSchema { tables, database_type: db_type, }; ctx.get_anymap_mut().insert(discovered); // db::generate(ctx).await?; } Ok(()) } }