1use crate::caps::BackendCaps;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5
6pub mod diagnostics;
7pub use diagnostics::*;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema, Default)]
10#[serde(transparent)]
11pub struct WorkbookId(pub String);
12
13impl WorkbookId {
14 pub fn as_str(&self) -> &str {
15 &self.0
16 }
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
20pub struct Warning {
21 pub code: String,
22 pub message: String,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
26pub struct WorkbookDescriptor {
27 pub workbook_id: WorkbookId,
28 pub short_id: String,
29 pub slug: String,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub folder: Option<String>,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub path: Option<String>,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub client_path: Option<String>,
36 pub bytes: u64,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub last_modified: Option<String>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub revision_id: Option<String>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub caps: Option<BackendCaps>,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
46pub struct WorkbookListResponse {
47 pub workbooks: Vec<WorkbookDescriptor>,
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub next_offset: Option<u32>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
53pub struct WorkbookDescription {
54 pub workbook_id: WorkbookId,
55 pub short_id: String,
56 pub slug: String,
57 pub path: String,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub client_path: Option<String>,
60 pub bytes: u64,
61 pub sheet_count: usize,
62 pub defined_names: usize,
63 pub tables: usize,
64 pub macros_present: bool,
65 pub last_modified: Option<String>,
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub revision_id: Option<String>,
68 pub caps: BackendCaps,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
72pub struct WorkbookSummaryResponse {
73 pub workbook_id: WorkbookId,
74 pub slug: String,
75 pub sheet_count: usize,
76 pub total_cells: u64,
77 pub total_formulas: u64,
78 pub breakdown: WorkbookBreakdown,
79 pub region_counts: RegionCountSummary,
80 #[serde(skip_serializing_if = "Vec::is_empty")]
81 pub key_named_ranges: Vec<NamedRangeDescriptor>,
82 #[serde(skip_serializing_if = "Vec::is_empty")]
83 pub suggested_entry_points: Vec<EntryPoint>,
84 #[serde(skip_serializing_if = "Vec::is_empty")]
85 pub notes: Vec<String>,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
89pub struct WorkbookBreakdown {
90 pub data_sheets: u32,
91 pub calculator_sheets: u32,
92 pub parameter_sheets: u32,
93 pub metadata_sheets: u32,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
97pub struct RegionCountSummary {
98 pub data: u32,
99 pub parameters: u32,
100 pub outputs: u32,
101 pub calculator: u32,
102 pub metadata: u32,
103 pub other: u32,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
107pub struct EntryPoint {
108 pub sheet_name: String,
109 pub region_id: Option<u32>,
110 pub bounds: Option<String>,
111 pub rationale: String,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
115pub struct SheetSummary {
116 pub name: String,
117 pub visible: bool,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub row_count: Option<u32>,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub column_count: Option<u32>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub non_empty_cells: Option<u32>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub formula_cells: Option<u32>,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub cached_values: Option<u32>,
128 pub classification: SheetClassification,
129 #[serde(skip_serializing_if = "Vec::is_empty")]
130 pub style_tags: Vec<String>,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
134#[serde(rename_all = "snake_case")]
135pub enum SheetClassification {
136 Data,
137 Calculator,
138 Mixed,
139 Metadata,
140 Empty,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
144pub struct SheetListResponse {
145 pub workbook_id: WorkbookId,
146 pub sheets: Vec<SheetSummary>,
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub next_offset: Option<u32>,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
152pub struct SheetOverviewResponse {
153 pub workbook_id: WorkbookId,
154 pub sheet_name: String,
155 pub narrative: String,
156 pub regions: Vec<SheetRegion>,
157 pub detected_regions: Vec<DetectedRegion>,
158 pub detected_region_count: u32,
159 pub detected_regions_truncated: bool,
160 pub key_ranges: Vec<String>,
161 pub formula_ratio: f32,
162 pub notable_features: Vec<String>,
163 pub notes: Vec<String>,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
167pub struct SheetRegion {
168 pub kind: RegionKind,
169 pub address: String,
170 pub description: String,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
174pub enum RegionKind {
175 #[serde(rename = "likely_table")]
176 Table,
177 #[serde(rename = "likely_data")]
178 Data,
179 #[serde(rename = "likely_parameters")]
180 Parameters,
181 #[serde(rename = "likely_outputs")]
182 Outputs,
183 #[serde(rename = "likely_calculator")]
184 Calculator,
185 #[serde(rename = "likely_metadata")]
186 Metadata,
187 #[serde(rename = "likely_styles")]
188 Styles,
189 #[serde(rename = "likely_comments")]
190 Comments,
191 #[serde(rename = "unknown")]
192 Other,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
196pub struct DetectedRegion {
197 pub id: u32,
198 pub bounds: String,
199 pub header_row: Option<u32>,
200 pub headers: Vec<String>,
201 pub header_count: u32,
202 pub headers_truncated: bool,
203 pub row_count: u32,
204 pub classification: RegionKind,
205 pub region_kind: Option<RegionKind>,
206 pub confidence: f32,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
210pub struct SheetPageResponse {
211 pub workbook_id: WorkbookId,
212 pub sheet_name: String,
213 #[serde(skip_serializing_if = "Vec::is_empty")]
214 pub rows: Vec<RowSnapshot>,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub next_start_row: Option<u32>,
217 #[serde(skip_serializing_if = "Option::is_none")]
218 pub header_row: Option<RowSnapshot>,
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub compact: Option<SheetPageCompact>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub values_only: Option<SheetPageValues>,
223 pub format: SheetPageFormat,
224 #[serde(default, skip_serializing_if = "is_false")]
226 pub truncated: bool,
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub budget: Option<ReadBudget>,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
237pub struct ReadBudget {
238 #[serde(skip_serializing_if = "Option::is_none")]
240 pub max_cells: Option<usize>,
241 #[serde(skip_serializing_if = "Option::is_none")]
243 pub max_payload_bytes: Option<usize>,
244 pub rows_returned: usize,
246 pub cells_returned: usize,
248 #[serde(skip_serializing_if = "Option::is_none")]
250 pub total_rows_available: Option<u32>,
251 #[serde(skip_serializing_if = "Option::is_none")]
253 pub continuation: Option<String>,
254}
255
256fn is_false(v: &bool) -> bool {
257 !v
258}
259
260#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
261pub struct RowSnapshot {
262 pub row_index: u32,
263 pub cells: Vec<CellSnapshot>,
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
267pub struct CellSnapshot {
268 pub address: String,
269 pub value: Option<CellValue>,
270 pub formula: Option<String>,
271 pub cached_value: Option<CellValue>,
272 pub number_format: Option<String>,
273 pub style_tags: Vec<String>,
274 pub notes: Vec<String>,
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
278#[serde(tag = "kind", content = "value")]
279pub enum CellValue {
280 Text(String),
281 Number(f64),
282 Bool(bool),
283 Error(String),
284 Date(String),
285}
286
287#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
288#[serde(rename_all = "snake_case")]
289pub enum CellValueKind {
290 Text,
291 Number,
292 Bool,
293 Error,
294 Date,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
298#[serde(untagged)]
299pub enum CellValuePrimitive {
300 Text(String),
301 Number(f64),
302 Bool(bool),
303}
304
305#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
306#[serde(rename_all = "snake_case")]
307pub enum TableOutputFormat {
308 Json,
309 Values,
310 Csv,
311 Dense,
312 Rows,
313}
314
315#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, Default)]
316#[serde(rename_all = "snake_case")]
317pub enum SheetPageFormat {
318 #[default]
319 Full,
320 Compact,
321 ValuesOnly,
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
325pub struct SheetPageCompact {
326 pub headers: Vec<String>,
327 pub header_row: Vec<Option<CellValue>>,
328 pub rows: Vec<Vec<Option<CellValue>>>,
329}
330
331#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
332pub struct SheetPageValues {
333 pub rows: Vec<Vec<Option<CellValue>>>,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
337pub struct SheetStatisticsResponse {
338 pub workbook_id: WorkbookId,
339 pub sheet_name: String,
340 pub row_count: u32,
341 pub column_count: u32,
342 pub density: f32,
343 #[serde(skip_serializing_if = "Vec::is_empty")]
344 pub numeric_columns: Vec<ColumnSummary>,
345 #[serde(skip_serializing_if = "Vec::is_empty")]
346 pub text_columns: Vec<ColumnSummary>,
347 pub null_counts: BTreeMap<String, u32>,
348 pub duplicate_warnings: Vec<String>,
349}
350
351#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
352pub struct ColumnSummary {
353 pub header: Option<String>,
354 pub column: String,
355 #[serde(skip_serializing_if = "Vec::is_empty")]
356 pub samples: Vec<CellValue>,
357 pub min: Option<f64>,
358 pub max: Option<f64>,
359 pub mean: Option<f64>,
360}
361
362#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
363pub struct SheetFormulaMapResponse {
364 pub workbook_id: WorkbookId,
365 pub sheet_name: String,
366 pub groups: Vec<FormulaGroup>,
367 #[serde(skip_serializing_if = "Option::is_none")]
368 pub formula_parse_diagnostics: Option<FormulaParseDiagnostics>,
369 #[serde(skip_serializing_if = "Option::is_none")]
370 pub next_offset: Option<u32>,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
374pub struct FormulaGroup {
375 pub fingerprint: String,
376 #[serde(skip_serializing_if = "Vec::is_empty")]
377 pub addresses: Vec<String>,
378 #[serde(skip_serializing_if = "Option::is_none")]
379 pub count: Option<u32>,
380 pub formula: String,
381 pub is_array: bool,
382 pub is_shared: bool,
383 pub is_volatile: bool,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
387pub struct FormulaTraceResponse {
388 pub workbook_id: WorkbookId,
389 pub sheet_name: String,
390 pub origin: String,
391 pub direction: TraceDirection,
392 pub layers: Vec<TraceLayer>,
393 pub next_cursor: Option<TraceCursor>,
394 #[serde(skip_serializing_if = "Option::is_none")]
395 pub formula_parse_diagnostics: Option<FormulaParseDiagnostics>,
396 pub notes: Vec<String>,
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
400pub struct FormulaTraceEdge {
401 pub from: String,
402 pub to: String,
403 pub formula: Option<String>,
404 pub note: Option<String>,
405}
406
407#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
408pub struct TraceLayer {
409 pub depth: u32,
410 pub summary: TraceLayerSummary,
411 pub highlights: TraceLayerHighlights,
412 pub edges: Vec<FormulaTraceEdge>,
413 pub has_more: bool,
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
417pub struct TraceLayerSummary {
418 pub total_nodes: usize,
419 pub formula_nodes: usize,
420 pub value_nodes: usize,
421 pub blank_nodes: usize,
422 pub external_nodes: usize,
423 pub unique_formula_groups: usize,
424}
425
426#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
427pub struct TraceLayerHighlights {
428 pub top_ranges: Vec<TraceRangeHighlight>,
429 pub top_formula_groups: Vec<TraceFormulaGroupHighlight>,
430 pub notable_cells: Vec<TraceCellHighlight>,
431}
432
433#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
434pub struct TraceRangeHighlight {
435 pub start: String,
436 pub end: String,
437 pub count: usize,
438 pub literals: usize,
439 pub formulas: usize,
440 pub blanks: usize,
441 pub sample_values: Vec<CellValue>,
442 pub sample_formulas: Vec<String>,
443 pub sample_addresses: Vec<String>,
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
447pub struct TraceFormulaGroupHighlight {
448 pub fingerprint: String,
449 pub formula: String,
450 pub count: usize,
451 pub sample_addresses: Vec<String>,
452}
453
454#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
455pub struct TraceCellHighlight {
456 pub address: String,
457 pub kind: TraceCellKind,
458 pub value: Option<CellValue>,
459 pub formula: Option<String>,
460}
461
462#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
463#[serde(rename_all = "snake_case")]
464pub enum TraceCellKind {
465 Formula,
466 Literal,
467 Blank,
468 External,
469}
470
471#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
472pub struct TraceCursor {
473 pub depth: u32,
474 pub offset: usize,
475}
476
477#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
478#[serde(rename_all = "snake_case")]
479pub enum TraceDirection {
480 Precedents,
481 Dependents,
482}
483
484#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
485#[serde(rename_all = "snake_case")]
486pub enum NamedRangeScope {
487 Workbook,
488 Sheet,
489}
490
491#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
492pub struct NamedRangeDescriptor {
493 pub name: String,
494 pub scope: Option<String>,
495 #[serde(skip_serializing_if = "Option::is_none")]
497 pub scope_kind: Option<NamedRangeScope>,
498 #[serde(skip_serializing_if = "Option::is_none")]
500 pub scope_sheet_name: Option<String>,
501 pub refers_to: String,
502 pub kind: NamedItemKind,
503 pub sheet_name: Option<String>,
504 pub comment: Option<String>,
505}
506
507#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
508#[serde(rename_all = "snake_case")]
509pub enum NamedItemKind {
510 NamedRange,
511 Table,
512 Formula,
513 Unknown,
514}
515
516#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
517pub struct NamedRangesResponse {
518 pub workbook_id: WorkbookId,
519 pub items: Vec<NamedRangeDescriptor>,
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
523pub struct DefineNameResponse {
524 pub workbook_id: WorkbookId,
525 pub name: String,
526 pub refers_to: String,
527 pub scope_kind: NamedRangeScope,
528 #[serde(skip_serializing_if = "Option::is_none")]
529 pub scope_sheet_name: Option<String>,
530}
531
532#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
533pub struct UpdateNameResponse {
534 pub workbook_id: WorkbookId,
535 pub name: String,
536 pub refers_to: String,
537 pub scope_kind: NamedRangeScope,
538 #[serde(skip_serializing_if = "Option::is_none")]
539 pub scope_sheet_name: Option<String>,
540 #[serde(skip_serializing_if = "Option::is_none")]
541 pub previous_refers_to: Option<String>,
542}
543
544#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
545pub struct DeleteNameResponse {
546 pub workbook_id: WorkbookId,
547 pub name: String,
548 pub deleted: bool,
549}
550
551#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
552pub struct FindFormulaMatch {
553 pub address: String,
554 pub sheet_name: String,
555 pub formula: String,
556 pub cached_value: Option<CellValue>,
557 pub context: Vec<RowSnapshot>,
558}
559
560#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
561pub struct FindFormulaResponse {
562 pub workbook_id: WorkbookId,
563 pub matches: Vec<FindFormulaMatch>,
564 #[serde(skip_serializing_if = "Option::is_none")]
565 pub next_offset: Option<u32>,
566}
567
568#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
569pub struct VolatileScanEntry {
570 pub address: String,
571 pub sheet_name: String,
572 pub function: String,
573 pub note: Option<String>,
574}
575
576#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
577pub struct VolatileScanResponse {
578 pub workbook_id: WorkbookId,
579 pub items: Vec<VolatileScanEntry>,
580 #[serde(skip_serializing_if = "Option::is_none")]
581 pub formula_parse_diagnostics: Option<FormulaParseDiagnostics>,
582 #[serde(skip_serializing_if = "Option::is_none")]
583 pub next_offset: Option<u32>,
584}
585
586#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
587pub struct StyleDescriptor {
588 pub font: Option<FontDescriptor>,
589 pub fill: Option<FillDescriptor>,
590 pub borders: Option<BordersDescriptor>,
591 pub alignment: Option<AlignmentDescriptor>,
592 pub number_format: Option<String>,
593}
594
595#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
596pub struct FontDescriptor {
597 pub name: Option<String>,
598 pub size: Option<f64>,
599 pub bold: Option<bool>,
600 pub italic: Option<bool>,
601 pub underline: Option<String>,
602 pub strikethrough: Option<bool>,
603 pub color: Option<String>,
604}
605
606#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
607#[serde(tag = "kind", rename_all = "snake_case")]
608pub enum FillDescriptor {
609 Pattern(PatternFillDescriptor),
610 Gradient(GradientFillDescriptor),
611}
612
613#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
614pub struct PatternFillDescriptor {
615 pub pattern_type: Option<String>,
616 pub foreground_color: Option<String>,
617 pub background_color: Option<String>,
618}
619
620#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
621pub struct GradientFillDescriptor {
622 pub degree: Option<f64>,
623 pub stops: Vec<GradientStopDescriptor>,
624}
625
626#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
627pub struct GradientStopDescriptor {
628 pub position: f64,
629 pub color: String,
630}
631
632#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
633pub struct BordersDescriptor {
634 pub left: Option<BorderSideDescriptor>,
635 pub right: Option<BorderSideDescriptor>,
636 pub top: Option<BorderSideDescriptor>,
637 pub bottom: Option<BorderSideDescriptor>,
638 pub diagonal: Option<BorderSideDescriptor>,
639 pub vertical: Option<BorderSideDescriptor>,
640 pub horizontal: Option<BorderSideDescriptor>,
641 pub diagonal_up: Option<bool>,
642 pub diagonal_down: Option<bool>,
643}
644
645#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
646pub struct BorderSideDescriptor {
647 pub style: Option<String>,
648 pub color: Option<String>,
649}
650
651#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
652pub struct AlignmentDescriptor {
653 pub horizontal: Option<String>,
654 pub vertical: Option<String>,
655 pub wrap_text: Option<bool>,
656 pub text_rotation: Option<u32>,
657}
658
659#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
664pub struct StylePatch {
665 #[serde(default)]
666 pub font: Option<Option<FontPatch>>,
667 #[serde(default)]
668 pub fill: Option<Option<FillPatch>>,
669 #[serde(default)]
670 pub borders: Option<Option<BordersPatch>>,
671 #[serde(default)]
672 pub alignment: Option<Option<AlignmentPatch>>,
673 #[serde(default)]
674 pub number_format: Option<Option<String>>,
675}
676
677#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
678pub struct FontPatch {
679 #[serde(default)]
680 pub name: Option<Option<String>>,
681 #[serde(default)]
682 pub size: Option<Option<f64>>,
683 #[serde(default)]
684 pub bold: Option<Option<bool>>,
685 #[serde(default)]
686 pub italic: Option<Option<bool>>,
687 #[serde(default)]
688 pub underline: Option<Option<String>>,
689 #[serde(default)]
690 pub strikethrough: Option<Option<bool>>,
691 #[serde(default)]
692 pub color: Option<Option<String>>,
693}
694
695#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
696#[serde(tag = "kind", rename_all = "snake_case")]
697pub enum FillPatch {
698 Pattern(PatternFillPatch),
699 Gradient(GradientFillPatch),
700}
701
702#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
703pub struct PatternFillPatch {
704 #[serde(default)]
705 pub pattern_type: Option<Option<String>>,
706 #[serde(default)]
707 pub foreground_color: Option<Option<String>>,
708 #[serde(default)]
709 pub background_color: Option<Option<String>>,
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
713pub struct GradientFillPatch {
714 #[serde(default)]
715 pub degree: Option<Option<f64>>,
716 #[serde(default)]
717 pub stops: Option<Vec<GradientStopPatch>>,
718}
719
720#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
721pub struct GradientStopPatch {
722 pub position: f64,
723 pub color: String,
724}
725
726#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
727pub struct BordersPatch {
728 #[serde(default)]
729 pub left: Option<Option<BorderSidePatch>>,
730 #[serde(default)]
731 pub right: Option<Option<BorderSidePatch>>,
732 #[serde(default)]
733 pub top: Option<Option<BorderSidePatch>>,
734 #[serde(default)]
735 pub bottom: Option<Option<BorderSidePatch>>,
736 #[serde(default)]
737 pub diagonal: Option<Option<BorderSidePatch>>,
738 #[serde(default)]
739 pub vertical: Option<Option<BorderSidePatch>>,
740 #[serde(default)]
741 pub horizontal: Option<Option<BorderSidePatch>>,
742 #[serde(default)]
743 pub diagonal_up: Option<Option<bool>>,
744 #[serde(default)]
745 pub diagonal_down: Option<Option<bool>>,
746}
747
748#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
749pub struct BorderSidePatch {
750 #[serde(default)]
751 pub style: Option<Option<String>>,
752 #[serde(default)]
753 pub color: Option<Option<String>>,
754}
755
756#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
757pub struct AlignmentPatch {
758 #[serde(default)]
759 pub horizontal: Option<Option<String>>,
760 #[serde(default)]
761 pub vertical: Option<Option<String>>,
762 #[serde(default)]
763 pub wrap_text: Option<Option<bool>>,
764 #[serde(default)]
765 pub text_rotation: Option<Option<u32>>,
766}
767
768#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
769pub struct SheetStylesResponse {
770 pub workbook_id: WorkbookId,
771 pub sheet_name: String,
772 pub styles: Vec<StyleSummary>,
773 #[serde(skip_serializing_if = "Vec::is_empty")]
774 pub conditional_rules: Vec<String>,
775 pub total_styles: u32,
776 pub styles_truncated: bool,
777}
778
779#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
780pub struct StyleSummary {
781 pub style_id: String,
782 pub occurrences: u32,
783 pub tags: Vec<String>,
784 #[serde(skip_serializing_if = "Vec::is_empty")]
785 pub example_cells: Vec<String>,
786 pub descriptor: Option<StyleDescriptor>,
787 #[serde(skip_serializing_if = "Vec::is_empty")]
788 pub cell_ranges: Vec<String>,
789 pub ranges_truncated: bool,
790}
791
792#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
793pub struct WorkbookStyleSummaryResponse {
794 pub workbook_id: WorkbookId,
795 #[serde(skip_serializing_if = "Option::is_none")]
796 pub theme: Option<ThemeSummary>,
797 #[serde(skip_serializing_if = "Option::is_none")]
798 pub inferred_default_style_id: Option<String>,
799 #[serde(skip_serializing_if = "Option::is_none")]
800 pub inferred_default_font: Option<FontDescriptor>,
801 pub styles: Vec<WorkbookStyleUsage>,
802 pub total_styles: u32,
803 pub styles_truncated: bool,
804 #[serde(skip_serializing_if = "Vec::is_empty")]
805 pub conditional_formats: Vec<ConditionalFormatSummary>,
806 pub conditional_formats_truncated: bool,
807 pub scan_truncated: bool,
808 #[serde(skip_serializing_if = "Vec::is_empty")]
809 pub notes: Vec<String>,
810}
811
812#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
813pub struct WorkbookStyleUsage {
814 pub style_id: String,
815 pub occurrences: u32,
816 pub tags: Vec<String>,
817 #[serde(skip_serializing_if = "Vec::is_empty")]
818 pub example_cells: Vec<String>,
819 pub descriptor: Option<StyleDescriptor>,
820}
821
822#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
823pub struct ThemeSummary {
824 pub name: Option<String>,
825 pub colors: BTreeMap<String, String>,
826 pub font_scheme: ThemeFontSchemeSummary,
827}
828
829#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
830pub struct ThemeFontSchemeSummary {
831 pub major_latin: Option<String>,
832 pub major_east_asian: Option<String>,
833 pub major_complex_script: Option<String>,
834 pub minor_latin: Option<String>,
835 pub minor_east_asian: Option<String>,
836 pub minor_complex_script: Option<String>,
837}
838
839#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
840pub struct ConditionalFormatSummary {
841 pub sheet_name: String,
842 pub range: String,
843 pub rule_types: Vec<String>,
844 pub rule_count: u32,
845}
846
847#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
848pub struct ManifestStubResponse {
849 pub workbook_id: WorkbookId,
850 pub slug: String,
851 pub manifest_yaml: String,
852 pub sheets: Vec<ManifestSheetStub>,
853}
854
855#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
856pub struct ManifestSheetStub {
857 pub sheet_name: String,
858 pub classification: SheetClassification,
859 pub candidate_expectations: Vec<String>,
860 pub notes: Vec<String>,
861}
862
863#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
864#[serde(rename_all = "snake_case")]
865pub enum FindMode {
866 #[default]
867 Value,
868 Label,
869}
870
871#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
872#[serde(rename_all = "snake_case")]
873pub enum LabelDirection {
874 Right,
875 Below,
876 Any,
877}
878
879#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
880pub struct FindValueMatch {
881 pub address: String,
882 pub sheet_name: String,
883 pub value: Option<CellValue>,
884 pub row_context: Option<RowContext>,
885 pub neighbors: Option<NeighborValues>,
886 pub label_hit: Option<LabelHit>,
887}
888
889#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
890pub struct RowContext {
891 pub headers: Vec<String>,
892 pub values: Vec<Option<CellValue>>,
893}
894
895#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
896pub struct NeighborValues {
897 pub left: Option<CellValue>,
898 pub right: Option<CellValue>,
899 pub up: Option<CellValue>,
900 pub down: Option<CellValue>,
901}
902
903#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
904pub struct LabelHit {
905 pub label_address: String,
906 pub label: String,
907}
908
909#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
910pub struct FindValueResponse {
911 pub workbook_id: WorkbookId,
912 pub matches: Vec<FindValueMatch>,
913 pub match_count: u32,
914 #[serde(skip_serializing_if = "Option::is_none")]
915 pub next_offset: Option<u32>,
916}
917
918pub type TableRow = BTreeMap<String, Option<CellValue>>;
919
920#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
921pub struct ReadTableResponse {
922 pub workbook_id: WorkbookId,
923 pub sheet_name: String,
924 pub table_name: Option<String>,
925 #[serde(skip_serializing_if = "Vec::is_empty")]
926 pub warnings: Vec<Warning>,
927 #[serde(skip_serializing_if = "Vec::is_empty")]
928 pub headers: Vec<String>,
929 #[serde(skip_serializing_if = "Vec::is_empty")]
930 pub rows: Vec<TableRow>,
931 #[serde(skip_serializing_if = "Option::is_none")]
932 pub values: Option<Vec<Vec<Option<CellValuePrimitive>>>>,
933 #[serde(skip_serializing_if = "Option::is_none")]
934 pub types: Option<Vec<Vec<Option<CellValueKind>>>>,
935 #[serde(skip_serializing_if = "Option::is_none")]
936 pub csv: Option<String>,
937 pub total_rows: u32,
938 #[serde(skip_serializing_if = "Option::is_none")]
939 pub next_offset: Option<u32>,
940}
941
942#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
943pub struct ColumnTypeSummary {
944 pub name: String,
945 pub inferred_type: String,
946 pub nulls: u32,
947 pub distinct: u32,
948 pub top_values: Vec<String>,
949 pub min: Option<f64>,
950 pub max: Option<f64>,
951 pub mean: Option<f64>,
952}
953
954#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
955pub struct TableProfileResponse {
956 pub workbook_id: WorkbookId,
957 pub sheet_name: String,
958 pub table_name: Option<String>,
959 pub headers: Vec<String>,
960 pub column_types: Vec<ColumnTypeSummary>,
961 pub row_count: u32,
962 #[serde(skip_serializing_if = "Vec::is_empty")]
963 pub samples: Vec<TableRow>,
964 #[serde(skip_serializing_if = "Vec::is_empty")]
965 pub notes: Vec<String>,
966}
967
968#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
977pub struct RangeValuesResponse {
978 pub workbook_id: WorkbookId,
979 pub sheet_name: String,
980 #[serde(skip_serializing_if = "Vec::is_empty")]
981 pub warnings: Vec<Warning>,
982 pub values: Vec<RangeValuesEntry>,
983}
984
985#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
990pub struct RangeValuesEntry {
991 pub range: String,
992 #[serde(skip_serializing_if = "Option::is_none")]
993 pub rows: Option<Vec<Vec<Option<CellValue>>>>,
994 #[serde(skip_serializing_if = "Option::is_none")]
999 pub formulas: Option<Vec<Vec<Option<String>>>>,
1000 #[serde(skip_serializing_if = "Option::is_none")]
1001 pub values: Option<Vec<Vec<Option<CellValuePrimitive>>>>,
1002 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub dense: Option<RangeValuesDensePayload>,
1005 #[serde(skip_serializing_if = "Option::is_none")]
1006 pub csv: Option<String>,
1007 #[serde(skip_serializing_if = "Option::is_none")]
1009 pub rows_keyed: Option<Vec<RangeValuesRowEntry>>,
1010 #[serde(skip_serializing_if = "Option::is_none")]
1011 pub next_start_row: Option<u32>,
1012}
1013
1014#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1019pub struct RangeValuesRowEntry {
1020 pub row: u32,
1022 pub cells: BTreeMap<String, CellValuePrimitive>,
1024}
1025
1026#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1027pub struct RangeValuesDensePayload {
1028 pub encoding: String,
1030 pub col_count: u32,
1032 pub dictionary: Vec<Option<CellValuePrimitive>>,
1034 pub row_runs: Vec<Vec<RangeValuesDenseRun>>,
1036 #[serde(skip_serializing_if = "Vec::is_empty")]
1038 pub formulas: Vec<RangeValuesDenseFormula>,
1039}
1040
1041#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1042pub struct RangeValuesDenseRun {
1043 pub value_idx: u32,
1044 pub len: u32,
1045}
1046
1047#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1048pub struct RangeValuesDenseFormula {
1049 pub row: u32,
1051 pub col: u32,
1053 pub formula: String,
1054}
1055
1056#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1057pub struct InspectCellsResponse {
1058 pub workbook_id: WorkbookId,
1059 pub sheet_name: String,
1060 pub range: String,
1062 #[serde(skip_serializing_if = "Vec::is_empty")]
1064 pub targets: Vec<String>,
1065 pub cells: Vec<CellSnapshot>,
1066 pub truncated: bool,
1067 #[serde(skip_serializing_if = "Option::is_none")]
1069 pub budget: Option<ReadBudget>,
1070}
1071
1072#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1073pub struct CloseWorkbookResponse {
1074 pub workbook_id: WorkbookId,
1075 pub message: String,
1076}
1077
1078#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1079pub struct VbaProjectSummaryResponse {
1080 pub workbook_id: WorkbookId,
1081 pub has_vba: bool,
1082 pub code_page: Option<u16>,
1083 pub sys_kind: Option<String>,
1084 pub modules: Vec<VbaModuleDescriptor>,
1085 pub modules_truncated: bool,
1086 pub references: Vec<VbaReferenceDescriptor>,
1087 pub references_truncated: bool,
1088 pub notes: Vec<String>,
1089}
1090
1091#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1092pub struct VbaModuleDescriptor {
1093 pub name: String,
1094 pub stream_name: String,
1095 pub doc_string: String,
1096 pub text_offset: u64,
1097 pub help_context: u32,
1098 pub module_type: String,
1099 pub read_only: bool,
1100 pub private: bool,
1101}
1102
1103#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1104pub struct VbaReferenceDescriptor {
1105 pub kind: String,
1106 pub debug: String,
1107}
1108
1109#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1110pub struct VbaModuleSourceResponse {
1111 pub workbook_id: WorkbookId,
1112 pub module_name: String,
1113 pub offset_lines: u32,
1114 pub limit_lines: u32,
1115 pub total_lines: u32,
1116 pub truncated: bool,
1117 pub source: String,
1118}
1119
1120#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)]
1123#[serde(rename_all = "snake_case")]
1124pub enum LayoutMode {
1125 #[default]
1126 Values,
1127 Formulas,
1128}
1129
1130#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)]
1131#[serde(rename_all = "snake_case")]
1132pub enum LayoutRender {
1133 #[default]
1134 Json,
1135 Ascii,
1136 Both,
1137}
1138
1139#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1140pub struct LayoutPageColumnInfo {
1141 pub col: String,
1143 pub index: u32,
1145 pub width_chars: f64,
1147 #[serde(skip_serializing_if = "std::ops::Not::not")]
1149 pub is_default_width: bool,
1150}
1151
1152#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1153pub struct LayoutCellBorders {
1154 #[serde(skip_serializing_if = "Option::is_none")]
1155 pub top: Option<String>,
1156 #[serde(skip_serializing_if = "Option::is_none")]
1157 pub bottom: Option<String>,
1158 #[serde(skip_serializing_if = "Option::is_none")]
1159 pub left: Option<String>,
1160 #[serde(skip_serializing_if = "Option::is_none")]
1161 pub right: Option<String>,
1162}
1163
1164impl LayoutCellBorders {
1165 pub fn is_empty(&self) -> bool {
1166 self.top.is_none() && self.bottom.is_none() && self.left.is_none() && self.right.is_none()
1167 }
1168}
1169
1170#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1171pub struct LayoutCellInfo {
1172 pub address: String,
1173 #[serde(skip_serializing_if = "Option::is_none")]
1174 pub value: Option<String>,
1175 #[serde(skip_serializing_if = "Option::is_none")]
1176 pub bold: Option<bool>,
1177 #[serde(skip_serializing_if = "Option::is_none")]
1178 pub italic: Option<bool>,
1179 #[serde(skip_serializing_if = "Option::is_none")]
1181 pub align_h: Option<String>,
1182 #[serde(skip_serializing_if = "Option::is_none")]
1183 pub borders: Option<LayoutCellBorders>,
1184 #[serde(skip_serializing_if = "Option::is_none")]
1186 pub merge_start: Option<bool>,
1187}
1188
1189#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1190pub struct LayoutRowInfo {
1191 pub row: u32,
1192 pub cells: Vec<LayoutCellInfo>,
1193}
1194
1195#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1196pub struct LayoutPageResponse {
1197 pub workbook_id: WorkbookId,
1198 pub sheet_name: String,
1199 pub range: String,
1201 pub columns: Vec<LayoutPageColumnInfo>,
1202 #[serde(skip_serializing_if = "Vec::is_empty")]
1204 pub merged_cells: Vec<String>,
1205 pub rows: Vec<LayoutRowInfo>,
1206 #[serde(skip_serializing_if = "Option::is_none")]
1208 pub ascii_render: Option<String>,
1209 #[serde(skip_serializing_if = "std::ops::Not::not")]
1211 pub truncated: bool,
1212 #[serde(skip_serializing_if = "Vec::is_empty")]
1213 pub notes: Vec<String>,
1214}
1215
1216#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1217pub struct GridPayload {
1218 pub sheet: String,
1219 pub anchor: String,
1220 #[serde(default)]
1221 #[serde(skip_serializing_if = "Vec::is_empty")]
1222 pub columns: Vec<GridColumnHint>,
1223 #[serde(default)]
1224 #[serde(skip_serializing_if = "Vec::is_empty")]
1225 pub merges: Vec<String>,
1226 pub rows: Vec<GridRow>,
1227}
1228
1229#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1230pub struct GridColumnHint {
1231 pub offset: u32,
1232 pub width_chars: f64,
1233}
1234
1235#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1236pub struct GridRow {
1237 pub cells: Vec<GridCell>,
1238}
1239
1240#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
1241pub struct GridCell {
1242 pub offset: [u32; 2], #[serde(skip_serializing_if = "Option::is_none")]
1244 pub v: Option<serde_json::Value>,
1245 #[serde(skip_serializing_if = "Option::is_none")]
1246 pub f: Option<String>,
1247 #[serde(skip_serializing_if = "Option::is_none")]
1248 pub fmt: Option<String>,
1249 #[serde(skip_serializing_if = "Option::is_none")]
1250 pub style: Option<crate::model::StylePatch>,
1251}