Skip to content
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
2 changes: 1 addition & 1 deletion lib/jsonapi-resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
require 'jsonapi/active_relation/join_manager'
require 'jsonapi/resource_identity'
require 'jsonapi/resource_fragment'
require 'jsonapi/resource_id_tree'
require 'jsonapi/resource_tree'
require 'jsonapi/resource_set'
require 'jsonapi/path'
require 'jsonapi/path_segment'
54 changes: 34 additions & 20 deletions lib/jsonapi/active_relation_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ module JSONAPI
class ActiveRelationResource < BasicResource
root_resource

def find_related_ids(relationship, options = {})
self.class.find_related_fragments([self], relationship.name, options).keys.collect { |rid| rid.id }
end

class << self
# Finds Resources using the `filters`. Pagination and sort options are used when provided
#
Expand Down Expand Up @@ -90,8 +94,11 @@ def find_to_populate_by_keys(keys, options = {})
# the ResourceInstances matching the filters, sorting, and pagination rules along with any request
# additional_field values
def find_fragments(filters, options = {})
include_directives = options[:include_directives] ? options[:include_directives].include_directives : {}
include_directives = options.fetch(:include_directives, {})
resource_klass = self

fragments = {}

linkage_relationships = to_one_relationships_for_linkage(include_directives[:include_related])

sort_criteria = options.fetch(:sort_criteria) { [] }
Expand Down Expand Up @@ -129,18 +136,26 @@ def find_fragments(filters, options = {})
if linkage_relationship.polymorphic? && linkage_relationship.belongs_to?
linkage_relationship.resource_types.each do |resource_type|
klass = resource_klass_for(resource_type)
linkage_fields << {relationship_name: name, resource_klass: klass}

linkage_table_alias = join_manager.join_details_by_polymorphic_relationship(linkage_relationship, resource_type)[:alias]
primary_key = klass._primary_key

linkage_fields << {relationship_name: name,
resource_klass: klass,
field: "#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}",
alias: "#{linkage_table_alias}_#{primary_key}"}

pluck_fields << Arel.sql("#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}")
end
else
klass = linkage_relationship.resource_klass
linkage_fields << {relationship_name: name, resource_klass: klass}

linkage_table_alias = join_manager.join_details_by_relationship(linkage_relationship)[:alias]
primary_key = klass._primary_key

linkage_fields << {relationship_name: name,
resource_klass: klass,
field: "#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}",
alias: "#{linkage_table_alias}_#{primary_key}"}

pluck_fields << Arel.sql("#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}")
end
end
Expand All @@ -158,7 +173,6 @@ def find_fragments(filters, options = {})
pluck_fields << Arel.sql(field)
end

fragments = {}
rows = records.pluck(*pluck_fields)
rows.each do |row|
rid = JSONAPI::ResourceIdentity.new(resource_klass, pluck_fields.length == 1 ? row : row[0])
Expand Down Expand Up @@ -204,23 +218,23 @@ def find_fragments(filters, options = {})
# @return [Hash{ResourceIdentity => {identity: => ResourceIdentity, cache: cache_field, attributes: => {name => value}, related: {relationship_name: [] }}}]
# the ResourceInstances matching the filters, sorting, and pagination rules along with any request
# additional_field values
def find_related_fragments(source_rids, relationship_name, options = {})
def find_related_fragments(source, relationship_name, options = {})
relationship = _relationship(relationship_name)

if relationship.polymorphic? # && relationship.foreign_key_on == :self
find_related_polymorphic_fragments(source_rids, relationship, options, false)
find_related_polymorphic_fragments(source, relationship, options, false)
else
find_related_monomorphic_fragments(source_rids, relationship, options, false)
find_related_monomorphic_fragments(source, relationship, options, false)
end
end

def find_included_fragments(source_rids, relationship_name, options)
def find_included_fragments(source, relationship_name, options)
relationship = _relationship(relationship_name)

if relationship.polymorphic? # && relationship.foreign_key_on == :self
find_related_polymorphic_fragments(source_rids, relationship, options, true)
find_related_polymorphic_fragments(source, relationship, options, true)
else
find_related_monomorphic_fragments(source_rids, relationship, options, true)
find_related_monomorphic_fragments(source, relationship, options, true)
end
end

Expand All @@ -231,7 +245,7 @@ def find_included_fragments(source_rids, relationship_name, options)
# @option options [Hash] :context The context of the request, set in the controller
#
# @return [Integer] the count
def count_related(source_rid, relationship_name, options = {})
def count_related(source_resource, relationship_name, options = {})
relationship = _relationship(relationship_name)
related_klass = relationship.resource_klass

