ruby_json_api_client 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.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +25 -0
  6. data/Rakefile +2 -0
  7. data/lib/ruby_json_api_client/adapters/ams_adapter.rb +15 -0
  8. data/lib/ruby_json_api_client/adapters/json_api_adapter.rb +15 -0
  9. data/lib/ruby_json_api_client/adapters/rest_adapter.rb +80 -0
  10. data/lib/ruby_json_api_client/base.rb +98 -0
  11. data/lib/ruby_json_api_client/collection.rb +13 -0
  12. data/lib/ruby_json_api_client/serializers/ams_serializer.rb +187 -0
  13. data/lib/ruby_json_api_client/serializers/json_api_serializer.rb +93 -0
  14. data/lib/ruby_json_api_client/store.rb +171 -0
  15. data/lib/ruby_json_api_client/version.rb +3 -0
  16. data/lib/ruby_json_api_client.rb +14 -0
  17. data/ruby_json_api_client.gemspec +34 -0
  18. data/spec/integration/ams/find_spec.rb +46 -0
  19. data/spec/integration/ams/has_many_links_spec.rb +161 -0
  20. data/spec/integration/ams/has_many_sideload_spec.rb +170 -0
  21. data/spec/integration/ams/has_one_links_spec.rb +57 -0
  22. data/spec/integration/ams/has_one_sideload_spec.rb +87 -0
  23. data/spec/integration/ams/query_spec.rb +65 -0
  24. data/spec/integration/json_api/find_spec.rb +44 -0
  25. data/spec/integration/json_api/query_spec.rb +65 -0
  26. data/spec/spec_helper.rb +7 -0
  27. data/spec/support/classes.rb +26 -0
  28. data/spec/unit/adapters/json_api_spec.rb +4 -0
  29. data/spec/unit/adapters/rest_spec.rb +109 -0
  30. data/spec/unit/base_spec.rb +60 -0
  31. data/spec/unit/collection_spec.rb +17 -0
  32. data/spec/unit/serializers/ams_spec.rb +480 -0
  33. data/spec/unit/serializers/json_api_spec.rb +114 -0
  34. data/spec/unit/store_spec.rb +243 -0
  35. metadata +262 -0
