jat 0.0.3 → 0.0.5

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jat/attribute.rb +36 -4
  3. data/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads.rb +7 -3
  4. data/lib/jat/plugins/_activerecord_preloads/lib/preloader.rb +7 -13
  5. data/lib/jat/plugins/_lower_camel_case/_lower_camel_case.rb +32 -0
  6. data/lib/jat/plugins/_preloads/_preloads.rb +8 -2
  7. data/lib/jat/plugins/cache/cache.rb +9 -5
  8. data/lib/jat/plugins/json_api/json_api.rb +145 -105
  9. data/lib/jat/plugins/json_api/lib/fields_param_parser.rb +40 -0
  10. data/lib/jat/plugins/json_api/lib/include_param_parser.rb +84 -0
  11. data/lib/jat/plugins/json_api/lib/map.rb +92 -27
  12. data/lib/jat/plugins/json_api/lib/params/fields/validate.rb +8 -5
  13. data/lib/jat/plugins/json_api/lib/response.rb +84 -196
  14. data/lib/jat/plugins/json_api/lib/response_piece.rb +166 -0
  15. data/lib/jat/plugins/json_api_activerecord/json_api_activerecord.rb +31 -0
  16. data/lib/jat/plugins/{_json_api_activerecord → json_api_activerecord}/lib/preloads.rb +16 -24
  17. data/lib/jat/plugins/json_api_lower_camel_case/json_api_lower_camel_case.rb +30 -0
  18. data/lib/jat/plugins/json_api_maps_cache/json_api_maps_cache.rb +54 -0
  19. data/lib/jat/plugins/json_api_validate_params/json_api_validate_params.rb +57 -0
  20. data/lib/jat/plugins/json_api_validate_params/lib/params_error.rb +6 -0
  21. data/lib/jat/plugins/json_api_validate_params/lib/validate_fields_param.rb +59 -0
  22. data/lib/jat/plugins/json_api_validate_params/lib/validate_include_param.rb +33 -0
  23. data/lib/jat/plugins/simple_api/lib/fields_param_parser.rb +97 -0
  24. data/lib/jat/plugins/simple_api/lib/map.rb +80 -10
  25. data/lib/jat/plugins/simple_api/lib/response.rb +78 -89
  26. data/lib/jat/plugins/simple_api/lib/response_piece.rb +84 -0
  27. data/lib/jat/plugins/simple_api/simple_api.rb +83 -24
  28. data/lib/jat/plugins/simple_api_activerecord/lib/preloads.rb +55 -0
  29. data/lib/jat/plugins/simple_api_activerecord/simple_api_activerecord.rb +31 -0
  30. data/lib/jat/plugins/simple_api_lower_camel_case/simple_api_lower_camel_case.rb +30 -0
  31. data/lib/jat/plugins/simple_api_maps_cache/simple_api_maps_cache.rb +48 -0
  32. data/lib/jat/plugins/simple_api_validate_params/lib/fields_error.rb +6 -0
  33. data/lib/jat/plugins/simple_api_validate_params/lib/validate_fields_param.rb +45 -0
  34. data/lib/jat/plugins/simple_api_validate_params/simple_api_validate_params.rb +45 -0
  35. data/lib/jat/plugins/to_str/to_str.rb +10 -4
  36. data/lib/jat/plugins.rb +3 -16
  37. data/lib/jat.rb +28 -30
  38. data/test/lib/jat/attribute_test.rb +15 -5
  39. data/test/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads_test.rb +34 -15
  40. data/test/lib/jat/plugins/_activerecord_preloads/lib/preloader_test.rb +10 -24
  41. data/test/lib/jat/plugins/_camel_lower/_camel_lower_test.rb +26 -0
  42. data/test/lib/jat/plugins/_preloads/lib/format_user_preloads_test.rb +1 -1
  43. data/test/lib/jat/plugins/_preloads/lib/preloads_with_path_test.rb +1 -1
  44. data/test/lib/jat/plugins/cache/cache_test.rb +11 -11
  45. data/test/lib/jat/plugins/json_api/json_api_test.rb +63 -47
  46. data/test/lib/jat/plugins/json_api/lib/{params/fields_test.rb → fields_param_parser_test.rb} +7 -6
  47. data/test/lib/jat/plugins/json_api/lib/{params/include_test.rb → include_param_parser_test.rb} +4 -4
  48. data/test/lib/jat/plugins/json_api/lib/map_test.rb +150 -79
  49. data/test/lib/jat/plugins/json_api/lib/response_test.rb +32 -32
  50. data/test/lib/jat/plugins/{_json_api_activerecord/_json_api_activerecord_test.rb → json_api_activerecord/json_api_activerecord_test.rb} +14 -5
  51. data/test/lib/jat/plugins/{_json_api_activerecord → json_api_activerecord}/lib/preloads_test.rb +11 -10
  52. data/test/lib/jat/plugins/json_api_camel_lower/json_api_camel_lower_test.rb +79 -0
  53. data/test/lib/jat/plugins/json_api_maps_cache/json_api_maps_cache_test.rb +107 -0
  54. data/test/lib/jat/plugins/json_api_validate_params/json_api_validate_params_test.rb +84 -0
  55. data/test/lib/jat/plugins/simple_api/lib/{params/parse_test.rb → fields_param_parser_test.rb} +10 -4
  56. data/test/lib/jat/plugins/simple_api/lib/map_test.rb +111 -34
  57. data/test/lib/jat/plugins/simple_api/lib/response_test.rb +80 -74
  58. data/test/lib/jat/plugins/simple_api/simple_api_test.rb +91 -25
  59. data/test/lib/jat/plugins/simple_api_activerecord/lib/preloads_test.rb +135 -0
  60. data/test/lib/jat/plugins/simple_api_activerecord/simple_api_activerecord_test.rb +38 -0
  61. data/test/lib/jat/plugins/simple_api_camel_lower/simple_api_camel_lower_test.rb +48 -0
  62. data/test/lib/jat/plugins/simple_api_maps_cache/simple_api_maps_cache_test.rb +95 -0
  63. data/test/lib/jat/plugins/simple_api_validate_params/simple_api_validate_params_test.rb +89 -0
  64. data/test/lib/jat/plugins/to_str/to_str_test.rb +3 -3
  65. data/test/lib/jat_test.rb +47 -24
  66. data/test/lib/plugin_test.rb +3 -3
  67. data/test/test_helper.rb +0 -3
  68. data/test/test_plugin.rb +9 -12
  69. metadata +60 -71
  70. data/CHANGELOG.md +0 -7
  71. data/README.md +0 -21
  72. data/jat.gemspec +0 -37
  73. data/lib/jat/plugins/_json_api_activerecord/_json_api_activerecord.rb +0 -22
  74. data/lib/jat/plugins/camel_lower/camel_lower.rb +0 -18
  75. data/lib/jat/plugins/json_api/lib/construct_traversal_map.rb +0 -91
  76. data/lib/jat/plugins/json_api/lib/presenters/document_links_presenter.rb +0 -48
  77. data/lib/jat/plugins/json_api/lib/presenters/document_meta_presenter.rb +0 -48
  78. data/lib/jat/plugins/json_api/lib/presenters/jsonapi_presenter.rb +0 -48
  79. data/lib/jat/plugins/json_api/lib/presenters/links_presenter.rb +0 -48
  80. data/lib/jat/plugins/json_api/lib/presenters/meta_presenter.rb +0 -48
  81. data/lib/jat/plugins/json_api/lib/presenters/relationship_links_presenter.rb +0 -53
  82. data/lib/jat/plugins/json_api/lib/presenters/relationship_meta_presenter.rb +0 -53
  83. data/lib/jat/plugins/json_api/lib/traversal_map.rb +0 -34
  84. data/lib/jat/plugins/simple_api/lib/construct_traversal_map.rb +0 -45
  85. data/lib/jat/plugins/simple_api/lib/params/parse.rb +0 -68
  86. data/lib/jat/presenter.rb +0 -51
  87. data/test/lib/jat/plugins/camel_lower/camel_lower_test.rb +0 -78
  88. data/test/lib/jat/plugins/json_api/lib/construct_traversal_map_test.rb +0 -119
  89. data/test/lib/jat/plugins/json_api/lib/params/fields/parse_test.rb +0 -24
  90. data/test/lib/jat/plugins/json_api/lib/params/fields/validate_test.rb +0 -47
  91. data/test/lib/jat/plugins/json_api/lib/params/include/parse_test.rb +0 -46
  92. data/test/lib/jat/plugins/json_api/lib/params/include/validate_test.rb +0 -51
  93. data/test/lib/jat/plugins/json_api/lib/presenters/document_links_presenter_test.rb +0 -69
  94. data/test/lib/jat/plugins/json_api/lib/presenters/document_meta_presenter_test.rb +0 -69
  95. data/test/lib/jat/plugins/json_api/lib/presenters/jsonapi_presenter_test.rb +0 -69
  96. data/test/lib/jat/plugins/json_api/lib/presenters/links_presenter_test.rb +0 -69
  97. data/test/lib/jat/plugins/json_api/lib/presenters/meta_presenter_test.rb +0 -69
  98. data/test/lib/jat/plugins/json_api/lib/presenters/relationship_links_presenter_test.rb +0 -75
  99. data/test/lib/jat/plugins/json_api/lib/presenters/relationship_meta_presenter_test.rb +0 -75
  100. data/test/lib/jat/plugins/json_api/lib/traversal_map_test.rb +0 -58
  101. data/test/lib/jat/plugins/simple_api/lib/construct_traversal_map_test.rb +0 -100
  102. data/test/lib/jat/presenter_test.rb +0 -61
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Jat
4
+ module Plugins
5
+ module JsonApi
6
+ class IncludeParamParser
7
+ module ClassMethods
8
+ COMMA = ","
9
+ DOT = "."
10
+
11
+ # Returns the Jat class that this IncludeParamParser class is namespaced under.
12
+ attr_accessor :jat_class
13
+
14
+ # Since IncludeParamParser is anonymously subclassed when Jat is subclassed,
15
+ # and then assigned to a constant of the Jat subclass, make inspect
16
+ # reflect the likely name for the class.
17
+ def inspect
18
+ "#{jat_class.inspect}::IncludeParamParser"
19
+ end
20
+
21
+ def parse(includes_string_param)
22
+ return {} unless includes_string_param
23
+
24
+ includes_hash = parse_to_nested_hash(includes_string_param)
25
+ typed_includes(jat_class, includes_hash, {})
26
+ end
27
+
28
+ private
29
+
30
+ def parse_to_nested_hash(includes_string_param)
31
+ includes_string_param.split(COMMA).each_with_object({}) do |part, obj|
32
+ includes = parse_part(part)
33
+ deep_merge!(obj, includes)
34
+ end
35
+ end
36
+
37
+ def typed_includes(jat_class, includes, result)
38
+ includes.each do |included_attr_name, nested_includes|
39
+ add_typed_include(result, jat_class, included_attr_name)
40
+
41
+ nested_serializer = jat_class.attributes.fetch(included_attr_name).serializer.call
42
+ typed_includes(nested_serializer, nested_includes, result)
43
+ end
44
+
45
+ result
46
+ end
47
+
48
+ def add_typed_include(result, serializer, included_attr_name)
49
+ type = serializer.get_type
50
+
51
+ includes = result[type] || []
52
+ includes |= [included_attr_name]
53
+
54
+ result[type] = includes
55
+ end
56
+
57
+ def parse_part(part)
58
+ val = {}
59
+
60
+ part.split(DOT).reverse_each do |inc|
61
+ val = {inc.to_sym => val}
62
+ end
63
+
64
+ val
65
+ end
66
+
67
+ def deep_merge!(this_hash, other_hash)
68
+ this_hash.merge!(other_hash) do |_key, this_val, other_val|
69
+ deep_merge(this_val, other_val)
70
+ end
71
+ end
72
+
73
+ def deep_merge(this_hash, other_hash)
74
+ this_hash.merge(other_hash) do |_key, this_val, other_val|
75
+ deep_merge(this_val, other_val)
76
+ end
77
+ end
78
+ end
79
+
80
+ extend ClassMethods
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,53 +1,118 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./params/fields"
4
- require_relative "./params/include"
5
- require_relative "./construct_traversal_map"
6
-
7
3
  class Jat
