roar-jsonapi 0.0.1

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.
@@ -0,0 +1,161 @@
1
+ require 'test_helper'
2
+ require 'roar/json/json_api'
3
+
4
+ class FieldsetsOptionsTest < Minitest::Spec
5
+ Include = Roar::JSON::JSONAPI::Options::Include
6
+
7
+ describe 'with non-empty :include and non-empty :fields option' do
8
+ it 'rewrites :include and parses :fields' do
9
+ [{ include: [:articles],
10
+ fields: { articles: [:title, :body], people: [] } },
11
+ { include: ['articles'],
12
+ fields: { articles: ['title,body'], people: [] } },
13
+ { include: 'articles',
14
+ fields: { 'articles' => 'title,body', 'people' => '' } }].each do |options|
15
+ options = Include.(options, relationships: { 'articles' => 'articles' })
16
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
17
+ included: {
18
+ include: [:articles],
19
+ articles: {
20
+ include: [:id, :attributes, :relationships],
21
+ attributes: { include: [:title, :body] },
22
+ relationships: { include: [:title, :body] },
23
+ _json_api_parsed: true
24
+ },
25
+ people: {
26
+ attributes: { include: [] },
27
+ relationships: { include: [] },
28
+ _json_api_parsed: true
29
+ }
30
+ })
31
+ end
32
+ end
33
+ end
34
+
35
+ describe 'with empty :include option' do
36
+ it 'rewrites :include' do
37
+ [{ include: [] },
38
+ { include: [''] },
39
+ { include: '' }].each do |options|
40
+ options = Include.(options, {})
41
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
42
+ included: { include: [] })
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'with empty :include option and non-empty :fields option' do
48
+ it 'parses :fields (_self), but does not include other resources' do
49
+ [{ include: [], fields: { articles: [:title, :body], people: [] } },
50
+ { include: [''], fields: { articles: ['title,body'], people: [] } },
51
+ { include: '', fields: { 'articles' => 'title,body', 'people' => '' } }].each do |options|
52
+ options = Include.(options, relationships: { '_self' => 'articles' })
53
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
54
+ included: {
55
+ include: [],
56
+ people: {
57
+ attributes: { include: [] },
58
+ relationships: { include: [] },
59
+ _json_api_parsed: true
60
+ }
61
+ },
62
+ attributes: { include: [:title, :body] },
63
+ relationships: { include: [:title, :body] })
64
+ end
65
+ end
66
+
67
+ it 'parses :fields, but does not include other resources' do
68
+ [{ include: [], fields: { articles: [:title, :body], people: [:email] } },
69
+ { include: [''], fields: { articles: ['title,body'], people: ['email'] } },
70
+ { include: '', fields: { 'articles' => 'title,body', 'people' => 'email' } }].each do |options|
71
+ options = Include.(options, relationships: { 'author' => 'people', 'articles' => 'articles' })
72
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
73
+ included: {
74
+ include: [],
75
+ articles: {
76
+ attributes: { include: [:title, :body] },
77
+ relationships: { include: [:title, :body] },
78
+ _json_api_parsed: true
79
+ },
80
+ author: {
81
+ attributes: { include: [:email] },
82
+ relationships: { include: [:email] },
83
+ _json_api_parsed: true
84
+ }
85
+ })
86
+ end
87
+ end
88
+ end
89
+
90
+ describe 'with non-empty :include option' do
91
+ it 'rewrites :include given a relationship name' do
92
+ [{ include: [:comments] },
93
+ { include: ['comments'] },
94
+ { include: 'comments' }].each do |options|
95
+ options = Include.(options, {})
96
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
97
+ included: {
98
+ include: [:comments],
99
+ comments: {
100
+ include: [:id, :attributes, :relationships],
101
+ _json_api_parsed: true
102
+ }
103
+ })
104
+ end
105
+ end
106
+
107
+ it 'rewrites :include given a dot-separated path of relationship names' do
108
+ [{ include: [:"comments.author.employer"] },
109
+ { include: ['comments.author.employer'] },
110
+ { include: 'comments.author.employer' }].each do |options|
111
+ options = Include.(options, {})
112
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
113
+ included: {
114
+ include: [:comments],
115
+ comments: {
116
+ include: [:id, :attributes, :relationships, :included],
117
+ included: {
118
+ author: {
119
+ include: [:id, :attributes, :relationships, :included],
120
+ included: {
121
+ employer: {
122
+ include: [:id, :attributes, :relationships],
123
+ _json_api_parsed: true
124
+ }
125
+ },
126
+ _json_api_parsed: true
127
+ }
128
+ },
129
+ _json_api_parsed: true
130
+ }
131
+ })
132
+ end
133
+ end
134
+
135
+ it 'does not rewrite :include if _json_api_parsed: true' do
136
+ options = Include.({ include: [:id, :attributes],
137
+ _json_api_parsed: true }, {})
138
+ options.must_equal(include: [:id, :attributes],
139
+ _json_api_parsed: true)
140
+ end
141
+ end
142
+
143
+ describe 'with falsey :include options' do
144
+ it 'does not rewrite include: false' do
145
+ options = Include.({ include: false }, {})
146
+ options.must_equal(include: false)
147
+ end
148
+
149
+ it 'does not rewrite include: nil' do
150
+ options = Include.({ include: nil }, {})
151
+ options.must_equal(include: nil)
152
+ end
153
+ end
154
+
155
+ describe 'with falsey :fields options' do
156
+ it 'does not parse fields: nil' do
157
+ options = Include.({ fields: nil }, {})
158
+ options.must_equal(fields: nil)
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,293 @@
1
+ require 'test_helper'
2
+ require 'roar/json/json_api'
3
+ require 'json'
4
+
5
+ class JSONAPIFieldsetsTest < Minitest::Spec
6
+ Article = Struct.new(:id, :title, :summary, :comments, :author)
7
+ Comment = Struct.new(:id, :body, :good, :comment_author)
8
+ Author = Struct.new(:id, :name, :email)
9
+
10
+ describe 'Single Resource Object With Options' do
11
+ class DocumentSingleResourceObjectDecorator < Roar::Decorator
12
+ include Roar::JSON::JSONAPI.resource :articles
13
+
14
+ attributes do
15
+ property :title
16
+ property :summary
17
+ end
18
+
19
+ has_many :comments do
20
+ attributes do
21
+ property :body
22
+ property :good
23
+ end
24
+
25
+ has_one :comment_author, class: Comment do
26
+ type :authors
27
+
28
+ attributes do
29
+ property :name
30
+ property :email
31
+ end
32
+ end
33
+ end
34
+
35
+ has_one :author do
36
+ type :authors
37
+
38
+ attributes do
39
+ property :name
40
+ property :email
41
+ end
42
+ end
43
+ end
44
+
45
+ let(:comments) {
46
+ [
47
+ Comment.new('c:1', 'Cool!', true,
48
+ Author.new('a:2', 'Tim', 'troll@trollblazer.io')),
49
+ Comment.new('c:2', 'Nah', false)
50
+ ]
51
+ }
52
+
53
+ let(:article) {
54
+ Article.new(1, 'My Article', 'An interesting read.', comments,
55
+ Author.new('a:1', 'Celso', 'celsito@trb.to'))
56
+ }
57
+
58
+ it 'includes scalars' do
59
+ DocumentSingleResourceObjectDecorator.new(article)
60
+ .to_json(
61
+ fields: { articles: 'title' }
62
+ )
63
+ .must_equal_json(%(
64
+ {
65
+ "data": {
66
+ "id": "1",
67
+ "attributes": {
68
+ "title": "My Article"
69
+ },
70
+ "type": "articles"
71
+ }
72
+ }
73
+ ))
74
+ end
75
+
76
+ it 'includes compound objects' do
77
+ DocumentSingleResourceObjectDecorator.new(article)
78
+ .to_json(
79
+ fields: { articles: 'title' },
80
+ include: :comments
81
+ )
82
+ .must_equal_json(%(
83
+ {
84
+ "data": {
85
+ "id": "1",
86
+ "attributes": {
87
+ "title": "My Article"
88
+ },
89
+ "type": "articles"
90
+ },
91
+ "included": [
92
+ {
93
+ "type": "comments",
94
+ "id": "c:1",
95
+ "attributes": {
96
+ "body": "Cool!",
97
+ "good": true
98
+ },
99
+ "relationships": {
100
+ "comment-author": {
101
+ "data": {
102
+ "type": "authors",
103
+ "id": "a:2"
104
+ }
105
+ }
106
+ }
107
+ },
108
+ {
109
+ "type": "comments",
110
+ "id": "c:2",
111
+ "attributes": {
112
+ "body": "Nah",
113
+ "good": false
114
+ },
115
+ "relationships": {
116
+ "comment-author": {
117
+ "data": null
118
+ }
119
+ }
120
+ }
121
+ ]
122
+ }
123
+ ))
124
+ end
125
+
126
+ it 'includes nested compound objects' do
127
+ DocumentSingleResourceObjectDecorator.new(article)
128
+ .to_json(
129
+ fields: { articles: 'title' },
130
+ include: 'comments.author'
131
+ )
132
+ .must_equal_json(%(
133
+ {
134
+ "data": {
135
+ "id": "1",
136
+ "attributes": {
137
+ "title": "My Article"
138
+ },
139
+ "type": "articles"
140
+ },
141
+ "included": [
142
+ {
143
+ "type": "comments",
144
+ "id": "c:1",
145
+ "attributes": {
146
+ "body": "Cool!",
147
+ "good": true
148
+ },
149
+ "relationships": {
150
+ "comment-author": {
151
+ "data": {
152
+ "type": "authors",
153
+ "id": "a:2"
154
+ }
155
+ }
156
+ },
157
+ "included": [
158
+ {
159
+ "type": "authors",
160
+ "id": "a:2",
161
+ "attributes": {
162
+ "email": "troll@trollblazer.io",
163
+ "name": "Tim"
164
+ }
165
+ }
166
+ ]
167
+ },
168
+ {
169
+ "type": "comments",
170
+ "id": "c:2",
171
+ "attributes": {
172
+ "body": "Nah",
173
+ "good": false
174
+ },
175
+ "relationships": {
176
+ "comment-author": {
177
+ "data": null
178
+ }
179
+ }
180
+ }
181
+ ]
182
+ }
183
+ ))
184
+ end
185
+
186
+ it 'includes other compound objects' do
187
+ DocumentSingleResourceObjectDecorator.new(article)
188
+ .to_json(
189
+ fields: { articles: 'title' },
190
+ include: :author
191
+ )
192
+ .must_equal_json(%(
193
+ {
194
+ "data": {
195
+ "id": "1",
196
+ "attributes": {
197
+ "title": "My Article"
198
+ },
199
+ "type": "articles"
200
+ },
201
+ "included": [
202
+ {
203
+ "type": "authors",
204
+ "id": "a:1",
205
+ "attributes": {
206
+ "email": "celsito@trb.to",
207
+ "name": "Celso"
208
+ }
209
+ }
210
+ ]
211
+ }
212
+ ))
213
+ end
214
+
215
+ describe 'collection' do
216
+ it 'supports :includes' do
217
+ DocumentSingleResourceObjectDecorator.for_collection.new([article])
218
+ .to_hash(
219
+ fields: { articles: 'title' },
220
+ include: :author
221
+ )
222
+ .must_equal Hash[{
223
+ 'data' => [
224
+ { 'type' => 'articles',
225
+ 'id' => '1',
226
+ 'attributes' => { 'title'=>'My Article' } }
227
+ ],
228
+ 'included' =>
229
+ [{ 'type' => 'authors', 'id' => 'a:1', 'attributes' => { 'name' => 'Celso', 'email' => 'celsito@trb.to' } }]
230
+ }]
231
+ end
232
+
233
+ # include: ROAR API
234
+ it 'blaaaaaaa' do
235
+ DocumentSingleResourceObjectDecorator.for_collection.new([article])
236
+ .to_hash(
237
+ fields: { articles: 'title', authors: [:email] },
238
+ include: :author
239
+ )
240
+ .must_equal Hash[{
241
+ 'data' => [
242
+ { 'type' => 'articles',
243
+ 'id' => '1',
244
+ 'attributes' => { 'title'=>'My Article' } }
245
+ ],
246
+ 'included' =>
247
+ [{ 'type' => 'authors', 'id' => 'a:1', 'attributes' => { 'email'=>'celsito@trb.to' } }]
248
+ }]
249
+ end
250
+ end
251
+ end
252
+
253
+ describe 'Collection Resources With Options' do
254
+ class CollectionResourceObjectDecorator < Roar::Decorator
255
+ include Roar::JSON::JSONAPI.resource :articles
256
+
257
+ attributes do
258
+ property :title
259
+ property :summary
260
+ end
261
+ end
262
+
263
+ let(:document) {
264
+ %({
265
+ "data": [
266
+ {
267
+ "id": "1",
268
+ "attributes": {
269
+ "title": "My Article"
270
+ },
271
+ "type": "articles"
272
+ },
273
+ {
274
+ "id": "2",
275
+ "attributes": {
276
+ "title": "My Other Article"
277
+ },
278
+ "type": "articles"
279
+ }
280
+ ]
281
+ })
282
+ }
283
+
284
+ it do
285
+ CollectionResourceObjectDecorator.for_collection.new([
286
+ Article.new(1, 'My Article', 'An interesting read.'),
287
+ Article.new(2, 'My Other Article', 'An interesting read.')
288
+ ]).to_json(
289
+ fields: { articles: :title }
290
+ ).must_equal_json document
291
+ end
292
+ end
293
+ end