Skip to content

Commit 040f980

Browse files
authored
Make SortedSet for identity arrays optional (#1427)
* Make SortedSet for identity arrays optional * Fix tests to use sort_related_identities_by_primary_key option override * Keep SortedSet as a development dependency, unless required * Remove sorted_set dependency * Add better messaging about using SortedSet * Clarify setting sort_criteria for includes vs. related resources
1 parent ef0551d commit 040f980

File tree

6 files changed

+28
-7
lines changed

6 files changed

+28
-7
lines changed

jsonapi-resources.gemspec

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

lib/jsonapi/active_relation_retrieval.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ def find_related_fragments(source_fragment, relationship, options = {})
271271
source_resource_klasses.each do |resource_klass|
272272
inverse_direct_relationship = _relationship(resource_klass._type.to_s.singularize)
273273

274-
fragments.merge!(resource_klass.find_related_fragments_from_inverse([source_fragment], inverse_direct_relationship, options, true))
274+
fragments.merge!(resource_klass.find_related_fragments_from_inverse([source_fragment], inverse_direct_relationship, options, false))
275275
end
276276
fragments
277277
else
@@ -317,9 +317,16 @@ def find_related_fragments_from_inverse(source, source_relationship, options, co
317317
linkage_relationships = to_one_relationships_for_linkage(include_directives[:include_related])
318318

319319
sort_criteria = []
320-
options[:sort_criteria].try(:each) do |sort|
321-
field = sort[:field].to_s == 'id' ? _primary_key : sort[:field]
322-
sort_criteria << { field: field, direction: sort[:direction] }
320+
321+
# Do not sort the related_fragments. This can be keyed off `connect_source_identity` to indicate whether this
322+
# is a related resource primary step vs. an include step.
323+
sort_related_fragments = !connect_source_identity
324+
325+
if sort_related_fragments
326+
options[:sort_criteria].try(:each) do |sort|
327+
field = sort[:field].to_s == 'id' ? _primary_key : sort[:field]
328+
sort_criteria << { field: field, direction: sort[:direction] }
329+
end
323330
end
324331

325332
join_manager = ActiveRelation::JoinManager.new(resource_klass: self,

lib/jsonapi/configuration.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class Configuration
4343
:resource_cache_usage_report_function,
4444
:default_exclude_links,
4545
:default_resource_retrieval_strategy,
46-
:use_related_resource_records_for_joins
46+
:use_related_resource_records_for_joins,
47+
:related_identities_set
4748

4849
def initialize
4950
#:underscored_key, :camelized_key, :dasherized_key, or custom
@@ -182,6 +183,13 @@ def initialize
182183
# This setting allows included resources to account for permission scopes. It can be overridden explicitly per
183184
# relationship. Furthermore, specifying a `relation_name` on a relationship will cause this setting to be ignored.
184185
self.use_related_resource_records_for_joins = true
186+
187+
# Collect the include keys into a Set or a SortedSet. SortedSet carries a small performance cost in the rails app
188+
# but produces consistent and more human navigable result sets.
189+
# To use SortedSet be sure to add `sorted_set` to your Gemfile and the following two lines to your JR initializer:
190+
# require 'sorted_set'
191+
# config.related_identities_set = SortedSet
192+
self.related_identities_set = Set
185193
end
186194

187195
def cache_formatters=(bool)
@@ -327,6 +335,8 @@ def allow_include=(allow_include)
327335
attr_writer :default_resource_retrieval_strategy
328336

329337
attr_writer :use_related_resource_records_for_joins
338+
339+
attr_writer :related_identities_set
330340
end
331341

332342
class << self

lib/jsonapi/resource_fragment.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def initialize(identity, resource: nil, cache: nil, primary: false)
2525
@primary = primary
2626

2727
@related = {}
28-
@related_from = Set.new
28+
@related_from = JSONAPI.configuration.related_identities_set.new
2929
end
3030

3131
def initialize_related(relationship_name)

lib/jsonapi/resource_set.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def flatten_resource_tree(resource_tree, flattened_tree = {})
180180
flattened_tree[resource_klass][id][:resource] ||= fragment.resource if fragment.resource
181181

182182
fragment.related.try(:each_pair) do |relationship_name, related_rids|
183-
flattened_tree[resource_klass][id][:relationships][relationship_name] ||= Set.new
183+
flattened_tree[resource_klass][id][:relationships][relationship_name] ||= JSONAPI.configuration.related_identities_set.new
184184
flattened_tree[resource_klass][id][:relationships][relationship_name].merge(related_rids)
185185
end
186186
end

test/test_helper.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939

4040
JSONAPI.configure do |config|
4141
config.json_key_format = :camelized_key
42+
43+
require 'sorted_set'
44+
config.related_identities_set = SortedSet
4245
end
4346

4447
ActiveSupport::Deprecation.silenced = true

0 commit comments

Comments
 (0)