Skip to content

Commit

Permalink
Add ListAll methods to resources with ListWithPagination methods (#282)
Browse files Browse the repository at this point in the history
* Add ListAll methods to resources with ListWithPagination methods
  • Loading branch information
weirdian2k3 authored Apr 21, 2024
1 parent 3413314 commit 3554221
Show file tree
Hide file tree
Showing 14 changed files with 952 additions and 0 deletions.
24 changes: 24 additions & 0 deletions customer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
// See: https://help.shopify.com/api/reference/customer
type CustomerService interface {
List(context.Context, interface{}) ([]Customer, error)
ListAll(context.Context, interface{}) ([]Customer, error)
ListWithPagination(ctx context.Context, options interface{}) ([]Customer, *Pagination, error)
Count(context.Context, interface{}) (int, error)
Get(context.Context, uint64, interface{}) (*Customer, error)
Expand Down Expand Up @@ -111,6 +112,29 @@ func (s *CustomerServiceOp) List(ctx context.Context, options interface{}) ([]Cu
return resource.Customers, err
}

// ListAll Lists all customers, iterating over pages
func (s *CustomerServiceOp) ListAll(ctx context.Context, options interface{}) ([]Customer, error) {
collector := []Customer{}

for {
entities, pagination, err := s.ListWithPagination(ctx, options)

if err != nil {
return collector, err
}

collector = append(collector, entities...)

if pagination.NextPageOptions == nil {
break
}

options = pagination.NextPageOptions
}

return collector, nil
}

// ListWithPagination lists customers and return pagination to retrieve next/previous results.
func (s *CustomerServiceOp) ListWithPagination(ctx context.Context, options interface{}) ([]Customer, *Pagination, error) {
path := fmt.Sprintf("%s.json", customersBasePath)
Expand Down
112 changes: 112 additions & 0 deletions customer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,118 @@ func TestCustomerList(t *testing.T) {
}
}

func TestCustomerListAll(t *testing.T) {
setup()
defer teardown()

listURL := fmt.Sprintf("https://fooshop.myshopify.com/%s/customers.json", client.pathPrefix)

cases := []struct {
name string
expectedCustomers []Customer
expectedRequestURLs []string
expectedLinkHeaders []string
expectedBodies []string
expectedErr error
}{
{
name: "Pulls the next page",
expectedRequestURLs: []string{
listURL,
fmt.Sprintf("%s?page_info=pg2", listURL),
},
expectedLinkHeaders: []string{
`<http://valid.url?page_info=pg2>; rel="next"`,
`<http://valid.url?page_info=pg1>; rel="previous"`,
},
expectedBodies: []string{
`{"customers": [{"id":1},{"id":2}]}`,
`{"customers": [{"id":3},{"id":4}]}`,
},
expectedCustomers: []Customer{{Id: 1}, {Id: 2}, {Id: 3}, {Id: 4}},
expectedErr: nil,
},
{
name: "Stops when there is not a next page",
expectedRequestURLs: []string{
listURL,
},
expectedLinkHeaders: []string{
`<http://valid.url?page_info=pg2>; rel="previous"`,
},
expectedBodies: []string{
`{"customers": [{"id":1}]}`,
},
expectedCustomers: []Customer{{Id: 1}},
expectedErr: nil,
},
{
name: "Returns errors when required",
expectedRequestURLs: []string{
listURL,
},
expectedLinkHeaders: []string{
`<http://valid.url?paage_info=pg2>; rel="previous"`,
},
expectedBodies: []string{
`{"customers": []}`,
},
expectedCustomers: []Customer{},
expectedErr: errors.New("page_info is missing"),
},
}

for i, c := range cases {
t.Run(c.name, func(t *testing.T) {
if len(c.expectedRequestURLs) != len(c.expectedLinkHeaders) {
t.Errorf(
"test case must have the same number of expected request urls (%d) as expected link headers (%d)",
len(c.expectedRequestURLs),
len(c.expectedLinkHeaders),
)

return
}

if len(c.expectedRequestURLs) != len(c.expectedBodies) {
t.Errorf(
"test case must have the same number of expected request urls (%d) as expected bodies (%d)",
len(c.expectedRequestURLs),
len(c.expectedBodies),
)

return
}

for i := range c.expectedRequestURLs {
response := &http.Response{
StatusCode: 200,
Body: httpmock.NewRespBodyFromString(c.expectedBodies[i]),
Header: http.Header{
"Link": {c.expectedLinkHeaders[i]},
},
}

httpmock.RegisterResponder("GET", c.expectedRequestURLs[i], httpmock.ResponderFromResponse(response))
}

customers, err := client.Customer.ListAll(context.Background(), nil)
if !reflect.DeepEqual(customers, c.expectedCustomers) {
t.Errorf("test %d Customer.ListAll orders returned %+v, expected %+v", i, customers, c.expectedCustomers)
}

if (c.expectedErr != nil || err != nil) && err.Error() != c.expectedErr.Error() {
t.Errorf(
"test %d Customer.ListAll err returned %+v, expected %+v",
i,
err,
c.expectedErr,
)
}
})
}
}

func TestCustomerListWithPagination(t *testing.T) {
setup()
defer teardown()
Expand Down
24 changes: 24 additions & 0 deletions order.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
// See: https://help.shopify.com/api/reference/order
type OrderService interface {
List(context.Context, interface{}) ([]Order, error)
ListAll(context.Context, interface{}) ([]Order, error)
ListWithPagination(context.Context, interface{}) ([]Order, *Pagination, error)
Count(context.Context, interface{}) (int, error)
Get(context.Context, uint64, interface{}) (*Order, error)
Expand Down Expand Up @@ -538,6 +539,29 @@ func (s *OrderServiceOp) List(ctx context.Context, options interface{}) ([]Order
return orders, nil
}

// ListAll Lists all orders, iterating over pages
func (s *OrderServiceOp) ListAll(ctx context.Context, options interface{}) ([]Order, error) {
collector := []Order{}

for {
entities, pagination, err := s.ListWithPagination(ctx, options)

if err != nil {
return collector, err
}

collector = append(collector, entities...)

if pagination.NextPageOptions == nil {
break
}

options = pagination.NextPageOptions
}

return collector, nil
}

func (s *OrderServiceOp) ListWithPagination(ctx context.Context, options interface{}) ([]Order, *Pagination, error) {
path := fmt.Sprintf("%s.json", ordersBasePath)
resource := new(OrdersResource)
Expand Down
24 changes: 24 additions & 0 deletions order_risk.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
// See: https://shopify.dev/docs/api/admin-rest/2023-10/resources/order-risk
type OrderRiskService interface {
List(context.Context, uint64, interface{}) ([]OrderRisk, error)
ListAll(context.Context, uint64, interface{}) ([]OrderRisk, error)
ListWithPagination(context.Context, uint64, interface{}) ([]OrderRisk, *Pagination, error)
Get(context.Context, uint64, uint64, interface{}) (*OrderRisk, error)
Create(context.Context, uint64, OrderRisk) (*OrderRisk, error)
Expand Down Expand Up @@ -79,6 +80,29 @@ func (s *OrderRiskServiceOp) List(ctx context.Context, orderId uint64, options i
return orders, nil
}

// ListAll Lists all OrderRisk, iterating over pages
func (s *OrderRiskServiceOp) ListAll(ctx context.Context, orderId uint64, options interface{}) ([]OrderRisk, error) {
collector := []OrderRisk{}

for {
entities, pagination, err := s.ListWithPagination(ctx, orderId, options)

if err != nil {
return collector, err
}

collector = append(collector, entities...)

if pagination.NextPageOptions == nil {
break
}

options = pagination.NextPageOptions
}

return collector, nil
}

func (s *OrderRiskServiceOp) ListWithPagination(ctx context.Context, orderId uint64, options interface{}) ([]OrderRisk, *Pagination, error) {
path := fmt.Sprintf("%s/%d/%s.json", ordersRiskBasePath, orderId, ordersRiskResourceName)
resource := new(OrdersRisksResource)
Expand Down
112 changes: 112 additions & 0 deletions order_risk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,118 @@ func TestOrderRiskListError(t *testing.T) {
}
}

func TestOrderRiskListAll(t *testing.T) {
setup()
defer teardown()

listURL := fmt.Sprintf("https://fooshop.myshopify.com/%s/orders/450789469/risks.json", client.pathPrefix)

cases := []struct {
name string
expectedOrderRisks []OrderRisk
expectedRequestURLs []string
expectedLinkHeaders []string
expectedBodies []string
expectedErr error
}{
{
name: "Pulls the next page",
expectedRequestURLs: []string{
listURL,
fmt.Sprintf("%s?page_info=pg2", listURL),
},
expectedLinkHeaders: []string{
`<http://valid.url?page_info=pg2>; rel="next"`,
`<http://valid.url?page_info=pg1>; rel="previous"`,
},
expectedBodies: []string{
`{"risks": [{"id":1},{"id":2}]}`,
`{"risks": [{"id":3},{"id":4}]}`,
},
expectedOrderRisks: []OrderRisk{{Id: 1}, {Id: 2}, {Id: 3}, {Id: 4}},
expectedErr: nil,
},
{
name: "Stops when there is not a next page",
expectedRequestURLs: []string{
listURL,
},
expectedLinkHeaders: []string{
`<http://valid.url?page_info=pg2>; rel="previous"`,
},
expectedBodies: []string{
`{"risks": [{"id":1}]}`,
},
expectedOrderRisks: []OrderRisk{{Id: 1}},
expectedErr: nil,
},
{
name: "Returns errors when required",
expectedRequestURLs: []string{
listURL,
},
expectedLinkHeaders: []string{
`<http://valid.url?paage_info=pg2>; rel="previous"`,
},
expectedBodies: []string{
`{"risks": []}`,
},
expectedOrderRisks: []OrderRisk{},
expectedErr: errors.New("page_info is missing"),
},
}

for i, c := range cases {
t.Run(c.name, func(t *testing.T) {
if len(c.expectedRequestURLs) != len(c.expectedLinkHeaders) {
t.Errorf(
"test case must have the same number of expected request urls (%d) as expected link headers (%d)",
len(c.expectedRequestURLs),
len(c.expectedLinkHeaders),
)

return
}

if len(c.expectedRequestURLs) != len(c.expectedBodies) {
t.Errorf(
"test case must have the same number of expected request urls (%d) as expected bodies (%d)",
len(c.expectedRequestURLs),
len(c.expectedBodies),
)

return
}

for i := range c.expectedRequestURLs {
response := &http.Response{
StatusCode: 200,
Body: httpmock.NewRespBodyFromString(c.expectedBodies[i]),
Header: http.Header{
"Link": {c.expectedLinkHeaders[i]},
},
}

httpmock.RegisterResponder("GET", c.expectedRequestURLs[i], httpmock.ResponderFromResponse(response))
}

risks, err := client.OrderRisk.ListAll(context.Background(), 450789469, nil)
if !reflect.DeepEqual(risks, c.expectedOrderRisks) {
t.Errorf("test %d OrderRisk.ListAll orders returned %+v, expected %+v", i, risks, c.expectedOrderRisks)
}

if (c.expectedErr != nil || err != nil) && err.Error() != c.expectedErr.Error() {
t.Errorf(
"test %d OrderRisk.ListAll err returned %+v, expected %+v",
i,
err,
c.expectedErr,
)
}
})
}
}

func TestOrderRiskListWithPagination(t *testing.T) {
setup()
defer teardown()
Expand Down
Loading

0 comments on commit 3554221

Please sign in to comment.