jsonapi-deserializable 0.1.1.beta2 → 0.1.1.beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 93ceb39a5f3d032a99748170ac818e096e691d05
4
- data.tar.gz: adfdd698f25de948e225c87087f850376d900f09
3
+ metadata.gz: f3004871b4ea0f17caaeab2c1f000c632337c486
4
+ data.tar.gz: 4eb06414674e45c45fc3d276ffa966bc97313ae7
5
5
  SHA512:
6
- metadata.gz: 52f05a26b475cf2afa912ab7e3e207f4d925c32e58c5ba99edfc8a52685c5c536ecdc8d8e0e7e2d06d44916be0b1af383ba035339c87754824a0988cf93ce48c
7
- data.tar.gz: aa7bfa1f75f1ec8bd00dc69025dffbc7127874b86f946dd1489798837727630df4a15a9410cb8047a26c195b6b6082e185bb3d9770cc586668d9b52f274c5769
6
+ metadata.gz: fdf14b9d40b30ea331a01b10212be3b5582785e45634ab7e49e2d81957a4408af6ce838d05dc27e9d86828a704cef1a2eb23e5331d2c13d4fa131829c6a4c03e
7
+ data.tar.gz: ee5342f0d5444e68773e504353000090dc71117fba3eee3a0af21399c32836085eab9f8076dd70a2cfe54385a85f9140c692007199f12b70ef60315ca76cad64
data/README.md CHANGED
@@ -1,8 +1,11 @@
1
1
  # jsonapi-deserializable