8
4
  module Plugins
9
5
  module JsonApi
10
6
  class Map
11
- class << self
7
+ module ClassMethods
8
+ # Returns the Jat class that this Map class is namespaced under.
9
+ attr_accessor :jat_class
10
+
11
+ # Since Map is anonymously subclassed when Jat is subclassed,
12
+ # and then assigned to a constant of the Jat subclass, make inspect
13
+ # reflect the likely name for the class.
14
+ def inspect
15
+ "#{jat_class.inspect}::Map"
16
+ end
17
+
12
18
  # Returns structure like
13
19
  # {
14
- # type => {
20
+ # type1 => {
15
21
  # attributes: [attr1, attr2, ...],
16
22
  # relationships: [rel1, rel2, ...]
17
- # }
23
+ # },
24
+ # type2 => { ... }
18
25
  # }
19
- def call(jat)
20
- params = jat.context[:params]
21
- fields = params && (params[:fields] || params["fields"])
22
- includes = params && (params[:include] || params["include"])
26
+ def call(context)
27
+ exposed = context[:exposed]&.to_sym || :default
28
+ fields = context[:fields]
29
+ includes = context[:include]
30
+
31
+ construct_map(exposed, fields, includes)
32
+ end
33
+
34
+ private
35
+
36
+ def construct_map(exposed, fields, includes)
37
+ fields = jat_class::FieldsParamParser.parse(fields) if fields
38
+ includes = jat_class::IncludeParamParser.parse(includes) if includes
39
+
40
+ new(exposed, fields, includes).to_h
41
+ end
42
+ end
43
+
44
+ module InstanceMethods
45
+ attr_reader :jat_class, :exposed, :includes, :fields
23
46
 
