Skip to content

Commit 0bbbc0b

Browse files
authored
Rework ResourceIdentity <=> operator (#1430)
add tests for ResourceIdentity, including that comparison does not allocate memory
1 parent cd1a529 commit 0bbbc0b

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

jsonapi-resources.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
2929
spec.add_development_dependency 'database_cleaner'
3030
spec.add_development_dependency 'hashie'
3131
spec.add_development_dependency 'sorted_set'
32+
spec.add_development_dependency 'memory_profiler'
3233
spec.add_dependency 'activerecord', '>= 5.1'
3334
spec.add_dependency 'railties', '>= 5.1'
3435
spec.add_dependency 'concurrent-ruby'

lib/jsonapi/resource_identity.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ module JSONAPI
1313
# rid = ResourceIdentity.new(PostResource, 12)
1414
#
1515
class ResourceIdentity
16+
include Comparable
17+
1618
# Store the identity parts as an array to avoid allocating a new array for the hash method to work on
1719
def initialize(resource_klass, id)
1820
@identity_parts = [resource_klass, id]
@@ -41,7 +43,16 @@ def hash
4143
end
4244

4345
def <=>(other_identity)
44-
self.id <=> other_identity.id
46+
return nil unless other_identity.is_a?(ResourceIdentity)
47+
48+
case self.resource_klass.name <=> other_identity.resource_klass.name
49+
when -1
50+
-1
51+
when 1
52+
1
53+
else
54+
self.id <=> other_identity.id
55+
end
4556
end
4657

4758
# Creates a string representation of the identifier.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
require File.expand_path('../../../test_helper', __FILE__)
2+
require 'memory_profiler'
3+
4+
class ResourceIdentity < ActiveSupport::TestCase
5+
6+
def test_can_generate_a_consistent_hash_for_comparison
7+
rid = JSONAPI::ResourceIdentity.new(PostResource, 12)
8+
assert_equal(rid.hash, [PostResource, 12].hash)
9+
end
10+
11+
def test_equality
12+
rid = JSONAPI::ResourceIdentity.new(PostResource, 12)
13+
rid2 = JSONAPI::ResourceIdentity.new(PostResource, 12)
14+
assert_equal(rid, rid2) # uses == internally
15+
assert rid.eql?(rid2)
16+
end
17+
18+
def test_inequality
19+
rid = JSONAPI::ResourceIdentity.new(PostResource, 12)
20+
rid2 = JSONAPI::ResourceIdentity.new(PostResource, 13)
21+
refute_equal(rid, rid2)
22+
end
23+
24+
def test_sorting_by_resource_class_name
25+
rid = JSONAPI::ResourceIdentity.new(CommentResource, 13)
26+
rid2 = JSONAPI::ResourceIdentity.new(PostResource, 13)
27+
rid3 = JSONAPI::ResourceIdentity.new(SectionResource, 13)
28+
assert_equal([rid2, rid3, rid].sort, [rid, rid2, rid3])
29+
end
30+
31+
def test_sorting_by_id_secondarily
32+
rid = JSONAPI::ResourceIdentity.new(PostResource, 12)
33+
rid2 = JSONAPI::ResourceIdentity.new(PostResource, 13)
34+
rid3 = JSONAPI::ResourceIdentity.new(PostResource, 14)
35+
36+
assert_equal([rid2, rid3, rid].sort, [rid, rid2, rid3])
37+
end
38+
39+
def test_to_s
40+
rid = JSONAPI::ResourceIdentity.new(PostResource, 12)
41+
assert_equal(rid.to_s, 'PostResource:12')
42+
end
43+
44+
def test_comparisons_return_nil_for_non_resource_identity
45+
rid = JSONAPI::ResourceIdentity.new(PostResource, 13)
46+
rid2 = "PostResource:13"
47+
assert_nil(rid <=> rid2)
48+
end
49+
50+
def test_comparisons_allocate_no_new_memory
51+
rid = JSONAPI::ResourceIdentity.new(PostResource, 13)
52+
rid2 = JSONAPI::ResourceIdentity.new(PostResource, 13)
53+
allocation_report = MemoryProfiler.report do
54+
rid == rid2
55+
end
56+
assert_equal 0, allocation_report.total_allocated
57+
end
58+
end

0 commit comments

Comments
 (0)