Skip to content

Make SortedSet for identity arrays optional #1427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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