diff --git a/packages/forest_admin_datasource_zendesk/lib/forest_admin_datasource_zendesk/collections/base_collection.rb b/packages/forest_admin_datasource_zendesk/lib/forest_admin_datasource_zendesk/collections/base_collection.rb index a9aac3202..398a892e0 100644 --- a/packages/forest_admin_datasource_zendesk/lib/forest_admin_datasource_zendesk/collections/base_collection.rb +++ b/packages/forest_admin_datasource_zendesk/lib/forest_admin_datasource_zendesk/collections/base_collection.rb @@ -45,15 +45,24 @@ def aggregate_count(_caller, _filter) # Zendesk Search has no `id:` operator, so collections short-circuit # PK lookups to /resource/{id} when the filter is `id = N` or `id IN [...]`. + # + # The agent parses Number values through `to_f`, so an `id IN [...]` filter + # arrives as floats (e.g. `123.0`). Zendesk's REST ids are integers, so the + # values are normalised here before hitting /show_many or /resource/{id}; + # otherwise the API rejects `123.0` (500) or the id-keyed result map misses. def extract_id_lookup(node) return nil unless node.is_a?(Leaf) && node.field == 'id' case node.operator - when Operators::EQUAL then [node.value] - when Operators::IN then Array(node.value) + when Operators::EQUAL then [normalize_id(node.value)] + when Operators::IN then Array(node.value).map { |v| normalize_id(v) } end end + def normalize_id(value) + Integer(value, exception: false) || value + end + def project(record, projection) return record if projection.nil? diff --git a/packages/forest_admin_datasource_zendesk/spec/forest_admin_datasource_zendesk/collections/ticket_spec.rb b/packages/forest_admin_datasource_zendesk/spec/forest_admin_datasource_zendesk/collections/ticket_spec.rb index 3d7ff9e06..251f07e34 100644 --- a/packages/forest_admin_datasource_zendesk/spec/forest_admin_datasource_zendesk/collections/ticket_spec.rb +++ b/packages/forest_admin_datasource_zendesk/spec/forest_admin_datasource_zendesk/collections/ticket_spec.rb @@ -86,6 +86,24 @@ def zendesk_record(attrs) expect(client).to have_received(:fetch_tickets_by_ids).with([1, 2]).once end + it 'coerces float ids (as produced by the agent parser) to integers' do + bulk_response = { 1 => { 'id' => 1, 'requester_id' => nil } } + allow(client).to receive_messages(fetch_tickets_by_ids: bulk_response, fetch_user_emails: {}) + + filter = Filter.new(condition_tree: Leaf.new('id', 'in', [1.0, 2.0])) + expect(collection.list(nil, filter, ['id']).map { |r| r['id'] }).to eq([1]) + expect(client).to have_received(:fetch_tickets_by_ids).with([1, 2]) + end + + it 'coerces a float id on an EQUAL lookup to an integer' do + ticket = { 'id' => 215, 'requester_id' => nil } + allow(client).to receive_messages(fetch_tickets_by_ids: { 215 => ticket }, fetch_user_emails: {}) + + filter = Filter.new(condition_tree: Leaf.new('id', 'equal', 215.0)) + expect(collection.list(nil, filter, ['id']).map { |r| r['id'] }).to eq([215]) + expect(client).to have_received(:fetch_tickets_by_ids).with([215]) + end + it 'silently drops ids the bulk endpoint did not return' do allow(client).to receive(:fetch_tickets_by_ids).with([1, 2]).and_return( 1 => { 'id' => 1, 'requester_id' => nil } diff --git a/packages/forest_admin_datasource_zendesk/spec/forest_admin_datasource_zendesk/collections/user_spec.rb b/packages/forest_admin_datasource_zendesk/spec/forest_admin_datasource_zendesk/collections/user_spec.rb index 24f1f7fe3..bcf0a325d 100644 --- a/packages/forest_admin_datasource_zendesk/spec/forest_admin_datasource_zendesk/collections/user_spec.rb +++ b/packages/forest_admin_datasource_zendesk/spec/forest_admin_datasource_zendesk/collections/user_spec.rb @@ -38,6 +38,16 @@ def zendesk_user(attrs) expect(client).not_to have_received(:search) end + it 'coerces a float id (as produced by the agent parser) to an integer' do + user = zendesk_user('id' => 7, 'email' => 'a@b.com', 'name' => 'A') + allow(client).to receive_messages(find_user: user, search: []) + + filter = Filter.new(condition_tree: Leaf.new('id', 'equal', 7.0)) + collection.list(nil, filter, ['id', 'email']) + expect(client).to have_received(:find_user).with(7) + expect(client).not_to have_received(:search) + end + it 'searches with type:user otherwise' do allow(client).to receive(:search).and_return([])