Skip to content

Commit da68023

Browse files
committed
add _get_all()
* allow for retrieval of all objects of a given type without local pagination code * add unit tests for related utility methods * update existing list-retrieval methods * update POD
1 parent 2789400 commit da68023

File tree

4 files changed

+166
-8
lines changed

4 files changed

+166
-8
lines changed

README.pod

+13
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,19 @@ convert_to_form_fields(), _get() can now easily handle the same calling
13391339
form as _post(), eliminating the need for _get_collections() and
13401340
_get_with_args(). We have also updated _delete() accordingly.
13411341

1342+
=item add _get_all()
1343+
1344+
Similar to methods provided by other SDKs, calls using this method will allow
1345+
access to all records for a given object type without having to manually
1346+
paginate through the results. It is not intended to be used directly, but
1347+
will be accessed through new and existing list-retrieval methods. In order to
1348+
maintain backwards-compatibility with existing list retrieval behavior, this
1349+
method supports passing a value of 0 for 'limit' in order to retrieve all
1350+
records. Any other positive integer value for 'limit' will attempt to retrieve
1351+
that number of records up to the maximum available. As before, not passing a
1352+
value for 'limit', or explicitly passing an undefined value, retrieves whatever
1353+
number of records the API returns by default.
1354+
13421355
=back
13431356

13441357
=head3 UPDATES

lib/Net/Stripe.pm

+89-8
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,19 @@ convert_to_form_fields(), _get() can now easily handle the same calling
254254
form as _post(), eliminating the need for _get_collections() and
255255
_get_with_args(). We have also updated _delete() accordingly.
256256
257+
=item add _get_all()
258+
259+
Similar to methods provided by other SDKs, calls using this method will allow
260+
access to all records for a given object type without having to manually
261+
paginate through the results. It is not intended to be used directly, but
262+
will be accessed through new and existing list-retrieval methods. In order to
263+
maintain backwards-compatibility with existing list retrieval behavior, this
264+
method supports passing a value of 0 for 'limit' in order to retrieve all
265+
records. Any other positive integer value for 'limit' will attempt to retrieve
266+
that number of records up to the maximum available. As before, not passing a
267+
value for 'limit', or explicitly passing an undefined value, retrieves whatever
268+
number of records the API returns by default.
269+
257270
=back
258271
259272
=head3 UPDATES
@@ -560,13 +573,14 @@ Charges: {
560573
$customer = $customer->id;
561574
}
562575
my %args = (
576+
path => 'charges',
563577
created => $created,
564578
customer => $customer,
565579
ending_before => $ending_before,
566580
limit => $limit,
567581
starting_after => $starting_after,
568582
);
569-
$self->_get('charges', \%args);
583+
$self->_get_all(%args);
570584
}
571585

572586
method capture_charge(
@@ -788,11 +802,12 @@ Customers: {
788802
$customer = $customer->id;
789803
}
790804
my %args = (
805+
path => "customers/$customer/subscriptions",
791806
ending_before => $ending_before,
792807
limit => $limit,
793808
starting_after => $starting_after,
794809
);
795-
return $self->_get("customers/$customer/subscriptions", \%args);
810+
return $self->_get_all(%args);
796811
}
797812

798813
method get_customer(Str :$customer_id) {
@@ -808,13 +823,14 @@ Customers: {
808823

809824
method get_customers(HashRef :$created?, Str :$ending_before?, Int :$limit?, Str :$starting_after?, Str :$email?) {
810825
my %args = (
826+
path => 'customers',
811827
created => $created,
812828
ending_before => $ending_before,
813829
limit => $limit,
814830
starting_after => $starting_after,
815831
email => $email,
816832
);
817-
$self->_get('customers', \%args);
833+
$self->_get_all(%args);
818834
}
819835
}
820836

@@ -946,13 +962,14 @@ Cards: {
946962
}
947963

948964
my %args = (
965+
path => "customers/$customer/sources",
949966
object => "card",
950967
created => $created,
951968
ending_before => $ending_before,
952969
limit => $limit,
953970
starting_after => $starting_after,
954971
);
955-
$self->_get("customers/$customer/sources", \%args);
972+
$self->_get_all(%args);
956973
}
957974

