sanger-jsonapi-resources 0.1.1 → 0.2.0

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +35 -12
  4. data/lib/bug_report_templates/rails_5_latest.rb +125 -0
  5. data/lib/bug_report_templates/rails_5_master.rb +140 -0
  6. data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +26 -0
  7. data/lib/jsonapi/active_relation/join_manager.rb +297 -0
  8. data/lib/jsonapi/active_relation_resource.rb +898 -0
  9. data/lib/jsonapi/acts_as_resource_controller.rb +130 -113
  10. data/lib/jsonapi/basic_resource.rb +1164 -0
  11. data/lib/jsonapi/cached_response_fragment.rb +129 -0
  12. data/lib/jsonapi/callbacks.rb +2 -0
  13. data/lib/jsonapi/compatibility_helper.rb +29 -0
  14. data/lib/jsonapi/compiled_json.rb +13 -1
  15. data/lib/jsonapi/configuration.rb +88 -21
  16. data/lib/jsonapi/error.rb +29 -0
  17. data/lib/jsonapi/error_codes.rb +4 -0
  18. data/lib/jsonapi/exceptions.rb +82 -50
  19. data/lib/jsonapi/formatter.rb +5 -3
  20. data/lib/jsonapi/include_directives.rb +22 -67
  21. data/lib/jsonapi/link_builder.rb +76 -80
  22. data/lib/jsonapi/mime_types.rb +6 -10
  23. data/lib/jsonapi/naive_cache.rb +2 -0
  24. data/lib/jsonapi/operation.rb +18 -5
  25. data/lib/jsonapi/operation_result.rb +76 -16
  26. data/lib/jsonapi/paginator.rb +2 -0
  27. data/lib/jsonapi/path.rb +45 -0
  28. data/lib/jsonapi/path_segment.rb +78 -0
  29. data/lib/jsonapi/processor.rb +193 -115
  30. data/lib/jsonapi/relationship.rb +145 -14
  31. data/lib/jsonapi/request.rb +734 -0
  32. data/lib/jsonapi/resource.rb +3 -1251
  33. data/lib/jsonapi/resource_controller.rb +2 -0
  34. data/lib/jsonapi/resource_controller_metal.rb +7 -1
  35. data/lib/jsonapi/resource_fragment.rb +56 -0
  36. data/lib/jsonapi/resource_identity.rb +44 -0
  37. data/lib/jsonapi/resource_serializer.rb +158 -284
  38. data/lib/jsonapi/resource_set.rb +196 -0
  39. data/lib/jsonapi/resource_tree.rb +236 -0
  40. data/lib/jsonapi/resources/railtie.rb +9 -0
  41. data/lib/jsonapi/resources/version.rb +1 -1
  42. data/lib/jsonapi/response_document.rb +107 -83
  43. data/lib/jsonapi/routing_ext.rb +50 -26
  44. data/lib/jsonapi-resources.rb +23 -5
  45. data/lib/tasks/check_upgrade.rake +52 -0
  46. metadata +43 -31
  47. data/lib/jsonapi/cached_resource_fragment.rb +0 -127
  48. data/lib/jsonapi/operation_dispatcher.rb +0 -88
  49. data/lib/jsonapi/operation_results.rb +0 -35
  50. data/lib/jsonapi/relationship_builder.rb +0 -167
  51. data/lib/jsonapi/request_parser.rb +0 -678
@@ -1,15 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
4
  class OperationResult
3
5
  attr_accessor :code
4
6
  attr_accessor :meta
5
7
  attr_accessor :links
6
8
  attr_accessor :options
9
+ attr_accessor :warnings
7
10
 
8
11
  def initialize(code, options = {})
9
- @code = code
12
+ @code = Rack::Utils.status_code(code)
10
13
  @options = options
11
14
  @meta = options.fetch(:meta, {})
12
15
  @links = options.fetch(:links, {})
16
+ @warnings = options.fetch(:warnings, {})
17
+ end
18
+
19
+ def to_hash(serializer = nil)
20
+ {}
13
21
  end
14
22
  end
15
23
 
