jsonapi-serializers 1.0.1 → 2.0.0.pre.beta.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0fd9ca8b21d90e0ca99ef6d7c9930e1b6ba9a370e96bf1d0e9cb76b24cf96b34
4
- data.tar.gz: '079ac81b6b1a1c99ed075c2479ddd142f3f7db6552a86834201bcb1a0d6de5ff'
3
+ metadata.gz: f99b86af11e529f51cb077d231c973924183808e8d88b0660fa44a2112098a28
4
+ data.tar.gz: 80b21e2bd747fa2c838ce4ca73e62f1ecf6121b868fcb8edd045dc4bf31604b0
5
5
  SHA512:
6
- metadata.gz: bfb423c4750432656c8937c52c6dfd0598f32d9548688f5e3b01c90eb08433cb88a29a5dba7bff0c07a91d64a50b0ceae2c416f9f0b14a46254dd315dc992be9
7
- data.tar.gz: 9988ef3702519bdc37a40e46f1c9ee28fd1133b94a84f6dfe296feeed668e50f082cd2dd1cb96ed330598e2722d074da4e48808afa41cab81472758cd457d424
6
+ metadata.gz: 88010cf85c872256685733787d5bb7a74a3dd4ff338797f2f5cd66b3fbc708b5293fbf63c1033d6a4adb56e430d5878be518f3ef98456bf13e3861a08eb6f8ac
7
+ data.tar.gz: fd1d79a679235e3115bce25d7b16054cc16097512a52a05df402d0a8ac754c0aad14136054bddbf2c84e99618be9e6058a220e0e64ddbe6e0eb99b6c0c8082b0
@@ -2,10 +2,8 @@ language: ruby
2
2
  sudo: false
3
3
  cache: bundler
4
4
  rvm:
5
- - 1.9.3
6
- - 2.1.1
7
- - 2.2.2
8
- - 2.3.1
5
+ - 2.3
6
+ - 2.5
9
7
  before_install:
10
8
  - gem install bundler
11
9
  script: bundle exec rspec
