Make resource deserialization local. (#17)

This commit is contained in:
Lucas Hosseini 2017-07-25 07:56:40 +02:00 committed by GitHub
parent 046c1de821
commit 1707ec44f5
9 changed files with 109 additions and 157 deletions

View File

@ -35,9 +35,9 @@ module JSONAPI
new(payload).to_h
end
def initialize(payload)
@document = payload
@data = @document['data'] || {}
def initialize(payload, root: '/data')
@data = payload || {}
@root = root
@type = @data['type']
@id = @data['id']
@attributes = @data['attributes'] || {}
@ -58,7 +58,7 @@ module JSONAPI
def register_mappings(keys, path)
keys.each do |k|
@reverse_mapping[k] = path
@reverse_mapping[k] = @root + path
end
end
@ -74,7 +74,7 @@ module JSONAPI
return {} unless block
hash = block.call(@type)
register_mappings(hash.keys, '/data/type')
register_mappings(hash.keys, '/type')
hash
end
@ -83,7 +83,7 @@ module JSONAPI
return {} unless @id && block
hash = block.call(@id)
register_mappings(hash.keys, '/data/id')
register_mappings(hash.keys, '/id')
hash
end
@ -98,7 +98,7 @@ module JSONAPI
return {} unless block
hash = block.call(val, self.class.key_formatter.call(key))
register_mappings(hash.keys, "/data/attributes/#{key}")
register_mappings(hash.keys, "/attributes/#{key}")
hash
end
@ -125,7 +125,7 @@ module JSONAPI
id = val['data'] && val['data']['id']
type = val['data'] && val['data']['type']
hash = block.call(val, id, type, self.class.key_formatter.call(key))
register_mappings(hash.keys, "/data/relationships/#{key}")
register_mappings(hash.keys, "/relationships/#{key}")
hash
end
# rubocop: enable Metrics/AbcSize
@ -139,7 +139,7 @@ module JSONAPI
ids = val['data'].map { |ri| ri['id'] }
types = val['data'].map { |ri| ri['type'] }
hash = block.call(val, ids, types, self.class.key_formatter.call(key))
register_mappings(hash.keys, "/data/relationships/#{key}")
register_mappings(hash.keys, "/relationships/#{key}")
hash
end
# rubocop: enable Metrics/AbcSize

View File

@ -5,11 +5,9 @@ describe JSONAPI::Deserializable::Resource, '.attribute' do
context 'when a block is specified' do
it 'creates corresponding field' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => { 'foo' => 'bar' }
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attribute(:foo) { |foo| Hash[foo: foo] }
end
@ -23,11 +21,9 @@ describe JSONAPI::Deserializable::Resource, '.attribute' do
context 'when no block is specified' do
it 'defaults to creating a field with same name' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => { 'foo' => 'bar' }
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attribute(:foo)
end
@ -41,7 +37,7 @@ describe JSONAPI::Deserializable::Resource, '.attribute' do
context 'when attribute is absent' do
it 'does not create corresponding field if attribute is absent' do
payload = { 'data' => { 'type' => 'foo', 'attributes' => {} } }
payload = { 'type' => 'foo', 'attributes' => {} }
klass = Class.new(JSONAPI::Deserializable::Resource) do
attribute(:foo) { |foo| Hash[foo: foo] }
end
@ -54,7 +50,7 @@ describe JSONAPI::Deserializable::Resource, '.attribute' do
context 'when attributes member is absent' do
it 'does not create corresponding field if no attribute specified' do
payload = { 'data' => { 'type' => 'foo' } }
payload = { 'type' => 'foo' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
attribute(:foo) { |foo| Hash[foo: foo] }
end

View File

@ -5,11 +5,9 @@ describe JSONAPI::Deserializable::Resource, '.attributes' do
context 'when no keys are specified' do
it 'defaults to creating fields with same name' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'baz' => 'foo' }
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes
end
@ -23,11 +21,9 @@ describe JSONAPI::Deserializable::Resource, '.attributes' do
context 'when keys are specified' do
it 'creates fields with same name for whitelisted attributes' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'baz' => 'foo', 'bar' => 'foo' }
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes :foo, :baz
end
@ -43,11 +39,9 @@ describe JSONAPI::Deserializable::Resource, '.attributes' do
context 'when no keys are specified' do
it 'defaults to creating fields with same name' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'baz' => 'foo' }
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes do |val, key|
Hash["#{key}_attr".to_sym => val]
@ -63,11 +57,9 @@ describe JSONAPI::Deserializable::Resource, '.attributes' do
context 'when keys are specified' do
it 'creates customized fields for whitelisted attributes' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'baz' => 'foo', 'bar' => 'foo' }
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes(:foo, :baz) do |val, key|
Hash["#{key}_attr".to_sym => val]

View File

@ -12,7 +12,6 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
context 'relationship is not empty' do
let(:payload) do
{
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
@ -23,13 +22,12 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
}
}
}
}
end
it 'creates corresponding fields' do
actual = deserializable_foo.call(payload)
expected = { foo_ids: %w(bar baz), foo_types: %w(foo foo),
foo_rel: payload['data']['relationships']['foo'] }
foo_rel: payload['relationships']['foo'] }
expect(actual).to eq(expected)
end
@ -48,7 +46,6 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
context 'relationship is empty' do
it 'creates corresponding fields' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
@ -56,10 +53,9 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
}
}
}
}
actual = deserializable_foo.call(payload)
expected = { foo_ids: [], foo_types: [],
foo_rel: payload['data']['relationships']['foo'] }
foo_rel: payload['relationships']['foo'] }
expect(actual).to eq(expected)
end
@ -68,11 +64,9 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
context 'relationship is absent' do
it 'does not create corresponding fields' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {}
}
}
actual = deserializable_foo.call(payload)
expected = {}
@ -82,11 +76,7 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
context 'there is no relationships member' do
it 'does not create corresponding fields' do
payload = {
'data' => {
'type' => 'foo'
}
}
payload = { 'type' => 'foo' }
actual = deserializable_foo.call(payload)
expected = {}