958975
method post_card(
@@ -1570,11 +1587,12 @@ Plans: {
15701587

15711588
method get_plans(Str :$ending_before?, Int :$limit?, Str :$starting_after?) {
15721589
my %args = (
1590+
path => 'plans',
15731591
ending_before => $ending_before,
15741592
limit => $limit,
15751593
starting_after => $starting_after,
15761594
);
1577-
$self->_get('plans', \%args);
1595+
$self->_get_all(%args);
15781596
}
15791597
}
15801598

@@ -1701,11 +1719,12 @@ Coupons: {
17011719

17021720
method get_coupons(Str :$ending_before?, Int :$limit?, Str :$starting_after?) {
17031721
my %args = (
1722+
path => 'coupons',
17041723
ending_before => $ending_before,
17051724
limit => $limit,
17061725
starting_after => $starting_after,
17071726
);
1708-
$self->_get('coupons', \%args);
1727+
$self->_get_all(%args);
17091728
}
17101729
}
17111730

@@ -1941,9 +1960,10 @@ Invoices: {
19411960
$customer = $customer->id;
19421961
}
19431962
my %args = (
1963+
path => 'invoices/upcoming',
19441964
customer => $customer,
19451965
);
1946-
return $self->_get("invoices/upcoming", \%args);
1966+
return $self->_get_all(%args);
19471967
}
19481968
}
19491969

@@ -2119,12 +2139,13 @@ InvoiceItems: {
21192139
$customer = $customer->id;
21202140
}
21212141
my %args = (
2142+
path => 'invoiceitems',
21222143
created => $created,
21232144
ending_before => $ending_before,
21242145
limit => $limit,
21252146
starting_after => $starting_after,
21262147
);
2127-
$self->_get('invoiceitems', \%args);
2148+
$self->_get_all(%args);
21282149
}
21292150
}
21302151

@@ -2458,6 +2479,66 @@ fun _post_2019_10_17_processing(
24582479
return $hash;
24592480
}
24602481

2482+
method _get_all(
2483+
Str :$path!,
2484+
Maybe[Str] :$ending_before?,
2485+
Maybe[Int] :$limit?,
2486+
Maybe[Str] :$starting_after?,
2487+
%object_filters,
2488+
) {
2489+
2490+
# minimize the number of API calls by retrieving as many results as
2491+
# possible per call. the API currently returns a maximum of 100 results.
2492+
my $API_PAGE_SIZE = 100;
2493+
my $PAGE_SIZE = $limit;
2494+
my $GET_MORE;
2495+
if ( defined( $limit ) && ( $limit eq '0' || $limit > $API_PAGE_SIZE ) ) {
2496+
$PAGE_SIZE = $API_PAGE_SIZE;
2497+
$GET_MORE = 1;
2498+
}
2499+
2500+
my %args = (
2501+
%object_filters,
2502+
ending_before => $ending_before,
2503+
limit => $PAGE_SIZE,
2504+
starting_after => $starting_after,
2505+
);
2506+
my $list = $self->_get($path, \%args);
2507+
2508+
if ( $GET_MORE ) {
2509+
# passing 'ending_before' causes the API to start with the oldest
2510+
# records. so in order to always provide records in reverse-chronological
2511+
# order, we must prepend these to the existing records.
2512+
my $REVERSE = defined( $ending_before ) && ! defined( $starting_after );
2513+
my $MAX_COUNT = $limit eq '0' ? undef : $limit;
2514+
while ( 1 ) {
2515+
my $PAGE_SIZE = $API_PAGE_SIZE;
2516+
if ( defined( $MAX_COUNT ) ) {
2517+
my $TO_FETCH = $MAX_COUNT - scalar( $list->elements );
2518+
last if $TO_FETCH <= 0;
2519+
$PAGE_SIZE = $TO_FETCH if $TO_FETCH < $PAGE_SIZE;
2520+
}
2521+
2522+
my %args = (
2523+
%object_filters,
2524+
limit => $PAGE_SIZE,
2525+
( $REVERSE ? $list->_previous_page_args() : $list->_next_page_args() ),
2526+
);
2527+
my $page = $self->_get($path, \%args);
2528+
2529+
last if $page->is_empty;
2530+
2531+
$list = Net::Stripe::List::_merge_lists(
2532+
lists => [ $REVERSE ?
2533+
( $page, $list ) :
2534+
( $list, $page )
2535+
],
2536+
);
2537+
}
2538+
}
2539+
return $list;
2540+
}
2541+
24612542
method _build_api_base { 'https://api.stripe.com/v1' }
24622543