data/README.md CHANGED
@@ -29,6 +29,7 @@ This library is up-to-date with the finalized v1 JSON API spec.
29
29
  * [Compound documents and includes](#compound-documents-and-includes)
30
30
  * [Relationship path handling](#relationship-path-handling)
31
31
  * [Control links and data in relationships](#control-links-and-data-in-relationships)
32
+ * [Instrumentation](#instrumentation)
32
33
  * [Rails example](#rails-example)
33
34
  * [Sinatra example](#sinatra-example)
34
35
  * [Unfinished business](#unfinished-business)
@@ -641,6 +642,30 @@ Notice that linkage data is now included for the `author` relationship:
641
642
  }
642
643
  ```
643
644
 
645
+ ## Instrumentation
646
+
647
+ Using [ActiveSupport::Notifications](https://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) you can subscribe to key notifications to better understand the performance of your serialization.
648
+
649
+ The following notifications can be subscribed to:
650
+
651
+ * `render.jsonapi_serializers.serialize_primary` - time spent serializing a single object
652
+ * `render.jsonapi_serializers.find_recursive_relationships` - time spent finding objects to serialize through relationships
653
+
654
+ This is an example of how you might subscribe to all events that come from `jsonapi-serializers`.
655
+
656
+ ```ruby
657
+ require 'active_support/notifications'
658
+
659
+ ActiveSupport::Notifications.subscribe(/^render\.jsonapi_serializers\..*/) do |*args|
660
+ event = ActiveSupport::Notifications::Event.new(*args)
661
+
662
+ puts event.name
663
+ puts event.time
664
+ puts event.end
665
+ puts event.payload
666
+ end
667
+ ```
668
+
644
669
  ## Rails example
645
670
 
646
671
  ```ruby
@@ -24,4 +24,5 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "rspec", "~> 3.2"
25
25
  spec.add_development_dependency "factory_girl", "~> 4.5"
26
26
  spec.add_development_dependency "activemodel", "~> 4.2"
27
+ spec.add_development_dependency "pry"
27
28
  end
@@ -1,5 +1,6 @@
1
1
  require 'set'
2
2
  require 'active_support/inflector'
3
+ require 'active_support/notifications'
3
4
 
4
5
  module JSONAPI
5
6
  module Serializer
@@ -394,38 +395,43 @@ module JSONAPI
394
395
  end
395
396
 
396
397
  def self.serialize_primary(object, options = {})
397
- serializer_class = options[:serializer] || find_serializer_class(object, options)
398
-
399
- # Spec: Primary data MUST be either:
400
- # - a single resource object or null, for requests that target single resources.
401
- # http://jsonapi.org/format/#document-structure-top-level
402
- return if object.nil?
403
-
404
- serializer = serializer_class.new(object, options)
405
- data = {
406
- 'type' => serializer.type.to_s,
407
- }
408
-
409
- # "The id member is not required when the resource object originates at the client
410
- # and represents a new resource to be created on the server."
411
- # http://jsonapi.org/format/#document-resource-objects
412
- # We'll assume that if the id is blank, it means the resource is to be created.
413
- data['id'] = serializer.id.to_s if serializer.id && !serializer.id.empty?
414
-
415
- # Merge in optional top-level members if they are non-nil.
416
- # http://jsonapi.org/format/#document-structure-resource-objects
417
- # Call the methods once now to avoid calling them twice when evaluating the if's below.
418
- attributes = serializer.attributes
419
- links = serializer.links
420
- relationships = serializer.relationships
421
- jsonapi = serializer.jsonapi
422
- meta = serializer.meta
423
- data['attributes'] = attributes if !attributes.empty?
424
- data['links'] = links if !links.empty?
425
- data['relationships'] = relationships if !relationships.empty?
426
- data['jsonapi'] = jsonapi if !jsonapi.nil?
427
- data['meta'] = meta if !meta.nil?
428
- data
398
+ ActiveSupport::Notifications.instrument(
399
+ 'render.jsonapi_serializers.serialize_primary',
400
+ {class_name: object&.class&.name}
401
+ ) do
402
+ serializer_class = options[:serializer] || find_serializer_class(object, options)
403
+
404
+ # Spec: Primary data MUST be either:
405
+ # - a single resource object or null, for requests that target single resources.
406
+ # http://jsonapi.org/format/#document-structure-top-level
407
+ return if object.nil?
408
+
409
+ serializer = serializer_class.new(object, options)
410
+ data = {
411
+ 'type' => serializer.type.to_s,
412
+ }
413
+
414
+ # "The id member is not required when the resource object originates at the client
415
+ # and represents a new resource to be created on the server."
416
+ # http://jsonapi.org/format/#document-resource-objects
417
+ # We'll assume that if the id is blank, it means the resource is to be created.
418
+ data['id'] = serializer.id.to_s if serializer.id && !serializer.id.empty?
419
+
420
+ # Merge in optional top-level members if they are non-nil.
421
+ # http://jsonapi.org/format/#document-structure-resource-objects
422
+ # Call the methods once now to avoid calling them twice when evaluating the if's below.
423
+ attributes = serializer.attributes
424
+ links = serializer.links
425
+ relationships = serializer.relationships
426
+ jsonapi = serializer.jsonapi
427
+ meta = serializer.meta
428
+ data['attributes'] = attributes if !attributes.empty?
429
+ data['links'] = links if !links.empty?
430
+ data['relationships'] = relationships if !relationships.empty?
431
+ data['jsonapi'] = jsonapi if !jsonapi.nil?
432
+ data['meta'] = meta if !meta.nil?
433
+ data
434
+ end
429
435
  end
430
436
  class << self; protected :serialize_primary; end
431
437
 
@@ -447,88 +453,93 @@ module JSONAPI
447
453
  # ['users', '2'] => {object: <User>, include_linkages: []},
448
454
  # }
449
455
  def self.find_recursive_relationships(root_object, root_inclusion_tree, results, options)
450
- root_inclusion_tree.each do |attribute_name, child_inclusion_tree|
451
- # Skip the sentinal value, but we need to preserve it for siblings.
452
- next if attribute_name == :_include
453
-
454
- serializer = JSONAPI::Serializer.find_serializer(root_object, options)
455
- unformatted_attr_name = serializer.unformat_name(attribute_name).to_sym
456
-
457
- # We know the name of this relationship, but we don't know where it is stored internally.
458
- # Check if it is a has_one or has_many relationship.
459
- object = nil
460
- is_collection = false
461
- is_valid_attr = false
462
- if serializer.has_one_relationships.has_key?(unformatted_attr_name)
463
- is_valid_attr = true
464
- attr_data = serializer.has_one_relationships[unformatted_attr_name]
465
- object = serializer.has_one_relationship(unformatted_attr_name, attr_data)
466
- elsif serializer.has_many_relationships.has_key?(unformatted_attr_name)
467
- is_valid_attr = true
468
- is_collection = true
469
- attr_data = serializer.has_many_relationships[unformatted_attr_name]
470
- object = serializer.has_many_relationship(unformatted_attr_name, attr_data)
471
- end
456
+ ActiveSupport::Notifications.instrument(
457
+ 'render.jsonapi_serializers.find_recursive_relationships',
458
+ {class_name: root_object.class.name},
459
+ ) do
460
+ root_inclusion_tree.each do |attribute_name, child_inclusion_tree|
461
+ # Skip the sentinal value, but we need to preserve it for siblings.
462
+ next if attribute_name == :_include
463
+
464
+ serializer = JSONAPI::Serializer.find_serializer(root_object, options)
465
+ unformatted_attr_name = serializer.unformat_name(attribute_name).to_sym
466
+
467
+ # We know the name of this relationship, but we don't know where it is stored internally.
468
+ # Check if it is a has_one or has_many relationship.
469
+ object = nil
470
+ is_collection = false
471
+ is_valid_attr = false
472
+ if serializer.has_one_relationships.has_key?(unformatted_attr_name)
473
+ is_valid_attr = true
474
+ attr_data = serializer.has_one_relationships[unformatted_attr_name]
475
+ object = serializer.has_one_relationship(unformatted_attr_name, attr_data)
476
+ elsif serializer.has_many_relationships.has_key?(unformatted_attr_name)
477
+ is_valid_attr = true
478
+ is_collection = true
479
+ attr_data = serializer.has_many_relationships[unformatted_attr_name]
480
+ object = serializer.has_many_relationship(unformatted_attr_name, attr_data)
481
+ end
472
482
 
473
- if !is_valid_attr
474
- raise JSONAPI::Serializer::InvalidIncludeError.new(
475
- "'#{attribute_name}' is not a valid include.")
476
- end
483
+ if !is_valid_attr
484
+ raise JSONAPI::Serializer::InvalidIncludeError.new(
485
+ "'#{attribute_name}' is not a valid include.")
486
+ end
477
487
 
478
- if attribute_name != serializer.format_name(attribute_name)
479
- expected_name = serializer.format_name(attribute_name)
488
+ if attribute_name != serializer.format_name(attribute_name)
489
+ expected_name = serializer.format_name(attribute_name)
480
490
 
481
- raise JSONAPI::Serializer::InvalidIncludeError.new(
482
- "'#{attribute_name}' is not a valid include. Did you mean '#{expected_name}' ?"
483
- )
484
- end
491
+ raise JSONAPI::Serializer::InvalidIncludeError.new(
492
+ "'#{attribute_name}' is not a valid include. Did you mean '#{expected_name}' ?"
493
+ )
494
+ end
495
+
496
+ # We're finding relationships for compound documents, so skip anything that doesn't exist.
497
+ next if object.nil?
485
498
 
486
- # We're finding relationships for compound documents, so skip anything that doesn't exist.
487
- next if object.nil?
488
-
489
- # Full linkage: a request for comments.author MUST automatically include comments
490
- # in the response.
491
- objects = is_collection ? object : [object]
492
- if child_inclusion_tree[:_include] == true
493
- # Include the current level objects if the _include attribute exists.
494
- # If it is not set, that indicates that this is an inner path and not a leaf and will
495
- # be followed by the recursion below.
496
- objects.each do |obj|
497
- obj_serializer = JSONAPI::Serializer.find_serializer(obj, options)
498
- # Use keys of ['posts', '1'] for the results to enforce uniqueness.
499
- # Spec: A compound document MUST NOT include more than one resource object for each
500
- # type and id pair.
501
- # http://jsonapi.org/format/#document-structure-compound-documents
502
- key = [obj_serializer.type, obj_serializer.id]
503
-
504
- # This is special: we know at this level if a child of this parent will also been
505
- # included in the compound document, so we can compute exactly what linkages should
506
- # be included by the object at this level. This satisfies this part of the spec:
507
- #
508
- # Spec: Resource linkage in a compound document allows a client to link together
509
- # all of the included resource objects without having to GET any relationship URLs.
510
- # http://jsonapi.org/format/#document-structure-resource-relationships
511
- current_child_includes = []
512
- inclusion_names = child_inclusion_tree.keys.reject { |k| k == :_include }
513
- inclusion_names.each do |inclusion_name|
514
- if child_inclusion_tree[inclusion_name][:_include]
515
- current_child_includes << inclusion_name
499
+ # Full linkage: a request for comments.author MUST automatically include comments
500
+ # in the response.
501
+ objects = is_collection ? object : [object]
502
+ if child_inclusion_tree[:_include] == true
503
+ # Include the current level objects if the _include attribute exists.
504
+ # If it is not set, that indicates that this is an inner path and not a leaf and will
505
+ # be followed by the recursion below.
506
+ objects.each do |obj|
507
+ obj_serializer = JSONAPI::Serializer.find_serializer(obj, options)
508
+ # Use keys of ['posts', '1'] for the results to enforce uniqueness.
509
+ # Spec: A compound document MUST NOT include more than one resource object for each
510
+ # type and id pair.
511
+ # http://jsonapi.org/format/#document-structure-compound-documents
512
+ key = [obj_serializer.type, obj_serializer.id]
513
+
514
+ # This is special: we know at this level if a child of this parent will also been
515
+ # included in the compound document, so we can compute exactly what linkages should
516
+ # be included by the object at this level. This satisfies this part of the spec:
517
+ #
518
+ # Spec: Resource linkage in a compound document allows a client to link together
519
+ # all of the included resource objects without having to GET any relationship URLs.
520
+ # http://jsonapi.org/format/#document-structure-resource-relationships
521
+ current_child_includes = []
522
+ inclusion_names = child_inclusion_tree.keys.reject { |k| k == :_include }
523
+ inclusion_names.each do |inclusion_name|
524
+ if child_inclusion_tree[inclusion_name][:_include]
525
+ current_child_includes << inclusion_name
526
+ end
516
527
  end
517
- end
518
528
 
519
- # Special merge: we might see this object multiple times in the course of recursion,
520
- # so merge the include_linkages each time we see it to load all the relevant linkages.
521
- current_child_includes += results[key] && results[key][:include_linkages] || []
522
- current_child_includes.uniq!
523
- results[key] = {object: obj, include_linkages: current_child_includes}
529
+ # Special merge: we might see this object multiple times in the course of recursion,
530
+ # so merge the include_linkages each time we see it to load all the relevant linkages.
531
+ current_child_includes += results[key] && results[key][:include_linkages] || []
532
+ current_child_includes.uniq!
533
+ results[key] = {object: obj, include_linkages: current_child_includes}
534
+ end
524
535
  end
525
- end
526
536
 
527
- # Recurse deeper!
528
- if !child_inclusion_tree.empty?
529
- # For each object we just loaded, find all deeper recursive relationships.
530
- objects.each do |obj|
531
- find_recursive_relationships(obj, child_inclusion_tree, results, options)
537
+ # Recurse deeper!
538
+ if !child_inclusion_tree.empty?
539
+ # For each object we just loaded, find all deeper recursive relationships.
540
+ objects.each do |obj|
541
+ find_recursive_relationships(obj, child_inclusion_tree, results, options)
542
+ end
532
543
  end
533
544
  end
534
545
  end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Serializer
3
- VERSION = '1.0.1'
3
+ VERSION = '2.0.0-beta.1'
4
4
  end
5
5
  end
@@ -1,6 +1,7 @@
1
1
  require 'active_model/errors'
2
2
  require 'active_model/naming'
3
3
  require 'active_model/translation'
4
+ require 'pry'
4
5
 
5
6
  describe JSONAPI::Serializer do
6
7
  def serialize_primary(object, options = {})
@@ -16,6 +17,7 @@ describe JSONAPI::Serializer do
16
17
  primary_data = serialize_primary(nil, {serializer: MyApp::PostSerializer})
17
18
  expect(primary_data).to be_nil
18
19
  end
20
+
19
21
  it 'can serialize primary data for a simple object' do
20
22
  post = create(:post)
21
23
  primary_data = serialize_primary(post, {serializer: MyApp::SimplestPostSerializer})
@@ -31,6 +33,7 @@ describe JSONAPI::Serializer do
31
33
  },
32
34
  })
33
35
  end
36
+
34
37
  it 'can serialize primary data for a simple object with a long name' do
35
38
  long_comment = create(:long_comment, post: create(:post))
36
39
  primary_data = serialize_primary(long_comment, {serializer: MyApp::LongCommentSerializer})
@@ -59,6 +62,7 @@ describe JSONAPI::Serializer do
59
62
  },
60
63
  })
