feat: add lists endpoint with save and delete list item methods
Implement SaveListItemRequest and SaveListItemResponse models. Add save_list_item (create/update via PUT) and delete_list_item methods. Tests cover creating, updating, deleting list items and not-found error.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
use reqwest::Method;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::client::OnspringClient;
|
||||
use crate::error::Result;
|
||||
use crate::models::{SaveListItemRequest, SaveListItemResponse};
|
||||
|
||||
impl OnspringClient {
|
||||
/// Creates or updates a list item in the specified list.
|
||||
pub async fn save_list_item(
|
||||
&self,
|
||||
list_id: i32,
|
||||
request: SaveListItemRequest,
|
||||
) -> Result<SaveListItemResponse> {
|
||||
let path = format!("/Lists/id/{}/items", list_id);
|
||||
self.request(Method::PUT, &path, &[], Some(&request)).await
|
||||
}
|
||||
|
||||
/// Deletes a list item from the specified list.
|
||||
pub async fn delete_list_item(&self, list_id: i32, item_id: Uuid) -> Result<()> {
|
||||
let path = format!("/Lists/id/{}/itemId/{}", list_id, item_id);
|
||||
self.request_no_content(Method::DELETE, &path, &[], Option::<&()>::None)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
mod apps;
|
||||
mod fields;
|
||||
mod files;
|
||||
mod lists;
|
||||
mod ping;
|
||||
mod records;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Request to create or update a list item.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SaveListItemRequest {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<Uuid>,
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub numeric_value: Option<f64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub color: Option<String>,
|
||||
}
|
||||
|
||||
/// Response from saving a list item.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SaveListItemResponse {
|
||||
pub id: Uuid,
|
||||
}
|
||||
@@ -2,6 +2,7 @@ mod app;
|
||||
mod enums;
|
||||
mod field;
|
||||
pub mod file;
|
||||
pub mod list;
|
||||
mod paging;
|
||||
pub mod record;
|
||||
|
||||
@@ -9,5 +10,6 @@ pub use app::*;
|
||||
pub use enums::*;
|
||||
pub use field::*;
|
||||
pub use file::*;
|
||||
pub use list::*;
|
||||
pub use paging::*;
|
||||
pub use record::*;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
mod common;
|
||||
|
||||
use uuid::Uuid;
|
||||
use wiremock::matchers::{method, path};
|
||||
use wiremock::{Mock, ResponseTemplate};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_save_list_item_create() {
|
||||
let (mock_server, client) = common::setup().await;
|
||||
let new_id = Uuid::new_v4();
|
||||
|
||||
Mock::given(method("PUT"))
|
||||
.and(path("/Lists/id/10/items"))
|
||||
.respond_with(ResponseTemplate::new(201).set_body_json(serde_json::json!({
|
||||
"id": new_id.to_string()
|
||||
})))
|
||||
.mount(&mock_server)
|
||||
.await;
|
||||
|
||||
let request = onspring::models::list::SaveListItemRequest {
|
||||
id: None,
|
||||
name: "New Item".to_string(),
|
||||
numeric_value: Some(1.0),
|
||||
color: Some("#ff0000".to_string()),
|
||||
};
|
||||
let result = client.save_list_item(10, request).await.unwrap();
|
||||
assert_eq!(result.id, new_id);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_save_list_item_update() {
|
||||
let (mock_server, client) = common::setup().await;
|
||||
let existing_id = Uuid::new_v4();
|
||||
|
||||
Mock::given(method("PUT"))
|
||||
.and(path("/Lists/id/10/items"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
|
||||
"id": existing_id.to_string()
|
||||
})))
|
||||
.mount(&mock_server)
|
||||
.await;
|
||||
|
||||
let request = onspring::models::list::SaveListItemRequest {
|
||||
id: Some(existing_id),
|
||||
name: "Updated Item".to_string(),
|
||||
numeric_value: None,
|
||||
color: None,
|
||||
};
|
||||
let result = client.save_list_item(10, request).await.unwrap();
|
||||
assert_eq!(result.id, existing_id);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_list_item() {
|
||||
let (mock_server, client) = common::setup().await;
|
||||
let item_id = Uuid::new_v4();
|
||||
|
||||
Mock::given(method("DELETE"))
|
||||
.and(path(format!("/Lists/id/10/itemId/{}", item_id)))
|
||||
.respond_with(ResponseTemplate::new(204))
|
||||
.mount(&mock_server)
|
||||
.await;
|
||||
|
||||
let result = client.delete_list_item(10, item_id).await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_list_item_not_found() {
|
||||
let (mock_server, client) = common::setup().await;
|
||||
let item_id = Uuid::new_v4();
|
||||
|
||||
Mock::given(method("DELETE"))
|
||||
.and(path(format!("/Lists/id/10/itemId/{}", item_id)))
|
||||
.respond_with(ResponseTemplate::new(404))
|
||||
.mount(&mock_server)
|
||||
.await;
|
||||
|
||||
let result = client.delete_list_item(10, item_id).await;
|
||||
assert!(result.is_err());
|
||||
if let Err(onspring::OnspringError::Api { status_code, .. }) = result {
|
||||
assert_eq!(status_code, 404);
|
||||
} else {
|
||||
panic!("Expected Api error");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user