jsonapi-serializers 1.0.1 → 2.0.0.pre.beta.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.
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.