61
64
  end
65
+
62
66
  it 'can serialize primary data for a simple object with resource-level metadata' do
63
67
  post = create(:post)
64
68
  primary_data = serialize_primary(post, {serializer: MyApp::PostSerializerWithMetadata})
@@ -80,6 +84,7 @@ describe JSONAPI::Serializer do
80
84
  },
81
85
  })
82
86
  end
87
+
83
88
  context 'without any linkage includes (default)' do
84
89
  it 'can serialize primary data for an object with to-one and to-many relationships' do
85
90
  post = create(:post)
@@ -111,6 +116,7 @@ describe JSONAPI::Serializer do
111
116
  },
112
117
  })
113
118
  end
119
+
114
120
  it 'does not include relationship links if relationship_{self_link,_related_link} are nil' do
115
121
  post = create(:post)
116
122
  primary_data = serialize_primary(post, {serializer: MyApp::PostSerializerWithoutLinks})
@@ -129,6 +135,7 @@ describe JSONAPI::Serializer do
129
135
  },
130
136
  })
131
137
  end
138
+
132
139
  it 'does not include id when it is nil' do
133
140
  post = create(:post)
134
141
  post.id = nil
@@ -145,6 +152,7 @@ describe JSONAPI::Serializer do
145
152
  },
146
153
  })