@@ -20,46 +28,98 @@ module JSONAPI
20
28
  @errors = errors
21
29
  super(code, options)
22
30
  end
31
+
32
+ def to_hash(serializer = nil)
33
+ {
34
+ errors: errors.collect do |error|
35
+ # :nocov:
36
+ error.to_hash
37
+ # :nocov:
38
+ end
39
+ }
40
+ end
23
41
  end
24
42
 
25
- class ResourceOperationResult < OperationResult
26
- attr_accessor :resource
43
+ class ResourceSetOperationResult < OperationResult
44
+ attr_accessor :resource_set, :pagination_params
27
45
 
28
- def initialize(code, resource, options = {})
29
- @resource = resource
46
+ def initialize(code, resource_set, options = {})
47
+ @resource_set = resource_set
48
+ @pagination_params = options.fetch(:pagination_params, {})
30
49
  super(code, options)
31
50
  end
51
+
52
+ def to_hash(serializer)
53
+ if serializer
54
+ serializer.serialize_resource_set_to_hash_single(resource_set)
55
+ else
56
+ # :nocov:
57
+ {}
58
+ # :nocov:
59
+ end
60
+ end
32
61
  end
33
62
 
34
- class ResourcesOperationResult < OperationResult
35
- attr_accessor :resources, :pagination_params, :record_count, :page_count
63
+ class ResourcesSetOperationResult < OperationResult
64
+ attr_accessor :resource_set, :pagination_params, :record_count, :page_count
36
65
 
37
- def initialize(code, resources, options = {})
38
- @resources = resources
66
+ def initialize(code, resource_set, options = {})
67
+ @resource_set = resource_set
39
68
  @pagination_params = options.fetch(:pagination_params, {})
40
69
  @record_count = options[:record_count]
41
70
  @page_count = options[:page_count]
42
71
  super(code, options)
43
72
  end
73
+
74
+ def to_hash(serializer)
75
+ if serializer
76
+ serializer.serialize_resource_set_to_hash_plural(resource_set)
77
+ else
78
+ # :nocov:
79
+ {}
80
+ # :nocov:
81
+ end
82
+ end
44
83
  end
45
84
 
46
- class RelatedResourcesOperationResult < ResourcesOperationResult
47
- attr_accessor :source_resource, :_type
85
+ class RelatedResourcesSetOperationResult < ResourcesSetOperationResult
86
+ attr_accessor :resource_set, :source_resource, :_type
48
87
 
49
- def initialize(code, source_resource, type, resources, options = {})
88
+ def initialize(code, source_resource, type, resource_set, options = {})
50
89
  @source_resource = source_resource
51
90
  @_type = type
52
- super(code, resources, options)
91
+ super(code, resource_set, options)
92
+ end
93
+
94
+ def to_hash(serializer = nil)
95
+ if serializer
96
+ serializer.serialize_related_resource_set_to_hash_plural(resource_set, source_resource)
97
+ else
98
+ # :nocov:
99
+ {}
100
+ # :nocov:
101
+ end
53
102
  end
54
103
  end
55
104
 
56
- class LinksObjectOperationResult < OperationResult
57
- attr_accessor :parent_resource, :relationship
105
+ class RelationshipOperationResult < OperationResult
106
+ attr_accessor :parent_resource, :relationship, :resource_ids
58
107
 
59
- def initialize(code, parent_resource, relationship, options = {})
108
+ def initialize(code, parent_resource, relationship, resource_ids, options = {})
60
109
  @parent_resource = parent_resource
61
110
  @relationship = relationship
111
+ @resource_ids = resource_ids
62
112
  super(code, options)
63
113
  end
114
+
115
+ def to_hash(serializer = nil)
116
+ if serializer
117
+ serializer.serialize_to_relationship_hash(parent_resource, relationship, resource_ids)
118
+ else
119
+ # :nocov:
120
+ {}
121
+ # :nocov:
122
+ end
123
+ end
64
124
  end
65
125
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
4
  class Paginator
3
5
  def initialize(_params)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONAPI
