Skip to content

Commit

Permalink
Make SortedSet for identity arrays optional (#1427)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
lgebhardt authored Jan 11, 2024
1 parent ef0551d commit 040f980
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 7 deletions.
1 change: 1 addition & 0 deletions jsonapi-resources.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'concurrent-ruby-ext'
spec.add_development_dependency 'database_cleaner'
spec.add_development_dependency 'hashie'
spec.add_development_dependency 'sorted_set'
spec.add_dependency 'activerecord', '>= 5.1'
spec.add_dependency 'railties', '>= 5.1'
spec.add_dependency 'concurrent-ruby'
Expand Down
15 changes: 11 additions & 4 deletions lib/jsonapi/active_relation_retrieval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def find_related_fragments(source_fragment, relationship, options = {})
source_resource_klasses.each do |resource_klass|
inverse_direct_relationship = _relationship(resource_klass._type.to_s.singularize)

fragments.merge!(resource_klass.find_related_fragments_from_inverse([source_fragment], inverse_direct_relationship, options, true))
fragments.merge!(resource_klass.find_related_fragments_from_inverse([source_fragment], inverse_direct_relationship, options, false))
end
fragments
else
Expand Down Expand Up @@ -317,9 +317,16 @@ def find_related_fragments_from_inverse(source, source_relationship, options, co
linkage_relationships = to_one_relationships_for_linkage(include_directives[:include_related])

sort_criteria = []
options[:sort_criteria].try(:each) do |sort|
field = sort[:field].to_s == 'id' ? _primary_key : sort[:field]
sort_criteria << { field: field, direction: sort[:direction] }

# Do not sort the related_fragments. This can be keyed off `connect_source_identity` to indicate whether this
# is a related resource primary step vs. an include step.
sort_related_fragments = !connect_source_identity

if sort_related_fragments
options[:sort_criteria].try(:each) do |sort|
field = sort[:field].to_s == 'id' ? _primary_key : sort[:field]
sort_criteria << { field: field, direction: sort[:direction] }
end
end

join_manager = ActiveRelation::JoinManager.new(resource_klass: self,
Expand Down
12 changes: 11 additions & 1 deletion lib/jsonapi/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ class Configuration
:resource_cache_usage_report_function,
:default_exclude_links,
:default_resource_retrieval_strategy,
:use_related_resource_records_for_joins
:use_related_resource_records_for_joins,
:related_identities_set

def initialize
#:underscored_key, :camelized_key, :dasherized_key, or custom
Expand Down Expand Up @@ -182,6 +183,13 @@ def initialize
# This setting allows included resources to account for permission scopes. It can be overridden explicitly per
# relationship. Furthermore, specifying a `relation_name` on a relationship will cause this setting to be ignored.
self.use_related_resource_records_for_joins = true

# Collect the include keys into a Set or a SortedSet. SortedSet carries a small performance cost in the rails app
# but produces consistent and more human navigable result sets.
# To use SortedSet be sure to add `sorted_set` to your Gemfile and the following two lines to your JR initializer:
# require 'sorted_set'
# config.related_identities_set = SortedSet
self.related_identities_set = Set
end

def cache_formatters=(bool)
Expand Down Expand Up @@ -327,6 +335,8 @@ def allow_include=(allow_include)
attr_writer :default_resource_retrieval_strategy

attr_writer :use_related_resource_records_for_joins

attr_writer :related_identities_set
end

class << self
Expand Down
2 changes: 1 addition & 1 deletion lib/jsonapi/resource_fragment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def initialize(identity, resource: nil, cache: nil, primary: false)
@primary = primary

@related = {}
@related_from = Set.new
@related_from = JSONAPI.configuration.related_identities_set.new
end

def initialize_related(relationship_name)
Expand Down
2 changes: 1 addition & 1 deletion lib/jsonapi/resource_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def flatten_resource_tree(resource_tree, flattened_tree = {})
flattened_tree[resource_klass][id][:resource] ||= fragment.resource if fragment.resource

fragment.related.try(:each_pair) do |relationship_name, related_rids|
flattened_tree[resource_klass][id][:relationships][relationship_name] ||= Set.new
flattened_tree[resource_klass][id][:relationships][relationship_name] ||= JSONAPI.configuration.related_identities_set.new
flattened_tree[resource_klass][id][:relationships][relationship_name].merge(related_rids)
end
end
Expand Down
3 changes: 3 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@

JSONAPI.configure do |config|
config.json_key_format = :camelized_key

require 'sorted_set'
config.related_identities_set = SortedSet
end

ActiveSupport::Deprecation.silenced = true
Expand Down

0 comments on commit 040f980

Please sign in to comment.