Skip to content

Commit 0af7dec

Browse files
authored
Merge pull request #280 from intercom/issue_274
Issue 274 - Add Scroll Functionality
2 parents a3cf070 + fbe269e commit 0af7dec

File tree

5 files changed

+165
-0
lines changed

5 files changed

+165
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
require 'intercom/scroll_collection_proxy'
2+
3+
module Intercom
4+
module ApiOperations
5+
module Scroll
6+
7+
def scroll()
8+
collection_name = Utils.resource_class_to_collection_name(collection_class)
9+
finder_details = {}
10+
finder_details[:url] = "/#{collection_name}"
11+
ScrollCollectionProxy.new(collection_name, finder_details: finder_details, client: @client)
12+
end
13+
14+
end
15+
end
16+
end
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
require "intercom/utils"
2+
require "ext/sliceable_hash"
3+
4+
module Intercom
5+
class ScrollCollectionProxy
6+
7+
attr_reader :resource_name, :scroll_url, :resource_class, :scroll_param, :records
8+
9+
def initialize(resource_name, finder_details: {}, client:)
10+
@resource_name = resource_name
11+
@resource_class = Utils.constantize_resource_name(resource_name)
12+
@scroll_url = (finder_details[:url] || "/#{@resource_name}") + '/scroll'
13+
@client = client
14+
15+
end
16+
17+
def next(scroll_parameter=nil)
18+
@records = []
19+
if not scroll_parameter
20+
#First time so do initial get without scroll_param
21+
response_hash = @client.get(@scroll_url, '')
22+
else
23+
#Not first call so use get next page
24+
response_hash = @client.get(@scroll_url, scroll_param: scroll_parameter)
25+
end
26+
raise Intercom::HttpError.new('Http Error - No response entity returned') unless response_hash
27+
@scroll_param = extract_scroll_param(response_hash)
28+
top_level_entity_key = deserialize_response_hash(response_hash)
29+
response_hash[top_level_entity_key] = response_hash[top_level_entity_key].map do |object_json|
30+
Lib::TypedJsonDeserializer.new(object_json).deserialize
31+
end
32+
@records = response_hash[@resource_name]
33+
self
34+
end
35+
36+
def each(&block)
37+
scroll_param = nil
38+
loop do
39+
if not scroll_param
40+
response_hash = @client.get(@scroll_url, '')
41+
else
42+
response_hash = @client.get(@scroll_url, scroll_param: scroll_param)
43+
end
44+
raise Intercom::HttpError.new('Http Error - No response entity returned') unless response_hash
45+
response_hash[deserialize_response_hash(response_hash)].each do |object_json|
46+
block.call Lib::TypedJsonDeserializer.new(object_json).deserialize
47+
end
48+
scroll_param = extract_scroll_param(response_hash)
49+
break if not records_present?(response_hash)
50+
end
51+
self
52+
end
53+
54+
def [](target_index)
55+
self.each_with_index do |item, index|
56+
return item if index == target_index
57+
end
58+
nil
59+
end
60+
61+
include Enumerable
62+
63+
private
64+
65+
def deserialize_response_hash(response_hash)
66+
top_level_type = response_hash.delete('type')
67+
if resource_name == 'subscriptions'
68+
top_level_entity_key = 'items'
69+
else
70+
top_level_entity_key = Utils.entity_key_from_type(top_level_type)
71+
end
72+
end
73+
74+
def records_present?(response_hash)
75+
(response_hash[@resource_name].length > 0)
76+
end
77+
78+
def extract_scroll_param(response_hash)
79+
return nil unless records_present?(response_hash)
80+
response_hash['scroll_param']
81+
end
82+
end
83+
end

lib/intercom/service/user.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'intercom/service/base_service'
22
require 'intercom/api_operations/load'
33
require 'intercom/api_operations/list'
4+
require 'intercom/api_operations/scroll'
45
require 'intercom/api_operations/find'
56
require 'intercom/api_operations/find_all'
67
require 'intercom/api_operations/save'
@@ -14,6 +15,7 @@ module Service
1415
class User < BaseService
1516
include ApiOperations::Load
1617
include ApiOperations::List
18+
include ApiOperations::Scroll
1719
include ApiOperations::Find
1820
include ApiOperations::FindAll
1921
include ApiOperations::Save

spec/spec_helper.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,14 @@ def page_of_users(include_next_link= false)
216216
}
217217
end
218218

219+
def users_scroll(include_users= false)
220+
{
221+
"type"=>"user.list",
222+
"scroll_param"=> ("da6bbbac-25f6-4f07-866b-b911082d7"),
223+
"users"=> (include_users ? [test_user("[email protected]"), test_user("[email protected]"), test_user("[email protected]")] : []),
224+
}
225+
end
226+
219227
def users_pagination(include_next_link=false, per_page=0, page=0, total_pages=0, total_count=0, user_list=[])
220228
{
221229
"type"=>"user.list",
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
require "spec_helper"
2+
3+
describe Intercom::ScrollCollectionProxy do
4+
let (:client) { Intercom::Client.new(app_id: 'app_id', api_key: 'api_key') }
5+
6+
it "stops iterating if no users returned" do
7+
client.expects(:get).with("/users/scroll", '').returns(users_scroll(false))
8+
emails = []
9+
client.users.scroll.each { |user| emails << user.email }
10+
emails.must_equal %W()
11+
end
12+
13+
it "keeps iterating if users returned" do
14+
client.expects(:get).with("/users/scroll", '').returns(users_scroll(true))
15+
client.expects(:get).with('/users/scroll', {:scroll_param => 'da6bbbac-25f6-4f07-866b-b911082d7'}).returns(users_scroll(false))
16+
emails = []
17+
client.users.scroll.each { |user| emails << user.email }
18+
end
19+
20+
it "supports indexed array access" do
21+
client.expects(:get).with("/users/scroll", '').returns(users_scroll(true))
22+
client.users.scroll[0].email.must_equal '[email protected]'
23+
end
24+
25+
it "supports map" do
26+
client.expects(:get).with("/users/scroll", '').returns(users_scroll(true))
27+
client.expects(:get).with('/users/scroll', {:scroll_param => 'da6bbbac-25f6-4f07-866b-b911082d7'}).returns(users_scroll(false))
28+
emails = client.users.scroll.map { |user| user.email }
29+
30+
end
31+
32+
it "returns one page scroll" do
33+
client.expects(:get).with("/users/scroll", '').returns(users_scroll(true))
34+
scroll = client.users.scroll.next
35+
emails = []
36+
scroll.records.each {|usr| emails << usr.email}
37+
38+
end
39+
40+
it "keeps iterating if called with scroll_param" do
41+
client.expects(:get).with("/users/scroll", '').returns(users_scroll(true))
42+
client.expects(:get).with('/users/scroll', {:scroll_param => 'da6bbbac-25f6-4f07-866b-b911082d7'}).returns(users_scroll(true))
43+
scroll = client.users.scroll.next
44+
scroll = client.users.scroll.next('da6bbbac-25f6-4f07-866b-b911082d7')
45+
emails =[]
46+
scroll.records.each {|usr| puts usr.email}
47+
end
48+
49+
it "works with an empty list" do
50+
client.expects(:get).with("/users/scroll", '').returns(users_scroll(false))
51+
scroll = client.users.scroll.next
52+
emails = []
53+
scroll.records.each {|usr| emails << usr.email}
54+
emails.must_equal %W()
55+
end
56+
end

0 commit comments

Comments
 (0)