Browse Source

Merge pull request #611 from Shopify/selective-cursor-versions

Allow cursor pagination in 2019-07 release for select resources
Drew Martin 5 years ago
parent
commit
b7bd602a8f

+ 13 - 15
lib/shopify_api/paginated_collection.rb

@@ -4,43 +4,39 @@ module ShopifyAPI
   class PaginatedCollection < ActiveResource::Collection
     module CollectionPagination
       def initialize(args)
-        @previous_url_params = extract_url_params(pagination_link_headers.previous_link)
-        @next_url_params = extract_url_params(pagination_link_headers.next_link)
+        @next_url = pagination_link_headers.next_link&.url&.to_s
+        @previous_url = pagination_link_headers.previous_link&.url&.to_s
         super(args)
       end
 
       def next_page?
         ensure_available
-        @next_url_params.present?
+        @next_url.present?
       end
 
       def previous_page?
         ensure_available
-        @previous_url_params.present?
+        @previous_url.present?
       end
 
       def fetch_next_page
-        fetch_page(@next_url_params)
+        fetch_page(@next_url)
       end
 
       def fetch_previous_page
-        fetch_page(@previous_url_params)
+        fetch_page(@previous_url)
       end
 
       private
 
       AVAILABLE_IN_VERSION = ShopifyAPI::ApiVersion::Release.new('2019-10')
+      AVAILABLE_IN_VERSION_EARLY = ShopifyAPI::ApiVersion::Release.new('2019-07')
 
-      def fetch_page(url_params)
+      def fetch_page(url)
         ensure_available
-        return [] unless url_params.present?
+        return [] unless url.present?
 
-        resource_class.where(url_params)
-      end
-
-      def extract_url_params(link_header)
-        return nil unless link_header.present?
-        Rack::Utils.parse_nested_query(link_header.url.query)
+        resource_class.all(from: url)
       end
 
       def pagination_link_headers
@@ -50,7 +46,9 @@ module ShopifyAPI
       end
 
       def ensure_available
-        raise NotImplementedError unless ShopifyAPI::Base.api_version >= AVAILABLE_IN_VERSION
+        return if ShopifyAPI::Base.api_version >= AVAILABLE_IN_VERSION
+        return if ShopifyAPI::Base.api_version >= AVAILABLE_IN_VERSION_EARLY && resource_class.early_july_pagination?
+        raise NotImplementedError
       end
     end
 

+ 2 - 1
lib/shopify_api/resources.rb

@@ -1,2 +1,3 @@
 require 'shopify_api/resources/base'
-Dir.glob("#{File.dirname(__FILE__)}/resources/*").each { |file| require(file) } 
+require 'shopify_api/resources/array_base'
+Dir.glob("#{File.dirname(__FILE__)}/resources/*").each { |file| require(file) }

+ 13 - 0
lib/shopify_api/resources/array_base.rb

@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module ShopifyAPI
+  class ArrayBase < Base
+    class << self
+      private
+
+      def instantiate_record(record, *)
+        record
+      end
+    end
+  end
+end

+ 12 - 0
lib/shopify_api/resources/base.rb

@@ -125,6 +125,18 @@ module ShopifyAPI
           @prefix_options[resource_id]
         end
       end
+
+      def early_july_pagination?
+        !!early_july_pagination
+      end
+
+      private
+
+      attr_accessor :early_july_pagination
+
+      def early_july_pagination_release!
+        self.early_july_pagination = true
+      end
     end
 
     def persisted?

+ 1 - 0
lib/shopify_api/resources/collect.rb

@@ -1,5 +1,6 @@
 module ShopifyAPI
   # For adding/removing products from custom collections
   class Collect < Base
+    early_july_pagination_release!
   end
 end

+ 10 - 1
lib/shopify_api/resources/collection_listing.rb

@@ -2,8 +2,17 @@ module ShopifyAPI
   class CollectionListing < Base
     self.primary_key = :collection_id
 
+    early_july_pagination_release!
+
     def product_ids