24632544
method _build_ua {

lib/Net/Stripe/List.pm

+26
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,32 @@ method last {
2727
return $self->get(scalar($self->elements)-1);
2828
}
2929

30+
method _next_page_args() {
31+
return (
32+
starting_after => $self->get(-1)->id,
33+
);
34+
}
35+
36+
method _previous_page_args() {
37+
return (
38+
ending_before => $self->get(0)->id,
39+
);
40+
}
41+
42+
fun _merge_lists(
43+
ArrayRef[Net::Stripe::List] :$lists!,
44+
) {
45+
my $has_count = defined( $lists->[-1]->count );
46+
my $url = $lists->[-1]->url;
47+
my %list_args = (
48+
count => $has_count ? scalar( map { $_->elements } @$lists ) : undef,
49+
data => [ map { $_->elements } @$lists ],
50+
has_more => 0,
51+
url => $url,
52+
);
53+
return Net::Stripe::List->new( %list_args );
54+
}
55+
3056
__PACKAGE__->meta->make_immutable;
3157
1;
3258

t/local.t

+38
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,42 @@ For_later_deprecation: {
150150
is_deeply $return, $expected, 'convert_to_form_fields object encoding';
151151
}
152152

153+
List_pagination: {
154+
my $url = '/v1/customers';
155+
my @data_a;
156+
foreach my $i ( 1..5 ) {
157+
push @data_a, Net::Stripe::Customer->new(
158+
id => sprintf( 'cus_%02d', $i ),
159+
);
160+
}
161+
my $list_a = Net::Stripe::List->new(
162+
count => scalar( @data_a ),
163+
data => \@data_a,
164+
has_more => undef,
165+
url => $url,
166+
);
167+
168+
my @data_b;
169+
foreach my $i ( 6..10 ) {
170+
push @data_b, Net::Stripe::Customer->new(
171+
id => sprintf( 'cus_%02d', $i ),
172+
);
173+
}
174+
my $list_b = Net::Stripe::List->new(
175+
count => scalar( @data_b ),
176+
data => \@data_b,
177+
has_more => undef,
178+
url => $url,
179+
);
180+
is_deeply { $list_b->_previous_page_args() }, { ending_before => 'cus_06' }, '_previous_page_args';
181+
is_deeply { $list_b->_next_page_args() }, { starting_after => 'cus_10' }, '_next_page_args';
182+
183+
my $merged = Net::Stripe::List::_merge_lists(
184+
lists => [ $list_a, $list_b ],
185+
);
186+
is_deeply [ map { $_ ->id } $merged->elements ], [ map { $_->id } ( $list_a->elements, $list_b->elements ) ], 'merged list ids match';
187+
is $merged->url, $url, 'merged list url matches';
188+
ok defined( $merged->count ), 'merged list has count';
189+
}
190+
153191
done_testing();

0 commit comments

Comments
 (0)