24
- default_attrs = jat.traversal_map.exposed
25
- includes_attrs = requested_includes_fields(jat, includes)
26
- fields_attrs = requested_fields(jat, fields)
47
+ EXPOSED_TYPES = {all: :all, default: :default, none: :none}.freeze
27
48
 
28
- default_attrs.merge!(includes_attrs).merge!(fields_attrs)
49
+ def initialize(exposed, fields, includes)
50
+ @jat_class = self.class.jat_class
51
+ @exposed = EXPOSED_TYPES.fetch(exposed)
52
+ @fields = fields
53
+ @includes = includes
54
+ end
55
+
56
+ def to_h
57
+ map = {}
58
+ append_map(map, jat_class)
59
+ map
29
60
  end
30
61
 
31
62
  private
32
63
 
33
- def requested_includes_fields(jat, includes)
34
- return {} unless includes
64
+ def append_map(map, jat_class)
65
+ type = jat_class.get_type
66
+ return map if map.key?(type)
67
+
68
+ type_map = {serializer: jat_class}
69
+ map[type] = type_map
70
+
71
+ fill_type_map(map, type_map, type, jat_class)
72
+
73
+ type_map[:attributes] ||= FROZEN_EMPTY_ARRAY
74
+ type_map[:relationships] ||= FROZEN_EMPTY_ARRAY
75
+ end
76
+
77
+ def fill_type_map(map, type_map, type, jat_class)
78
+ jat_class.attributes.each_value do |attribute|
79
+ next unless expose?(type, attribute)
35
80
 