-      get(:product_ids)
+      ProductId.all(params: { collection_id: collection_id })
+    end
+
+    class ProductId < ArrayBase
+      self.resource_prefix = 'collection_listings/:collection_id/'
+
+      early_july_pagination_release!
     end
+    private_constant :ProductId
   end
 end

+ 2 - 0
lib/shopify_api/resources/customer_saved_search.rb

@@ -2,6 +2,8 @@ require 'shopify_api/resources/customer'
 
 module ShopifyAPI
   class CustomerSavedSearch < Base
+    early_july_pagination_release!
+
     def customers(params = {})
       Customer.search(params.merge({:customer_saved_search_id => self.id}))
     end

+ 1 - 0
lib/shopify_api/resources/event.rb

@@ -3,5 +3,6 @@ module ShopifyAPI
     include DisablePrefixCheck
 
     conditional_prefix :resource, true
+    early_july_pagination_release!
   end
 end

+ 1 - 0
lib/shopify_api/resources/metafield.rb

@@ -3,6 +3,7 @@ module ShopifyAPI
     include DisablePrefixCheck
 
     conditional_prefix :resource, true
+    early_july_pagination_release!
 
     def value
       return if attributes["value"].nil?

+ 2 - 0
lib/shopify_api/resources/product.rb

@@ -3,6 +3,8 @@ module ShopifyAPI
     include Events
     include Metafields
 
+    early_july_pagination_release!
+
     # compute the price range
     def price_range
       prices = variants.collect(&:price).collect(&:to_f)

+ 8 - 1
lib/shopify_api/resources/product_listing.rb

@@ -2,8 +2,15 @@ module ShopifyAPI
   class ProductListing < Base
     self.primary_key = :product_id
 
+    early_july_pagination_release!
+
     def self.product_ids
-      get(:product_ids)
+      ProductId.all
+    end
+
+    class ProductId < ArrayBase
+      self.resource_prefix = 'product_listings/'
     end
+    private_constant :ProductId
   end
 end

+ 38 - 0
test/collection_listing_test.rb

@@ -38,4 +38,42 @@ class CollectionListingTest < Test::Unit::TestCase
 
     assert_equal [1, 2], collection_listing.product_ids
   end
+
+  def test_get_collection_listing_product_ids_multi_page_with_cursor
+    version = ShopifyAPI::ApiVersion::Release.new('2019-07')
+    ShopifyAPI::Base.api_version = version.to_s
+
+    collection_listing = ShopifyAPI::CollectionListing.new(collection_id: 1)
+
+    url = "https://this-is-my-test-shop.myshopify.com/admin/api/2019-07/collection_listings/1/product_ids.json"
+
+    next_page_info = "notarealpageinfobutthatsokay"
+    next_page_url = "#{url}?page_info=#{next_page_info}"
+    link_header = "<#{next_page_url}>; rel=\"next\""
+
+    fake(
+      "collection_listings/1/product_ids",
+      method: :get,
+      status: 201,
+      url: url,
+      body: load_fixture('collection_listing_product_ids'),
+      link: link_header,
+    )
+
+    product_ids = collection_listing.product_ids
+    assert_equal [1, 2], product_ids
+    assert product_ids.next_page?
+
+    fake(
+      "collection_listings/1/product_ids",
+      method: :get,
+      status: 201,
+      url: next_page_url,
+      body: load_fixture('collection_listing_product_ids2'),
+      link: link_header,
+    )
+
+    next_page = product_ids.fetch_next_page
+    assert_equal [3, 4], next_page
+  end
 end

+ 1 - 0
test/fixtures/collection_listing_product_ids2.json

@@ -0,0 +1 @@
+[3, 4]

+ 1 - 1
test/fixtures/product_listing_product_ids.json

@@ -1 +1 @@
-[2, 1]
+[4, 3]

+ 1 - 0
test/fixtures/product_listing_product_ids2.json

@@ -0,0 +1 @@
+[2, 1]

