diff --git a/docs/catalog/stripe.md b/docs/catalog/stripe.md index afa51e94..36b74821 100644 --- a/docs/catalog/stripe.md +++ b/docs/catalog/stripe.md @@ -107,6 +107,7 @@ The Stripe Wrapper supports data read and modify from Stripe API. | [File Links](https://stripe.com/docs/api/file_links/list) | ✅ | ❌ | ❌ | ❌ | ❌ | | [Invoices](https://stripe.com/docs/api/invoices/list) | ✅ | ❌ | ❌ | ❌ | ❌ | | [Mandates](https://stripe.com/docs/api/mandates) | ✅ | ❌ | ❌ | ❌ | ❌ | +| [Meters](https://docs.stripe.com/api/billing/meter/list) | ✅ | ❌ | ❌ | ❌ | ❌ | | [PaymentIntents](https://stripe.com/docs/api/payment_intents/list) | ✅ | ❌ | ❌ | ❌ | ❌ | | [Payouts](https://stripe.com/docs/api/payouts/list) | ✅ | ❌ | ❌ | ❌ | ❌ | | [Prices](https://stripe.com/docs/api/prices/list) | ✅ | ❌ | ❌ | ❌ | ❌ | @@ -494,6 +495,33 @@ While any column is allowed in a where clause, it is most efficient to filter by - id +### Meters + +_read only_ + +A billing meter is a resource that allows you to track usage of a particular event. + +Ref: [Stripe docs](https://docs.stripe.com/api/billing/meter) + +```sql +create foreign table stripe.meter ( + id text, + display_name text, + event_name text, + event_time_window text, + status text, + attrs jsonb +) + server stripe_server + options ( + object 'billing/meters' + ); +``` + +While any column is allowed in a where clause, it is most efficient to filter by: + +- id + ### Payment Intents _read only_ diff --git a/wrappers/.ci/docker-compose-native.yaml b/wrappers/.ci/docker-compose-native.yaml index d45ae1bd..8425d595 100644 --- a/wrappers/.ci/docker-compose-native.yaml +++ b/wrappers/.ci/docker-compose-native.yaml @@ -49,7 +49,7 @@ services: retries: 3 stripe: - image: stripe/stripe-mock:v0.144.0 + image: stripe/stripe-mock:v0.188.0 container_name: stripe-mock ports: - "12111:12111" diff --git a/wrappers/src/fdw/stripe_fdw/README.md b/wrappers/src/fdw/stripe_fdw/README.md index 51ac921a..8cfccf09 100644 --- a/wrappers/src/fdw/stripe_fdw/README.md +++ b/wrappers/src/fdw/stripe_fdw/README.md @@ -10,6 +10,7 @@ This is a foreign data wrapper for [Stripe](https://stripe.com/) developed using | Version | Date | Notes | | ------- | ---------- | ---------------------------------------------------- | +| 0.1.11 | 2024-09-20 | Added Meter object | | 0.1.10 | 2024-08-26 | Added 'api_key_name' server option | | 0.1.9 | 2024-07-01 | Added 'api_version' server option | | 0.1.7 | 2023-07-13 | Added fdw stats collection | diff --git a/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs b/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs index a279c874..ef56cadd 100644 --- a/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs +++ b/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs @@ -255,7 +255,7 @@ fn inc_stats_request_cnt(stats_metadata: &mut JsonB) -> StripeFdwResult<()> { } #[wrappers_fdw( - version = "0.1.10", + version = "0.1.11", author = "Supabase", website = "https://github.com/supabase/wrappers/tree/main/wrappers/src/fdw/stripe_fdw", error_type = "StripeFdwError" @@ -307,6 +307,7 @@ impl StripeFdw { "tokens" => vec![], "topups" => vec!["status"], "transfers" => vec!["destination"], + "billing/meters" => vec![], "checkout/sessions" => vec!["customer", "payment_intent", "subscription"], _ => { return Err(StripeFdwError::ObjectNotImplemented(obj.to_string())); @@ -603,6 +604,17 @@ impl StripeFdw { ], tgt_cols, ), + "billing/meters" => body_to_rows( + resp_body, + vec![ + ("id", "string"), + ("display_name", "string"), + ("event_name", "string"), + ("event_time_window", "string"), + ("status", "string"), + ], + tgt_cols, + ), "checkout/sessions" => body_to_rows( resp_body, vec![ diff --git a/wrappers/src/fdw/stripe_fdw/tests.rs b/wrappers/src/fdw/stripe_fdw/tests.rs index 00eee4b4..e2c340d1 100644 --- a/wrappers/src/fdw/stripe_fdw/tests.rs +++ b/wrappers/src/fdw/stripe_fdw/tests.rs @@ -464,6 +464,26 @@ mod tests { ) .unwrap(); + c.update( + r#" + CREATE FOREIGN TABLE billing_meters ( + id text, + display_name text, + event_name text, + event_time_window text, + status text, + attrs jsonb + ) + SERVER my_stripe_server + OPTIONS ( + object 'billing/meters' + ) + "#, + None, + None, + ) + .unwrap(); + c.update( r#" CREATE FOREIGN TABLE checkout_sessions ( @@ -552,7 +572,7 @@ mod tests { .collect::>(); assert_eq!( results, - vec![("cus_MJiBgSUgeWFN0z", Timestamp::from(287883090000000i64))] + vec![("cus_QXg1o8vcGmoR32", Timestamp::from(287883090000000i64))] ); let results = c @@ -564,7 +584,14 @@ mod tests { .unwrap() .filter_map(|r| r.get_by_name::<&str, _>("id").unwrap()) .collect::>(); - assert_eq!(results, vec!["cus_MJiBgSUgeWFN0z"]); + assert_eq!(results, vec!["cus_QXg1o8vcGmoR32"]); + + let results = c + .select("SELECT id, display_name FROM billing_meters", None, None) + .unwrap() + .filter_map(|r| r.get_by_name::<&str, _>("id").unwrap()) + .collect::>(); + assert_eq!(results, vec!["meter_123"]); let results = c .select( @@ -577,7 +604,7 @@ mod tests { .collect::>(); assert_eq!( results, - vec!["cs_test_a1DmlfbOPqmbKHfpwpFQ0RM3pVXmKoESZbJxnKrPdMsLDPPMGYtEBcHGPR"] + vec!["cs_test_a1YS1URlnyQCN5fUUduORoQ7Pw41PJqDWkIVQCpJPqkfIhd6tVY8XB1OLY"] ); // Stripe mock service cannot return 404 error code correctly for @@ -605,7 +632,7 @@ mod tests { .collect::>(); assert_eq!( results, - vec![(("dp_1Lb4lXDciZwYG8GPXn1Bh0MY", 1000), "usd")] + vec![(("dp_1Pgc71B7WZ01zgkWMevJiAUx", 1000), "usd")] ); let results = c @@ -619,7 +646,7 @@ mod tests { .collect::>(); assert_eq!( results, - vec![("evt_1Lb4lfDciZwYG8GPHARl3JTf", "plan.created")] + vec![("evt_1Pgc76B7WZ01zgkWwyRHS12y", "plan.created")] ); let results = c @@ -638,8 +665,8 @@ mod tests { vec![( ( ( - "file_1Lb4liDciZwYG8GPvkwgZXix", - "file_1Lb4liDciZwYG8GPvkwgZXix" + "file_1Pgag2B7WZ01zgkWITx3dIQc", + "file_1Pgag2B7WZ01zgkWITx3dIQc" ), "dispute_evidence" ), @@ -660,10 +687,10 @@ mod tests { assert_eq!( results, vec![(( - "link_1Lb4liDciZwYG8GPQ8qAqnEa", - "file_1Lb4liDciZwYG8GP2VGapbrq" + "link_1Pgc76B7WZ01zgkWPhd77i13", + "file_1Pgag2B7WZ01zgkWITx3dIQc" ), - "https://dcr-upload-mydev.dev.stripe.me/links/MDB8YWNjdF8xTGI0bEREY2lad1lHOEdQfGZsX3Rlc3RfbFNhUld1aDYzdDd6eDYzU01RUzNzZWlE00zJ1o9SLI" + "https://sangeekp-15t6ai--upload-mydev.dev.stripe.me/links/MDB8YWNjdF8xUGdhZlRCN1daMDF6Z2tXfGZsX3Rlc3Rfb0Jkam9sNHdEZUpXRHUzSGhXNTRkZDI500qGiHOxxv" ) ] ); @@ -681,7 +708,7 @@ mod tests { .collect::>(); assert_eq!( results, - vec![((("cus_MJiBgSUgeWFN0z", 1000), "usd"), "draft")] + vec![((("cus_QXg1o8vcGmoR32", 1000), "usd"), "draft")] ); let results = c @@ -708,7 +735,7 @@ mod tests { .collect::>(); assert_eq!( results, - vec![((("po_1Lb4lcDciZwYG8GPa5iKACTe", 1100), "usd"), "in_transit")] + vec![((("po_1Pgc79B7WZ01zgkWu1KToYf4", 1100), "usd"), "in_transit")] ); let results = c @@ -727,8 +754,8 @@ mod tests { results, vec![( ( - (("price_1Lb4lXDciZwYG8GPenVxKLUQ", true), "usd"), - "prod_MJiB8qAdQc9hgR" + (("price_1PgafmB7WZ01zgkW6dKueIc5", true), "usd"), + "prod_QXg1hqf4jFNsqG" ), "recurring" )] @@ -762,11 +789,11 @@ mod tests { .collect::>(); assert_eq!( results, - vec![((("re_1Lb4lXDciZwYG8GPkrV42Kaz", 100), "usd"), "succeeded")] + vec![((("re_1Pgc72B7WZ01zgkWqPvrRrPE", 100), "usd"), "succeeded")] ); let results = c - .select("SELECT * FROM stripe_setup_attempts where setup_intent='seti_1Lb4lgDciZwYG8GPdEjT5Ico'", None, None).unwrap() + .select("SELECT * FROM stripe_setup_attempts where setup_intent='seti_1Pgag7B7WZ01zgkWSgwGdb8Z'", None, None).unwrap() .filter_map(|r| { r.get_by_name::<&str, _>("id") .unwrap() @@ -795,7 +822,7 @@ mod tests { assert_eq!( results, vec![( - ("seti_1Lb4lgDciZwYG8GPdEjT5Ico", "requires_payment_method"), + ("seti_1Pgag7B7WZ01zgkWSgwGdb8Z", "requires_payment_method"), "off_session" )] ); @@ -818,7 +845,7 @@ mod tests { results, vec![( ( - ("cus_MJiBtCqOF1Bb3F", "usd"), + ("cus_QXg1o8vcGmoR32", "usd"), Timestamp::from(287883090000000i64) ), Timestamp::from(287883090000000i64) @@ -838,7 +865,7 @@ mod tests { .collect::>(); assert_eq!( results, - vec![((("tu_1Lb4leDciZwYG8GPbKaCK9X3", 1000), "usd"), "pending")] + vec![((("tu_1Pgc7BB7WZ01zgkWwH7rkBgR", 1000), "usd"), "pending")] ); let results = c @@ -855,8 +882,8 @@ mod tests { assert_eq!( results, vec![( - (("tr_1Lb4lcDciZwYG8GPNq6RhhYq", 1100), "usd"), - "acct_1Lb4lDDciZwYG8GP" + (("tr_1Pgc7BB7WZ01zgkWVJfE40RX", 1100), "usd"), + "acct_1PgafTB7WZ01zgkW" )] );