Expand All @@ -244,7 +258,7 @@ def count_related(source_rid, relationship_name, options = {})

records = apply_request_settings_to_records(records: records(options),
resource_klass: related_klass,
primary_keys: source_rid.id,
primary_keys: source_resource.id,
join_manager: join_manager,
filters: filters,
options: options)
Expand Down Expand Up @@ -375,11 +389,11 @@ def find_records_by_keys(keys, options = {})
apply_request_settings_to_records(records: records(options), primary_keys: keys, options: options)
end

def find_related_monomorphic_fragments(source_rids, relationship, options, connect_source_identity)
def find_related_monomorphic_fragments(source_fragments, relationship, options, connect_source_identity)
filters = options.fetch(:filters, {})
source_ids = source_rids.collect {|rid| rid.id}
source_ids = source_fragments.collect {|item| item.identity.id}

include_directives = options[:include_directives] ? options[:include_directives].include_directives : {}
include_directives = options.fetch(:include_directives, {})
resource_klass = relationship.resource_klass
linkage_relationships = resource_klass.to_one_relationships_for_linkage(include_directives[:include_related])

Expand Down Expand Up @@ -501,12 +515,12 @@ def find_related_monomorphic_fragments(source_rids, relationship, options, conne

# Gets resource identities where the related resource is polymorphic and the resource type and id
# are stored on the primary resources. Cache fields will always be on the related resources.
def find_related_polymorphic_fragments(source_rids, relationship, options, connect_source_identity)
def find_related_polymorphic_fragments(source_fragments, relationship, options, connect_source_identity)
filters = options.fetch(:filters, {})
source_ids = source_rids.collect {|rid| rid.id}
source_ids = source_fragments.collect {|item| item.identity.id}

resource_klass = relationship.resource_klass
include_directives = options[:include_directives] ? options[:include_directives].include_directives : {}
include_directives = options.fetch(:include_directives, {})

linkage_relationships = []

Expand Down
20 changes: 13 additions & 7 deletions lib/jsonapi/basic_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,12 @@ def identity
JSONAPI::ResourceIdentity.new(self.class, id)
end

def cache_field_value
_model.public_send(self.class._cache_field)
end

def cache_id
[id, self.class.hash_cache_field(_model.public_send(self.class._cache_field))]
[id, self.class.hash_cache_field(cache_field_value)]
end

def is_new?
Expand Down Expand Up @@ -285,9 +289,7 @@ def _replace_to_many_links(relationship_type, relationship_key_values, options)
reflect = reflect_relationship?(relationship, options)

if reflect
existing_rids = self.class.find_related_fragments([identity], relationship_type, options)

existing = existing_rids.keys.collect { |rid| rid.id }
existing = find_related_ids(relationship, options)

to_delete = existing - (relationship_key_values & existing)
to_delete.each do |key|
Expand Down Expand Up @@ -417,6 +419,10 @@ def _replace_fields(field_data)
:completed
end

def find_related_ids(relationship, options = {})
send(relationship.foreign_key)
end

class << self
def inherited(subclass)
subclass.abstract(false)
Expand Down Expand Up @@ -636,7 +642,7 @@ def model_name(model, options = {})
end

def model_hint(model: _model_name, resource: _type)
resource_type = ((resource.is_a?(Class)) && (resource < JSONAPI::Resource)) ? resource._type : resource.to_s
resource_type = ((resource.is_a?(Class)) && (resource < JSONAPI::BasicResource)) ? resource._type : resource.to_s

_model_hints[model.to_s.gsub('::', '/').underscore] = resource_type.to_s
end
Expand Down Expand Up @@ -709,7 +715,7 @@ def resources_for(records, context)
end

def resource_for(model_record, context)
resource_klass = self.resource_klass_for_model(model_record)
resource_klass = resource_klass_for_model(model_record)
resource_klass.new(model_record, context)
end

Expand Down Expand Up @@ -1083,7 +1089,7 @@ def _add_relationship(klass, *attrs)
end
end

# ResourceBuilder methods
# ResourceBuilder methods
def define_relationship_methods(relationship_name, relationship_klass, options)
relationship = register_relationship(
relationship_name,
Expand Down
4 changes: 2 additions & 2 deletions lib/jsonapi/include_directives.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ def initialize(resource_klass, includes_array)
end
end

def include_directives
@include_directives_hash
def [](name)
@include_directives_hash[name]
end

private
Expand Down
Loading