36
- include_types = Params::Include.call(jat, includes)
37
- ConstructTraversalMap
38
- .new(jat.class, :exposed, manually_exposed: include_types)
39
- .to_h
81
+ fill_attr(map, type_map, attribute)
82
+ end
40
83
  end
41
84
 
42
- def requested_fields(jat, fields)
43
- return {} unless fields
85
+ def fill_attr(map, type_map, attribute)
86
+ name = attribute.name
44
87
 
45
- fields_types = Params::Fields.call(jat, fields)
46
- ConstructTraversalMap
47
- .new(jat.class, :manual, manually_exposed: fields_types)
48
- .to_h
88
+ if attribute.relation?
89
+ (type_map[:relationships] ||= []) << name
90
+ append_map(map, attribute.serializer.call)
91
+ else
92
+ (type_map[:attributes] ||= []) << name
93
+ end
94
+ end
95
+
96
+ def expose?(type, attribute)
97
+ attribute_name = attribute.name
98
+ fields_attribute_names = fields && fields[type]
99
+ return fields_attribute_names.include?(attribute_name) if fields_attribute_names
100
+
101
+ includes_attribute_names = includes && includes[type]
102
+ includes_attribute_names&.include?(attribute_name) || attribute_exposed?(attribute)
103
+ end
104
+
105
+ def attribute_exposed?(attribute)
106
+ case exposed
107
+ when :all then true
108
+ when :none then false
109
+ else attribute.exposed?
110
+ end
49
111
  end
