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    Camel,
57    Pascal,
58    ScreamingSnake,
59}
60
61#[derive(Debug, Clone, Default)]
62pub struct InputNormalizationOptions {
63    pub trim: bool,
64    pub skip_empty_rows: bool,
65    pub normalize_headers: bool,
66    pub header_case: Option<HeaderCase>,
67    pub dedupe_headers: bool,
68}
69
70/// Controls how JSON input files are parsed into rows.
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
72pub enum JsonMode {
73    /// Each element of a top-level JSON array becomes a row (default).
74    ///
75    /// If the root is an object the object itself becomes a single row.
76    #[default]
77    Array,
78    /// Each key-value pair of a JSON object becomes a row with "key" and "value" columns.
79    ///
80    /// Useful for flat configuration or metadata objects.
81    Object,
82    /// Recursively flatten nested JSON objects and arrays into a single row per top-level
83    /// element, using dotted key paths (e.g. `address.city`) for nested fields.
84    Flatten,
85}
86
87/// Controls how XML input files are parsed into rows.
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
89pub enum XmlMode {
90    /// Detect and extract tabular rows from the XML structure (default).
91    ///
92    /// Looks first for direct `<row>` children, then for any element whose direct
93    /// children are all leaf elements (no deeper nesting).
94    #[default]
95    Rows,
96    /// Collect every leaf text element in the document as a separate row.
97    ///
98    /// Each row has two columns: `tag` (element name) and `value` (text content).
99    Descendants,
100    /// Extract XML element attributes as columns.
101    ///
102    /// Every element that carries at least one XML attribute becomes a row; attribute
103    /// names map to column names. Text content of the element is also included as a
104    /// `value` column when present.
105    Attributes,
106}
107
108/// Options that control how JSON and XML inputs are extracted into rows.
109#[derive(Debug, Clone, Default)]
110pub struct ExtractionOptions {
111    pub json_mode: JsonMode,
112    pub xml_mode: XmlMode,
113}
114
115/// The SQL-compatible type inferred for a column.
116#[derive(Debug, Clone, PartialEq)]
117pub enum InferredType {
118    Integer,
119    Real,
120    Text,
121    /// Column contains a mix of numeric and text values.
122    Mixed,
123}
124
125impl InferredType {
126    pub fn as_str(&self) -> &'static str {
127        match self {
128            InferredType::Integer => "INTEGER",
129            InferredType::Real => "REAL",
130            InferredType::Text => "TEXT",
131            InferredType::Mixed => "MIXED",
132        }
133    }
134}
135
136/// Per-column information returned by inspection commands.
137#[derive(Debug, Clone)]
138pub struct ColumnInfo {
139    pub table_name: String,
140    pub column_name: String,
141    pub inferred_type: InferredType,
142    pub nullable: bool,
143}
144
145/// Optional per-column statistics (enabled by `--stats`).
146#[derive(Debug, Clone)]
147pub struct ColumnStats {
148    pub distinct_count: usize,
149    pub min_value: Option<String>,
150    pub max_value: Option<String>,
151}
152
153/// Summary of a single loaded table, returned by `load_table_summaries`.
154#[derive(Debug, Clone)]
155pub struct TableSummary {
156    /// The logical SQL table name (explicit or auto-generated).
157    pub table_name: String,
158    /// The original file path as provided on the command line.
159    pub source_path: String,
160    /// The sheet/tag/key/index selector, if any.
161    pub source_selector: Option<String>,
162    pub row_count: usize,
163    pub columns: Vec<ColumnInfo>,
164    /// Up to `sample` rows of actual data (column values in column order).
165    pub sample_rows: Vec<Vec<QueryValue>>,
166    /// Non-fatal warnings (e.g. mixed-type columns, duplicate header normalisations).
167    pub warnings: Vec<String>,
168    /// Per-column statistics; `None` when `--stats` is not requested.
169    pub column_stats: Option<Vec<ColumnStats>>,
170}