1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Deserialize)]
5#[serde(rename_all = "camelCase")]
6pub struct Document {
7 pub document_id: String,
8 pub title: String,
9 pub body: Option<Body>,
10 pub revision_id: Option<String>,
11}
12
13#[derive(Debug, Clone, Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct Body {
17 pub content: Option<Vec<StructuralElement>>,
18}
19
20#[derive(Debug, Clone, Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct StructuralElement {
24 pub start_index: Option<i32>,
25 pub end_index: Option<i32>,
26 pub paragraph: Option<Paragraph>,
27 pub table: Option<Table>,
28 pub section_break: Option<SectionBreak>,
29}
30
31#[derive(Debug, Clone, Deserialize)]
33#[serde(rename_all = "camelCase")]
34pub struct Paragraph {
35 pub elements: Vec<ParagraphElement>,
36 pub paragraph_style: Option<ParagraphStyle>,
37}
38
39#[derive(Debug, Clone, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct ParagraphElement {
43 pub start_index: Option<i32>,
44 pub end_index: Option<i32>,
45 pub text_run: Option<TextRun>,
46}
47
48#[derive(Debug, Clone, Deserialize)]
50#[serde(rename_all = "camelCase")]
51pub struct TextRun {
52 pub content: String,
53 pub text_style: Option<TextStyle>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58#[serde(rename_all = "camelCase")]
59pub struct TextStyle {
60 #[serde(skip_serializing_if = "Option::is_none")]
61 pub bold: Option<bool>,
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub italic: Option<bool>,
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub underline: Option<bool>,
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub strikethrough: Option<bool>,
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub font_size: Option<Dimension>,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct Dimension {
75 pub magnitude: f64,
76 pub unit: String,
77}
78
79impl Dimension {
80 pub fn pt(magnitude: f64) -> Self {
81 Self {
82 magnitude,
83 unit: "PT".to_string(),
84 }
85 }
86}
87
88#[derive(Debug, Clone, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub struct ParagraphStyle {
92 pub named_style_type: Option<String>,
93 pub alignment: Option<String>,
94}
95
96#[derive(Debug, Clone, Deserialize)]
98#[serde(rename_all = "camelCase")]
99pub struct Table {
100 pub rows: i32,
101 pub columns: i32,
102 pub table_rows: Vec<TableRow>,
103}
104
105#[derive(Debug, Clone, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct TableRow {
109 pub table_cells: Vec<TableCell>,
110}
111
112#[derive(Debug, Clone, Deserialize)]
114#[serde(rename_all = "camelCase")]
115pub struct TableCell {
116 pub content: Vec<StructuralElement>,
117}
118
119#[derive(Debug, Clone, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct SectionBreak {
123 pub section_style: Option<SectionStyle>,
124}
125
126#[derive(Debug, Clone, Deserialize)]
128#[serde(rename_all = "camelCase")]
129pub struct SectionStyle {
130 pub section_type: Option<String>,
131}
132
133#[derive(Debug, Clone, Serialize)]
135#[serde(rename_all = "camelCase")]
136pub struct BatchUpdateRequest {
137 pub requests: Vec<Request>,
138}
139
140#[derive(Debug, Clone, Serialize)]
142#[serde(rename_all = "camelCase")]
143pub struct Request {
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub insert_text: Option<InsertTextRequest>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub delete_content_range: Option<DeleteContentRangeRequest>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub update_text_style: Option<UpdateTextStyleRequest>,
150}
151
152impl Request {
153 pub fn insert_text(text: impl Into<String>, index: i32) -> Self {
154 Self {
155 insert_text: Some(InsertTextRequest {
156 text: text.into(),
157 location: Location { index },
158 }),
159 delete_content_range: None,
160 update_text_style: None,
161 }
162 }
163
164 pub fn delete_range(start: i32, end: i32) -> Self {
165 Self {
166 insert_text: None,
167 delete_content_range: Some(DeleteContentRangeRequest {
168 range: Range {
169 start_index: start,
170 end_index: end,
171 },
172 }),
173 update_text_style: None,
174 }
175 }
176}
177
178#[derive(Debug, Clone, Serialize)]
180#[serde(rename_all = "camelCase")]
181pub struct InsertTextRequest {
182 pub text: String,
183 pub location: Location,
184}
185
186#[derive(Debug, Clone, Serialize)]
188#[serde(rename_all = "camelCase")]
189pub struct Location {
190 pub index: i32,
191}
192
193#[derive(Debug, Clone, Serialize)]
195#[serde(rename_all = "camelCase")]
196pub struct DeleteContentRangeRequest {
197 pub range: Range,
198}
199
200#[derive(Debug, Clone, Serialize)]
202#[serde(rename_all = "camelCase")]
203pub struct Range {
204 pub start_index: i32,
205 pub end_index: i32,
206}
207
208#[derive(Debug, Clone, Serialize)]
210#[serde(rename_all = "camelCase")]
211pub struct UpdateTextStyleRequest {
212 pub range: Range,
213 pub text_style: TextStyle,
214 pub fields: String,
215}
216
217#[derive(Debug, Clone, Deserialize)]
219#[serde(rename_all = "camelCase")]
220pub struct BatchUpdateResponse {
221 pub document_id: String,
222 pub replies: Vec<serde_json::Value>,
223}
224
225#[derive(Debug, Clone, Serialize)]
227pub struct CreateDocumentRequest {
228 pub title: String,
229}
230
231impl CreateDocumentRequest {
232 pub fn new(title: impl Into<String>) -> Self {
233 Self {
234 title: title.into(),
235 }
236 }
237}