open_lark/service/cloud_docs/sheets/v3/data_operation/
find_cells.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    core::{
5        api_req::ApiRequest,
6        api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
7        constants::AccessTokenType,
8        endpoints::cloud_docs::*,
9        req_option,
10        standard_response::StandardResponse,
11        validation::{self, ValidationResult},
12        SDKResult,
13    },
14    impl_executable_builder_owned,
15    service::sheets::v3::{
16        data_operation::{FindCondition, FindReplaceResult},
17        SpreadsheetSheetService,
18    },
19};
20
21#[derive(Serialize, Debug, Default)]
22pub struct FindCellsRequest {
23    #[serde(skip)]
24    api_request: ApiRequest,
25    #[serde(skip)]
26    spreadsheet_token: String,
27    /// 工作表的id
28    #[serde(skip)]
29    sheet_id: String,
30    /// 查找条件
31    find_condition: FindCondition,
32    /// 查找的字符串,当search_by_regex字段为 true 时,该字段为正则表达式
33    ///
34    /// 示例值:"如下
35    ///
36    /// - 普通查找示例: "hello"
37    /// - 正则查找示例: "[A-Z]\w+""
38    find: String,
39}
40
41impl FindCellsRequest {
42    pub fn builder() -> FindCellsRequestBuilder {
43        FindCellsRequestBuilder::default()
44    }
45
46    /// 验证请求参数
47    pub fn validate(&self) -> SDKResult<()> {
48        // 验证必需字段
49        if self.spreadsheet_token.is_empty() {
50            return Err(crate::core::error::LarkAPIError::illegal_param(
51                "spreadsheet_token cannot be empty".to_string(),
52            ));
53        }
54
55        if self.sheet_id.is_empty() {
56            return Err(crate::core::error::LarkAPIError::illegal_param(
57                "sheet_id cannot be empty".to_string(),
58            ));
59        }
60
61        if self.find.is_empty() {
62            return Err(crate::core::error::LarkAPIError::illegal_param(
63                "find cannot be empty".to_string(),
64            ));
65        }
66
67        // 验证查找条件
68        if let ValidationResult::Invalid(msg) = validation::validate_find_options(
69            &self.find_condition.match_case,
70            &self.find_condition.match_entire_cell,
71            &self.find_condition.search_by_regex,
72            &self.find_condition.include_formulas,
73        ) {
74            return Err(crate::core::error::LarkAPIError::illegal_param(format!(
75                "Invalid find options: {}",
76                msg
77            )));
78        }
79
80        // 验证范围格式(如果指定了范围)
81        if !self.find_condition.range.is_empty() {
82            if let ValidationResult::Invalid(msg) =
83                validation::validate_cell_range(&self.find_condition.range)
84            {
85                return Err(crate::core::error::LarkAPIError::illegal_param(format!(
86                    "Invalid search range '{}': {}",
87                    self.find_condition.range, msg
88                )));
89            }
90        }
91
92        // 验证查找字符串长度
93        if self.find.len() > 1000 {
94            return Err(crate::core::error::LarkAPIError::illegal_param(
95                "find string too long. Maximum 1000 characters allowed".to_string(),
96            ));
97        }
98
99        Ok(())
100    }
101}
102
103#[derive(Default)]
104pub struct FindCellsRequestBuilder {
105    request: FindCellsRequest,
106}
107
108impl FindCellsRequestBuilder {
109    pub fn spreadsheet_token(mut self, spreadsheet_token: impl ToString) -> Self {
110        self.request.spreadsheet_token = spreadsheet_token.to_string();
111        self
112    }
113
114    pub fn sheet_id(mut self, sheet_id: impl ToString) -> Self {
115        self.request.sheet_id = sheet_id.to_string();
116        self
117    }
118
119    pub fn find(mut self, find: impl ToString) -> Self {
120        self.request.find = find.to_string();
121        self
122    }
123
124    pub fn range(mut self, range: impl ToString) -> Self {
125        self.request.find_condition.range = range.to_string();
126        self
127    }
128
129    pub fn match_case(mut self, match_case: bool) -> Self {
130        self.request.find_condition.match_case = Some(match_case);
131        self
132    }
133
134    pub fn match_entire_cell(mut self, match_entire_cell: bool) -> Self {
135        self.request.find_condition.match_entire_cell = Some(match_entire_cell);
136        self
137    }
138
139    pub fn search_by_regex(mut self, search_by_regex: bool) -> Self {
140        self.request.find_condition.search_by_regex = Some(search_by_regex);
141        self
142    }
143
144    pub fn include_formulas(mut self, include_formulas: bool) -> Self {
145        self.request.find_condition.include_formulas = Some(include_formulas);
146        self
147    }
148
149    pub fn build(self) -> FindCellsRequest {
150        let mut request = self.request;
151        request.api_request.body = serde_json::to_vec(&request).unwrap();
152        request
153    }
154
155    /// 验证请求参数
156    pub fn validate(&self) -> SDKResult<()> {
157        // 验证必需字段
158        if self.request.spreadsheet_token.is_empty() {
159            return Err(crate::core::error::LarkAPIError::illegal_param(
160                "spreadsheet_token cannot be empty".to_string(),
161            ));
162        }
163
164        if self.request.sheet_id.is_empty() {
165            return Err(crate::core::error::LarkAPIError::illegal_param(
166                "sheet_id cannot be empty".to_string(),
167            ));
168        }
169
170        if self.request.find.is_empty() {
171            return Err(crate::core::error::LarkAPIError::illegal_param(
172                "find cannot be empty".to_string(),
173            ));
174        }
175
176        // 验证查找条件
177        if let ValidationResult::Invalid(msg) = validation::validate_find_options(
178            &self.request.find_condition.match_case,
179            &self.request.find_condition.match_entire_cell,
180            &self.request.find_condition.search_by_regex,
181            &self.request.find_condition.include_formulas,
182        ) {
183            return Err(crate::core::error::LarkAPIError::illegal_param(format!(
184                "Invalid find options: {}",
185                msg
186            )));
187        }
188
189        // 验证范围格式(如果指定了范围)
190        if !self.request.find_condition.range.is_empty() {
191            if let ValidationResult::Invalid(msg) =
192                validation::validate_cell_range(&self.request.find_condition.range)
193            {
194                return Err(crate::core::error::LarkAPIError::illegal_param(format!(
195                    "Invalid search range '{}': {}",
196                    self.request.find_condition.range, msg
197                )));
198            }
199        }
200
201        // 验证查找字符串长度
202        if self.request.find.len() > 1000 {
203            return Err(crate::core::error::LarkAPIError::illegal_param(
204                "find string too long. Maximum 1000 characters allowed".to_string(),
205            ));
206        }
207
208        Ok(())
209    }
210}
211
212// Trait implementation
213impl_executable_builder_owned!(
214    FindCellsRequestBuilder,
215    SpreadsheetSheetService,
216    FindCellsRequest,
217    FindCellsResponse,
218    find_cells
219);
220
221/// 查找单元格响应
222#[derive(Deserialize, Debug)]
223pub struct FindCellsResponse {
224    /// 符合条件的信息
225    pub find_result: FindReplaceResult,
226}
227
228impl ApiResponseTrait for FindCellsResponse {
229    fn data_format() -> ResponseFormat {
230        ResponseFormat::Data
231    }
232}
233
234impl SpreadsheetSheetService {
235    /// 查找单元格
236    pub async fn find_cells(
237        &self,
238        request: FindCellsRequest,
239        option: Option<req_option::RequestOption>,
240    ) -> SDKResult<FindCellsResponse> {
241        let mut api_req = request.api_request;
242        api_req.api_path = SHEETS_V3_SPREADSHEET_SHEET_FIND
243            .replace("{}", &request.spreadsheet_token)
244            .replace("{}", &request.sheet_id);
245        api_req.http_method = reqwest::Method::POST;
246        api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::App];
247
248        let api_resp: BaseResponse<FindCellsResponse> =
249            crate::core::http::Transport::request(api_req, &self.config, option).await?;
250
251        api_resp.into_result()
252    }
253}