From f143b180e45c6792f304fc2a0ff7385158e5957f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20M=C3=BCller?= Date: Sun, 11 Feb 2024 21:00:19 -0800 Subject: [PATCH] Add support for updating a watchlist So far watchlists have been effectively immutable: one could only create one, retrieve it, and delete it eventually. With this change we add support for updating such a list, allowing for renaming and/or changing of contained symbols. --- CHANGELOG.md | 1 + src/api/v2/watchlist.rs | 77 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fae97dc7..6333652f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - This variant is now used to signal a multitude of conditions, including certain order submission issues - Added `name` attribute to `api::v2::watchlist::Watchlist` type +- Added support for updating a watchlist - Bumped minimum supported Rust version to `1.63` - Bumped `websocket-util` dependency to `0.12` - Bumped `tokio-tungstenite` dependency to `0.20` diff --git a/src/api/v2/watchlist.rs b/src/api/v2/watchlist.rs index 2e180bda..ef2a8640 100644 --- a/src/api/v2/watchlist.rs +++ b/src/api/v2/watchlist.rs @@ -60,7 +60,7 @@ pub struct Watchlist { } -/// A create watchlist request item +/// A request to create a watch list. #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct CreateReq { /// The watchlist's name. @@ -72,6 +72,10 @@ pub struct CreateReq { } +/// A request to update a watch list. +pub type UpdateReq = CreateReq; + + Endpoint! { /// The representation of a POST request to the /v2/watchlists endpoint. pub Post(CreateReq), @@ -122,6 +126,41 @@ Endpoint! { } +Endpoint! { + /// The representation of a PUT request to the + /// /v2/watchlists/{watchlist-id} endpoint. + pub Update((Id, UpdateReq)), + Ok => Watchlist, [ + /// The watchlist object with the given ID was retrieved successfully. + /* 200 */ OK, + ], + Err => UpdateError, [ + /// No watchlist was found with the given ID. + /* 404 */ NOT_FOUND => NotFound, + /// The watchlist name was not unique or other parts of the input + /// are not valid. + /* 422 */ UNPROCESSABLE_ENTITY => InvalidInput, + ] + + fn path(input: &Self::Input) -> Str { + let (id, _) = input; + format!("/v2/watchlists/{}", id.as_simple()).into() + } + + #[inline] + fn method() -> Method { + Method::PUT + } + + fn body(input: &Self::Input) -> Result, Self::ConversionError> { + let (_, request) = input; + let json = to_json(request)?; + let bytes = Bytes::from(json); + Ok(Some(bytes)) + } +} + + EndpointNoParse! { /// The representation of a DELETE request to the /// /v2/watchlists/{watchlist-id} endpoint. @@ -253,6 +292,42 @@ mod tests { }; } + /// Check that we can update a watchlist. + #[test(tokio::test)] + async fn update() { + let api_info = ApiInfo::from_env().unwrap(); + let client = Client::new(api_info); + let symbols = vec!["AAPL".to_string()]; + let id = Uuid::new_v4().to_string(); + let created = client + .issue::(&CreateReq { + name: id.clone(), + symbols: symbols.clone(), + }) + .await + .unwrap(); + + let id2 = Uuid::new_v4().to_string(); + let symbols = vec!["AMZN".to_string(), "SPY".to_string()]; + + let req = UpdateReq { + name: id2.clone(), + symbols: symbols.clone(), + }; + + let result = client.issue::(&(created.id, req)).await; + let () = client.issue::(&created.id).await.unwrap(); + + let watchlist = result.unwrap(); + assert_eq!(watchlist.name, id2.to_string()); + let symbols = watchlist + .assets + .iter() + .map(|asset| &asset.symbol) + .collect::>(); + assert_eq!(symbols, vec!["AMZN", "SPY"]); + } + /// Verify that we report the appropriate error when attempting to /// delete a watchlist that does not exist. #[test(tokio::test)]