147
154
  end
155
+
148
156
  it 'serializes object when multiple attributes are declared once' do
149
157
  post = create(:post)
150
158
  primary_data = serialize_primary(post, {serializer: MyApp::MultipleAttributesSerializer})
@@ -161,6 +169,7 @@ describe JSONAPI::Serializer do
161
169
  })
162
170
  end
163
171
  end
172
+
164
173
  context 'with linkage includes' do
165
174
  it 'can serialize primary data for a null to-one relationship' do
166
175
  post = create(:post, author: nil)
@@ -200,6 +209,7 @@ describe JSONAPI::Serializer do
200
209
  },
201
210
  })
202
211
  end
212
+
203
213
  it 'can serialize primary data for a simple to-one relationship' do
204
214
  post = create(:post, :with_author)
205
215
  options = {
@@ -241,6 +251,7 @@ describe JSONAPI::Serializer do
241
251
  },
242
252
  })
243
253
  end
254
+
244
255
  it 'can serialize primary data for an empty to-many relationship' do
245
256
  post = create(:post, long_comments: [])
246
257
  options = {
@@ -279,6 +290,7 @@ describe JSONAPI::Serializer do
279
290
  },
280
291
  })
281
292
  end
293
+
282
294
  it 'can serialize primary data for a simple to-many relationship' do