50
112
  end
113
+
114
+ extend ClassMethods
115
+ include InstanceMethods
51
116
  end
52
117
  end
53
118
  end
@@ -8,17 +8,20 @@ class Jat
8
8
  class Validate
9
9
  class << self
10
10
  def call(jat, fields)
11
+ full_map = jat.maps.full
12
+
11
13
  fields.each do |type, attributes_names|
12
- new(jat, type).validate(attributes_names)
14
+ new(jat, type, full_map).validate(attributes_names)
13
15
  end
14
16
  end
15
17
  end
16
18
 
17
- attr_reader :jat, :type
19
+ attr_reader :jat, :type, :full_map
18
20
 
19
- def initialize(jat, type)
21
+ def initialize(jat, type, full_map)
20
22
  @jat = jat
21
23
  @type = type
24
+ @full_map = full_map
22
25
  end
23
26
 
24
27
  def validate(attributes_names)
@@ -29,7 +32,7 @@ class Jat
29
32
  private
30
33
 
31
34
  def check_fields_type
32
- return if jat.traversal_map.full.key?(type)
35
+ return if full_map.key?(type)
33
36
 
34
37
  raise Error, "#{jat.class} and its children have no requested type `#{type}`"
35
38
  end
@@ -41,7 +44,7 @@ class Jat
41
44
  end
42
45
 
43
46
  def check_attribute_name(attribute_name)
44
- type_data = jat.traversal_map.full.fetch(type)
47
+ type_data = full_map.fetch(type)
45
48
  type_serializer = type_data.fetch(:serializer)
46
49
  return if type_serializer.attributes.key?(attribute_name)
47
50
 
@@ -5,234 +5,122 @@ class Jat
5
5
  module Plugins
6
6
  module JsonApi
7
7
  class Response
8
- attr_reader :jat, :jat_class, :object, :context
9
-
10
- def initialize(jat)
11
- @jat = jat
12
- @jat_class = jat.class
13
- @object = jat.object
14
- @context = jat.context
15
- end
16
-
17
- def response
18
- data, includes = data_with_includes
19
- meta = document_meta
20
- links = document_links
21
- jsonapi = jsonapi_data
22
-
23
- result = {}
24
- result[:links] = links if links.any?
25
- result[:data] = data if data
26
- result[:included] = includes.values if includes.any?
27
- result[:meta] = meta if meta.any?
28
- result[:jsonapi] = jsonapi if jsonapi.any?
29
- result
30
- end
31
-
32
- private
33
-
34
- def data_with_includes
35
- includes = {}
36
- data = many?(object, context) ? many(object, includes) : one(object, includes)
37
- [data, includes]
38
- end
39
-
40
- def many(objs, includes)
41
- objs.map { |obj| one(obj, includes) }
42
- end
43
-
44
- def one(obj, includes)
45
- ResponseData.new(jat_class, obj, context, full_map, includes).data
46
- end
47
-
48
- def many?(data, context)
49
- many = context[:many]
50
- many.nil? ? data.is_a?(Enumerable) : many
51
- end
52
-
53
- def full_map
54
- @full_map ||= jat.traversal_map.current
55
- end
56
-
57
- def jsonapi_data
58
- data = context[:jsonapi]&.transform_keys(&:to_sym) || {}
59
- jsonapi_data = jat_class.jsonapi_data
60
- return data if jsonapi_data.empty?
61
-
62
- presenter = jat_class::JsonapiPresenter.new(object, context)
63
- jsonapi_data.each_key do |key|
64
- data[key] = presenter.public_send(key) unless data.key?(key)
8
+ module ClassMethods
9
+ # Returns the Jat class that this Response class is namespaced under.
10
+ attr_accessor :jat_class
11
+
12
+ # Since Response is anonymously subclassed when Jat is subclassed,
13
+ # and then assigned to a constant of the Jat subclass, make inspect
14
+ # reflect the likely name for the class.
15
+ def inspect
16
+ "#{jat_class.inspect}::Response"
65
17
  end
66
- data.compact!
67
- data
68
- end
69
18
 