4
+ class Path
5
+ attr_reader :segments, :resource_klass
6
+ def initialize(resource_klass:,
7
+ path_string:,
8
+ ensure_default_field: true,
9
+ parse_fields: true)
10
+ @resource_klass = resource_klass
11
+
12
+ current_resource_klass = resource_klass
13
+ @segments = path_string.to_s.split('.').collect do |segment_string|
14
+ segment = PathSegment.parse(source_resource_klass: current_resource_klass,
15
+ segment_string: segment_string,
16
+ parse_fields: parse_fields)
17
+
18
+ current_resource_klass = segment.resource_klass
19
+ segment
20
+ end
21
+
22
+ if ensure_default_field && parse_fields && @segments.last.is_a?(PathSegment::Relationship)
23
+ last = @segments.last
24
+ @segments << PathSegment::Field.new(resource_klass: last.resource_klass,
25
+ field_name: last.resource_klass._primary_key)
26
+ end
27
+ end
28
+
29
+ def relationship_segments
30
+ @segments.select {|p| p.is_a?(PathSegment::Relationship)}
31
+ end
32
+
33
+ def relationship_path_string
34
+ relationship_segments.collect(&:to_s).join('.')
35
+ end
36
+
37
+ def last_relationship
38
+ if @segments.last.is_a?(PathSegment::Relationship)
39
+ @segments.last
40
+ else
41
+ @segments[-2]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONAPI
4
+ class PathSegment
5
+ def self.parse(source_resource_klass:, segment_string:, parse_fields: true)
6
+ first_part, last_part = segment_string.split('#', 2)
7
+ relationship = source_resource_klass._relationship(first_part)
8
+
9
+ if relationship
10
+ if last_part
11
+ unless relationship.resource_types.include?(last_part)
12
+ raise JSONAPI::Exceptions::InvalidRelationship.new(source_resource_klass._type, segment_string)
13
+ end
14
+ resource_klass = source_resource_klass.resource_klass_for(last_part)
15
+ end
16
+ return PathSegment::Relationship.new(relationship: relationship, resource_klass: resource_klass)
17
+ else
18
+ if last_part.blank? && parse_fields
19
+ return PathSegment::Field.new(resource_klass: source_resource_klass, field_name: first_part)
20
+ else
21
+ raise JSONAPI::Exceptions::InvalidRelationship.new(source_resource_klass._type, segment_string)
22
+ end
23
+ end
24
+ end
25
+
26
+ class Relationship
27
+ attr_reader :relationship, :resource_klass
28
+
29
+ def initialize(relationship:, resource_klass: nil)
30
+ @relationship = relationship
31
+ @resource_klass = resource_klass
32
+ end
33
+
34
+ def eql?(other)
35
+ other.is_a?(self.class) && relationship == other.relationship && resource_klass == other.resource_klass
36
+ end
37
+
38
+ def hash
39
+ [relationship, resource_klass].hash
40
+ end
41
+
42
+ def to_s
43
+ @resource_klass ? "#{relationship.parent_resource_klass._type}.#{relationship.name}##{resource_klass._type}" : "#{resource_klass._type}.#{relationship.name}"
44
+ end
45
+
46
+ def resource_klass
47
+ @resource_klass || relationship.resource_klass
48
+ end
49
+
50
+ def path_specified_resource_klass?
51
+ !@resource_klass.nil?
52
+ end
53
+ end
54
+
55
+ class Field
56
+ attr_reader :resource_klass, :field_name
57
+
58
+ def initialize(resource_klass:, field_name:)
59
+ @resource_klass = resource_klass
60
+ @field_name = field_name
61
+ end
62
+
63
+ def eql?(other)
64
+ other.is_a?(self.class) && field_name == other.field_name && resource_klass == other.resource_klass
65
+ end
66
+
67
+ def delegated_field_name
68
+ resource_klass._attribute_delegated_name(field_name)
69
+ end
70
+
71
+ def to_s
72
+ # :nocov:
73
+ "#{resource_klass._type}.#{field_name.to_s}"
74
+ # :nocov:
75
+ end
76
+ end
77
+ end
78
+ end