Skip to main content

flowscope_export/
lib.rs

1//! Database export for FlowScope analysis results.
2//!
3//! Exports `AnalyzeResult` to queryable database formats (DuckDB, SQLite).
4//!
5//! Two export modes are available:
6//! - **Binary export** (`export_duckdb`): Creates a DuckDB database file (native only)
7//! - **SQL export** (`export_sql`): Generates DDL + INSERT statements (WASM-compatible)
8//!
9//! # Identifier quoting
10//!
11//! The SQL export emits node labels and qualified names as string literals
12//! bound through parameterized inserts (see `sql_backend`/`duckdb_backend`),
13//! so data values cannot cause SQL injection against the export database.
14//!
15//! However, DDL for the **schema of imported tables** (`tables_ddl`) is
16//! string-interpolated and does *not* apply full identifier quoting for
17//! arbitrary user-supplied names. The intended use is inspection/analysis of
18//! the exported `AnalyzeResult`, not replaying the DDL against a production
19//! database. Treat the generated SQL as read-only output; if you intend to
20//! execute it against a shared database, review/adjust identifier quoting
21//! for your target dialect first.
22
23mod csv;
24pub mod dali_compat;
25mod error;
26mod extract;
27mod html;
28mod join_export;
29mod json;
30mod mermaid;
31mod naming;
32mod schema;
33mod sql_backend;
34mod xlsx;
35
36#[cfg(feature = "duckdb")]
37mod duckdb_backend;
38
39pub use error::ExportError;
40pub use extract::{ColumnMapping, ScriptInfo, TableDependency, TableInfo, TableType};
41pub use mermaid::MermaidView;
42pub use naming::ExportNaming;
43
44use flowscope_core::AnalyzeResult;
45
46/// Supported export formats for filenames and UI integrations.
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum ExportFormat {
49    DuckDb,
50    Sql { schema: bool },
51    Json { compact: bool },
52    Mermaid { view: MermaidView },
53    Html,
54    CsvBundle,
55    Xlsx,
56    Png,
57}
58
59pub type Format = ExportFormat;
60
61/// Export analysis result to a database file.
62///
63/// Returns raw bytes of the database file.
64/// Only works with `ExportFormat::DuckDb` when the `duckdb` feature is enabled.
65pub fn export(result: &AnalyzeResult, format: ExportFormat) -> Result<Vec<u8>, ExportError> {
66    match format {
67        #[cfg(feature = "duckdb")]
68        ExportFormat::DuckDb => duckdb_backend::export(result),
69        #[cfg(not(feature = "duckdb"))]
70        ExportFormat::DuckDb => Err(ExportError::UnsupportedFormat("DuckDB feature not enabled")),
71        ExportFormat::Sql { .. } => Ok(sql_backend::export_sql(result, None)?.into_bytes()),
72        ExportFormat::Json { compact } => Ok(json::export_json(result, compact)?.into_bytes()),
73        ExportFormat::Mermaid { view } => Ok(mermaid::export_mermaid(result, view).into_bytes()),
74        ExportFormat::Html => {
75            Ok(html::export_html(result, "FlowScope", chrono::Utc::now()).into_bytes())
76        }
77        ExportFormat::CsvBundle => csv::export_csv_bundle(result),
78        ExportFormat::Xlsx => xlsx::export_xlsx(result),
79        ExportFormat::Png => Err(ExportError::UnsupportedFormat("PNG export is UI-only")),
80    }
81}
82
83/// Export analysis result to DuckDB format.
84///
85/// Requires the `duckdb` feature (native only, not WASM-compatible).
86#[cfg(feature = "duckdb")]
87pub fn export_duckdb(result: &AnalyzeResult) -> Result<Vec<u8>, ExportError> {
88    duckdb_backend::export(result)
89}
90
91/// Export analysis result as SQL statements.
92///
93/// Returns DDL (CREATE TABLE/VIEW) + INSERT statements that can be
94/// executed by duckdb-wasm in the browser.
95///
96/// This is the WASM-compatible export path.
97///
98/// If `schema` is provided, all tables and views will be prefixed with that schema
99/// (e.g., "myschema.tablename") and a `CREATE SCHEMA IF NOT EXISTS` statement will be added.
100pub fn export_sql(result: &AnalyzeResult, schema: Option<&str>) -> Result<String, ExportError> {
101    sql_backend::export_sql(result, schema)
102}
103
104pub fn export_json(result: &AnalyzeResult, compact: bool) -> Result<String, ExportError> {
105    json::export_json(result, compact)
106}
107
108pub fn export_mermaid(result: &AnalyzeResult, view: MermaidView) -> Result<String, ExportError> {
109    Ok(mermaid::export_mermaid(result, view))
110}
111
112pub fn export_csv_bundle(result: &AnalyzeResult) -> Result<Vec<u8>, ExportError> {
113    csv::export_csv_bundle(result)
114}
115
116pub fn export_xlsx(result: &AnalyzeResult) -> Result<Vec<u8>, ExportError> {
117    xlsx::export_xlsx(result)
118}
119
120pub fn export_html(
121    result: &AnalyzeResult,
122    project_name: &str,
123    exported_at: chrono::DateTime<chrono::Utc>,
124) -> Result<String, ExportError> {
125    Ok(html::export_html(result, project_name, exported_at))
126}