use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::{
core::{
api_req::ApiRequest,
api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
constants::AccessTokenType,
endpoints::cloud_docs::*,
http::Transport,
req_option::RequestOption,
SDKResult,
},
impl_executable_builder_owned,
};
use super::AppTableService;
impl AppTableService {
pub async fn create(
&self,
request: CreateTableRequest,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<CreateTableResponse>> {
let mut api_req = request.api_request;
api_req.http_method = Method::POST;
api_req.api_path = BITABLE_V1_TABLE_CREATE.replace("{app_token}", &request.app_token);
api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
api_req.body = serde_json::to_vec(&CreateTableRequestBody {
table: request.table,
})?;
let api_resp = Transport::request(api_req, &self.config, option).await?;
Ok(api_resp)
}
}
#[derive(Debug, Default)]
pub struct CreateTableRequest {
api_request: ApiRequest,
app_token: String,
table: TableData,
}
impl CreateTableRequest {
pub fn builder() -> CreateTableRequestBuilder {
CreateTableRequestBuilder::default()
}
pub fn new(app_token: impl ToString, table: TableData) -> Self {
Self {
api_request: ApiRequest::default(),
app_token: app_token.to_string(),
table,
}
}
}
#[derive(Default)]
pub struct CreateTableRequestBuilder {
request: CreateTableRequest,
}
impl CreateTableRequestBuilder {
pub fn app_token(mut self, app_token: impl ToString) -> Self {
self.request.app_token = app_token.to_string();
self
}
pub fn table(mut self, table: TableData) -> Self {
self.request.table = table;
self
}
pub fn build(self) -> CreateTableRequest {
self.request
}
}
impl_executable_builder_owned!(
CreateTableRequestBuilder,
AppTableService,
CreateTableRequest,
BaseResponse<CreateTableResponse>,
create
);
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TableData {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_view_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fields: Option<Vec<TableField>>,
}
impl TableData {
pub fn new(name: impl ToString) -> Self {
Self {
name: name.to_string(),
default_view_name: None,
fields: None,
}
}
pub fn with_default_view_name(mut self, view_name: impl ToString) -> Self {
self.default_view_name = Some(view_name.to_string());
self
}
pub fn with_fields(mut self, fields: Vec<TableField>) -> Self {
self.fields = Some(fields);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableField {
pub field_name: String,
#[serde(rename = "type")]
pub field_type: i32,
#[serde(skip_serializing_if = "Option::is_none")]
pub property: Option<serde_json::Value>,
}
impl TableField {
pub fn text(name: impl ToString) -> Self {
Self {
field_name: name.to_string(),
field_type: 1, property: None,
}
}
pub fn number(name: impl ToString) -> Self {
Self {
field_name: name.to_string(),
field_type: 2, property: None,
}
}
pub fn single_select(name: impl ToString, options: Vec<String>) -> Self {
let options_value: Vec<serde_json::Value> = options
.into_iter()
.map(|opt| serde_json::json!({"name": opt}))
.collect();
Self {
field_name: name.to_string(),
field_type: 3, property: Some(serde_json::json!({"options": options_value})),
}
}
pub fn multi_select(name: impl ToString, options: Vec<String>) -> Self {
let options_value: Vec<serde_json::Value> = options
.into_iter()
.map(|opt| serde_json::json!({"name": opt}))
.collect();
Self {
field_name: name.to_string(),
field_type: 4, property: Some(serde_json::json!({"options": options_value})),
}
}
pub fn date(name: impl ToString) -> Self {
Self {
field_name: name.to_string(),
field_type: 5, property: None,
}
}
}
#[derive(Serialize)]
struct CreateTableRequestBody {
table: TableData,
}
#[derive(Deserialize, Debug)]
pub struct CreateTableResponse {
pub table_id: String,
pub default_view_id: String,
pub field_id_list: Vec<String>,
}
impl ApiResponseTrait for CreateTableResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
#[cfg(test)]
#[allow(unused_variables, unused_unsafe)]
mod tests {
use super::*;
#[test]
fn test_create_table_request() {
let table = TableData::new("测试数据表")
.with_default_view_name("主视图")
.with_fields(vec![
TableField::text("标题"),
TableField::number("数量"),
TableField::single_select("状态", vec!["进行中".to_string(), "已完成".to_string()]),
]);
let request = CreateTableRequest::builder()
.app_token("bascnmBA*****yGehy8")
.table(table)
.build();
assert_eq!(request.app_token, "bascnmBA*****yGehy8");
assert_eq!(request.table.name, "测试数据表");
}
#[test]
fn test_table_field_types() {
let text_field = TableField::text("标题");
assert_eq!(text_field.field_type, 1);
assert_eq!(text_field.field_name, "标题");
let number_field = TableField::number("数量");
assert_eq!(number_field.field_type, 2);
let select_field =
TableField::single_select("状态", vec!["A".to_string(), "B".to_string()]);
assert_eq!(select_field.field_type, 3);
assert!(select_field.property.is_some());
}
}