diff --git a/CHANGELOG.md b/CHANGELOG.md index 60d0e7a4a..54059ca51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,8 @@ should include the dependency `stripe_webhook` and import from that crate instea - `Deleted<>` objects (such `Deleted`) no longer expose a boolean `deleted`. This was always `true` and only used internally as a discriminant when deserializing. The generic type `Deleted` has been removed and replaced by generated types such as `DeletedAccount`, which sometimes contain additional fields. +- Optional `List` no longer deserialized with `serde(default)`, the type has been changed `List` -> `Option>`. The default +implementation of `List` produced data not upholding the `List` invariant of having a meaningful `url`. - Types used only for requests now use borrowed types more consistently (and more often). For example, previously the top-level `CreateCustomer.description` expected `Option<&str>`, but `CreateCustomerShipping.phone` expected `Option`. Now both expect `Option<&str>`. In general, the following changes are made to request parameters that required owned data: diff --git a/examples/endpoints/src/checkout.rs b/examples/endpoints/src/checkout.rs index 82cc05f15..ab9d7c97a 100644 --- a/examples/endpoints/src/checkout.rs +++ b/examples/endpoints/src/checkout.rs @@ -75,16 +75,17 @@ pub async fn run_checkout_session_example(client: &stripe::Client) -> Result<(), params.send(client).await? }; + let created_item = &checkout_session.line_items.expect("line items were created").data[0]; println!( "created a {} checkout session for {} {:?} for {} {} at {}", checkout_session.payment_status, - checkout_session.line_items.data[0].quantity.unwrap(), - match &checkout_session.line_items.data[0].price.as_ref().unwrap().product { + created_item.quantity.unwrap(), + match &created_item.price.as_ref().unwrap().product { Expandable::Object(p) => &p.name, _ => panic!("product not found"), }, checkout_session.amount_subtotal.unwrap() / 100, - checkout_session.line_items.data[0].price.as_ref().unwrap().currency, + created_item.price.as_ref().unwrap().currency, checkout_session.url.unwrap() ); Ok(()) diff --git a/generated/stripe_checkout/src/checkout_session/mod.rs b/generated/stripe_checkout/src/checkout_session/mod.rs index 583e69809..7f3067e46 100644 --- a/generated/stripe_checkout/src/checkout_session/mod.rs +++ b/generated/stripe_checkout/src/checkout_session/mod.rs @@ -71,8 +71,8 @@ pub struct CheckoutSession { /// Details on the state of invoice creation for the Checkout Session. pub invoice_creation: Option, /// The line items purchased by the customer. - #[serde(default)] - pub line_items: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub line_items: Option>, /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. pub livemode: bool, /// The IETF language tag of the locale Checkout is displayed in. diff --git a/generated/stripe_misc/src/tax_calculation/mod.rs b/generated/stripe_misc/src/tax_calculation/mod.rs index c3f71e779..5a31ce2c4 100644 --- a/generated/stripe_misc/src/tax_calculation/mod.rs +++ b/generated/stripe_misc/src/tax_calculation/mod.rs @@ -19,7 +19,7 @@ pub struct TaxCalculation { /// Unique identifier for the calculation. pub id: Option, /// The list of items the customer is purchasing. - pub line_items: stripe_types::List, + pub line_items: Option>, /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. pub livemode: bool, /// The shipping cost details for the calculation. diff --git a/generated/stripe_misc/src/tax_transaction/mod.rs b/generated/stripe_misc/src/tax_transaction/mod.rs index 5cc26c0d0..4c04b9cb6 100644 --- a/generated/stripe_misc/src/tax_transaction/mod.rs +++ b/generated/stripe_misc/src/tax_transaction/mod.rs @@ -19,7 +19,7 @@ pub struct TaxTransaction { /// Unique identifier for the transaction. pub id: stripe_misc::tax_transaction::TaxTransactionId, /// The tax collected or refunded, by line item. - pub line_items: stripe_types::List, + pub line_items: Option>, /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. pub livemode: bool, /// Set of [key-value pairs](https://stripe.com/docs/api/metadata) that you can attach to an object. diff --git a/generated/stripe_shared/src/account/mod.rs b/generated/stripe_shared/src/account/mod.rs index abea4f61b..4acdc1e74 100644 --- a/generated/stripe_shared/src/account/mod.rs +++ b/generated/stripe_shared/src/account/mod.rs @@ -46,8 +46,8 @@ pub struct Account { #[serde(skip_serializing_if = "Option::is_none")] pub email: Option, /// External accounts (bank accounts and debit cards) currently attached to this account. - #[serde(default)] - pub external_accounts: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub external_accounts: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub future_requirements: Option, /// Unique identifier for the object. diff --git a/generated/stripe_shared/src/charge/mod.rs b/generated/stripe_shared/src/charge/mod.rs index e2d8efd96..a4337db7a 100644 --- a/generated/stripe_shared/src/charge/mod.rs +++ b/generated/stripe_shared/src/charge/mod.rs @@ -109,7 +109,7 @@ pub struct Charge { /// If the charge is only partially refunded, this attribute will still be false. pub refunded: bool, /// A list of refunds that have been applied to the charge. - pub refunds: stripe_types::List, + pub refunds: Option>, /// ID of the review associated with this charge if one exists. pub review: Option>, /// Shipping information for the charge. diff --git a/generated/stripe_shared/src/customer/mod.rs b/generated/stripe_shared/src/customer/mod.rs index 9d1e0d6f0..42d26399b 100644 --- a/generated/stripe_shared/src/customer/mod.rs +++ b/generated/stripe_shared/src/customer/mod.rs @@ -88,11 +88,11 @@ pub struct Customer { /// Appears on invoices emailed to this customer. pub shipping: Option, /// The customer's payment sources, if any. - #[serde(default)] - pub sources: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub sources: Option>, /// The customer's current subscriptions, if any. - #[serde(default)] - pub subscriptions: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub subscriptions: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub tax: Option, /// Describes the customer's tax exemption status, which is `none`, `exempt`, or `reverse`. @@ -101,8 +101,8 @@ pub struct Customer { #[serde(skip_serializing_if = "Option::is_none")] pub tax_exempt: Option, /// The customer's tax IDs. - #[serde(default)] - pub tax_ids: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub tax_ids: Option>, /// ID of the test clock that this customer belongs to. #[serde(skip_serializing_if = "Option::is_none")] pub test_clock: Option>, diff --git a/generated/stripe_shared/src/file/mod.rs b/generated/stripe_shared/src/file/mod.rs index 44b1de8f5..56f9abff3 100644 --- a/generated/stripe_shared/src/file/mod.rs +++ b/generated/stripe_shared/src/file/mod.rs @@ -15,8 +15,8 @@ pub struct File { /// Unique identifier for the object. pub id: stripe_shared::file::FileId, /// A list of [file links](https://stripe.com/docs/api#file_links) that point at this file. - #[serde(default)] - pub links: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub links: Option>, /// The [purpose](https://stripe.com/docs/file-upload#uploading-a-file) of the uploaded file. pub purpose: FilePurpose, /// The size of the file object in bytes. diff --git a/generated/stripe_shared/src/payment_link/mod.rs b/generated/stripe_shared/src/payment_link/mod.rs index a06115edc..6ab514bbf 100644 --- a/generated/stripe_shared/src/payment_link/mod.rs +++ b/generated/stripe_shared/src/payment_link/mod.rs @@ -38,8 +38,8 @@ pub struct PaymentLink { /// Configuration for creating invoice for payment mode payment links. pub invoice_creation: Option, /// The line items representing what is being sold. - #[serde(default)] - pub line_items: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub line_items: Option>, /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. pub livemode: bool, /// Set of [key-value pairs](https://stripe.com/docs/api/metadata) that you can attach to an object. diff --git a/generated/stripe_shared/src/quote/mod.rs b/generated/stripe_shared/src/quote/mod.rs index d80809163..f13825609 100644 --- a/generated/stripe_shared/src/quote/mod.rs +++ b/generated/stripe_shared/src/quote/mod.rs @@ -66,8 +66,8 @@ pub struct Quote { /// All invoices will be billed using the specified settings. pub invoice_settings: Option, /// A list of items the customer is being quoted for. - #[serde(default)] - pub line_items: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub line_items: Option>, /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. pub livemode: bool, /// Set of [key-value pairs](https://stripe.com/docs/api/metadata) that you can attach to an object. diff --git a/generated/stripe_shared/src/quotes_resource_upfront/mod.rs b/generated/stripe_shared/src/quotes_resource_upfront/mod.rs index ae0ec9d58..507fccd36 100644 --- a/generated/stripe_shared/src/quotes_resource_upfront/mod.rs +++ b/generated/stripe_shared/src/quotes_resource_upfront/mod.rs @@ -7,7 +7,7 @@ pub struct QuotesResourceUpfront { /// The line items that will appear on the next invoice after this quote is accepted. /// /// This does not include pending invoice items that exist on the customer but may still be included in the next invoice. - #[serde(default)] - pub line_items: stripe_types::List, + #[serde(skip_serializing_if = "Option::is_none")] + pub line_items: Option>, pub total_details: stripe_shared::QuotesResourceTotalDetails, } diff --git a/generated/stripe_treasury/src/treasury_transaction/mod.rs b/generated/stripe_treasury/src/treasury_transaction/mod.rs index 712a548ac..f05d96250 100644 --- a/generated/stripe_treasury/src/treasury_transaction/mod.rs +++ b/generated/stripe_treasury/src/treasury_transaction/mod.rs @@ -19,7 +19,7 @@ pub struct TreasuryTransaction { /// A list of TransactionEntries that are part of this Transaction. /// /// This cannot be expanded in any list endpoints. - pub entries: stripe_types::List, + pub entries: Option>, /// The FinancialAccount associated with this object. pub financial_account: String, /// ID of the flow that created the Transaction. diff --git a/openapi/src/rust_object.rs b/openapi/src/rust_object.rs index ca33e67ea..cb6c246db 100644 --- a/openapi/src/rust_object.rs +++ b/openapi/src/rust_object.rs @@ -221,23 +221,6 @@ impl StructField { } } -/// Specifications for a `serde(default = ...)` attribute -#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash)] -pub enum DeserDefault { - /// Just `serde(default)` - #[default] - Default, -} - -impl DeserDefault { - /// The corresponding `serde` attribute - pub fn to_serde_attr(self) -> &'static str { - match self { - Self::Default => "#[serde(default)]", - } - } -} - pub struct ObjectRef { pub path: ComponentPath, pub feature_gate: Option, diff --git a/openapi/src/rust_type.rs b/openapi/src/rust_type.rs index 0b6018d37..1ea946604 100644 --- a/openapi/src/rust_type.rs +++ b/openapi/src/rust_type.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Display, Formatter}; use crate::components::Components; -use crate::rust_object::{DeserDefault, ObjectMetadata, RustObject}; +use crate::rust_object::{ObjectMetadata, RustObject}; use crate::types::{ComponentPath, RustIdent}; use crate::visitor::{Visit, VisitMut}; @@ -202,7 +202,7 @@ impl RustType { pub fn into_nullable(self) -> Self { match self { - Self::Container(Container::List(_)) | Self::Container(Container::Option(_)) => self, + Self::Container(Container::Option(_)) => self, _ => Self::option(self), } } @@ -248,15 +248,6 @@ impl RustType { self.as_object().map(|r| r.0) } - pub fn deser_default(&self) -> Option { - match self { - Self::Simple(SimpleType::Bool) - | Self::Container(Container::Vec(_)) - | Self::Container(Container::List(_)) => Some(DeserDefault::Default), - _ => None, - } - } - pub fn visit<'a, T: Visit<'a>>(&'a self, visitor: &mut T) { use RustType::*; match self { diff --git a/openapi/src/templates/structs.rs b/openapi/src/templates/structs.rs index 07f0ced97..010b64fc0 100644 --- a/openapi/src/templates/structs.rs +++ b/openapi/src/templates/structs.rs @@ -90,9 +90,6 @@ impl<'a> ObjectWriter<'a> { if let Some(skip_ser) = field.rust_type.skip_serializing() { let _ = writeln!(out, r#"#[serde(skip_serializing_if = "{skip_ser}")]"#); } - if let Some(default) = field.rust_type.deser_default() { - let _ = writeln!(out, "{}", default.to_serde_attr()); - } } let printable = self.get_printable(&field.rust_type); diff --git a/stripe_types/src/pagination.rs b/stripe_types/src/pagination.rs index 8931851ac..5b3f43338 100644 --- a/stripe_types/src/pagination.rs +++ b/stripe_types/src/pagination.rs @@ -118,12 +118,6 @@ pub struct List { pub url: String, } -impl Default for List { - fn default() -> Self { - List { data: Vec::new(), has_more: false, total_count: None, url: String::new() } - } -} - impl Clone for List { fn clone(&self) -> Self { List { diff --git a/tests/tests/it/blocking/charge.rs b/tests/tests/it/blocking/charge.rs index a387aa10f..54893bae9 100644 --- a/tests/tests/it/blocking/charge.rs +++ b/tests/tests/it/blocking/charge.rs @@ -10,6 +10,6 @@ fn is_charge_retrievable() { assert_eq!(charge.id, "ch_123"); assert!(charge.customer.is_none()); assert!(charge.invoice.is_none()); - assert_eq!(charge.refunds.data.len(), 1); + assert_eq!(charge.refunds.unwrap().data.len(), 1); }); } diff --git a/tests/tests/it/main.rs b/tests/tests/it/main.rs index 8f6525cef..a0366d4b0 100644 --- a/tests/tests/it/main.rs +++ b/tests/tests/it/main.rs @@ -8,4 +8,7 @@ mod price; mod async_tests; #[cfg(feature = "blocking")] mod blocking; +// NB: pagination utils ideally could be used for blocking tests as well, but tricky because the `MockServer` is async +// and the blocking client unconditionally creates its own runtime already +#[cfg(feature = "async")] mod pagination_utils;