Allow the serializer to return sparse fieldsets
This commit is contained in:
parent
41c1e0a106
commit
a363c90bfb
7
lib/fast_jsonapi/fieldset.rb
Normal file
7
lib/fast_jsonapi/fieldset.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module FastJsonapi
|
||||||
|
class Fieldset
|
||||||
|
def initialize(fields)
|
||||||
|
@fields = fields
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -7,6 +7,7 @@ require 'fast_jsonapi/attribute'
|
|||||||
require 'fast_jsonapi/relationship'
|
require 'fast_jsonapi/relationship'
|
||||||
require 'fast_jsonapi/link'
|
require 'fast_jsonapi/link'
|
||||||
require 'fast_jsonapi/serialization_core'
|
require 'fast_jsonapi/serialization_core'
|
||||||
|
require 'fast_jsonapi/fieldset'
|
||||||
|
|
||||||
module FastJsonapi
|
module FastJsonapi
|
||||||
module ObjectSerializer
|
module ObjectSerializer
|
||||||
@ -41,8 +42,8 @@ module FastJsonapi
|
|||||||
|
|
||||||
return serializable_hash unless @resource
|
return serializable_hash unless @resource
|
||||||
|
|
||||||
serializable_hash[:data] = self.class.record_hash(@resource, @params)
|
serializable_hash[:data] = self.class.record_hash(@resource, @fieldsets[self.class.reflected_record_type.to_sym], @params)
|
||||||
serializable_hash[:included] = self.class.get_included_records(@resource, @includes, @known_included_objects, @params) if @includes.present?
|
serializable_hash[:included] = self.class.get_included_records(@resource, @includes, @known_included_objects, @fieldsets, @params) if @includes.present?
|
||||||
serializable_hash
|
serializable_hash
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -51,9 +52,10 @@ module FastJsonapi
|
|||||||
|
|
||||||
data = []
|
data = []
|
||||||
included = []
|
included = []
|
||||||
|
fieldset = @fieldsets[self.class.reflected_record_type.to_sym]
|
||||||
@resource.each do |record|
|
@resource.each do |record|
|
||||||
data << self.class.record_hash(record, @params)
|
data << self.class.record_hash(record, fieldset, @params)
|
||||||
included.concat self.class.get_included_records(record, @includes, @known_included_objects, @params) if @includes.present?
|
included.concat self.class.get_included_records(record, @includes, @known_included_objects, @fieldsets, @params) if @includes.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
serializable_hash[:data] = data
|
serializable_hash[:data] = data
|
||||||
@ -70,6 +72,8 @@ module FastJsonapi
|
|||||||
private
|
private
|
||||||
|
|
||||||
def process_options(options)
|
def process_options(options)
|
||||||
|
@fieldsets = deep_symbolize(options[:fields].presence || {})
|
||||||
|
|
||||||
return if options.blank?
|
return if options.blank?
|
||||||
|
|
||||||
@known_included_objects = {}
|
@known_included_objects = {}
|
||||||
@ -85,6 +89,18 @@ module FastJsonapi
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def deep_symbolize(collection)
|
||||||
|
if collection.is_a? Hash
|
||||||
|
Hash[collection.map do |k, v|
|
||||||
|
[k.to_sym, deep_symbolize(v)]
|
||||||
|
end]
|
||||||
|
elsif collection.is_a? Array
|
||||||
|
collection.map { |i| deep_symbolize(i) }
|
||||||
|
else
|
||||||
|
collection.to_sym
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def is_collection?(resource, force_is_collection = nil)
|
def is_collection?(resource, force_is_collection = nil)
|
||||||
return force_is_collection unless force_is_collection.nil?
|
return force_is_collection unless force_is_collection.nil?
|
||||||
|
|
||||||
@ -104,6 +120,7 @@ module FastJsonapi
|
|||||||
subclass.race_condition_ttl = race_condition_ttl
|
subclass.race_condition_ttl = race_condition_ttl
|
||||||
subclass.data_links = data_links
|
subclass.data_links = data_links
|
||||||
subclass.cached = cached
|
subclass.cached = cached
|
||||||
|
subclass.fieldset = fieldset.dup if fieldset.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def reflected_record_type
|
def reflected_record_type
|
||||||
|
@ -21,7 +21,8 @@ module FastJsonapi
|
|||||||
:cache_length,
|
:cache_length,
|
||||||
:race_condition_ttl,
|
:race_condition_ttl,
|
||||||
:cached,
|
:cached,
|
||||||
:data_links
|
:data_links,
|
||||||
|
:fieldset
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -40,27 +41,30 @@ module FastJsonapi
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def attributes_hash(record, params = {})
|
def attributes_hash(record, fieldset = nil, params = {})
|
||||||
attributes_to_serialize.each_with_object({}) do |(_k, attribute), hash|
|
attributes = attributes_to_serialize
|
||||||
|
attributes = attributes.slice(*fieldset) if fieldset.present?
|
||||||
|
attributes.each_with_object({}) do |(_k, attribute), hash|
|
||||||
attribute.serialize(record, params, hash)
|
attribute.serialize(record, params, hash)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def relationships_hash(record, relationships = nil, params = {})
|
def relationships_hash(record, relationships = nil, fieldset = nil, params = {})
|
||||||
relationships = relationships_to_serialize if relationships.nil?
|
relationships = relationships_to_serialize if relationships.nil?
|
||||||
|
relationships = relationships.slice(*fieldset) if fieldset.present?
|
||||||
|
|
||||||
relationships.each_with_object({}) do |(_k, relationship), hash|
|
relationships.each_with_object({}) do |(_k, relationship), hash|
|
||||||
relationship.serialize(record, params, hash)
|
relationship.serialize(record, params, hash)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def record_hash(record, params = {})
|
def record_hash(record, fieldset, params = {})
|
||||||
if cached
|
if cached
|
||||||
record_hash = Rails.cache.fetch(record.cache_key, expires_in: cache_length, race_condition_ttl: race_condition_ttl) do
|
record_hash = Rails.cache.fetch(record.cache_key, expires_in: cache_length, race_condition_ttl: race_condition_ttl) do
|
||||||
temp_hash = id_hash(id_from_record(record), record_type, true)
|
temp_hash = id_hash(id_from_record(record), record_type, true)
|
||||||
temp_hash[:attributes] = attributes_hash(record, params) if attributes_to_serialize.present?
|
temp_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present?
|
||||||
temp_hash[:relationships] = {}
|
temp_hash[:relationships] = {}
|
||||||
temp_hash[:relationships] = relationships_hash(record, cachable_relationships_to_serialize, params) if cachable_relationships_to_serialize.present?
|
temp_hash[:relationships] = relationships_hash(record, cachable_relationships_to_serialize, fieldset, params) if cachable_relationships_to_serialize.present?
|
||||||
temp_hash[:links] = links_hash(record, params) if data_links.present?
|
temp_hash[:links] = links_hash(record, params) if data_links.present?
|
||||||
temp_hash
|
temp_hash
|
||||||
end
|
end
|
||||||
@ -68,8 +72,8 @@ module FastJsonapi
|
|||||||
record_hash
|
record_hash
|
||||||
else
|
else
|
||||||
record_hash = id_hash(id_from_record(record), record_type, true)
|
record_hash = id_hash(id_from_record(record), record_type, true)
|
||||||
record_hash[:attributes] = attributes_hash(record, params) if attributes_to_serialize.present?
|
record_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present?
|
||||||
record_hash[:relationships] = relationships_hash(record, nil, params) if relationships_to_serialize.present?
|
record_hash[:relationships] = relationships_hash(record, nil, fieldset, params) if relationships_to_serialize.present?
|
||||||
record_hash[:links] = links_hash(record, params) if data_links.present?
|
record_hash[:links] = links_hash(record, params) if data_links.present?
|
||||||
record_hash
|
record_hash
|
||||||
end
|
end
|
||||||
@ -100,7 +104,7 @@ module FastJsonapi
|
|||||||
end
|
end
|
||||||
|
|
||||||
# includes handler
|
# includes handler
|
||||||
def get_included_records(record, includes_list, known_included_objects, params = {})
|
def get_included_records(record, includes_list, known_included_objects, fieldsets, params = {})
|
||||||
return unless includes_list.present?
|
return unless includes_list.present?
|
||||||
|
|
||||||
includes_list.sort.each_with_object([]) do |include_item, included_records|
|
includes_list.sort.each_with_object([]) do |include_item, included_records|
|
||||||
@ -120,7 +124,7 @@ module FastJsonapi
|
|||||||
|
|
||||||
included_objects.each do |inc_obj|
|
included_objects.each do |inc_obj|
|
||||||
if remaining_items(items)
|
if remaining_items(items)
|
||||||
serializer_records = serializer.get_included_records(inc_obj, remaining_items(items), known_included_objects)
|
serializer_records = serializer.get_included_records(inc_obj, remaining_items(items), known_included_objects, fieldsets)
|
||||||
included_records.concat(serializer_records) unless serializer_records.empty?
|
included_records.concat(serializer_records) unless serializer_records.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -128,7 +132,8 @@ module FastJsonapi
|
|||||||
next if known_included_objects.key?(code)
|
next if known_included_objects.key?(code)
|
||||||
|
|
||||||
known_included_objects[code] = inc_obj
|
known_included_objects[code] = inc_obj
|
||||||
included_records << serializer.record_hash(inc_obj, params)
|
|
||||||
|
included_records << serializer.record_hash(inc_obj, fieldsets[serializer.reflected_record_type], params)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
36
spec/lib/object_serializer_fields_spec.rb
Normal file
36
spec/lib/object_serializer_fields_spec.rb
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe FastJsonapi::ObjectSerializer do
|
||||||
|
include_context 'movie class'
|
||||||
|
|
||||||
|
let(:fields) do
|
||||||
|
{
|
||||||
|
movie: %i[name actors],
|
||||||
|
actor: %i[name agency]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'only returns specified fields' do
|
||||||
|
hash = MovieSerializer.new(movie, fields: fields).serializable_hash
|
||||||
|
|
||||||
|
expect(hash[:data][:attributes].keys.sort).to eq %i[name]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'only returns specified relationships' do
|
||||||
|
hash = MovieSerializer.new(movie, fields: fields).serializable_hash
|
||||||
|
|
||||||
|
expect(hash[:data][:relationships].keys.sort).to eq %i[actors]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'only returns specified fields for included relationships' do
|
||||||
|
hash = MovieSerializer.new(movie, fields: fields, include: %i[actors]).serializable_hash
|
||||||
|
|
||||||
|
expect(hash[:included].first[:attributes].keys.sort).to eq %i[name]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'only returns specified relationships for included relationships' do
|
||||||
|
hash = MovieSerializer.new(movie, fields: fields, include: %i[actors]).serializable_hash
|
||||||
|
|
||||||
|
expect(hash[:included].first[:relationships].keys.sort).to eq %i[agency]
|
||||||
|
end
|
||||||
|
end
|
@ -64,7 +64,7 @@ describe FastJsonapi::ObjectSerializer do
|
|||||||
known_included_objects = {}
|
known_included_objects = {}
|
||||||
included_records = []
|
included_records = []
|
||||||
[movie, movie].each do |record|
|
[movie, movie].each do |record|
|
||||||
included_records.concat MovieSerializer.send(:get_included_records, record, includes_list, known_included_objects, nil)
|
included_records.concat MovieSerializer.send(:get_included_records, record, includes_list, known_included_objects, {}, nil)
|
||||||
end
|
end
|
||||||
expect(included_records.size).to eq 3
|
expect(included_records.size).to eq 3
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user