+ 24 - 1
test/pagination_test.rb

@@ -130,7 +130,7 @@ class PaginationTest < Test::Unit::TestCase
     end
   end
 
-  test "raises on an invalid API version" do
+  test "raises on an older API version" do
     version = ShopifyAPI::ApiVersion::Release.new('2019-04')
     ShopifyAPI::Base.api_version = version.to_s
 
@@ -142,6 +142,29 @@ class PaginationTest < Test::Unit::TestCase
     end
   end
 
+  test "raises on 2019-07 API version for models that don't support new pagination yet" do
+    version = ShopifyAPI::ApiVersion::Release.new('2019-07')
+    ShopifyAPI::Base.api_version = version.to_s
+
+    fake 'orders', :method => :get, :status => 200, api_version: version, :body => load_fixture('orders')
+    orders = ShopifyAPI::Order.all
+
+    assert_raises NotImplementedError do
+      orders.fetch_next_page
+    end
+  end
+
+  test "new pagination works on 2019-07 API version for select models" do
+    version = ShopifyAPI::ApiVersion::Release.new('2019-07')
+    ShopifyAPI::Base.api_version = version.to_s
+
+    fake 'events', :method => :get, :status => 200, api_version: version, :body => load_fixture('events')
+    events = ShopifyAPI::Event.all
+
+    assert_empty events.fetch_next_page
+    assert_empty events.fetch_previous_page
+  end
+
   test "does not raise on the unstable version" do
     version = ShopifyAPI::ApiVersion::Unstable.new
     ShopifyAPI::Base.api_version = version.to_s

+ 59 - 2
test/product_listing_test.rb

@@ -34,7 +34,64 @@ class ProductListingTest < Test::Unit::TestCase
 
     product_ids = ShopifyAPI::ProductListing.product_ids
     assert_equal 2, product_ids.count
-    assert_equal 2, product_ids.first
-    assert_equal 1, product_ids.last
+    assert_equal 4, product_ids.first
+    assert_equal 3, product_ids.last
+  end
+
+  def test_get_product_listing_product_ids_multi_page_with_cursor
+    version = ShopifyAPI::ApiVersion::Release.new('2019-10')
+    ShopifyAPI::Base.api_version = version.to_s
+
+    url = "https://this-is-my-test-shop.myshopify.com/admin/api/2019-10/product_listings/product_ids.json"
+
+    next_page_info = "notarealpageinfobutthatsokay"
+    next_page_url = "#{url}?page_info=#{next_page_info}"
+    link_header = "<#{next_page_url}>; rel=\"next\""
+
+    fake(
+      "product_listings/product_ids",
+      method: :get,
+      status: 201,
+      url: url,
+      body: load_fixture('product_listing_product_ids'),
+      link: link_header,
+    )
+
+    product_ids = ShopifyAPI::ProductListing.product_ids
+    assert_equal [4, 3], product_ids
+    assert product_ids.next_page?
+
+    fake(
+      "product_listings/product_ids",
+      method: :get,
+      status: 201,
+      url: next_page_url,
+      body: load_fixture('product_listing_product_ids2'),
+      link: link_header,
+    )
+
+    next_page = product_ids.fetch_next_page
+    assert_equal [2, 1], next_page
+  end
+
+  def test_get_product_listing_product_ids_multi_page_with_cursor_fails_on_older_api_version
+    version = ShopifyAPI::ApiVersion::Release.new('2019-07')
+    ShopifyAPI::Base.api_version = version.to_s
+
+    url = "https://this-is-my-test-shop.myshopify.com/admin/api/2019-07/product_listings/product_ids.json"
+
+    fake(
+      "product_listings/product_ids",
+      method: :get,
+      status: 201,
+      url: url,
+      body: load_fixture('product_listing_product_ids'),
+    )
+
+    product_ids = ShopifyAPI::ProductListing.product_ids
+    assert_equal [4, 3], product_ids
+    assert_raises NotImplementedError do
+      product_ids.next_page?
+    end
   end
 end