70
- def document_links
71
- data = context[:links]&.transform_keys(&:to_sym) || {}
72
- document_links = jat_class.document_links
73
- return data if document_links.empty?
74
-
75
- presenter = jat_class::DocumentLinksPresenter.new(object, context)
76
- document_links.each_key do |key|
77
- data[key] = presenter.public_send(key) unless data.key?(key)
19
+ def call(object, context)
20
+ new(object, context).to_h
78
21
  end
79
- data.compact!
80
- data
81
22
  end
82
23
 
83
- def document_meta
84
- data = context[:meta]&.transform_keys(&:to_sym) || {}
85
- document_meta = jat_class.added_document_meta
86
- return data if document_meta.empty?
24
+ module InstanceMethods
25
+ attr_reader :jat_class, :object, :context
87
26
 
88
- presenter = jat_class::DocumentMetaPresenter.new(object, context)
89
- document_meta.each_key do |key|
90
- data[key] = presenter.public_send(key) unless data.key?(key)
27
+ def initialize(object, context)
28
+ @object = object
29
+ @context = context
30
+ @jat_class = self.class.jat_class
91
31
  end
92
- data.compact!
93
- data
94
- end
95
- end
96
32
 
97
- class ResponseData
98
- attr_reader :jat_class, :object, :context, :full_map, :map, :includes, :presenter
99
-
100
- def initialize(jat_class, object, context, full_map, includes)
101
- @jat_class = jat_class
102
- @object = object
103
- @context = context
104
- @includes = includes
105
- @full_map = full_map
106
- @map = full_map.fetch(jat_class.type)
107
- @presenter = jat_class::Presenter.new(object, context)
108
- end
109
-
110
- def data
111
- return unless object
112
-
113
- attributes = get_attributes
114
- relationships = get_relationships
115
- links = get_links
116
- meta = get_meta
33
+ def to_h
34
+ data, includes = data_with_includes
35
+ meta = document_meta
36
+ links = document_links
37
+ jsonapi = jsonapi_data
117
38
 
118
- result = uid
119
- result[:attributes] = attributes if attributes
120
- result[:relationships] = relationships if relationships
121
- result[:links] = links if links.any?
122
- result[:meta] = meta if meta.any?
123
- result
124
- end
125
-
126
- def uid
127
- {type: jat_class.type, id: presenter.id}
128
- end
39
+ result = {}
40
+ result[:links] = links if links.any?
41
+ result[:data] = data if data
42
+ result[:included] = includes.values if includes.any?
43
+ result[:meta] = meta if meta.any?
44
+ result[:jsonapi] = jsonapi if jsonapi.any?
45
+ result
46
+ end
129
47
 
130
- private
48
+ private
131
49
 
132
- def get_attributes
133
- attributes_names = map[:attributes]
134
- return if attributes_names.empty?
50
+ def data_with_includes
51
+ includes = {}
52
+ map = jat_class::Map.call(context)
53
+ data = many?(object, context) ? many(object, includes, map) : one(object, includes, map)
54
+ [data, includes]
55
+ end
135
56
 
136
- attributes_names.each_with_object({}) do |name, attrs|
137
- attribute = jat_class.attributes[name]
138
- attrs[name] = presenter.public_send(attribute.original_name)
57
+ def many(objects, includes, map)
58
+ objects.map { |object| one(object, includes, map) }
139
59
  end
140
- end
141
60
 
142
- def get_relationships
143
- relationships_names = map[:relationships]
144
- return if relationships_names.empty?
145
-
146
- relationships_names.each_with_object({}) do |name, rels|
147
- rel_attribute = jat_class.attributes[name]
148
- rel_object = presenter.public_send(rel_attribute.original_name)
149
-
150
- rel_serializer = rel_attribute.serializer.call
151
- rel_links = get_relationship_links(rel_serializer, rel_object)
152
- rel_meta = get_relationship_meta(rel_serializer, rel_object)
153
- rel_data =
154
- if many?(rel_attribute, rel_object)
155
- many_relationships_data(rel_serializer, rel_object)
156
- else
157
- one_relationship_data(rel_serializer, rel_object)
158
- end
61
+ def one(object, includes, map)
62
+ jat_class::ResponsePiece.call(object, context, map, includes)
63
+ end
159
64
 
