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.
- checksums.yaml +4 -4
- data/lib/jat/attribute.rb +36 -4
- data/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads.rb +7 -3
- data/lib/jat/plugins/_activerecord_preloads/lib/preloader.rb +7 -13
- data/lib/jat/plugins/_lower_camel_case/_lower_camel_case.rb +32 -0
- data/lib/jat/plugins/_preloads/_preloads.rb +8 -2
- data/lib/jat/plugins/cache/cache.rb +9 -5
- data/lib/jat/plugins/json_api/json_api.rb +145 -105
- data/lib/jat/plugins/json_api/lib/fields_param_parser.rb +40 -0
- data/lib/jat/plugins/json_api/lib/include_param_parser.rb +84 -0
- data/lib/jat/plugins/json_api/lib/map.rb +92 -27
- data/lib/jat/plugins/json_api/lib/params/fields/validate.rb +8 -5
- data/lib/jat/plugins/json_api/lib/response.rb +84 -196
- data/lib/jat/plugins/json_api/lib/response_piece.rb +166 -0
- data/lib/jat/plugins/json_api_activerecord/json_api_activerecord.rb +31 -0
- data/lib/jat/plugins/{_json_api_activerecord → json_api_activerecord}/lib/preloads.rb +16 -24
- data/lib/jat/plugins/json_api_lower_camel_case/json_api_lower_camel_case.rb +30 -0
- data/lib/jat/plugins/json_api_maps_cache/json_api_maps_cache.rb +54 -0
- data/lib/jat/plugins/json_api_validate_params/json_api_validate_params.rb +57 -0
- data/lib/jat/plugins/json_api_validate_params/lib/params_error.rb +6 -0
- data/lib/jat/plugins/json_api_validate_params/lib/validate_fields_param.rb +59 -0
- data/lib/jat/plugins/json_api_validate_params/lib/validate_include_param.rb +33 -0
- data/lib/jat/plugins/simple_api/lib/fields_param_parser.rb +97 -0
- data/lib/jat/plugins/simple_api/lib/map.rb +80 -10
- data/lib/jat/plugins/simple_api/lib/response.rb +78 -89
- data/lib/jat/plugins/simple_api/lib/response_piece.rb +84 -0
- data/lib/jat/plugins/simple_api/simple_api.rb +83 -24
- data/lib/jat/plugins/simple_api_activerecord/lib/preloads.rb +55 -0
- data/lib/jat/plugins/simple_api_activerecord/simple_api_activerecord.rb +31 -0
- data/lib/jat/plugins/simple_api_lower_camel_case/simple_api_lower_camel_case.rb +30 -0
- data/lib/jat/plugins/simple_api_maps_cache/simple_api_maps_cache.rb +48 -0
- data/lib/jat/plugins/simple_api_validate_params/lib/fields_error.rb +6 -0
- data/lib/jat/plugins/simple_api_validate_params/lib/validate_fields_param.rb +45 -0
- data/lib/jat/plugins/simple_api_validate_params/simple_api_validate_params.rb +45 -0
- data/lib/jat/plugins/to_str/to_str.rb +10 -4
- data/lib/jat/plugins.rb +3 -16
- data/lib/jat.rb +28 -30
- data/test/lib/jat/attribute_test.rb +15 -5
- data/test/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads_test.rb +34 -15
- data/test/lib/jat/plugins/_activerecord_preloads/lib/preloader_test.rb +10 -24
- data/test/lib/jat/plugins/_camel_lower/_camel_lower_test.rb +26 -0
- data/test/lib/jat/plugins/_preloads/lib/format_user_preloads_test.rb +1 -1
- data/test/lib/jat/plugins/_preloads/lib/preloads_with_path_test.rb +1 -1
- data/test/lib/jat/plugins/cache/cache_test.rb +11 -11
- data/test/lib/jat/plugins/json_api/json_api_test.rb +63 -47
- data/test/lib/jat/plugins/json_api/lib/{params/fields_test.rb → fields_param_parser_test.rb} +7 -6
- data/test/lib/jat/plugins/json_api/lib/{params/include_test.rb → include_param_parser_test.rb} +4 -4
- data/test/lib/jat/plugins/json_api/lib/map_test.rb +150 -79
- data/test/lib/jat/plugins/json_api/lib/response_test.rb +32 -32
- data/test/lib/jat/plugins/{_json_api_activerecord/_json_api_activerecord_test.rb → json_api_activerecord/json_api_activerecord_test.rb} +14 -5
- data/test/lib/jat/plugins/{_json_api_activerecord → json_api_activerecord}/lib/preloads_test.rb +11 -10
- data/test/lib/jat/plugins/json_api_camel_lower/json_api_camel_lower_test.rb +79 -0
- data/test/lib/jat/plugins/json_api_maps_cache/json_api_maps_cache_test.rb +107 -0
- data/test/lib/jat/plugins/json_api_validate_params/json_api_validate_params_test.rb +84 -0
- data/test/lib/jat/plugins/simple_api/lib/{params/parse_test.rb → fields_param_parser_test.rb} +10 -4
- data/test/lib/jat/plugins/simple_api/lib/map_test.rb +111 -34
- data/test/lib/jat/plugins/simple_api/lib/response_test.rb +80 -74
- data/test/lib/jat/plugins/simple_api/simple_api_test.rb +91 -25
- data/test/lib/jat/plugins/simple_api_activerecord/lib/preloads_test.rb +135 -0
- data/test/lib/jat/plugins/simple_api_activerecord/simple_api_activerecord_test.rb +38 -0
- data/test/lib/jat/plugins/simple_api_camel_lower/simple_api_camel_lower_test.rb +48 -0
- data/test/lib/jat/plugins/simple_api_maps_cache/simple_api_maps_cache_test.rb +95 -0
- data/test/lib/jat/plugins/simple_api_validate_params/simple_api_validate_params_test.rb +89 -0
- data/test/lib/jat/plugins/to_str/to_str_test.rb +3 -3
- data/test/lib/jat_test.rb +47 -24
- data/test/lib/plugin_test.rb +3 -3
- data/test/test_helper.rb +0 -3
- data/test/test_plugin.rb +9 -12
- metadata +60 -71
- data/CHANGELOG.md +0 -7
- data/README.md +0 -21
- data/jat.gemspec +0 -37
- data/lib/jat/plugins/_json_api_activerecord/_json_api_activerecord.rb +0 -22
- data/lib/jat/plugins/camel_lower/camel_lower.rb +0 -18
- data/lib/jat/plugins/json_api/lib/construct_traversal_map.rb +0 -91
- data/lib/jat/plugins/json_api/lib/presenters/document_links_presenter.rb +0 -48
- data/lib/jat/plugins/json_api/lib/presenters/document_meta_presenter.rb +0 -48
- data/lib/jat/plugins/json_api/lib/presenters/jsonapi_presenter.rb +0 -48
- data/lib/jat/plugins/json_api/lib/presenters/links_presenter.rb +0 -48
- data/lib/jat/plugins/json_api/lib/presenters/meta_presenter.rb +0 -48
- data/lib/jat/plugins/json_api/lib/presenters/relationship_links_presenter.rb +0 -53
- data/lib/jat/plugins/json_api/lib/presenters/relationship_meta_presenter.rb +0 -53
- data/lib/jat/plugins/json_api/lib/traversal_map.rb +0 -34
- data/lib/jat/plugins/simple_api/lib/construct_traversal_map.rb +0 -45
- data/lib/jat/plugins/simple_api/lib/params/parse.rb +0 -68
- data/lib/jat/presenter.rb +0 -51
- data/test/lib/jat/plugins/camel_lower/camel_lower_test.rb +0 -78
- data/test/lib/jat/plugins/json_api/lib/construct_traversal_map_test.rb +0 -119
- data/test/lib/jat/plugins/json_api/lib/params/fields/parse_test.rb +0 -24
- data/test/lib/jat/plugins/json_api/lib/params/fields/validate_test.rb +0 -47
- data/test/lib/jat/plugins/json_api/lib/params/include/parse_test.rb +0 -46
- data/test/lib/jat/plugins/json_api/lib/params/include/validate_test.rb +0 -51
- data/test/lib/jat/plugins/json_api/lib/presenters/document_links_presenter_test.rb +0 -69
- data/test/lib/jat/plugins/json_api/lib/presenters/document_meta_presenter_test.rb +0 -69
- data/test/lib/jat/plugins/json_api/lib/presenters/jsonapi_presenter_test.rb +0 -69
- data/test/lib/jat/plugins/json_api/lib/presenters/links_presenter_test.rb +0 -69
- data/test/lib/jat/plugins/json_api/lib/presenters/meta_presenter_test.rb +0 -69
- data/test/lib/jat/plugins/json_api/lib/presenters/relationship_links_presenter_test.rb +0 -75
- data/test/lib/jat/plugins/json_api/lib/presenters/relationship_meta_presenter_test.rb +0 -75
- data/test/lib/jat/plugins/json_api/lib/traversal_map_test.rb +0 -58
- data/test/lib/jat/plugins/simple_api/lib/construct_traversal_map_test.rb +0 -100
- data/test/lib/jat/presenter_test.rb +0 -61
@@ -1,28 +1,98 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "./params/parse"
|
4
|
-
require_relative "./construct_traversal_map"
|
5
|
-
|
6
3
|
class Jat
|
7
4
|
module Plugins
|
8
5
|
module SimpleApi
|
9
6
|
class Map
|
10
|
-
|
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
|
+
|
11
18
|
# Returns structure like
|
12
19
|
# {
|
13
20
|
# key1 => { key11 => {}, key12 => { ... } },
|
14
21
|
# key2 => { key21 => {}, key22 => { ... } },
|
15
22
|
# }
|
16
|
-
def call(
|
17
|
-
|
18
|
-
fields =
|
19
|
-
|
23
|
+
def call(context)
|
24
|
+
exposed = context[:exposed]&.to_sym || :default
|
25
|
+
fields = context[:fields]
|
26
|
+
|
27
|
+
construct_map(exposed, fields)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def construct_map(exposed, fields)
|
33
|
+
fields = jat_class::FieldsParamParser.parse(fields) if fields
|
34
|
+
new(exposed, fields).to_h
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module InstanceMethods
|
39
|
+
attr_reader :exposed, :fields
|
40
|
+
|
41
|
+
EXPOSED_TYPES = {all: :all, default: :default, none: :none}.freeze
|
42
|
+
|
43
|
+
def initialize(exposed, fields)
|
44
|
+
@exposed = EXPOSED_TYPES.fetch(exposed)
|
45
|
+
@fields = fields
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_h
|
49
|
+
map_for(self.class.jat_class, fields)
|
50
|
+
end
|
51
|
+
|
52
|
+
def map_for(serializer, fields, stack = [])
|
53
|
+
serializer.attributes.each_with_object({}) do |name_attr, result|
|
54
|
+
name = name_attr[0]
|
55
|
+
attribute = name_attr[1]
|
56
|
+
next unless expose?(attribute, fields)
|
20
57
|
|
21
|
-
|
58
|
+
raise Error, recursive_error_message(stack, name) if stack.any?(name_attr)
|
59
|
+
stack << name_attr
|
22
60
|
|
23
|
-
|
61
|
+
result[name] =
|
62
|
+
if attribute.relation?
|
63
|
+
nested_serializer = attribute.serializer.call
|
64
|
+
nested_fields = fields&.[](name)
|
65
|
+
map_for(nested_serializer, nested_fields, stack)
|
66
|
+
else
|
67
|
+
FROZEN_EMPTY_HASH
|
68
|
+
end
|
69
|
+
|
70
|
+
stack.pop
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def expose?(attribute, fields)
|
77
|
+
case exposed
|
78
|
+
when :all then true
|
79
|
+
when :none then manually_exposed?(attribute, fields)
|
80
|
+
else attribute.exposed? || manually_exposed?(attribute, fields)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def manually_exposed?(attribute, fields)
|
85
|
+
fields&.include?(attribute.name)
|
86
|
+
end
|
87
|
+
|
88
|
+
def recursive_error_message(stack, name)
|
89
|
+
recursion = (stack.map!(&:first) << name).join(" -> ")
|
90
|
+
"Recursive serialization: #{recursion}"
|
24
91
|
end
|
25
92
|
end
|
93
|
+
|
94
|
+
extend ClassMethods
|
95
|
+
include InstanceMethods
|
26
96
|
end
|
27
97
|
end
|
28
98
|
end
|
@@ -5,129 +5,118 @@ class Jat
|
|
5
5
|
module Plugins
|
6
6
|
module SimpleApi
|
7
7
|
class Response
|
8
|
-
|
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"
|
17
|
+
end
|
9
18
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@object = jat.object
|
14
|
-
@context = jat.context
|
19
|
+
def call(object, context)
|
20
|
+
new(object, context).to_h
|
21
|
+
end
|
15
22
|
end
|
16
23
|
|
17
|
-
|
18
|
-
|
19
|
-
result = many? ? many(object) : one(object)
|
20
|
-
result = {root_key => result} if root_key
|
21
|
-
result ||= {}
|
24
|
+
module InstanceMethods
|
25
|
+
attr_reader :object, :context, :jat_class
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
next if meta.empty?
|
28
|
-
raise Error, "Response must have a root key to add metadata" if !result.empty? && !root_key
|
29
|
-
result[meta_key] = meta
|
27
|
+
def initialize(object, context)
|
28
|
+
@object = object
|
29
|
+
@context = context
|
30
|
+
@jat_class = self.class.jat_class
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
def to_h
|
34
|
+
# Add main response
|
35
|
+
is_many = many?
|
36
|
+
root = root_key(is_many)
|
34
37
|
|
35
|
-
|
38
|
+
response = is_many ? many(object) : one(object)
|
39
|
+
response = {root => response} if root
|
40
|
+
response ||= {}
|
36
41
|
|
37
|
-
|
38
|
-
result = context[:meta] || {}
|
42
|
+
add_metadata(response, root)
|
39
43
|
|
40
|
-
|
41
|
-
|
44
|
+
response
|
45
|
+
end
|
42
46
|
|
43
|
-
|
44
|
-
next if res.key?(key) # do not overwrite manually added meta
|
47
|
+
private
|
45
48
|
|
46
|
-
|
47
|
-
|
49
|
+
def many(objects)
|
50
|
+
objects.map { |obj| one(obj) }
|
48
51
|
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def many(objects)
|
52
|
-
objects.map { |obj| one(obj) }
|
53
|
-
end
|
54
52
|
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
def one(obj)
|
54
|
+
map = jat_class.map(context)
|
55
|
+
jat_class::ResponsePiece.to_h(obj, context, map)
|
56
|
+
end
|
58
57
|
|
59
|
-
|
60
|
-
@is_many ||= begin
|
58
|
+
def many?
|
61
59
|
many = context[:many]
|
62
60
|
many.nil? ? object.is_a?(Enumerable) : many
|
63
61
|
end
|
64
|
-
end
|
65
62
|
|
66
|
-
|
67
|
-
|
68
|
-
@root_key ||=
|
63
|
+
# We can provide nil or false to remove root
|
64
|
+
def root_key(is_many)
|
69
65
|
if context.key?(:root)
|
70
|
-
context[:root]
|
66
|
+
root = context[:root]
|
67
|
+
root ? root.to_sym : root
|
71
68
|
else
|
72
|
-
|
69
|
+
config = jat_class.config
|
70
|
+
is_many ? config[:root_many] : config[:root_one]
|
73
71
|
end
|
74
|
-
|
72
|
+
end
|
75
73
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
# Add metadata to response
|
75
|
+
# We can add metadata whether to empty response or to top-level namespace
|
76
|
+
# We should not mix metadata with object attributes
|
77
|
+
def add_metadata(response, root)
|
78
|
+
meta = metadata
|
79
|
+
return if meta.empty?
|
80
80
|
|
81
|
-
|
82
|
-
|
81
|
+
raise Error, "Response must have a root key to add metadata" if !response.empty? && !root
|
82
|
+
response[meta_key] = meta
|
83
|
+
end
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
85
|
+
def meta_key
|
86
|
+
context[:meta_key]&.to_sym || jat_class.config[:meta_key]
|
87
|
+
end
|
88
|
+
|
89
|
+
def metadata
|
90
|
+
data = context_metadata
|
91
91
|
|
92
|
-
|
93
|
-
|
92
|
+
meta = jat_class.added_meta
|
93
|
+
return data if meta.empty?
|
94
94
|
|
95
|
-
|
95
|
+
meta.each do |name, attribute|
|
96
|
+
next if data.key?(name)
|
96
97
|
|
97
|
-
|
98
|
-
attribute = jat_class.attributes.fetch(key)
|
99
|
-
value = presenter.public_send(attribute.original_name)
|
98
|
+
value = attribute_value(attribute)
|
100
99
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
value.map { |obj| response_data(attribute, obj, inner_keys) }
|
105
|
-
else
|
106
|
-
response_data(attribute, value, inner_keys)
|
107
|
-
end
|
108
|
-
else
|
109
|
-
value
|
100
|
+
unless value.nil?
|
101
|
+
data = data.dup if data.equal?(FROZEN_EMPTY_HASH)
|
102
|
+
data[name] = value
|
110
103
|
end
|
111
|
-
|
104
|
+
end
|
112
105
|
|
113
|
-
|
114
|
-
|
106
|
+
data
|
107
|
+
end
|
115
108
|
|
116
|
-
|
109
|
+
def context_metadata
|
110
|
+
context[:meta]&.transform_keys(&:to_sym) || FROZEN_EMPTY_HASH
|
111
|
+
end
|
117
112
|
|
118
|
-
|
119
|
-
|
113
|
+
def attribute_value(attribute)
|
114
|
+
attribute.block.call(object, context)
|
115
|
+
end
|
120
116
|
end
|
121
117
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
# handle boolean
|
126
|
-
return is_many if (is_many == true) || (is_many == false)
|
127
|
-
|
128
|
-
# handle nil
|
129
|
-
object.is_a?(Enumerable)
|
130
|
-
end
|
118
|
+
extend ClassMethods
|
119
|
+
include InstanceMethods
|
131
120
|
end
|
132
121
|
end
|
133
122
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Serializes to JSON-API format
|
4
|
+
class Jat
|
5
|
+
module Plugins
|
6
|
+
module SimpleApi
|
7
|
+
class ResponsePiece
|
8
|
+
module ClassMethods
|
9
|
+
# Returns the Jat class that this ResponsePiece class is namespaced under.
|
10
|
+
attr_accessor :jat_class
|
11
|
+
|
12
|
+
# Since ResponsePiece 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}::ResponsePiece"
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_h(object, context, map)
|
20
|
+
new(object, context).piece(map)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module InstanceMethods
|
25
|
+
attr_reader :jat_class, :object, :context
|
26
|
+
|
27
|
+
def initialize(object, context)
|
28
|
+
@object = object
|
29
|
+
@context = context
|
30
|
+
@jat_class = self.class.jat_class
|
31
|
+
end
|
32
|
+
|
33
|
+
def piece(map)
|
34
|
+
return unless object
|
35
|
+
|
36
|
+
result = {}
|
37
|
+
|
38
|
+
map.each do |key, inner_map|
|
39
|
+
attribute = jat_class.attributes.fetch(key)
|
40
|
+
value = attribute_value(attribute)
|
41
|
+
|
42
|
+
result[key] =
|
43
|
+
if attribute.relation?
|
44
|
+
if many?(attribute, value)
|
45
|
+
value.map { |obj| inner_piece(attribute, obj, inner_map) }
|
46
|
+
else
|
47
|
+
inner_piece(attribute, value, inner_map)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
result
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def attribute_value(attribute)
|
60
|
+
attribute.block.call(object, context)
|
61
|
+
end
|
62
|
+
|
63
|
+
def inner_piece(attribute, value, inner_map)
|
64
|
+
serializer = attribute.serializer.call
|
65
|
+
serializer::ResponsePiece.to_h(value, context, inner_map)
|
66
|
+
end
|
67
|
+
|
68
|
+
def many?(attribute, nested_object)
|
69
|
+
is_many = attribute.many?
|
70
|
+
|
71
|
+
# handle boolean
|
72
|
+
return is_many if (is_many == true) || (is_many == false)
|
73
|
+
|
74
|
+
# handle nil
|
75
|
+
nested_object.is_a?(Enumerable)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
extend ClassMethods
|
80
|
+
include InstanceMethods
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -1,61 +1,120 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "./lib/fields_param_parser"
|
3
4
|
require_relative "./lib/map"
|
4
5
|
require_relative "./lib/response"
|
6
|
+
require_relative "./lib/response_piece"
|
5
7
|
|
6
|
-
# Serializes to JSON-API format
|
7
8
|
class Jat
|
8
9
|
module Plugins
|
9
10
|
module SimpleApi
|
10
11
|
DEFAULT_META_KEY = :meta
|
11
12
|
|
13
|
+
def self.before_load(jat_class, **_opts)
|
14
|
+
response_plugin = jat_class.config[:response_plugin_loaded]
|
15
|
+
return unless response_plugin
|
16
|
+
|
17
|
+
raise Error, "Response plugin `#{response_plugin}` was already loaded before"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.load(jat_class, **_opts)
|
21
|
+
jat_class.include(InstanceMethods)
|
22
|
+
jat_class.extend(ClassMethods)
|
23
|
+
end
|
24
|
+
|
12
25
|
def self.after_load(jat_class, **opts)
|
13
|
-
jat_class.
|
26
|
+
jat_class.config[:response_plugin_loaded] = :simple_api
|
27
|
+
jat_class.plugin(:simple_api_activerecord, **opts) if opts[:activerecord]
|
28
|
+
|
29
|
+
jat_class.meta_key(DEFAULT_META_KEY)
|
30
|
+
|
31
|
+
fields_parser_class = Class.new(FieldsParamParser)
|
32
|
+
fields_parser_class.jat_class = jat_class
|
33
|
+
jat_class.const_set(:FieldsParamParser, fields_parser_class)
|
34
|
+
|
35
|
+
map_class = Class.new(Map)
|
36
|
+
map_class.jat_class = jat_class
|
37
|
+
jat_class.const_set(:Map, map_class)
|
38
|
+
|
39
|
+
response_class = Class.new(Response)
|
40
|
+
response_class.jat_class = jat_class
|
41
|
+
jat_class.const_set(:Response, response_class)
|
42
|
+
|
43
|
+
response_piece_class = Class.new(ResponsePiece)
|
44
|
+
response_piece_class.jat_class = jat_class
|
45
|
+
jat_class.const_set(:ResponsePiece, response_piece_class)
|
14
46
|
end
|
15
47
|
|
16
48
|
module InstanceMethods
|
17
|
-
def to_h
|
18
|
-
Response.
|
49
|
+
def to_h(object)
|
50
|
+
self.class::Response.call(object, context)
|
19
51
|
end
|
20
52
|
|
21
|
-
def
|
22
|
-
@
|
53
|
+
def map
|
54
|
+
@map ||= self.class.map(context)
|
23
55
|
end
|
24
56
|
end
|
25
57
|
|
26
58
|
module ClassMethods
|
27
59
|
def inherited(subclass)
|
28
|
-
subclass.root(@root) if defined?(@root)
|
29
|
-
|
30
60
|
super
|
61
|
+
|
62
|
+
fields_parser_class = Class.new(self::FieldsParamParser)
|
63
|
+
fields_parser_class.jat_class = subclass
|
64
|
+
subclass.const_set(:FieldsParamParser, fields_parser_class)
|
65
|
+
|
66
|
+
map_class = Class.new(self::Map)
|
67
|
+
map_class.jat_class = subclass
|
68
|
+
subclass.const_set(:Map, map_class)
|
69
|
+
|
70
|
+
response_class = Class.new(self::Response)
|
71
|
+
response_class.jat_class = subclass
|
72
|
+
subclass.const_set(:Response, response_class)
|
73
|
+
|
74
|
+
response_piece_class = Class.new(self::ResponsePiece)
|
75
|
+
response_piece_class.jat_class = subclass
|
76
|
+
subclass.const_set(:ResponsePiece, response_piece_class)
|
77
|
+
|
78
|
+
# Assign same meta
|
79
|
+
added_meta.each_value do |attribute|
|
80
|
+
params = attribute.params
|
81
|
+
subclass.attribute(params[:name], **params[:opts], ¶ms[:block])
|
82
|
+
end
|
31
83
|
end
|
32
84
|
|
33
|
-
def root(
|
34
|
-
|
85
|
+
def root(default = nil, one: nil, many: nil)
|
86
|
+
root_one = one || default
|
87
|
+
root_many = many || default
|
88
|
+
|
89
|
+
config[:root_one] = root_one ? root_one.to_sym : nil
|
90
|
+
config[:root_many] = root_many ? root_many.to_sym : nil
|
35
91
|
|
36
|
-
|
37
|
-
@root = new_root
|
92
|
+
{root_one: root_one, root_many: root_many}
|
38
93
|
end
|
39
94
|
|
40
|
-
def
|
41
|
-
|
95
|
+
def meta_key(new_meta_key)
|
96
|
+
config[:meta_key] = new_meta_key.to_sym
|
97
|
+
end
|
42
98
|
|
43
|
-
|
44
|
-
@
|
99
|
+
def added_meta
|
100
|
+
@added_meta ||= {}
|
45
101
|
end
|
46
102
|
|
47
|
-
def
|
48
|
-
|
103
|
+
def meta(name, **opts, &block)
|
104
|
+
new_attr = self::Attribute.new(name: name, opts: opts, block: block)
|
105
|
+
added_meta[new_attr.name] = new_attr
|
106
|
+
end
|
49
107
|
|
50
|
-
|
51
|
-
|
108
|
+
def map(context)
|
109
|
+
self::Map.call(context)
|
52
110
|
end
|
53
111
|
|
54
|
-
def
|
55
|
-
|
112
|
+
def map_full
|
113
|
+
@map_full ||= self::Map.call(exposed: :all)
|
114
|
+
end
|
56
115
|
|
57
|
-
|
58
|
-
@
|
116
|
+
def map_exposed
|
117
|
+
@map_exposed ||= self::Map.call(exposed: :default)
|
59
118
|
end
|
60
119
|
end
|
61
120
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Jat
|
4
|
+
module Plugins
|
5
|
+
module SimpleApiActiverecord
|
6
|
+
class Preloads
|
7
|
+
module ClassMethods
|
8
|
+
def call(jat)
|
9
|
+
result = {}
|
10
|
+
append_many(result, jat.class, jat.map)
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def append_many(result, jat_class, keys)
|
17
|
+
keys.each do |key, inner_keys|
|
18
|
+
attribute = jat_class.attributes.fetch(key)
|
19
|
+
preloads = attribute.preloads
|
20
|
+
next unless preloads
|
21
|
+
|
22
|
+
append_one(result, jat_class, preloads)
|
23
|
+
next if inner_keys.empty?
|
24
|
+
|
25
|
+
path = attribute.preloads_path
|
26
|
+
nested_result = nested(result, path)
|
27
|
+
nested_serializer = attribute.serializer.call
|
28
|
+
|
29
|
+
append_many(nested_result, nested_serializer, inner_keys)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def append_one(result, jat_class, preloads)
|
34
|
+
return if preloads.empty?
|
35
|
+
|
36
|
+
preloads = EnumDeepDup.call(preloads)
|
37
|
+
merge(result, preloads)
|
38
|
+
end
|
39
|
+
|
40
|
+
def merge(result, preloads)
|
41
|
+
result.merge!(preloads) do |_key, value_one, value_two|
|
42
|
+
merge(value_one, value_two)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def nested(result, path)
|
47
|
+
!path || path.empty? ? result : result.dig(*path)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
extend ClassMethods
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./lib/preloads"
|
4
|
+
|
5
|
+
class Jat
|
6
|
+
module Plugins
|
7
|
+
module SimpleApiActiverecord
|
8
|
+
def self.before_load(jat_class, **_opts)
|
9
|
+
return if jat_class.plugin_used?(:simple_api)
|
10
|
+
raise Error, "Please load :simple_api plugin first"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.load(jat_class, **_opts)
|
14
|
+
jat_class.include(InstanceMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.after_load(jat_class, **opts)
|
18
|
+
jat_class.plugin :_preloads, **opts
|
19
|
+
jat_class.plugin :_activerecord_preloads, **opts
|
20
|
+
end
|
21
|
+
|
22
|
+
module InstanceMethods
|
23
|
+
def preloads
|
24
|
+
@preloads ||= Preloads.call(self)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
register_plugin(:simple_api_activerecord, SimpleApiActiverecord)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Jat
|
4
|
+
module Plugins
|
5
|
+
module SimpleApiLowerCamelCase
|
6
|
+
def self.before_load(jat_class, **_opts)
|
7
|
+
raise Error, "Please load :simple_api plugin first" unless jat_class.plugin_used?(:simple_api)
|
8
|
+
|
9
|
+
jat_class.plugin :_lower_camel_case
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.load(jat_class, **_opts)
|
13
|
+
jat_class::Response.include(ResponseInstanceMethods)
|
14
|
+
end
|
15
|
+
|
16
|
+
module ResponseInstanceMethods
|
17
|
+
private
|
18
|
+
|
19
|
+
def context_metadata
|
20
|
+
metadata = super
|
21
|
+
return metadata if metadata.empty?
|
22
|
+
|
23
|
+
metadata.transform_keys! { |key| Jat::LowerCamelCaseTransformation.call(key) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
register_plugin(:simple_api_lower_camel_case, SimpleApiLowerCamelCase)
|
29
|
+
end
|
30
|
+
end
|