View File

@ -12,7 +12,6 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
context 'relationship is not nil' do
let(:payload) do
{
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
@ -20,13 +19,12 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
}
}
}
}
end
it 'creates corresponding fields' do
actual = deserializable_foo.call(payload)
expected = { foo_id: 'bar', foo_type: 'foo',
foo_rel: payload['data']['relationships']['foo'] }
foo_rel: payload['relationships']['foo'] }
expect(actual).to eq(expected)
end
@ -45,7 +43,6 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
context 'relationship value is nil' do
it 'creates corresponding fields' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
@ -53,11 +50,10 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
}
}
}
}
actual = deserializable_foo.call(payload)
expected = { foo_id: nil, foo_type: nil,
foo_rel: payload['data']['relationships']['foo'] }
foo_rel: payload['relationships']['foo'] }
expect(actual).to eq(expected)
end
@ -66,11 +62,9 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
context 'relationship is absent' do
it 'does not create corresponding fields' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {}
}
}
actual = deserializable_foo.call(payload)
expected = {}
@ -80,11 +74,7 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
context 'there is no relationships member' do
it 'does not create corresponding fields' do
payload = {
'data' => {
'type' => 'foo'
}
}
payload = { 'type' => 'foo' }
actual = deserializable_foo.call(payload)
expected = {}

View File

@ -2,7 +2,7 @@ require 'spec_helper'
describe JSONAPI::Deserializable::Resource, '.id' do
it 'creates corresponding field if id is present' do
payload = { 'data' => { 'type' => 'foo', 'id' => 'bar' } }
payload = { 'type' => 'foo', 'id' => 'bar' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
id { |i| Hash[id: i] }
end
@ -13,7 +13,7 @@ describe JSONAPI::Deserializable::Resource, '.id' do
end
it 'does not create corresponding field if id is absent' do
payload = { 'data' => { 'type' => 'foo' } }
payload = { 'type' => 'foo' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
id { |i| Hash[id: i] }
end
@ -24,7 +24,7 @@ describe JSONAPI::Deserializable::Resource, '.id' do
end
it 'defaults to creating an id field' do
payload = { 'data' => { 'type' => 'foo', 'id' => 'bar' } }
payload = { 'type' => 'foo', 'id' => 'bar' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
id
end

View File

@ -5,7 +5,6 @@ describe JSONAPI::Deserializable::Resource, '.key_format' do
let(:payload) do
{
'data' => {
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'foo-bar' => 'baz' },
'relationships' => {
@ -17,7 +16,6 @@ describe JSONAPI::Deserializable::Resource, '.key_format' do
}
}
}
}
end
context 'when all fields are whitelisted' do

View File

@ -2,7 +2,7 @@ require 'spec_helper'
describe JSONAPI::Deserializable::Resource, '.type' do
it 'creates corresponding field' do
payload = { 'data' => { 'type' => 'foo' } }
payload = { 'type' => 'foo' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
type { |t| Hash[type: t] }
end
@ -13,7 +13,7 @@ describe JSONAPI::Deserializable::Resource, '.type' do
end
it 'defaults to creating a type field' do
payload = { 'data' => { 'type' => 'foo' } }
payload = { 'type' => 'foo' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
type
end

View File

@ -2,7 +2,7 @@ require 'spec_helper'
describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for default type' do
payload = { 'data' => { 'type' => 'foo' } }
payload = { 'type' => 'foo' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
type
end
@ -13,7 +13,7 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
end
it 'generates reverse mapping for overriden type' do
payload = { 'data' => { 'type' => 'foo' } }
payload = { 'type' => 'foo' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
type { |t| { custom_type: t } }
end
@ -24,7 +24,7 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
end
it 'generates reverse mapping for default id' do
payload = { 'data' => { 'type' => 'foo', 'id' => 'bar' } }
payload = { 'type' => 'foo', 'id' => 'bar' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
id
end
@ -35,7 +35,7 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
end
it 'generates reverse mapping for overriden id' do
payload = { 'data' => { 'type' => 'foo', 'id' => 'bar' } }
payload = { 'type' => 'foo', 'id' => 'bar' }
klass = Class.new(JSONAPI::Deserializable::Resource) do
id { |i| { custom_id: i } }
end
@ -47,14 +47,12 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for default attributes' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => {
'foo' => 'bar',
'baz' => 'fiz'
}
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes
end
@ -67,14 +65,12 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for locally overriden attributes' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => {
'foo' => 'bar',
'baz' => 'fiz'
}
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attribute(:foo) { |foo| { custom_foo: foo } }
end
@ -86,14 +82,12 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for globally overriden attributes' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => {
'foo' => 'bar',
'baz' => 'fiz'
}
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes do |value, key|
{ "custom_#{key}".to_sym => value }
@ -109,7 +103,6 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for default has_one' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
@ -120,7 +113,6 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
}
}
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
has_one
end
@ -135,7 +127,6 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for overriden has_one' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
@ -146,7 +137,6 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
}
}
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
has_one do |_val, id, type, key|
{ "custom_#{key}_id".to_sym => id,
@ -169,7 +159,6 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for default has_many' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
@ -180,7 +169,6 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
}
}
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
has_many
end
@ -195,7 +183,6 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for overriden has_many' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
@ -206,7 +193,6 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
}
}
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
has_many do |_val, ids, types, key|
{ "custom_#{key}_ids".to_sym => ids,