@@ -0,0 +1,480 @@
1
+ require 'spec_helper'
2
+
3
+ describe RubyJsonApiClient::AmsSerializer do
4
+ let(:serializer) { RubyJsonApiClient::AmsSerializer.new }
5
+
6
+ describe :transform do
7
+ let(:json) { "{\"testing\":true, \"firstname\":\"ryan\"}" }
8
+ subject { serializer.transform(json)["testing"] }
9
+ it { should eql(true) }
10
+ end
11
+
12
+ describe :to_json do
13
+ context "using fields" do
14
+ subject { serializer.to_json(Person.new(firstname: 'ryan')) }
15
+ it do
16
+ should eq({ person: {
17
+ firstname: 'ryan',
18
+ lastname: nil
19
+ }}.to_json)
20
+ end
21
+ end
22
+
23
+ context "using a persisted model" do
24
+ subject { serializer.to_json(Person.new(id: 1, firstname: 'ryan')) }
25
+ it do
26
+ should eq({ person: {
27
+ id: 1,
28
+ firstname: 'ryan',
29
+ lastname: nil
30
+ } }.to_json)
31
+ end
32
+ end
33
+
34
+ context "using a has one relationship" do
35
+ subject do
36
+ person = Person.new(
37
+ id: 1,
38
+ firstname: 'ryan',
39
+ lastname: nil
40
+ )
41
+
42
+ person.item = Item.new(id: 2)
43
+ serializer.to_json(person)
44
+ end
45
+
46
+ it do
47
+ should eq({ person: {
48
+ id: 1,
49
+ firstname: 'ryan',
50
+ lastname: nil,
51
+ item_id: 2
52
+ } }.to_json)
53
+ end
54
+ end
55
+ end
56
+
57
+ describe :extract_single do
58
+ context "will error when" do
59
+ subject { ->{ serializer.extract_single(Person, 1, json) } }
60
+
61
+ context "no json root key exists" do
62
+ let(:json) { "{\"firstname\":\"ryan\"}" }
63
+ it { should raise_error }
64
+ end
65
+
66
+ context "no id" do
67
+ let(:json) { "{\"person\": { \"firstname\":\"ryan\" } }" }
68
+ it { should raise_error }
69
+ end
70
+
71
+ context "the id returned is not the id we are looking for" do
72
+ let(:json) { "{\"person\": { \"id\": 2, \"firstname\":\"ryan\" } }" }
73
+ it { should raise_error }
74
+ end
75
+ end
76
+
77
+ context "when payload contains" do
78
+ subject { serializer.extract_single(Person, 1, json) }
79
+
80
+ context "string ids" do
81
+ let(:json) { "{\"person\": { \"id\": \"1\", \"firstname\":\"ryan\" } }" }
82
+ it { should be_instance_of(Person) }
83
+ end
84
+
85
+ context "attributes that are defined" do
86
+ let(:json) { "{\"person\": { \"id\": \"1\", \"firstname\":\"ryan\" } }" }
87
+ it { should be_instance_of(Person) }
88
+ it { should respond_to(:firstname) }
89
+ its(:firstname) { should eq('ryan') }
90
+ end
91
+
92
+ context "attributes that are not defined" do
93
+ let(:json) { "{\"person\": { \"id\": \"1\", \"unknown\":\"ryan\" } }" }
94
+ it { should be_instance_of(Person) }
95
+ it { should_not respond_to(:unknown) }
96
+ end
97
+ end
98
+
99
+ context "using multi worded models" do
100
+ subject { serializer.extract_single(CellPhone, 1, json) }
101
+ let(:model) { subject }
102
+
103
+
104
+ let(:json) { "{\"cell_phone\": { \"id\": 1, \"number\": \"123-456-7890\" } }" }
105
+ it { should be_instance_of(CellPhone) }
106
+ its(:number) { should eq('123-456-7890') }
107
+ end
108
+ end
109
+
110
+ describe :extract_many do
111
+ context "will error when" do
112
+ subject { ->{ serializer.extract_many(Person, json) } }
113
+
114
+ context "there is no plural key in the response" do
115
+ let(:json) { "[{ \"id\": 1, \"firstname\": \"ryan\" }]" }
116
+ it { should raise_error }
117
+ end
118
+
119
+ context "there is no array of data" do
120
+ let(:json) { "{ \"id\": 1, \"firstname\": \"ryan\" }" }
121
+ it { should raise_error }
122
+ end
123
+ end
124
+
125
+ context "when payload contains" do
126
+ subject { serializer.extract_many(Person, json) }
127
+ let(:collection) { subject }
128
+
129
+ context "multiple records" do
130
+ let(:json) do
131
+ "{ \"people\": [{ \"id\": 1, \"firstname\": \"ryan\" }, { \"id\": 2, \"firstname\": \"ryan2\" }] }"
132
+ end
133
+
134
+ it { should have(2).items }
135
+
136
+ it "should serialize one of the records" do
137
+ expect(collection.first).to respond_to(:firstname)
138
+ expect(collection.first.firstname).to eq('ryan')
139
+ end
140
+ end
141
+ end
142
+
143
+ context "using a different key name" do
144
+ let(:json) do
145
+ {
146
+ peeps: [{
147
+ id: 1,
148
+ firstname: 'ryan'
149
+ }]
150
+ }.to_json
151
+ end
152
+
153
+ let(:collection) { serializer.extract_many(Person, json, "peeps") }
154
+
155
+ subject { collection }
156
+ it { should have(1).items }
157
+
158
+ context "the person" do
159
+ subject { collection.first }
160
+ it { should be_instance_of(Person) }
161
+ it { should respond_to(:firstname) }
162
+ its(:firstname) { should eq('ryan') }
163
+ end
164
+ end
165
+ end
166
+
167
+ describe :extract_many_relationship do
168
+ let(:person) { Person.new }
169
+
170
+ it "should extact relationships using links" do
171
+ expect(serializer).to receive(:extract_many_relationship_from_links)
172
+ .with(person, :items, {}, "http://items.test")
173
+ .and_return([])
174
+
175
+ person.meta = {
176
+ links: {
177
+ 'items' => "http://items.test"
178
+ }
179
+ }
180
+
181
+ serializer.extract_many_relationship(
182
+ person,
183
+ :items,
184
+ {},
185
+ "{}"
186
+ )
187
+ end
188
+
189
+ it "should extract relationships using sideloads" do
190
+ items = "[{ \"id\": 1, \"name\": \"first\" }, { \"id\": 2, \"name\": \"second\" }]"
191
+ response = "{ \"person\": { \"item_ids\": [1] }, \"items\": #{items} }"
192
+
193
+ expect(serializer).to receive(:extract_many_relationship_from_sideload)
194
+ .with(person, :items, {}, response)
195
+ .and_return([])
196
+
197
+ person.meta = {
198
+ data: {
199
+ 'item_ids' => [1]
200
+ }
201
+ }
202
+
203
+ serializer.extract_many_relationship(
204
+ person,
205
+ :items,
206
+ {},
207
+ response
208
+ )
209
+ end
210
+
211
+ it "should not try to extract sideloads if the parent record doesnt have ids" do
212
+ result = serializer.extract_many_relationship(
213
+ person,
214
+ :items,
215
+ {},
216
+ "{ \"person\": { }, \"items\": [{\"id\": 1 }] }"
217
+ )
218
+
219
+ expect(result).to match_array([])
220
+ end
221
+
222
+ it "should give an empty collection when there is no sideload or links present" do
223
+ result = serializer.extract_many_relationship(
224
+ person,
225
+ :items,
226
+ {},
227
+ "{ \"person\": { } }"
228
+ )
229
+
230
+ expect(result).to match_array([])
231
+ end
232
+ end
233
+
234
+ describe :extract_many_relationship_from_links do
235
+ let(:person) { Person.new }
236
+ let(:store) { double("store") }
237
+
238
+ before(:each) do
239
+ serializer.store = store
240
+
241
+ expect(store).to receive(:load_collection)
242
+ .with(Item, "http://www.example.com/items")
243
+ end
244
+
245
+ it "should have the store load the collection" do
246
+ serializer.extract_many_relationship_from_links(
247
+ person,
248
+ :items,
249
+ {},
250
+ "http://www.example.com/items"
251
+ )
252
+ end
253
+
254
+ it "should have the store load the collection for the given class" do
255
+ serializer.extract_many_relationship_from_links(
256
+ person,
257
+ :oddly_named_items,
258
+ { class_name: 'Item' },
259
+ "http://www.example.com/items"
260
+ )
261
+ end
262
+ end
263
+
264
+ describe :extract_many_relationship_from_sideload do
265
+ let(:person) do
266
+ Person.new(meta: {
267
+ data: {
268
+ "item_ids" => [2]
269
+ }
270
+ })
271
+ end
272
+
273
+ let(:response) do
274
+ {
275
+ person: {
276
+ id: 1,
277
+ item_ids: [2]
278
+ },
279
+ items: [
280
+ { id: 1, name: "test" },
281
+ { id: 2, name: "test 2" }
282
+ ]
283
+ }.to_json
284
+ end
285
+
286
+ it "should use extract many to pull the data" do
287
+ expect(serializer).to receive(:extract_many)
288
+ .with(Item, response, "items")
289
+ .and_return([])
290
+
291
+ serializer.extract_many_relationship_from_sideload(
292
+ person,
293
+ :items,
294
+ {},
295
+ response
296
+ )
297
+ end
298
+
299
+ it "should pass the right class name to extract many" do
300
+ expect(serializer).to receive(:extract_many)
301
+ .with(CellPhone, response, "items")
302
+ .and_return([])
303
+
304
+ serializer.extract_many_relationship_from_sideload(
305
+ person,
306
+ :items,
307
+ { class_name: 'CellPhone' },
308
+ response
309
+ )
310
+ end
311
+
312
+ it "should filter the ids in the relationship" do
313
+ result = serializer.extract_many_relationship_from_sideload(
314
+ person,
315
+ :items,
316
+ {},
317
+ response
318
+ )
319
+
320
+ expect(result).to have(1).items
321
+ expect(result.first.id).to eq(2)
322
+ end
323
+ end
324
+
325
+ describe :extract_single_relationship do
326
+ let(:person) { Person.new }
327
+ let(:item) { Item.new }
328
+ let(:response) { "{}" } # dummy response
329
+ subject { serializer.extract_single_relationship(person, :item, {}, response) }
330
+
331
+ context "from links" do
332
+ let(:person) do
333
+ Person.new(meta: { links: {
334
+ 'item' => 'http://example.com/item/1'
335
+ }})
336
+ end
337
+
338
+ before(:each) do
339
+ expect(serializer).to receive(:extract_single_relationship_from_links)
340
+ .with(person, :item, {}, "http://example.com/item/1")
341
+ .and_return(item)
342
+ end
343
+
344
+ it { should eq(item) }
345
+ end
346
+
347
+ context "from sideload" do
348
+ let(:person) do
349
+ Person.new(meta: { data: {
350
+ 'item_id' => 1
351
+ }})
352
+ end
353
+
354
+ let(:response) do
355
+ # for sideloader
356
+ {
357
+ items: [{
358
+ id: 1,
359
+ }]
360
+ }.to_json
361
+ end
362
+
363
+ before(:each) do
364
+ expect(serializer).to receive(:extract_single_relationship_from_sideload)
365
+ .with(person, :item, {}, response)
366
+ .and_return(item)
367
+ end
368
+
369
+ it { should eq(item) }
370
+ end
371
+
372
+ context "when nothing is found" do
373
+ it { should be_nil }
374
+ end
375
+ end
376
+
377
+ describe :extract_single_relationship_from_links do
378
+ let(:store) { double("store") }
379
+ let(:person) { Person.new }
380
+ let(:item) { Item.new }
381
+
382
+ before(:each) do
383
+ serializer.store = store
384
+
385
+ expect(store).to receive(:load_single)
386
+ .with(Item, nil, "http://example.com/items/1")
387
+ .and_return(item)
388
+ end
389
+
390
+ context "with no options" do
391
+ subject do
392
+ serializer.extract_single_relationship_from_links(
393
+ person, :item, {}, "http://example.com/items/1"
394
+ )
395
+ end
396
+
397
+ it { should eq(item) }
398
+ end
399
+
400
+ context "with a different class name" do
401
+ subject do
402
+ serializer.extract_single_relationship_from_links(
403
+ person, :favorite_item, { class_name: 'Item' }, "http://example.com/items/1"
404
+ )
405
+ end
406
+
407
+ it { should eq(item) }
408
+ end
409
+ end
410
+
411
+ describe :extract_single_relationship_from_sideload do
412
+ context "with no options" do
413
+ let(:person) do
414
+ Person.new(meta: { data: {
415
+ 'item_id' => 2
416
+ }})
417
+ end
418
+
419
+ subject do
420
+ serializer.extract_single_relationship_from_sideload(
421
+ person, :item, {}, response
422
+ )
423
+ end
424
+
425
+ let(:response) do
426
+ {
427
+ person: {
428
+ id: 1,
429
+ item_id: 2
430
+ },
431
+ items: [{
432
+ id: 1,
433
+ name: 'not for person'
434
+ },{
435
+ id: 2,
436
+ name: 'persons item'
437
+ }]
438
+ }.to_json
439
+ end
440
+
441
+ it { should be_instance_of(Item) }
442
+ its(:id) { should eq(2) }
443
+ its(:name) { should eq('persons item') }
444
+ end
445
+
446
+ context "with a different class name" do
447
+ let(:person) do
448
+ Person.new(meta: { data: {
449
+ 'favorite_item_id' => 2
450
+ }})
451
+ end
452
+
453
+ subject do
454
+ serializer.extract_single_relationship_from_sideload(
455
+ person, :favorite_item, { class_name: 'Item' }, response
456
+ )
457
+ end
458
+
459
+ let(:response) do
460
+ {
461
+ person: {
462
+ id: 1,
463
+ favorite_item_id: 2
464
+ },
465
+ favorite_items: [{
466
+ id: 1,
467
+ name: 'not for person'
468
+ },{
469
+ id: 2,
470
+ name: 'persons item'
471
+ }]
472
+ }.to_json
473
+ end
474
+
475
+ it { should be_instance_of(Item) }
476
+ its(:id) { should eq(2) }
477
+ its(:name) { should eq('persons item') }
478
+ end
479
+ end
480
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+
3
+ describe RubyJsonApiClient do
4
+ let(:serializer) { RubyJsonApiClient::JsonApiSerializer.new }
5
+
6
+ describe :transform do
7
+ let(:json) { "{\"testing\":true, \"firstname\":\"ryan\"}" }
8
+ subject { serializer.transform(json)["testing"] }
9
+ it { should eql(true) }
10
+ end
11
+
12
+ describe :extract_single do
13
+ context "will error when" do
14
+ subject { ->{ serializer.extract_single(Person, 1, json) } }
15
+
16
+ context "no json root key exists" do
17
+ let(:json) { "{\"firstname\":\"ryan\"}" }
18
+ it { should raise_error }
19
+ end
20
+
21
+ context "single resource is not a collection" do
22
+ let(:json) { "{ \"people\": { \"firstname\":\"ryan\" } }" }
23
+ it { should raise_error }
24
+ end
25
+
26
+ context "no id" do
27
+ let(:json) { "{\"people\": [{ \"firstname\":\"ryan\" }] }" }
28
+ it { should raise_error }
29
+ end
30
+
31
+ context "the id returned is not the id we are looking for" do
32
+ let(:json) { "{\"people\": [{ \"id\": 2, \"firstname\":\"ryan\" }] }" }
33
+ it { should raise_error }
34
+ end
35
+ end
36
+
37
+ context "when payload contains" do
38
+ subject { serializer.extract_single(Person, 1, json) }
39
+
40
+ context "string ids" do
41
+ let(:json) { "{\"people\": [{ \"id\": \"1\", \"firstname\":\"ryan\" }] }" }
42
+ it { should be_instance_of(Person) }
43
+ end
44
+
45
+ context "attributes that are defined" do
46
+ let(:json) { "{\"people\": [{ \"id\": \"1\", \"firstname\":\"ryan\" }] }" }
47
+ let(:model) { subject }
48
+
49
+ it { should be_instance_of(Person) }
50
+ it { should respond_to(:firstname) }
51
+
52
+ it "should set the right values" do
53
+ expect(model.firstname).to eq('ryan')
54
+ end
55
+ end
56
+
57
+ context "attributes that are not defined" do
58
+ let(:json) { "{\"people\": [{ \"id\": \"1\", \"unknown\":\"ryan\" }] }" }
59
+ it { should be_instance_of(Person) }
60
+ it { should_not respond_to(:unknown) }
61
+ end
62
+ end
63
+
64
+ context "using multi worded models" do
65
+ subject { serializer.extract_single(CellPhone, 1, json) }
66
+ let(:model) { subject }
67
+
68
+ class CellPhone < RubyJsonApiClient::Base
69
+ field :number
70
+ end
71
+
72
+ let(:json) { "{\"cell_phones\": [{ \"id\": 1, \"number\": \"123-456-7890\" }] }" }
73
+ it { should be_instance_of(CellPhone) }
74
+
75
+ it "should set the right number" do
76
+ expect(model.number).to eq('123-456-7890')
77
+ end
78
+ end
79
+ end
80
+
81
+ describe :extract_many do
82
+ context "will error when" do
83
+ subject { ->{ serializer.extract_many(Person, json) } }
84
+
85
+ context "there is no plural key in the response" do
86
+ let(:json) { "[{ \"id\": 1, \"firstname\": \"ryan\" }]" }
87
+ it { should raise_error }
88
+ end
89
+
90
+ context "there is no array of data" do
91
+ let(:json) { "{ \"id\": 1, \"firstname\": \"ryan\" }" }
92
+ it { should raise_error }
93
+ end
94
+ end
95
+
96
+ context "when payload contains" do
97
+ subject { serializer.extract_many(Person, json) }
98
+ let(:collection) { subject }
99
+
100
+ context "multiple records" do
101
+ let(:json) do
102
+ "{ \"people\": [{ \"id\": 1, \"firstname\": \"ryan\" }, { \"id\": 2, \"firstname\": \"ryan2\" }] }"
103
+ end
104
+
105
+ it { should have(2).items }
106
+
107
+ it "should serialize one of the records" do
108
+ expect(collection.first).to respond_to(:firstname)
109
+ expect(collection.first.firstname).to eq('ryan')
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end