283
295
  long_comments = create_list(:long_comment, 2)
284
296
  post = create(:post, long_comments: long_comments)
@@ -328,6 +340,7 @@ describe JSONAPI::Serializer do
328
340
  })
329
341
  end
330
342
  end
343
+
331
344
  it 'can serialize primary data for an empty serializer with no attributes' do
332
345
  post = create(:post)
333
346
  primary_data = serialize_primary(post, {serializer: MyApp::EmptySerializer})
@@ -339,6 +352,7 @@ describe JSONAPI::Serializer do
339
352
  },
340
353
  })
341
354
  end
355
+
342
356
  it 'can find the correct serializer by object class name' do
343
357
  post = create(:post)
344
358
  primary_data = serialize_primary(post)
@@ -502,22 +516,26 @@ describe JSONAPI::Serializer do
502
516
  it 'can serialize a nil object' do
503
517
  expect(JSONAPI::Serializer.serialize(nil)).to eq({'data' => nil})
504
518
  end
519
+
505
520
  it 'can serialize a nil object with includes' do
506
521
  # Also, the include argument is not validated in this case because we don't know the type.
507
522
  data = JSONAPI::Serializer.serialize(nil, include: ['fake'])
508
523
  expect(data).to eq({'data' => nil, 'included' => []})
509
524
  end
525
+
510
526
  it 'can serialize an empty array' do
511
527
  # Also, the include argument is not validated in this case because we don't know the type.
512
528
  data = JSONAPI::Serializer.serialize([], is_collection: true, include: ['fake'])
513
529
  expect(data).to eq({'data' => [], 'included' => []})
514
530
  end
531
+
515
532
  it 'can serialize a simple object' do
516
533
  post = create(:post)
517
534
  expect(JSONAPI::Serializer.serialize(post)).to eq({
518
535
  'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
519
536
  })
520
537
  end
538
+
521
539
  it 'can include a top level jsonapi node' do
522
540
  post = create(:post)
523
541
  jsonapi_version = {'version' => '1.0'}
@@ -526,6 +544,7 @@ describe JSONAPI::Serializer do
526
544
  'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
527
545
  })
528
546
  end
547
+
529
548
  it 'can include a top level meta node' do
530
549
  post = create(:post)
531
550
  meta = {authors: ['Yehuda Katz', 'Steve Klabnik'], copyright: 'Copyright 2015 Example Corp.'}
@@ -534,6 +553,7 @@ describe JSONAPI::Serializer do
534
553
  'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
535
554
  })
536
555
  end
556
+
537
557
  it 'can include a top level links node' do
538
558
  post = create(:post)
539
559
  links = {self: 'http://example.com/posts'}
@@ -542,6 +562,7 @@ describe JSONAPI::Serializer do
542
562
  'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
543
563
  })
