Skip to content

Commit

Permalink
Merge pull request #208 from arlyon/fix/list-params
Browse files Browse the repository at this point in the history
Fix list traversal
  • Loading branch information
arlyon committed Apr 7, 2022
2 parents d691b7c + f032570 commit dfd9703
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 20 deletions.
16 changes: 8 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,32 +112,32 @@ actix-web = "4.0.1"

[[example]]
name = "checkout"
required-features = ["runtime-tokio-hyper"]
required-features = ["async"]

[[example]]
name = "connect"
required-features = ["runtime-tokio-hyper"]
required-features = ["async"]

[[example]]
name = "customer"
required-features = ["runtime-tokio-hyper"]
required-features = ["async"]

[[example]]
name = "payment-intent"
required-features = ["runtime-tokio-hyper"]
required-features = ["async"]

[[example]]
name = "payment-link"
required-features = ["runtime-tokio-hyper"]
required-features = ["async"]

[[example]]
name = "subscriptions"
required-features = ["runtime-tokio-hyper"]
required-features = ["async"]

[[example]]
name = "webhook-axum"
required-features = ["runtime-tokio-hyper"]
required-features = ["async"]

[[example]]
name = "webhook-actix"
required-features = ["runtime-tokio-hyper"]
required-features = ["async"]
38 changes: 34 additions & 4 deletions examples/customer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//!
//! This example shows how to create and list customers.

use stripe::{Client, CreateCustomer, Customer};
use stripe::{Client, CreateCustomer, Customer, ListCustomers};

#[tokio::main]
async fn main() {
Expand All @@ -32,10 +32,40 @@ async fn main() {

println!("created a customer at https://dashboard.stripe.com/test/customers/{}", customer.id);

let all_customers = Customer::list(&client, Default::default()).await.unwrap();
let customer = Customer::create(
&client,
CreateCustomer {
name: Some("Someone Else"),
email: Some("test@async-stripe.com"),
description: Some(
"A fake customer that is used to illustrate the examples in async-stripe.",
),
metadata: Some(
[("async-stripe".to_string(), "true".to_string())].iter().cloned().collect(),
),

..Default::default()
},
)
.await
.unwrap();

println!("created a customer at https://dashboard.stripe.com/test/customers/{}", customer.id);

let first_page =
Customer::list(&client, ListCustomers { limit: Some(1), ..Default::default() })
.await
.unwrap();

println!(
"first page of customers: {:#?}",
first_page.data.iter().map(|c| c.name.as_ref().unwrap()).collect::<Vec<_>>()
);

let second_page = first_page.next(&client).await.unwrap();

println!(
"customers: {:#?}",
all_customers.data.iter().map(|c| c.name.as_ref().unwrap()).collect::<Vec<_>>()
"second page of customers: {:#?}",
second_page.data.iter().map(|c| c.name.as_ref().unwrap()).collect::<Vec<_>>()
);
}
80 changes: 72 additions & 8 deletions src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,11 @@ impl<T: DeserializeOwned + Send + 'static> List<T> {
/// Prefer `List::next` when possible
pub fn get_next(client: &Client, url: &str, last_id: &str) -> Response<List<T>> {
if url.starts_with("/v1/") {
// TODO: Maybe parse the URL? Perhaps `List` should always parse its `url` field.
let mut url = url.trim_start_matches("/v1/").to_string();
if url.contains('?') {
url.push_str(&format!("&starting_after={}", last_id));
} else {
url.push_str(&format!("?starting_after={}", last_id));
}
client.get(&url)
let path = url.trim_start_matches("/v1/").to_string(); // the url we get back is prefixed
client.get_query(
&path,
[("starting_after", last_id)].iter().cloned().collect::<HashMap<_, _>>(),
)
} else {
err(StripeError::UnsupportedVersion)
}
Expand Down Expand Up @@ -363,4 +360,71 @@ mod tests {
assert_eq!(to_snakecase("UPPER").as_str(), "upper");
assert_eq!(to_snakecase("lower").as_str(), "lower");
}

#[cfg(feature = "async")]
#[tokio::test]
async fn list() {
use httpmock::Method::GET;
use httpmock::MockServer;

use crate::Client;
use crate::{Customer, ListCustomers};

// Start a lightweight mock server.
let server = MockServer::start_async().await;

let client = Client::from_url(&*server.url("/"), "fake_key");

let next_item = server.mock(|when, then| {
when.method(GET).path("/v1/customers").query_param("starting_after", "cus_1");
then.status(200).body(
r#"{"object": "list", "data": [{
"id": "cus_2",
"object": "customer",
"balance": 0,
"created": 1649316731,
"currency": "gbp",
"delinquent": false,
"email": null,
"invoice_prefix": "4AF7482",
"invoice_settings": {},
"livemode": false,
"metadata": {},
"preferred_locales": [],
"tax_exempt": "none"
}], "has_more": true, "url": "/v1/customers"}"#,
);
});

let first_item = server.mock(|when, then| {
when.method(GET).path("/v1/customers");
then.status(200).body(
r#"{"object": "list", "data": [{
"id": "cus_1",
"object": "customer",
"balance": 0,
"created": 1649316731,
"currency": "gbp",
"delinquent": false,
"invoice_prefix": "4AF7482",
"invoice_settings": {},
"livemode": false,
"metadata": {},
"preferred_locales": [],
"tax_exempt": "none"
}], "has_more": true, "url": "/v1/customers"}"#,
);
});

let res = Customer::list(&client, ListCustomers::new()).await.unwrap();

println!("{:?}", res);

let res2 = res.next(&client).await.unwrap();

println!("{:?}", res2);

first_item.assert_hits_async(1).await;
next_item.assert_hits_async(1).await;
}
}

0 comments on commit dfd9703

Please sign in to comment.