Skip to main content

query_forge/
types.rs

1use std::path::Path;
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum QueryValue {
5    Null,
6    Integer(i64),
7    Real(f64),
8    Text(String),
9}
10
11#[derive(Debug, Clone, PartialEq)]
12pub struct QueryResult {
13    pub columns: Vec<String>,
14    pub rows: Vec<Vec<QueryValue>>,
15}
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct QueryParam {
19    pub name: String,
20    pub value: QueryValue,
21}
22
23#[derive(Debug, Clone, Copy)]
24pub struct WorkbookInput<'a> {
25    pub path: &'a Path,
26    pub sheet_name: Option<&'a str>,
27    pub table_name: Option<&'a str>,
28}
29
30#[derive(Debug, Clone)]
31pub struct TypeInferenceOptions {
32    pub infer_types: bool,
33    pub decimal_comma: bool,
34    pub date_format: Option<String>,
35    pub null_values: Vec<String>,
36    pub true_values: Vec<String>,
37    pub false_values: Vec<String>,
38}
39
40impl Default for TypeInferenceOptions {
41    fn default() -> Self {
42        Self {
43            infer_types: true,
44            decimal_comma: false,
45            date_format: None,
46            null_values: vec![String::new()],
47            true_values: vec!["true".to_owned()],
48            false_values: vec!["false".to_owned()],
49        }
50    }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub enum HeaderCase {
55    Snake,
56}
57
58#[derive(Debug, Clone, Default)]
59pub struct InputNormalizationOptions {
60    pub trim: bool,
61    pub skip_empty_rows: bool,
62    pub normalize_headers: bool,
63    pub header_case: Option<HeaderCase>,
64    pub dedupe_headers: bool,
65}
66
67/// Controls how JSON input files are parsed into rows.
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
69pub enum JsonMode {
70    /// Each element of a top-level JSON array becomes a row (default).
71    ///
72    /// If the root is an object the object itself becomes a single row.
73    #[default]
74    Array,
75    /// Each key-value pair of a JSON object becomes a row with "key" and "value" columns.
76    ///
77    /// Useful for flat configuration or metadata objects.
78    Object,
79    /// Recursively flatten nested JSON objects and arrays into a single row per top-level
80    /// element, using dotted key paths (e.g. `address.city`) for nested fields.
81    Flatten,
82}
83
84/// Controls how XML input files are parsed into rows.
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
86pub enum XmlMode {
87    /// Detect and extract tabular rows from the XML structure (default).
88    ///
89    /// Looks first for direct `<row>` children, then for any element whose direct
90    /// children are all leaf elements (no deeper nesting).
91    #[default]
92    Rows,
93    /// Collect every leaf text element in the document as a separate row.
94    ///
95    /// Each row has two columns: `tag` (element name) and `value` (text content).
96    Descendants,
97    /// Extract XML element attributes as columns.
98    ///
99    /// Every element that carries at least one XML attribute becomes a row; attribute
100    /// names map to column names. Text content of the element is also included as a
101    /// `value` column when present.
102    Attributes,
103}
104
105/// Options that control how JSON and XML inputs are extracted into rows.
106#[derive(Debug, Clone, Default)]
107pub struct ExtractionOptions {
108    pub json_mode: JsonMode,
109    pub xml_mode: XmlMode,
110}
111
112/// The SQL-compatible type inferred for a column.
113#[derive(Debug, Clone, PartialEq)]
114pub enum InferredType {
115    Integer,
116    Real,
117    Text,
118    /// Column contains a mix of numeric and text values.
119    Mixed,
120}
121
122impl InferredType {
123    pub fn as_str(&self) -> &'static str {
124        match self {
125            InferredType::Integer => "INTEGER",
126            InferredType::Real => "REAL",
127            InferredType::Text => "TEXT",
128            InferredType::Mixed => "MIXED",
129        }
130    }
131}
132
133/// Per-column information returned by inspection commands.
134#[derive(Debug, Clone)]
135pub struct ColumnInfo {
136    pub table_name: String,
137    pub column_name: String,
138    pub inferred_type: InferredType,
139    pub nullable: bool,
140}
141
142/// Optional per-column statistics (enabled by `--stats`).
143#[derive(Debug, Clone)]
144pub struct ColumnStats {
145    pub distinct_count: usize,
146    pub min_value: Option<String>,
147    pub max_value: Option<String>,
148}
149
150/// Summary of a single loaded table, returned by `load_table_summaries`.
151#[derive(Debug, Clone)]
152pub struct TableSummary {
153    /// The logical SQL table name (explicit or auto-generated).
154    pub table_name: String,
155    /// The original file path as provided on the command line.
156    pub source_path: String,
157    /// The sheet/tag/key/index selector, if any.
158    pub source_selector: Option<String>,
159    pub row_count: usize,
160    pub columns: Vec<ColumnInfo>,
161    /// Up to `sample` rows of actual data (column values in column order).
162    pub sample_rows: Vec<Vec<QueryValue>>,
163    /// Non-fatal warnings (e.g. mixed-type columns, duplicate header normalisations).
164    pub warnings: Vec<String>,
165    /// Per-column statistics; `None` when `--stats` is not requested.
166    pub column_stats: Option<Vec<ColumnStats>>,
167}