544
564
  end
565
+
545
566
  # TODO: remove this code on next major release
546
567
  it 'can include a top level errors node - deprecated' do
547
568
  post = create(:post)
@@ -562,15 +583,18 @@ describe JSONAPI::Serializer do
562
583
  'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
563
584
  })
564
585
  end
586
+
565
587
  it 'can serialize a single object with an `each` method by passing skip_collection_check: true' do
566
588
  post = create(:post)
567
589
  post.define_singleton_method(:each) do
568
590
  "defining this just to defeat the duck-type check"
569
591
  end
592
+
570
593
  expect(JSONAPI::Serializer.serialize(post, skip_collection_check: true)).to eq({
571
594
  'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
572
595
  })
573
596
  end
597
+
574
598
  it 'can serialize a collection' do
575
599
  posts = create_list(:post, 2)
576
600
  expect(JSONAPI::Serializer.serialize(posts, is_collection: true)).to eq({
@@ -580,6 +604,7 @@ describe JSONAPI::Serializer do
580
604
  ],
581
605
  })
582
606
  end
607
+
583
608
  it 'raises AmbiguousCollectionError if is_collection is not passed' do
584
609
  posts = create_list(:post, 2)
585
610
  error = JSONAPI::Serializer::AmbiguousCollectionError
@@ -596,10 +621,12 @@ describe JSONAPI::Serializer do
596
621
  options = {serializer: MyApp::PostSerializer}
597
622
  expect(JSONAPI::Serializer.serialize(nil, options)).to eq({'data' => nil})
598
623
  end
624
+
599
625
  it 'can serialize an empty array when given serializer' do
600
626
  options = {is_collection: true, serializer: MyApp::PostSerializer}
601
627
  expect(JSONAPI::Serializer.serialize([], options)).to eq({'data' => []})
602
628
  end
629
+
603
630
  it 'can serialize a simple object when given serializer' do
604
631
  post = create(:post)
605
632
  options = {serializer: MyApp::SimplestPostSerializer}
@@ -607,6 +634,7 @@ describe JSONAPI::Serializer do
607
634
  'data' => serialize_primary(post, {serializer: MyApp::SimplestPostSerializer}),
608
635
  })
609
636
  end
637
+
610
638
  it 'handles include of nil to-one relationship with compound document' do
611
639
  post = create(:post)
612
640
 
@@ -619,6 +647,7 @@ describe JSONAPI::Serializer do
619
647
  'included' => [],
620
648
  })
621
649
  end
650
+
622
651
  it 'handles include of simple to-one relationship with compound document' do
623
652
  post = create(:post, :with_author)
624
653
 
@@ -633,6 +662,7 @@ describe JSONAPI::Serializer do
633
662
  ],
634
663
  })
635
664
  end
665
+
636
666
  it 'handles include of empty to-many relationships with compound document' do
637
667
  post = create(:post, :with_author, long_comments: [])
638
668
 
@@ -645,6 +675,7 @@ describe JSONAPI::Serializer do
645
675
  'included' => [],
646
676
  })
647
677
  end
678
+
648
679
  it 'handles include of to-many relationships with compound document' do
649
680
  long_comments = create_list(:long_comment, 2)
650
681
  post = create(:post, :with_author, long_comments: long_comments)
@@ -661,6 +692,7 @@ describe JSONAPI::Serializer do
661
692
  ],
662
693
  })
663
694
  end
695
+
664
696
  it 'only includes one copy of each referenced relationship' do
665
697
  long_comment = create(:long_comment)
666
698
  long_comments = [long_comment, long_comment]
@@ -677,6 +709,7 @@ describe JSONAPI::Serializer do
677
709
  ],
678
710
  })
679
711
  end
712
+
680
713
  it 'handles circular-referencing relationships with compound document' do
681
714
  long_comments = create_list(:long_comment, 2)
682
715
  post = create(:post, :with_author, long_comments: long_comments)
@@ -696,10 +729,12 @@ describe JSONAPI::Serializer do
696
729
  ],
697
730
  })
698
731
  end
732
+
699
733
  it 'errors if include is not a defined attribute' do
700
734
  user = create(:user)
701
735
  expect { JSONAPI::Serializer.serialize(user, include: ['fake-attr']) }.to raise_error
702
736
  end
737
+
703
738
  it 'handles recursive loading of relationships' do
704
739
  user = create(:user)
705
740
  long_comments = create_list(:long_comment, 2, user: user)
@@ -737,6 +772,7 @@ describe JSONAPI::Serializer do
737
772
  expect(actual_data['included']).to eq(expected_data['included'])
