use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::mpsc;
use crate::app::action::Action;
use crate::app::cache::TtlCache;
use crate::app::effect_runner::EffectRunner;
use crate::app::ports::{
ConfigWriter, DsnBuilder, ErDiagramExporter, ErExportResult, ErLogWriter, MetadataProvider,
QueryExecutor, ServiceFileReader,
};
use crate::domain::connection::ConnectionProfile;
use crate::domain::{DatabaseMetadata, QueryResult, QuerySource};
pub(crate) struct NoopConfigWriter;
impl ConfigWriter for NoopConfigWriter {
fn get_cache_dir(&self, _project_name: &str) -> color_eyre::eyre::Result<PathBuf> {
Ok(PathBuf::from("/tmp"))
}
}
pub(crate) struct NoopErExporter;
impl ErDiagramExporter for NoopErExporter {
fn generate_and_export(
&self,
_tables: &[crate::domain::ErTableInfo],
_filename: &str,
_cache_dir: &Path,
) -> ErExportResult<PathBuf> {
Ok(PathBuf::from("/tmp/er.svg"))
}
}
pub(crate) struct NoopErLogWriter;
impl ErLogWriter for NoopErLogWriter {
fn write_er_failure_log(
&self,
_failed_tables: Vec<(String, String)>,
_cache_dir: PathBuf,
) -> std::io::Result<()> {
Ok(())
}
}
pub(crate) struct NoopDsnBuilder;
impl DsnBuilder for NoopDsnBuilder {
fn build_dsn(&self, _profile: &ConnectionProfile) -> String {
String::new()
}
}
pub(crate) struct NoopServiceFileReader;
impl ServiceFileReader for NoopServiceFileReader {
fn read_services(
&self,
) -> Result<
(
Vec<crate::domain::connection::ServiceEntry>,
std::path::PathBuf,
),
crate::app::ports::ServiceFileError,
> {
Ok((vec![], std::path::PathBuf::new()))
}
}
pub(crate) struct NoopClipboardWriter;
impl crate::app::ports::ClipboardWriter for NoopClipboardWriter {
fn copy_text(&self, _content: &str) -> Result<(), String> {
Ok(())
}
}
pub(crate) struct NoopFolderOpener;
impl crate::app::ports::FolderOpener for NoopFolderOpener {
fn open(&self, _path: &Path) -> Result<(), String> {
Ok(())
}
}
pub(crate) struct NoopQueryHistoryStore;
#[async_trait::async_trait]
impl crate::app::ports::QueryHistoryStore for NoopQueryHistoryStore {
async fn append(
&self,
_project_name: &str,
_connection_id: &crate::domain::ConnectionId,
_entry: &crate::domain::query_history::QueryHistoryEntry,
) -> Result<(), String> {
Ok(())
}
async fn load(
&self,
_project_name: &str,
_connection_id: &crate::domain::ConnectionId,
) -> Result<Vec<crate::domain::query_history::QueryHistoryEntry>, String> {
Ok(Vec::new())
}
}
pub(crate) fn make_runner(
metadata_provider: Arc<dyn MetadataProvider>,
query_executor: Arc<dyn QueryExecutor>,
connection_store: Arc<dyn crate::app::ports::ConnectionStore>,
cache: TtlCache<String, Arc<DatabaseMetadata>>,
action_tx: mpsc::Sender<Action>,
) -> EffectRunner {
EffectRunner::builder()
.metadata_provider(metadata_provider)
.query_executor(query_executor)
.dsn_builder(Arc::new(NoopDsnBuilder))
.er_exporter(Arc::new(NoopErExporter))
.config_writer(Arc::new(NoopConfigWriter))
.er_log_writer(Arc::new(NoopErLogWriter))
.connection_store(connection_store)
.service_file_reader(Arc::new(NoopServiceFileReader))
.clipboard(Arc::new(NoopClipboardWriter))
.folder_opener(Arc::new(NoopFolderOpener))
.query_history_store(Arc::new(NoopQueryHistoryStore))
.metadata_cache(cache)
.action_tx(action_tx)
.build()
}
pub(crate) fn sample_metadata() -> DatabaseMetadata {
DatabaseMetadata {
database_name: "testdb".to_string(),
schemas: vec![],
tables: vec![],
fetched_at: Instant::now(),
}
}
pub(crate) fn sample_query_result() -> QueryResult {
QueryResult {
query: "SELECT 1".to_string(),
columns: vec!["id".to_string()],
rows: vec![vec!["1".to_string()]],
row_count: 1,
execution_time_ms: 5,
executed_at: Instant::now(),
source: QuerySource::Preview,
error: None,
command_tag: None,
}
}