160
- result = {}
161
- result[:data] = rel_data
162
- result[:links] = rel_links if rel_links.any?
163
- result[:meta] = rel_meta if rel_meta.any?
164
- rels[name] = result
65
+ def many?(data, context)
66
+ many = context[:many]
67
+ many.nil? ? data.is_a?(Enumerable) : many
165
68
  end
166
- end
167
69
 
168
- def many_relationships_data(rel_serializer, rel_objects)
169
- return [] if rel_objects.empty?
70
+ def jsonapi_data
71
+ combine(jat_class.jsonapi_data, context_jsonapi)
72
+ end
170
73
 
171
- rel_objects.map { |rel_object| add_relationship_data(rel_serializer, rel_object) }
172
- end
74
+ def document_links
75
+ combine(jat_class.document_links, context_links)
76
+ end
173
77
 
174
- def one_relationship_data(rel_serializer, rel_object)
175
- return unless rel_object
78
+ def document_meta
79
+ combine(jat_class.added_document_meta, context_meta)
80
+ end
176
81
 
177
- add_relationship_data(rel_serializer, rel_object)
178
- end
82
+ def combine(attributes, context_data)
83
+ return context_data if attributes.empty?
179
84
 
180
- def add_relationship_data(rel_serializer, rel_object)
181
- rel_response_data = self.class.new(rel_serializer, rel_object, context, full_map, includes)
182
- rel_uid = rel_response_data.uid
183
- includes[rel_uid] ||= rel_response_data.data
184
- rel_uid
185
- end
85
+ data = context_data
186
86
 
187
- def many?(attribute, object)
188
- is_many = attribute.many?
87
+ attributes.each do |name, attribute|
88
+ next if data.key?(name)
189
89
 
190
- # handle boolean
191
- return is_many if (is_many == true) || (is_many == false)
90
+ value = attribute_value(attribute)
192
91
 
193
- # handle nil
194
- object.is_a?(Enumerable)
195
- end
92
+ unless value.nil?
93
+ data = data.dup if data.equal?(FROZEN_EMPTY_HASH)
94
+ data[name] = value
95
+ end
96
+ end
196
97
 
197
- def get_links
198
- links = jat_class.object_links
199
- return links if links.empty?
98
+ data
99
+ end
200
100
 
201
- presenter = jat_class::LinksPresenter.new(object, context)
202
- result = links.each_key.each_with_object({}) { |key, data| data[key] = presenter.public_send(key) }
203
- result.compact!
204
- result
205
- end
101
+ def attribute_value(attribute)
102
+ attribute.block.call(object, context)
103
+ end
206
104
 
207
- def get_meta
208
- meta = jat_class.added_object_meta
209
- return meta if meta.empty?
105
+ def context_jsonapi
106
+ context_attr_transform(:jsonapi)
107
+ end
210
108
 
211
- presenter = jat_class::MetaPresenter.new(object, context)
212
- result = meta.each_key.each_with_object({}) { |key, data| data[key] = presenter.public_send(key) }
213
- result.compact!
214
- result
215
- end
109
+ def context_links
110
+ context_attr_transform(:links)
111
+ end
216
112
 
217
- def get_relationship_links(rel_serializer, rel_object)
218
- links = rel_serializer.relationship_links
219
- return links if links.empty?
113
+ def context_meta
114
+ context_attr_transform(:meta)
115
+ end
220
116
 
221
- presenter = rel_serializer::RelationshipLinksPresenter.new(object, rel_object, context)
222
- result = links.each_key.each_with_object({}) { |key, data| data[key] = presenter.public_send(key) }
223
- result.compact!
224
- result
117
+ def context_attr_transform(key)
118
+ context[key]&.transform_keys(&:to_sym) || FROZEN_EMPTY_HASH
119
+ end
225
120
  end
226
121
 
227
- def get_relationship_meta(rel_serializer, rel_object)
228
- meta = rel_serializer.added_relationship_meta
229
- return meta if meta.empty?
230
-
231
- presenter = rel_serializer::RelationshipMetaPresenter.new(object, rel_object, context)
232
- result = meta.each_key.each_with_object({}) { |key, data| data[key] = presenter.public_send(key) }
233
- result.compact!
234
- result
235
- end
122
+ extend ClassMethods
123
+ include InstanceMethods
236
124
  end
237
125
  end
238
126
  end