738
773
  expect(actual_data).to eq(expected_data)
739
774
  end
775
+
740
776
  it 'handles recursive loading of multiple to-one relationships on children' do
741
777
  first_user = create(:user)
742
778
  second_user = create(:user)
@@ -774,6 +810,7 @@ describe JSONAPI::Serializer do
774
810
  expect(actual_data['included']).to eq(expected_data['included'])
775
811
  expect(actual_data).to eq(expected_data)
776
812
  end
813
+
777
814
  it 'includes linkage in compounded resources only if the immediate parent was also included' do
778
815
  comment_user = create(:user)
779
816
  long_comments = [create(:long_comment, user: comment_user)]
@@ -802,6 +839,7 @@ describe JSONAPI::Serializer do
802
839
  expect(actual_data['included']).to eq(expected_data['included'])
803
840
  expect(actual_data).to eq(expected_data)
804
841
  end
842
+
805
843
  it 'handles recursive loading of to-many relationships with overlapping include paths' do
806
844
  user = create(:user)
807
845
  long_comments = create_list(:long_comment, 2, user: user)
@@ -884,6 +922,7 @@ describe JSONAPI::Serializer do
884
922
  }
885
923
  })
886
924
  end
925
+
887
926
  it 'allows to limit fields(relationships) for serialized resource' do
888
927
  first_user = create(:user)
889
928
  second_user = create(:user)
@@ -909,6 +948,7 @@ describe JSONAPI::Serializer do
909
948
  }
910
949
  })
911
950
  end
951
+
912
952
  it "allows also to pass specific fields as array instead of comma-separates values" do
913
953
  first_user = create(:user)
914
954
  second_user = create(:user)
@@ -930,6 +970,7 @@ describe JSONAPI::Serializer do
930
970
  }
931
971
  })
932
972
  end
973
+
933
974
  it 'allows to limit fields(attributes and relationships) for included resources' do
934
975
  first_user = create(:user)
935
976
  second_user = create(:user)
@@ -983,18 +1024,21 @@ describe JSONAPI::Serializer do
983
1024
  result = JSONAPI::Serializer.send(:parse_relationship_paths, [])
984
1025
  expect(result).to eq({})
985
1026
  end
1027
+
986
1028
  it 'correctly handles single-level relationship paths' do
987
1029
  result = JSONAPI::Serializer.send(:parse_relationship_paths, ['foo'])
988
1030
  expect(result).to eq({
989
1031
  'foo' => {_include: true}
990
1032
  })
991
1033
  end
1034
+
992
1035
  it 'correctly handles multi-level relationship paths' do
993
1036
  result = JSONAPI::Serializer.send(:parse_relationship_paths, ['foo.bar'])
994
1037
  expect(result).to eq({
995
1038
  'foo' => {_include: true, 'bar' => {_include: true}}
996
1039
  })
997
1040
  end
1041
+
998
1042
  it 'correctly handles multi-level relationship paths with same parent' do
999
1043
  paths = ['foo', 'foo.bar']
1000
1044
  result = JSONAPI::Serializer.send(:parse_relationship_paths, paths)
@@ -1002,6 +1046,7 @@ describe JSONAPI::Serializer do
1002
1046
  'foo' => {_include: true, 'bar' => {_include: true}}
1003
1047
  })
1004
1048
  end
1049
+
1005
1050
  it 'correctly handles multi-level relationship paths with different parent' do
1006
1051
  paths = ['foo', 'bar', 'bar.baz']
1007
1052
  result = JSONAPI::Serializer.send(:parse_relationship_paths, paths)
@@ -1010,6 +1055,7 @@ describe JSONAPI::Serializer do
1010
1055
  'bar' => {_include: true, 'baz' => {_include: true}},
1011
1056
  })
1012
1057
  end
1058
+
1013
1059
  it 'correctly handles three-leveled path' do
1014
1060
  paths = ['foo', 'foo.bar', 'foo.bar.baz']
1015
1061
  result = JSONAPI::Serializer.send(:parse_relationship_paths, paths)
@@ -1017,6 +1063,7 @@ describe JSONAPI::Serializer do
1017
1063
  'foo' => {_include: true, 'bar' => {_include: true, 'baz' => {_include: true}}}
1018
1064
  })
1019
1065
  end
1066
+
1020
1067
  it 'correctly handles three-leveled path with skipped middle' do
1021
1068
  paths = ['foo', 'foo.bar.baz']
1022
1069
  result = JSONAPI::Serializer.send(:parse_relationship_paths, paths)
@@ -1025,6 +1072,7 @@ describe JSONAPI::Serializer do
1025
1072
  })
1026
1073
  end
