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,10 +5,8 @@ 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' }
}
'type' => 'foo',
'attributes' => { 'foo' => 'bar' }
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attribute(:foo) { |foo| Hash[foo: foo] }
@ -23,10 +21,8 @@ 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' }
}
'type' => 'foo',
'attributes' => { 'foo' => 'bar' }
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attribute(:foo)
@ -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,10 +5,8 @@ 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' }
}
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'baz' => 'foo' }
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes
@ -23,10 +21,8 @@ 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' }
}
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'baz' => 'foo', 'bar' => 'foo' }
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes :foo, :baz
@ -43,10 +39,8 @@ 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' }
}
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'baz' => 'foo' }
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes do |val, key|
@ -63,10 +57,8 @@ 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' }
}
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'baz' => 'foo', 'bar' => 'foo' }
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
attributes(:foo, :baz) do |val, key|

View File

@ -12,15 +12,13 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
context 'relationship is not empty' do
let(:payload) do
{
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => [
{ 'type' => 'foo', 'id' => 'bar' },
{ 'type' => 'foo', 'id' => 'baz' }
]
}
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => [
{ 'type' => 'foo', 'id' => 'bar' },
{ 'type' => 'foo', 'id' => 'baz' }
]
}
}
}
@ -29,7 +27,7 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
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,18 +46,16 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
context 'relationship is empty' do
it 'creates corresponding fields' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => []
}
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => []
}
}
}
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,10 +64,8 @@ describe JSONAPI::Deserializable::Resource, '.has_many' do
context 'relationship is absent' do
it 'does not create corresponding fields' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {}
}
'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,12 +12,10 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
context 'relationship is not nil' do
let(:payload) do
{
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => { 'type' => 'foo', 'id' => 'bar' }
}
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => { 'type' => 'foo', 'id' => 'bar' }
}
}
}
@ -26,7 +24,7 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
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,19 +43,17 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
context 'relationship value is nil' do
it 'creates corresponding fields' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => nil
}
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => nil
}
}
}
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,10 +62,8 @@ describe JSONAPI::Deserializable::Resource, '.has_one' do
context 'relationship is absent' do
it 'does not create corresponding fields' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {}
}
'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,16 +5,14 @@ describe JSONAPI::Deserializable::Resource, '.key_format' do
let(:payload) do
{
'data' => {
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'foo-bar' => 'baz' },
'relationships' => {
'baz' => {
'data' => nil
},
'bar-baz' => {
'data' => []
}
'type' => 'foo',
'attributes' => { 'foo' => 'bar', 'foo-bar' => 'baz' },
'relationships' => {
'baz' => {
'data' => nil
},
'bar-baz' => {
'data' => []
}
}
}

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,12 +47,10 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for default attributes' do
payload = {
'data' => {
'type' => 'foo',
'attributes' => {
'foo' => 'bar',
'baz' => 'fiz'
}
'type' => 'foo',
'attributes' => {
'foo' => 'bar',
'baz' => 'fiz'
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
@ -67,12 +65,10 @@ 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'
}
'type' => 'foo',
'attributes' => {
'foo' => 'bar',
'baz' => 'fiz'
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
@ -86,12 +82,10 @@ 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'
}
'type' => 'foo',
'attributes' => {
'foo' => 'bar',
'baz' => 'fiz'
}
}
klass = Class.new(JSONAPI::Deserializable::Resource) do
@ -109,15 +103,13 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for default has_one' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => nil
},
'baz' => {
'data' => nil
}
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => nil
},
'baz' => {
'data' => nil
}
}
}
@ -135,15 +127,13 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for overriden has_one' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => nil
},
'baz' => {
'data' => nil
}
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => nil
},
'baz' => {
'data' => nil
}
}
}
@ -169,15 +159,13 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for default has_many' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => []
},
'baz' => {
'data' => []
}
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => []
},
'baz' => {
'data' => []
}
}
}
@ -195,15 +183,13 @@ describe JSONAPI::Deserializable::Resource, '#reverse_mapping' do
it 'generates reverse mapping for overriden has_many' do
payload = {
'data' => {
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => []
},
'baz' => {
'data' => []
}
'type' => 'foo',
'relationships' => {
'foo' => {
'data' => []
},
'baz' => {
'data' => []
}
}
}