dataprof_core/partial.rs
1use crate::{classification::DataType, source::FileFormat};
2
3/// Result of fast schema inference — column names paired with inferred data types.
4#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
5pub struct SchemaResult {
6 /// Columns with their inferred types, in source order: CSV/Parquet follow
7 /// the header/schema, JSON/JSONL follow the first record's field order with
8 /// later-only fields appended in first-seen order.
9 pub columns: Vec<ColumnSchema>,
10 /// How many rows were sampled to infer the schema. 0 when nothing had to
11 /// be read: a Parquet file whose every column is typed by its encoding
12 /// is answered from the metadata alone.
13 pub rows_sampled: usize,
14 /// Time taken for inference in milliseconds.
15 pub inference_time_ms: u128,
16 /// `true` when the entire file was consumed or the schema was read from
17 /// metadata alone; `false` when inference stopped at the sample-size cap
18 /// and the schema may not have fully stabilized.
19 pub schema_stable: bool,
20}
21
22/// A single column's name and inferred data type.
23#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
24pub struct ColumnSchema {
25 pub name: String,
26 pub data_type: DataType,
27}
28
29/// Lightweight structural summary for a file.
30///
31/// This intentionally sits between `quick_row_count()` / `infer_schema()` and a
32/// full profile: it reports shape and sampled per-column counters, not quality
33/// scores, pattern detection, recommendations, or raw values.
34#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
35pub struct StructureReport {
36 /// Source identifier, currently the file path passed by the caller.
37 pub source: String,
38 /// Detected or explicitly provided file format.
39 pub format: FileFormat,
40 /// Exact or estimated row count for the source.
41 pub row_count: RowCountEstimate,
42 /// Number of rows consumed for the structural column summaries.
43 pub rows_sampled: usize,
44 /// True when the structural pass consumed the whole source.
45 pub source_exhausted: bool,
46 /// True when the structural pass stopped at the row sample cap.
47 pub truncated: bool,
48 /// Human-readable reason for truncation, if any.
49 pub truncation_reason: Option<String>,
50 /// CSV delimiter used for parsing, when applicable.
51 pub delimiter: Option<String>,
52 /// Per-column structural summaries.
53 pub columns: Vec<StructureColumnSummary>,
54 /// Non-fatal caveats, such as estimated row counts.
55 pub warnings: Vec<String>,
56}
57
58/// Sample-derived or metadata-derived structural summary for one column.
59///
60/// The counters and the type answer to different sources, and `provenance`
61/// names the one that decided the *type*. A counter is present only when it
62/// describes the whole source: for CSV/JSON/JSONL that is the bounded
63/// structural sample, disclosed by `rows_sampled` and `truncated`; for Parquet
64/// the counts come from the file footer and cover every row, so they hold even
65/// when the type sample was truncated. `None` keeps its usual meaning — not
66/// analyzed — and is what a counter reports rather than a partial number
67/// (#700).
68#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
69pub struct StructureColumnSummary {
70 pub name: String,
71 pub data_type: DataType,
72 pub total_count: Option<usize>,
73 pub null_count: Option<usize>,
74 pub null_ratio: Option<f64>,
75 pub unique_count: Option<usize>,
76 pub uniqueness_ratio: Option<f64>,
77 pub distinct_count_approximate: Option<bool>,
78 /// Which source governs this column's type: `"metadata"` when the declared
79 /// schema decided it, `"sample"` when only the column's values can. It
80 /// names the source, not the read — a `"sample"` column is one the metadata
81 /// could not type, whether or not the caller's row budget allowed any row
82 /// to be read for it. `rows_sampled` and `truncated` report the read.
83 ///
84 /// CSV/JSON/JSONL are always `"sample"`; a Parquet file carries both, since
85 /// only its text columns need values to be typed (#693).
86 pub provenance: String,
87}
88
89/// Result of a quick row count operation.
90#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
91pub struct RowCountEstimate {
92 /// The estimated or exact row count.
93 pub count: u64,
94 /// Whether the count is exact or an estimate.
95 pub exact: bool,
96 /// How the count was obtained.
97 pub method: CountMethod,
98 /// Time taken in milliseconds.
99 pub count_time_ms: u128,
100 /// Approximate 1-sigma relative standard error of the estimate, expressed
101 /// as a fraction of `count` (e.g. `0.02` ≈ ±2%). Populated only for
102 /// sampled estimates where a variance across sampling windows is available;
103 /// `None` for exact counts and when it cannot be estimated.
104 #[serde(default)]
105 pub relative_error: Option<f64>,
106}
107
108/// Method used to obtain the row count.
109#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
110pub enum CountMethod {
111 /// Read from Parquet file footer metadata (exact, zero row reading).
112 ParquetMetadata,
113 /// Full scan of the file (exact).
114 FullScan,
115 /// Sample-based estimation (approximate).
116 Sampling,
117 /// Full scan of a streaming source (no file metadata available).
118 StreamFullScan,
119}