2
- Ruby gem for validating and deserializing [JSON API](http://jsonapi.org)
3
- payloads into custom hashes.
4
- Built upon the [jsonapi-validations](https://github.com/beauby/jsonapi/tree/master/validations)
5
- gem.
2
+ Ruby gem for deserializing [JSON API](http://jsonapi.org) payloads into custom
3
+ hashes.
4
+
5
+ ## Status
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/jsonapi-deserializable.svg)](https://badge.fury.io/rb/jsonapi-deserializable)
8
+ [![Build Status](https://secure.travis-ci.org/beauby/jsonapi-deserializable.svg?branch=master)](http://travis-ci.org/beauby/jsonapi-deserializable?branch=master)
6
9
 
7
10
  ## Installation
8
11
  ```ruby
@@ -26,54 +29,23 @@ require 'jsonapi/deserializable'
26
29
  ```
27
30
 
28
31
  Then, define some resource/relationship classes:
29
- ```ruby
30
- class DeserializableUser < JSONAPI::Deserializable::Resource
31
- # List of required attributes / has_many/has_one relationships.
32
- # This directive is not mandatory. If not declared, no field
33
- # will be required.
34
- required do
35
- id # Optional, require an id for the primary resource.
36
-
37
- type :users # Optional, force a type for the primary resource.
38
- # or, still optional, force a set of allowed types for the primary resource:
39
- types [:users, :superusers] # Optional,
40
-
41
- attribute :name
42
- has_one :sponsor
43
- # or, optionally, spcecify a type for the relationship target:
44
- has_one :sponsor, :users
45
- end
46
-
47
- # List of optional attributes / has_many/has_one relationships.
48
- # This directive is not mandatory. If not declared, all fields
49
- # will be allowed. If declared, all fields that are not within
50
- # eitheroptional or required will be rejected.
51
- optional do
52
- attribute :address
53
- has_many :posts
54
- # or, optionally, specify a set of allowed types for the primary resource:
55
- has_many :posts, [:posts, :blogs]
56
- end
57
-
58
- ## The actual fields of the generated hash.
59
- # `attribute` is a shorthand for `field(key) { @attributes.send(key) }`.
60
- attribute :address
61
-
62
- field :id do
63
- @data.id
64
- end
65
32
 
66
- # `field` is the standard method for defining a key on the result hash.
67
- field :username do
68
- @document.data.attributes.name
69
- end
33
+ ### Resources
70
34
 
71
- field :post_ids do
72
- @relationships.posts.data.map(&:id)
35
+ ```ruby
36
+ class DeserializableCreatePost < JSONAPI::Deserializable::Resource
37
+ type
38
+ attribute :title
39
+ attribute :date { |date| field date: DateTime.parse(date) }
40
+ has_one :author do |rel, id, type|
41
+ field author_id: id
42
+ field author_type: type
73
43
  end
74
-
75
- field :sponsor_id do
76
- @relationships.sponsor.data && @relationships.sponsor.data.id
44
+ has_many :comments do |rel, ids, types|
45
+ field comment_ids: ids
46
+ field comment_types: types.map do |type|
47
+ camelize(singularize(type))
48
+ end
77
49
  end
78
50
  end
79
51
  ```
@@ -82,35 +54,52 @@ Finally, build your hash from the deserializable resource:
82
54
  payload = {
83
55
  'data' => {
84
56
  'id' => '1',
85
- 'type' => 'users',
57
+ 'type' => 'posts',
86
58
  'attributes' => {
87
- 'name' => 'Name',
88
- 'address' => 'Address'
59
+ 'title' => 'Title',
60
+ 'date' => '2016-01-10 02:30:00'
89
61
  },
90
62
  'relationships' => {
91
- 'sponsor' => {
63
+ 'author' => {
92
64
  'data' => { 'type' => 'users', 'id' => '1337' }
93
65
  },
94
- 'posts' => {
66
+ 'comments' => {
95
67
  'data' => [
96
- { 'type' => 'posts', 'id' => '123' },
97
- { 'type' => 'posts', 'id' => '234' },
98
- { 'type' => 'posts', 'id' => '345' }
68
+ { 'type' => 'comments', 'id' => '123' },
69
+ { 'type' => 'comments', 'id' => '234' },
70
+ { 'type' => 'comments', 'id' => '345' }
99
71
  ]
100
72
  }
101
73
  }
102
74
  }
103
75
  }
104
76
 
105
- DeserializableUser.new(payload).to_h
77
+ DeserializableCreateUser.(payload)
106
78
  # => {
107
- # username: 'Name',
108
- # address: 'Address',
109
- # sponsor_id: '1337',
110
- # post_ids: ['123', '234', '345']
79
+ # id: '1',
80
+ # title: 'Title',
81
+ # date: #<DateTime: 2016-01-10T02:30:00+00:00 ((2457398j,9000s,0n),+0s,2299161j)>,
82
+ # author_id: '1337',
83
+ # author_type: 'users',
84
+ # comment_ids: ['123', '234', '345']
85
+ # comment_types: ['Comment', 'Comment', 'Comment']
111
86
  # }
112
87
  ```
113
88
 
89
+ ### Relationships
90
+
91
+ ```
92
+ class DeserializablePostComments < JSONAPI::Deserializable::Relationship
93
+ has_many do |rel, ids, types|
94
+ field comment_ids: ids
95
+ field comment_types: types.map do |ri|
96
+ camelize(singularize(type))
97
+ end
98
+ field comments_meta: rel['meta']
99
+ end
100
+ end
101
+ ```
102
+
114
103
  ## License
115
104
 
116
105
  jsonapi-deserializable is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -1,3 +1,2 @@
1
- require 'jsonapi/deserializable/exceptions'
2
1
  require 'jsonapi/deserializable/relationship'
3
2
  require 'jsonapi/deserializable/resource'
@@ -1,4 +1,3 @@
1
- require 'jsonapi/deserializable/exceptions'
2
1
  require 'jsonapi/deserializable/relationship_dsl'
3
2
 
4
3
  module JSONAPI
@@ -7,31 +6,45 @@ module JSONAPI
7
6
  include RelationshipDSL
8
7
 
9
8
  class << self
10
- attr_accessor :field_blocks, :validations
9
+ attr_accessor :has_one_block, :has_many_block
11
10
  end
12
11
 
13
- self.field_blocks = {}
14
- self.validations = {}
15
-
16
12
  def self.inherited(klass)
17
- klass.field_blocks = field_blocks.dup
18
- klass.validations = Marshal.load(Marshal.dump(validations))
13
+ klass.has_one_block = has_one_block
14
+ klass.has_many_block = has_many_block
15
+ end
16
+
17
+ def self.call(payload)
18
+ new(payload).to_h
19
19
  end
20
20
 
21
21
  def initialize(payload)
22
- JSONAPI.validate_relationship!(payload, validations)
23
22
  @document = payload
24
23
  @data = payload['data']
24
+ deserialize!
25
25
  end
26
26
 
27
27
  def to_h
28
- return nil if @data.nil?
29
- return @_hash if @_hash
30
- @_hash = {}
31
- self.class.field_blocks.each do |key, block|
32
- @_hash[key] = instance_eval(&block)
28
+ @hash
29
+ end
30
+
31
+ private
32
+
33
+ def deserialize!
34
+ @hash = {}
35
+ if @data.is_a?(Array)
36
+ ids = @data.map { |ri| ri['id'] }
37
+ types = @data.map { |ri| ri['type'] }
38
+ instance_exec(@document, ids, types, &self.class.has_many_block)
39
+ else
40
+ id = @data && @data['id']
41
+ type = @data && @data['type']
42
+ instance_exec(@document, id, type, &self.class.has_one_block)
33
43
  end
34
- @_hash
44
+ end
45
+
46
+ def field(hash)
47
+ @hash.merge!(hash)
35
48
  end
36
49
  end
37
50
  end
@@ -6,24 +6,14 @@ module JSONAPI
6
6
  end
7
7
 
8
8
  module ClassMethods
9
- def has_one
10
- validations[:kind] = :has_one
9
+ def has_one(&block)
10
+ block ||= proc { |rel| field key.to_sym => rel }
11
+ self.has_one_block = block
11
12
  end
12
13
 
13
- def has_many
14
- validations[:kind] = :has_many
15
- end
16
-
17
- def type(value)
18
- (validations[:types] ||= []) << value
19
- end
20
-
21
- def types(values)
22
- (validations[:types] ||= []).concat(values)
23
- end
24
-
25
- def field(key, &block)
26
- field_blocks[key] = block
14
+ def has_many(&block)
15
+ block ||= proc { |rel| field key.to_sym => rel }
16
+ self.has_many_block = block
27
17
  end
28
18
  end
29
19
  end
@@ -1,5 +1,3 @@
1
- require 'jsonapi/validations'
2
- require 'jsonapi/deserializable/exceptions'
3
1
  require 'jsonapi/deserializable/resource_dsl'
4
2
 
5
3
  module JSONAPI
@@ -8,36 +6,104 @@ module JSONAPI
8
6
  include ResourceDSL
9
7
 
10
8
  class << self
11
- attr_accessor :field_blocks, :validations
9
+ attr_accessor :type_block, :id_block
10
+ attr_accessor :attr_blocks
11
+ attr_accessor :has_one_rel_blocks, :has_many_rel_blocks
12
12
  end
13
13
 
14
- self.field_blocks = {}
15
- self.validations = {}
14
+ self.attr_blocks = {}
15
+ self.has_one_rel_blocks = {}
16
+ self.has_many_rel_blocks = {}
16
17
 
17
18
  def self.inherited(klass)
18
19
  super
19
- klass.field_blocks = field_blocks.dup
20
- klass.validations = Marshal.load(Marshal.dump(validations))
20
+ klass.type_block = type_block
21
+ klass.id_block = id_block
22
+ klass.attr_blocks = attr_blocks.dup
23
+ klass.has_one_rel_blocks = has_one_rel_blocks.dup
24
+ klass.has_many_rel_blocks = has_many_rel_blocks.dup
25
+ end
26
+
27
+ def self.call(payload)
28
+ new(payload).to_h
21
29
  end
22
30
 
23
31
  def initialize(payload)
24
- JSONAPI.validate_resource!(payload, self.class.validations)
25
32
  @document = payload
26
33
  @data = @document['data']
27
- @attributes = @data['attributes']
28
- @relationships = @data['relationships']
34
+ @type = @data['type']
35
+ @id = @data['id']
36
+ @attributes = @data['attributes'] || {}
37
+ @relationships = @data['relationships'] || {}
38
+ deserialize!
29
39
  end
30
40
 
31
41
  def to_h
32
- return @_hash if @_hash
42
+ @hash
43
+ end
44
+
45
+ private
46
+
47
+ def deserialize!
48
+ @hash = {}
49
+ deserialize_type!
50
+ deserialize_id!
51
+ deserialize_attrs!
52
+ deserialize_rels!
53
+ end
33
54
 
34
- @_hash = {}
35
- @_hash[:_payload] = @document
36
- self.class.field_blocks.map do |k, v|
37
- @_hash[k] = instance_eval(&v)
55
+ def deserialize_type!
56
+ return unless @type && self.class.type_block
57
+ instance_exec(@type, &self.class.type_block)
58
+ end
59
+
60
+ def deserialize_id!
61
+ return unless @id && self.class.id_block
62
+ instance_exec(@id, &self.class.id_block)
63
+ end
64
+
65
+ def deserialize_attrs!
66
+ self.class.attr_blocks.each do |attr, block|
67
+ next unless @attributes.key?(attr)
68
+ instance_exec(@attributes[attr], &block)
38
69
  end
70
+ end
71
+
72
+ def deserialize_rels!
73
+ deserialize_has_one_rels!
74
+ deserialize_has_many_rels!
75
+ end
76
+
77
+ def deserialize_has_one_rels!
78
+ self.class.has_one_rel_blocks.each do |key, block|
79
+ rel = @relationships[key]
80
+ next unless rel && (rel['data'].nil? || rel['data'].is_a?(Hash))
81
+ deserialize_has_one_rel!(rel, &block)
82
+ end
83
+ end
84
+
85
+ def deserialize_has_one_rel!(rel, &block)
86
+ id = rel['data'] && rel['data']['id']
87
+ type = rel['data'] && rel['data']['type']
88
+ instance_exec(rel, id, type, &block)
89
+ end
90
+
91
+ def deserialize_has_many_rels!
92
+ self.class.has_many_rel_blocks.each do |key, block|
93
+ rel = @relationships[key]
94
+ next unless rel && rel['data'].is_a?(Array)
95
+ deserialize_has_many_rel!(rel, &block)
96
+ end
97
+ end
98
+
99
+ def deserialize_has_many_rel!(rel, &block)
100
+ ids = rel['data'].map { |ri| ri['id'] }
101
+ types = rel['data'].map { |ri| ri['type'] }
102
+ instance_exec(rel, ids, types, &block)
103
+ end
39
104
 
40
- @_hash
105
+ def field(hash)
106
+ @hash.merge!(hash)
41
107
  end
42
108
  end
43
109
  end
@@ -1,5 +1,3 @@
1
- require 'jsonapi/deserializable/validations'
2
-
3
1
  module JSONAPI
4
2
  module Deserializable
5
3
  module ResourceDSL
@@ -8,65 +6,32 @@ module JSONAPI
8
6
  end
9
7
 
10
8
  module ClassMethods
11
- def required(&block)
12
- add_validations!(Validations.new(:required, &block).to_h)
13
- end
14
-
15
- def optional(&block)
16
- add_validations!(Validations.new(:optional, &block).to_h)
17
- end
18
-
19
- def field(key, &block)
20
- field_blocks[key] = block
21
- end
22
-
23
- def id
24
- field(:id) { @data['id'] }
9
+ def type(&block)
10
+ block ||= proc { |type| field type: type }
11
+ self.type_block = block
25
12
  end
26
13
 
27
- def attribute(key, opts = {})
28
- hash_key = (opts[:key] || key).to_s
29
- field(key) { @attributes[hash_key] }
14
+ def id(&block)
15
+ block ||= proc { |id| field id: id }
16
+ self.id_block = block
30
17
  end
31
18
 
32
- def has_many_ids(key, opts = {})
33
- hash_key = (opts[:key] || key).to_s
34
- field(key) do
35
- @relationships[hash_key]['data'].map { |ri| ri['id'] }
19
+ def attribute(key, options = {}, &block)
20
+ unless block
21
+ options[:key] ||= key.to_sym
22
+ block = proc { |attr| field key => attr }
36
23
  end
24
+ attr_blocks[key.to_s] = block
37
25
  end
38
26
 
39
- def has_many_types(key, opts = {})
40
- hash_key = (opts[:key] || key).to_s
41
- field(key) do
42
- @relationships[hash_key]['data'].map { |ri| ri['type'] }
43
- end
44
- end
45
-
46
- def has_one_id(key, opts = {})
47
- hash_key = (opts[:key] || key).to_s
48
- field(key) { @relationships[hash_key]['data']['id'] }
27
+ def has_one(key, &block)
28
+ block ||= proc { |rel| field key.to_sym => rel }
29
+ has_one_rel_blocks[key.to_s] = block
49
30
  end
50
31
 
51
- def has_one_type(key, opts = {})
52
- hash_key = (opts[:key] || key).to_s
53
- field(key) { @relationships[hash_key]['data']['type'] }
54
- end
55
-
56
- private
57
-
58
- def add_validations!(hash)
59
- validations[:permitted] = hash[:permitted] if hash[:permitted]
60
- validations[:required] = hash[:required] if hash[:required]
61
- return unless hash[:types]
62
- validations[:types] ||= {}
63
- if hash[:types][:primary]
64
- validations[:types][:primary] = hash[:types][:primary]
65
- end
66
- return unless hash[:types][:relationships]
67
- validations[:types][:relationships] ||= {}
68
- validations[:types][:relationships]
69
- .merge!(hash[:types][:relationships])
32
+ def has_many(key, &block)
33
+ block ||= proc { |rel| field key.to_sym => rel }
34
+ has_many_rel_blocks[key.to_s] = block
70
35
  end
71
36
  end
72
37
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-deserializable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1.beta2
4
+ version: 0.1.1.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Hosseini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-02 00:00:00.000000000 Z
11
+ date: 2016-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: jsonapi-validations
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '0.1'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '0.1'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rake
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -61,14 +47,11 @@ extra_rdoc_files: []
61
47
  files:
62
48
  - README.md
63
49
  - lib/jsonapi/deserializable.rb
64
- - lib/jsonapi/deserializable/document_validator.rb
65
- - lib/jsonapi/deserializable/exceptions.rb
66
50
  - lib/jsonapi/deserializable/relationship.rb
67
51
  - lib/jsonapi/deserializable/relationship_dsl.rb
68
52
  - lib/jsonapi/deserializable/resource.rb
69
53
  - lib/jsonapi/deserializable/resource/dsl.rb
70
54
  - lib/jsonapi/deserializable/resource_dsl.rb
71
- - lib/jsonapi/deserializable/validations.rb
72
55
  homepage: https://github.com/beauby/jsonapi-deserializable
73
56
  licenses:
74
57
  - MIT
@@ -1,200 +0,0 @@
1
- require 'jsonapi/deserializable/field_list'
2
-
3
- module JSONAPI
4
- module Deserializable
5
- class DocumentValidator
6
- def self.validate!(payload, required_list, optional_list)
7
- new(payload, required_list, optional_list).validate!
8
- end
9
-
10
- def initialize(document, required, optional)
11
- whitelist = {
12
- id: :optional,
13
- types: [],
14
- attributes: {
15
- foo: :required,
16
- bar: :optional
17
- },
18
- relationships: {
19
- foobar: :required,
20
- barfoo: {
21
- required: true,
22
- types: [:baz],
23
- arity: :to_many
24
- }
25
- }
26
- }
27
-
28
-
29
- arities = {
30
- foobar: :to_many,
31
- barfoo: :to_one
32
- }
33
- types = {
34
- primary: [],
35
- relationships: {
36
- foobar: [:baz],
37
- barfoo: [:bazbaz]
38
- }
39
- }
40
- required: true,
41
- types: [:baz],
42
- arity: :to_many
43
- }
44
- }
45
- }
46
- @document = document
47
- @required = required || {}
48
- @optional = optional
49
- @fields = {}
50
- @fields[:primary_id] = true if @required[:primary_id]
51
- primary_types = @required[:primary_types]
52
- @fields[:primary_types] = primary_types if primary_types
53
- @fields[:attributes] = @required[:attributes].dup
54
- @fields[:relationships] = @required[:relationships].dup
55
- if @optional
56
- @fields[:primary_id] = true if @optional[:primary_id]
57
- primary_types = @optional[:primary_types]
58
- @fields[:primary_types] = primary_types if primary_types
59
- @fields[:attributes].merge
60
- end
61
- end
62
-
63
- def validate!
64
- raise INVALID_DOCUMENT unless @document.data
65
- @data = @document.data
66
- if @data.respond_to?(:each)
67
- raise INVALID_DOCUMENT, 'The request MUST include a single resource' \
68
- ' object as primary data'
69
- end
70
- @attributes = @data.attributes
71
- @relationships = @data.relationships
72
- validate_primary!
73
- validate_fields!
74
- end
75
-
76
- def validate_primary!
77
- validate_id!
78
- validate_type!
79
- end
80
-
81
- def id_required?
82
- @required[:primary_id]
83
- end
84
-
85
- def id_permitted?
86
- @fields[:primary_id]
87
- end
88
-
89
- def validate_id!
90
- if @data.id.nil?
91
- raise INVALID_DOCUMENT,
92
- 'Expected id for primary resource' if id_required?
93
- else
94
- raise INVALID_DOCUMENT,
95
- 'Unexpected id for primary resource' unless id_permitted?
96
- end
97
- end
98
-
99
- def type_valid?
100
- return false if @required &&
101
- @required[:primary_types] &&
102
- !@required[:primary_types].include?(@data.type.to_sym)
103
- return false if @optional &&
104
- @optional[:primary_types] &&
105
- !@optional[:primary_types].include?(@data.type.to_sym)
106
- true
107
- end
108
-
109
- def validate_type!
110
- return if type_valid?
111
- raise INVALID_DOCUMENT,
112
- "Unexpected type #{@data.type} for primary resource"
113
- end
114
-
115
- def validate_fields!
116
- validate_attributes!
117
- validate_relationships!
118
- end
119
-
120
- def attr_permitted?(attr_key)
121
- return true unless @optional
122
- return true if @optional[:attributes].include?(attr_key.to_sym)
123
- @required && @required[:attributes].include?(attr_key.to_sym)
124
- end
125
-
126
- def validate_attributes!
127
- @attributes.keys.each do |attr_key|
128
- next if attr_permitted?(attr_key)
129
- raise INVALID_DOCUMENT, "Unexpected attribute #{attr_key}"
130
- end
131
- return unless @required
132
- @required[:attributes].each do |attr_key|
133
- next if @attributes.defined?(attr_key)
134
- raise INVALID_DOCUMENT, "Expected attribute #{attr_key}"
135
- end
136
- end
137
-
138
- def rel_permitted?(rel_key)
139
- return true unless @optional
140
- return true if @optional[:relationships].key?(rel_key.to_sym)
141
- @required && @required[:relationships].key?(rel_key.to_sym)
142
- end
143
-
144
- def validate_relationships!
145
- @relationships.keys.each do |rel_key|
146
- next if rel_permitted?(rel_key)
147
- raise INVALID_DOCUMENT, "Unexpected relationship #{rel_key}"
148
- end
149
- return unless @required
150
- @required[:relationships].keys.each do |rel_key|
151
- next if @relationships.defined?(rel_key)
152
- raise INVALID_DOCUMENT, "Expected relationship #{rel_key}"
153
- end
154
- validate_relationship_types!
155
- end
156
-
157
- def validate_relationship_types!
158
- rels = {}
159
- rels.merge!(@required.relationships) if @required
160
- rels.merge(@optional.relationships) if @optional
161
- rels.each do |key, hash|
162
- rel = @relationships[key.to_s]
163
- unless rel.data
164
- raise INVALID_DOCUMENT, "Expected data for relationship #{key}"
165
- end
166
-
167
- if hash[:arity] == :to_one
168
- validate_to_one_relationship_type!(rel, hash[:types])
169
- else
170
- validate_to_many_relationship_type!(rel, hash[:types])
171
- end
172
- end
173
- end
174
-
175
- def validate_to_one_relationship_type!(rel, types)
176
- if rel.collection?
177
- raise INVALID_DOCUMENT,
178
- "Expected relationship #{key} to be has_one"
179
- end
180
- return unless types && !types.include?(rel.data.type.to_sym)
181
- raise INVALID_DOCUMENT, "Unexpected type: #{rel.data.type} for " \
182
- "relationship #{key}"
183
- end
184
-
185
- def validate_to_many_relationship_type!(rel, types)
186
- unless rel.collection?
187
- raise INVALID_DOCUMENT,
188
- "Expected relationship #{key} to be has_many"
189
- end
190
- return unless types
191
- rel.data.each do |ri|
192
- unless types.include?(ri.type.to_sym)
193
- raise INVALID_DOCUMENT, "Unexpected type: #{ri.type} for " \
194
- "relationship #{key}"
195
- end
196
- end
197
- end
198
- end
199
- end
200
- end
@@ -1,7 +0,0 @@
1
- require 'jsonapi/parser/exceptions'
2
-
3
- module JSONAPI
4
- module Deserializable
5
- INVALID_DOCUMENT = JSONAPI::Parser::InvalidDocument
6
- end
7
- end
@@ -1,101 +0,0 @@
1
- module JSONAPI
2
- module Deserializable
3
- class Validations
4
- def initialize(validation_type, &block)
5
- @validation_type = validation_type
6
- @hash = {
7
- @validation_type => {
8
- attributes: [],
9
- relationships: []
10
- },
11
- types: {
12
- relationships: {}
13
- }
14
- }
15
- instance_eval(&block)
16
- end
17
-
18
- def to_h
19
- @hash
20
- end
21
-
22
- private
23
-
24
- # Define whether the +id+ of the primary resource should be part of
25
- # this list.
26
- def id
27
- validations_hash[:id] = true
28
- end
29
-
30
- # Define the allowed type for the primary resource.
31
- # @param [Symbol] value The value of the type.
32
- def type(value)
33
- types_hash[:primary] = Array(value)
34
- end
35
-
36
- # Define the allowed type for the primary resource.
37
- # @param [Array<Symbol>] values List of allowed values of the type.
38
- def types(values)
39
- types_hash[:primary] = values
40
- end
41
-
42
- # Define an attribute with given key.
43
- # @param [Symbol] key The key of the attribute in the payload.
44
- def attribute(key)
45
- validations_hash[:attributes] << key
46
- end
47
-
48
- # TODO(beauby): Decide whether type: 'users' / types: [...] is better.
49
- #
50
- # @overload has_one(key)
51
- # Define a has_one relationship with given key.
52
- # @param [Symbol] key The key of the relationship in the payload.
53
- #
54
- # @overload has_one(key, type)
55
- # Define a has_one relationship with given key.
56
- # @param [Symbol] key The key of the relationship in the payload.
57
- # @param [Symbol] type The expected type of the relationship value.
58
- #
59
- # @overload has_one(key, types)
60
- # Define a has_one relationship with given key.
61
- # @param [Symbol] key The key of the relationship in the payload.
62
- # @param [Array<Symbol>] type List of acceptable types for the
63
- # relationship value.
64
- def has_many(key, types = nil)
65
- validations_hash[:relationships] << key
66
- types_hash[:relationships][key] = { kind: :has_many }
67
- return unless types
68
- types_hash[:relationships][key][:types] = Array(types)
69
- end
70
-
71
- # @overload has_one(key)
72
- # Define a has_one relationship with given key.
73
- # @param [Symbol] key The key of the relationship in the payload.
74
- #
75
- # @overload has_one(key, type)
76
- # Define a has_one relationship with given key.
77
- # @param [Symbol] key The key of the relationship in the payload.
78
- # @param [Symbol] type The expected type of the relationship value.
79
- #
80
- # @overload has_one(key, types)
81
- # Define a has_one relationship with given key.
82
- # @param [Symbol] key The key of the relationship in the payload.
83
- # @param [Array<Symbol>] type List of acceptable types for the
84
- # relationship value.
85
- def has_one(key, types = nil)
86
- validations_hash[:relationships] << key
87
- types_hash[:relationships][key] = { kind: :has_one }
88
- return unless types
89
- types_hash[:relationships][key][:types] = Array(types)
90
- end
91
-
92
- def validations_hash
93
- @hash[@validation_type]
94
- end
95
-
96
- def types_hash
97
- @hash[:types]
98
- end
99
- end
100
- end
101
- end