1027
1074
  end
1075
+
1028
1076
  describe 'if/unless handling with contexts' do
1029
1077
  it 'can be used to show/hide attributes' do
1030
1078
  post = create(:post)
@@ -1068,6 +1116,7 @@ describe JSONAPI::Serializer do
1068
1116
  expect(data['data']['attributes']).to_not have_key('body')
1069
1117
  end
1070
1118
  end
1119
+
1071
1120
  describe 'context' do
1072
1121
  it 'is passed through all relationship serializers' do
1073
1122
  # Force long_comments to be serialized by the context-sensitive serializer.
@@ -1113,6 +1162,7 @@ describe JSONAPI::Serializer do
1113
1162
  'related' => '/posts/1/author'
1114
1163
  })
1115
1164
  end
1165
+
1116
1166
  it 'adds base_url to links if passed' do
1117
1167
  long_comments = create_list(:long_comment, 1)
1118
1168
  post = create(:post, long_comments: long_comments)
@@ -1123,6 +1173,7 @@ describe JSONAPI::Serializer do
1123
1173
  'related' => 'http://example.com/posts/1/author'
1124
1174
  })
1125
1175
  end
1176
+
1126
1177
  it 'uses overriden base_url method if it exists' do
1127
1178
  long_comments = create_list(:long_comment, 1)
1128
1179
  post = create(:post, long_comments: long_comments)
@@ -1233,4 +1284,54 @@ describe JSONAPI::Serializer do
1233
1284
  expect(actual_data).to eq(expected_data)
1234
1285
  end
1235
1286
  end
1287
+
1288
+ describe 'instrumentation' do
1289
+ let(:post) { create(:post, :with_author) }
1290
+ let(:events) { [] }
1291
+
1292
+ before do
1293
+ ActiveSupport::Notifications.subscribe(notification_name) do |*args|
1294
+ events << ActiveSupport::Notifications::Event.new(*args)
1295
+ end
1296
+ end
1297
+
1298
+ describe 'serialize_primary' do
1299
+ let(:notification_name) { 'render.jsonapi_serializers.serialize_primary' }
1300
+
1301
+ it 'sends an event for a single serialize call' do
1302
+ JSONAPI::Serializer.serialize(post)
1303
+
1304
+ expect(events.length).to eq(1)
1305
+ expect(events[0].name).to eq(notification_name)
1306
+ expect(events[0].payload).to eq({class_name: "MyApp::Post"})
1307
+ end
1308
+
1309
+ it 'sends events for includes' do
1310
+ JSONAPI::Serializer.serialize(post, include: ['author'])
1311
+
1312
+ expect(events.length).to eq(2)
1313
+ expect(events[0].payload).to eq({class_name: "MyApp::Post"})
1314
+ expect(events[1].payload).to eq({class_name: "MyApp::User"})
1315
+ end
1316
+ end
1317
+
1318
+ describe 'find_recursive_relationships' do
1319
+ let(:notification_name) { 'render.jsonapi_serializers.find_recursive_relationships' }
1320
+
1321
+ it 'does not send event when there are no includes' do
1322
+ JSONAPI::Serializer.serialize(post)
1323
+ expect(events.length).to eq(0)
1324
+ end
1325
+
1326
+ it 'sends events for includes' do
1327
+ JSONAPI::Serializer.serialize(post, include: ['author'])
1328
+
1329
+ expect(events.length).to eq(2)
1330
+ expect(events[0].name).to eq(notification_name)
1331
+ expect(events[0].payload).to eq({class_name: "MyApp::User"})
1332
+ expect(events[1].name).to eq(notification_name)
1333
+ expect(events[1].payload).to eq({class_name: "MyApp::Post"})
1334
+ end
1335
+ end
1336
+ end
1236
1337
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-serializers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.0.0.pre.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Fotinakis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-10 00:00:00.000000000 Z
11
+ date: 2019-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '4.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  description: Pure Ruby readonly serializers for the JSON:API spec.
98
112
  email:
99
113
  - mike@fotinakis.com
@@ -132,12 +146,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
146
  version: '0'
133
147
  required_rubygems_version: !ruby/object:Gem::Requirement
134
148
  requirements:
135
- - - ">="
149
+ - - ">"
136
150
  - !ruby/object:Gem::Version
137
- version: '0'
151
+ version: 1.3.1
138
152
  requirements: []
139
- rubyforge_project:
140
- rubygems_version: 2.7.6
153
+ rubygems_version: 3.0.4
141
154
  signing_key:
142
155
  specification_version: 4
143
156
  summary: Pure Ruby readonly serializers for the JSON:API spec.