1use crate::caps::BackendCaps;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema, Default)]
7#[serde(transparent)]
8pub struct WorkbookId(pub String);
9
10impl WorkbookId {
11 pub fn as_str(&self) -> &str {
12 &self.0
13 }
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
17pub struct WorkbookDescriptor {
18 pub workbook_id: WorkbookId,
19 pub short_id: String,
20 pub slug: String,
21 pub folder: Option<String>,
22 pub path: String,
23 pub bytes: u64,
24 pub last_modified: Option<String>,
25 pub caps: BackendCaps,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
29pub struct WorkbookListResponse {
30 pub workbooks: Vec<WorkbookDescriptor>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
34pub struct WorkbookDescription {
35 pub workbook_id: WorkbookId,
36 pub short_id: String,
37 pub slug: String,
38 pub path: String,
39 pub bytes: u64,
40 pub sheet_count: usize,
41 pub defined_names: usize,
42 pub tables: usize,
43 pub macros_present: bool,
44 pub last_modified: Option<String>,
45 pub caps: BackendCaps,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
49pub struct WorkbookSummaryResponse {
50 pub workbook_id: WorkbookId,
51 pub workbook_short_id: String,
52 pub slug: String,
53 pub sheet_count: usize,
54 pub total_cells: u64,
55 pub total_formulas: u64,
56 pub breakdown: WorkbookBreakdown,
57 pub region_counts: RegionCountSummary,
58 pub key_named_ranges: Vec<NamedRangeDescriptor>,
59 pub suggested_entry_points: Vec<EntryPoint>,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
63pub struct WorkbookBreakdown {
64 pub data_sheets: u32,
65 pub calculator_sheets: u32,
66 pub parameter_sheets: u32,
67 pub metadata_sheets: u32,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
71pub struct RegionCountSummary {
72 pub data: u32,
73 pub parameters: u32,
74 pub outputs: u32,
75 pub calculator: u32,
76 pub metadata: u32,
77 pub other: u32,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
81pub struct EntryPoint {
82 pub sheet_name: String,
83 pub region_id: Option<u32>,
84 pub bounds: Option<String>,
85 pub rationale: String,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
89pub struct SheetSummary {
90 pub name: String,
91 pub visible: bool,
92 pub row_count: u32,
93 pub column_count: u32,
94 pub non_empty_cells: u32,
95 pub formula_cells: u32,
96 pub cached_values: u32,
97 pub classification: SheetClassification,
98 pub style_tags: Vec<String>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
102#[serde(rename_all = "snake_case")]
103pub enum SheetClassification {
104 Data,
105 Calculator,
106 Mixed,
107 Metadata,
108 Empty,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
112pub struct SheetListResponse {
113 pub workbook_id: WorkbookId,
114 pub workbook_short_id: String,
115 pub sheets: Vec<SheetSummary>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
119pub struct SheetOverviewResponse {
120 pub workbook_id: WorkbookId,
121 pub workbook_short_id: String,
122 pub sheet_name: String,
123 pub narrative: String,
124 pub regions: Vec<SheetRegion>,
125 pub detected_regions: Vec<DetectedRegion>,
126 pub key_ranges: Vec<String>,
127 pub formula_ratio: f32,
128 pub notable_features: Vec<String>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
132pub struct SheetRegion {
133 pub kind: RegionKind,
134 pub address: String,
135 pub description: String,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
139#[serde(rename_all = "snake_case")]
140pub enum RegionKind {
141 Table,
142 Data,
143 Parameters,
144 Outputs,
145 Calculator,
146 Metadata,
147 Styles,
148 Comments,
149 Other,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
153pub struct DetectedRegion {
154 pub id: u32,
155 pub bounds: String,
156 pub header_row: Option<u32>,
157 pub headers: Vec<String>,
158 pub row_count: u32,
159 pub classification: RegionKind,
160 pub region_kind: Option<RegionKind>,
161 pub confidence: f32,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
165pub struct SheetPageResponse {
166 pub workbook_id: WorkbookId,
167 pub workbook_short_id: String,
168 pub sheet_name: String,
169 pub rows: Vec<RowSnapshot>,
170 pub has_more: bool,
171 pub next_start_row: Option<u32>,
172 pub header_row: Option<RowSnapshot>,
173 pub compact: Option<SheetPageCompact>,
174 pub values_only: Option<SheetPageValues>,
175 pub format: SheetPageFormat,
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
179pub struct RowSnapshot {
180 pub row_index: u32,
181 pub cells: Vec<CellSnapshot>,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
185pub struct CellSnapshot {
186 pub address: String,
187 pub value: Option<CellValue>,
188 pub formula: Option<String>,
189 pub cached_value: Option<CellValue>,
190 pub number_format: Option<String>,
191 pub style_tags: Vec<String>,
192 pub notes: Vec<String>,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
196#[serde(tag = "kind", content = "value")]
197pub enum CellValue {
198 Text(String),
199 Number(f64),
200 Bool(bool),
201 Error(String),
202 Date(String),
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
206#[serde(rename_all = "snake_case")]
207#[derive(Default)]
208pub enum SheetPageFormat {
209 #[default]
210 Full,
211 Compact,
212 ValuesOnly,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
216pub struct SheetPageCompact {
217 pub headers: Vec<String>,
218 pub header_row: Vec<Option<CellValue>>,
219 pub rows: Vec<Vec<Option<CellValue>>>,
220}
221
222#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
223pub struct SheetPageValues {
224 pub rows: Vec<Vec<Option<CellValue>>>,
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
228pub struct SheetStatisticsResponse {
229 pub workbook_id: WorkbookId,
230 pub workbook_short_id: String,
231 pub sheet_name: String,
232 pub row_count: u32,
233 pub column_count: u32,
234 pub density: f32,
235 pub numeric_columns: Vec<ColumnSummary>,
236 pub text_columns: Vec<ColumnSummary>,
237 pub null_counts: BTreeMap<String, u32>,
238 pub duplicate_warnings: Vec<String>,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
242pub struct ColumnSummary {
243 pub header: Option<String>,
244 pub column: String,
245 pub samples: Vec<CellValue>,
246 pub min: Option<f64>,
247 pub max: Option<f64>,
248 pub mean: Option<f64>,
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
252pub struct SheetFormulaMapResponse {
253 pub workbook_id: WorkbookId,
254 pub workbook_short_id: String,
255 pub sheet_name: String,
256 pub groups: Vec<FormulaGroup>,
257 pub truncated: bool,
258}
259
260#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
261pub struct FormulaGroup {
262 pub fingerprint: String,
263 pub addresses: Vec<String>,
264 pub formula: String,
265 pub is_array: bool,
266 pub is_shared: bool,
267 pub is_volatile: bool,
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
271pub struct FormulaTraceResponse {
272 pub workbook_id: WorkbookId,
273 pub workbook_short_id: String,
274 pub sheet_name: String,
275 pub origin: String,
276 pub direction: TraceDirection,
277 pub layers: Vec<TraceLayer>,
278 pub next_cursor: Option<TraceCursor>,
279 pub notes: Vec<String>,
280}
281
282#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
283pub struct FormulaTraceEdge {
284 pub from: String,
285 pub to: String,
286 pub formula: Option<String>,
287 pub note: Option<String>,
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
291pub struct TraceLayer {
292 pub depth: u32,
293 pub summary: TraceLayerSummary,
294 pub highlights: TraceLayerHighlights,
295 pub edges: Vec<FormulaTraceEdge>,
296 pub has_more: bool,
297}
298
299#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
300pub struct TraceLayerSummary {
301 pub total_nodes: usize,
302 pub formula_nodes: usize,
303 pub value_nodes: usize,
304 pub blank_nodes: usize,
305 pub external_nodes: usize,
306 pub unique_formula_groups: usize,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
310pub struct TraceLayerHighlights {
311 pub top_ranges: Vec<TraceRangeHighlight>,
312 pub top_formula_groups: Vec<TraceFormulaGroupHighlight>,
313 pub notable_cells: Vec<TraceCellHighlight>,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
317pub struct TraceRangeHighlight {
318 pub start: String,
319 pub end: String,
320 pub count: usize,
321 pub literals: usize,
322 pub formulas: usize,
323 pub blanks: usize,
324 pub sample_values: Vec<CellValue>,
325 pub sample_formulas: Vec<String>,
326 pub sample_addresses: Vec<String>,
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
330pub struct TraceFormulaGroupHighlight {
331 pub fingerprint: String,
332 pub formula: String,
333 pub count: usize,
334 pub sample_addresses: Vec<String>,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
338pub struct TraceCellHighlight {
339 pub address: String,
340 pub kind: TraceCellKind,
341 pub value: Option<CellValue>,
342 pub formula: Option<String>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
346#[serde(rename_all = "snake_case")]
347pub enum TraceCellKind {
348 Formula,
349 Literal,
350 Blank,
351 External,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
355pub struct TraceCursor {
356 pub depth: u32,
357 pub offset: usize,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
361#[serde(rename_all = "snake_case")]
362pub enum TraceDirection {
363 Precedents,
364 Dependents,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
368pub struct NamedRangeDescriptor {
369 pub name: String,
370 pub scope: Option<String>,
371 pub refers_to: String,
372 pub kind: NamedItemKind,
373 pub sheet_name: Option<String>,
374 pub comment: Option<String>,
375}
376
377#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
378#[serde(rename_all = "snake_case")]
379pub enum NamedItemKind {
380 NamedRange,
381 Table,
382 Formula,
383 Unknown,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
387pub struct NamedRangesResponse {
388 pub workbook_id: WorkbookId,
389 pub workbook_short_id: String,
390 pub items: Vec<NamedRangeDescriptor>,
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
394pub struct FindFormulaMatch {
395 pub address: String,
396 pub sheet_name: String,
397 pub formula: String,
398 pub cached_value: Option<CellValue>,
399 pub context: Vec<RowSnapshot>,
400}
401
402#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
403pub struct FindFormulaResponse {
404 pub workbook_id: WorkbookId,
405 pub workbook_short_id: String,
406 pub matches: Vec<FindFormulaMatch>,
407}
408
409#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
410pub struct VolatileScanEntry {
411 pub address: String,
412 pub sheet_name: String,
413 pub function: String,
414 pub note: Option<String>,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
418pub struct VolatileScanResponse {
419 pub workbook_id: WorkbookId,
420 pub workbook_short_id: String,
421 pub items: Vec<VolatileScanEntry>,
422 pub truncated: bool,
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
426pub struct SheetStylesResponse {
427 pub workbook_id: WorkbookId,
428 pub workbook_short_id: String,
429 pub sheet_name: String,
430 pub styles: Vec<StyleSummary>,
431 pub conditional_rules: Vec<String>,
432}
433
434#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
435pub struct StyleSummary {
436 pub style_id: String,
437 pub occurrences: u32,
438 pub tags: Vec<String>,
439 pub example_cells: Vec<String>,
440}
441
442#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
443pub struct ManifestStubResponse {
444 pub workbook_id: WorkbookId,
445 pub workbook_short_id: String,
446 pub slug: String,
447 pub sheets: Vec<ManifestSheetStub>,
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
451pub struct ManifestSheetStub {
452 pub sheet_name: String,
453 pub classification: SheetClassification,
454 pub candidate_expectations: Vec<String>,
455 pub notes: Vec<String>,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
459#[serde(rename_all = "snake_case")]
460pub enum FindMode {
461 #[default]
462 Value,
463 Label,
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
467#[serde(rename_all = "snake_case")]
468pub enum LabelDirection {
469 Right,
470 Below,
471 Any,
472}
473
474#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
475pub struct FindValueMatch {
476 pub address: String,
477 pub sheet_name: String,
478 pub value: Option<CellValue>,
479 pub row_context: Option<RowContext>,
480 pub neighbors: Option<NeighborValues>,
481 pub label_hit: Option<LabelHit>,
482}
483
484#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
485pub struct RowContext {
486 pub headers: Vec<String>,
487 pub values: Vec<Option<CellValue>>,
488}
489
490#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
491pub struct NeighborValues {
492 pub left: Option<CellValue>,
493 pub right: Option<CellValue>,
494 pub up: Option<CellValue>,
495 pub down: Option<CellValue>,
496}
497
498#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
499pub struct LabelHit {
500 pub label_address: String,
501 pub label: String,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
505pub struct FindValueResponse {
506 pub workbook_id: WorkbookId,
507 pub workbook_short_id: String,
508 pub matches: Vec<FindValueMatch>,
509 pub truncated: bool,
510}
511
512pub type TableRow = BTreeMap<String, Option<CellValue>>;
513
514#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
515pub struct ReadTableResponse {
516 pub workbook_id: WorkbookId,
517 pub workbook_short_id: String,
518 pub sheet_name: String,
519 pub table_name: Option<String>,
520 pub headers: Vec<String>,
521 pub rows: Vec<TableRow>,
522 pub total_rows: u32,
523 pub has_more: bool,
524}
525
526#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
527pub struct ColumnTypeSummary {
528 pub name: String,
529 pub inferred_type: String,
530 pub nulls: u32,
531 pub distinct: u32,
532 pub top_values: Vec<String>,
533 pub min: Option<f64>,
534 pub max: Option<f64>,
535 pub mean: Option<f64>,
536}
537
538#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
539pub struct TableProfileResponse {
540 pub workbook_id: WorkbookId,
541 pub workbook_short_id: String,
542 pub sheet_name: String,
543 pub table_name: Option<String>,
544 pub headers: Vec<String>,
545 pub column_types: Vec<ColumnTypeSummary>,
546 pub row_count: u32,
547 pub samples: Vec<TableRow>,
548 pub notes: Vec<String>,
549}
550
551#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
552pub struct RangeValuesResponse {
553 pub workbook_id: WorkbookId,
554 pub workbook_short_id: String,
555 pub sheet_name: String,
556 pub values: Vec<RangeValuesEntry>,
557}
558
559#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
560pub struct RangeValuesEntry {
561 pub range: String,
562 pub rows: Vec<Vec<Option<CellValue>>>,
563}
564
565#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
566pub struct CloseWorkbookResponse {
567 pub workbook_id: WorkbookId,
568 pub message: String,
569}