jat 0.0.1 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jat/attribute.rb +107 -0
  3. data/lib/jat/config.rb +35 -0
  4. data/lib/jat/plugins/activerecord/activerecord.rb +23 -0
  5. data/lib/jat/plugins/cache/cache.rb +47 -0
  6. data/lib/jat/plugins/common/_activerecord_preloads/_activerecord_preloads.rb +38 -0
  7. data/lib/jat/plugins/common/_activerecord_preloads/lib/preloader.rb +93 -0
  8. data/lib/jat/plugins/common/_lower_camel_case/_lower_camel_case.rb +36 -0
  9. data/lib/jat/plugins/common/_preloads/_preloads.rb +63 -0
  10. data/lib/jat/plugins/common/_preloads/lib/format_user_preloads.rb +52 -0
  11. data/lib/jat/plugins/common/_preloads/lib/preloads_with_path.rb +78 -0
  12. data/lib/jat/plugins/json_api/json_api.rb +251 -0
  13. data/lib/jat/plugins/json_api/lib/fields_param_parser.rb +40 -0
  14. data/lib/jat/plugins/json_api/lib/include_param_parser.rb +84 -0
  15. data/lib/jat/plugins/json_api/lib/map.rb +119 -0
  16. data/lib/jat/plugins/json_api/lib/params/fields/parse.rb +27 -0
  17. data/lib/jat/plugins/json_api/lib/params/fields/validate.rb +58 -0
  18. data/lib/jat/plugins/json_api/lib/params/fields.rb +23 -0
  19. data/lib/jat/plugins/json_api/lib/params/include/parse.rb +55 -0
  20. data/lib/jat/plugins/json_api/lib/params/include/validate.rb +29 -0
  21. data/lib/jat/plugins/json_api/lib/params/include.rb +49 -0
  22. data/lib/jat/plugins/json_api/lib/response.rb +123 -0
  23. data/lib/jat/plugins/json_api/lib/response_piece.rb +175 -0
  24. data/lib/jat/plugins/json_api/plugins/json_api_activerecord/json_api_activerecord.rb +23 -0
  25. data/lib/jat/plugins/json_api/plugins/json_api_lower_camel_case/json_api_lower_camel_case.rb +34 -0
  26. data/lib/jat/plugins/json_api/plugins/json_api_maps_cache/json_api_maps_cache.rb +58 -0
  27. data/lib/jat/plugins/json_api/plugins/json_api_preloads/json_api_preloads.rb +38 -0
  28. data/lib/jat/plugins/json_api/plugins/json_api_preloads/lib/preloads.rb +76 -0
  29. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/json_api_validate_params.rb +61 -0
  30. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/lib/params_error.rb +6 -0
  31. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/lib/validate_fields_param.rb +59 -0
  32. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/lib/validate_include_param.rb +33 -0
  33. data/lib/jat/plugins/lower_camel_case/lower_camel_case.rb +23 -0
  34. data/lib/jat/plugins/maps_cache/maps_cache.rb +23 -0
  35. data/lib/jat/plugins/preloads/preloads.rb +23 -0
  36. data/lib/jat/plugins/simple_api/lib/fields_param_parser.rb +97 -0
  37. data/lib/jat/plugins/simple_api/lib/map.rb +99 -0
  38. data/lib/jat/plugins/simple_api/lib/response.rb +119 -0
  39. data/lib/jat/plugins/simple_api/lib/response_piece.rb +80 -0
  40. data/lib/jat/plugins/simple_api/plugins/simple_api_activerecord/simple_api_activerecord.rb +23 -0
  41. data/lib/jat/plugins/simple_api/plugins/simple_api_lower_camel_case/simple_api_lower_camel_case.rb +34 -0
  42. data/lib/jat/plugins/simple_api/plugins/simple_api_maps_cache/simple_api_maps_cache.rb +50 -0
  43. data/lib/jat/plugins/simple_api/plugins/simple_api_preloads/lib/preloads.rb +55 -0
  44. data/lib/jat/plugins/simple_api/plugins/simple_api_preloads/simple_api_preloads.rb +38 -0
  45. data/lib/jat/plugins/simple_api/plugins/simple_api_validate_params/lib/fields_error.rb +6 -0
  46. data/lib/jat/plugins/simple_api/plugins/simple_api_validate_params/lib/validate_fields_param.rb +45 -0
  47. data/lib/jat/plugins/simple_api/plugins/simple_api_validate_params/simple_api_validate_params.rb +49 -0
  48. data/lib/jat/plugins/simple_api/simple_api.rb +125 -0
  49. data/lib/jat/plugins/to_str/to_str.rb +54 -0
  50. data/lib/jat/plugins/types/types.rb +54 -0
  51. data/lib/jat/plugins/validate_params/validate_params.rb +23 -0
  52. data/lib/jat/plugins.rb +39 -0
  53. data/lib/jat/utils/enum_deep_dup.rb +29 -0
  54. data/lib/jat/utils/enum_deep_freeze.rb +19 -0
  55. data/lib/jat.rb +66 -141
  56. data/test/lib/jat/attribute_test.rb +152 -0
  57. data/test/lib/jat/config_test.rb +57 -0
  58. data/test/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads_test.rb +59 -0
  59. data/test/lib/jat/plugins/_activerecord_preloads/lib/preloader_test.rb +84 -0
  60. data/test/lib/jat/plugins/_camel_lower/_camel_lower_test.rb +26 -0
  61. data/test/lib/jat/plugins/_preloads/_preloads_test.rb +68 -0
  62. data/test/lib/jat/plugins/_preloads/lib/format_user_preloads_test.rb +47 -0
  63. data/test/lib/jat/plugins/_preloads/lib/preloads_with_path_test.rb +33 -0
  64. data/test/lib/jat/plugins/cache/cache_test.rb +82 -0
  65. data/test/lib/jat/plugins/json_api/json_api_test.rb +162 -0
  66. data/test/lib/jat/plugins/json_api/lib/fields_param_parser_test.rb +38 -0
  67. data/test/lib/jat/plugins/json_api/lib/include_param_parser_test.rb +41 -0
  68. data/test/lib/jat/plugins/json_api/lib/map_test.rb +188 -0
  69. data/test/lib/jat/plugins/json_api/lib/response_test.rb +489 -0
  70. data/test/lib/jat/plugins/json_api_activerecord/json_api_activerecord_test.rb +24 -0
  71. data/test/lib/jat/plugins/json_api_camel_lower/json_api_camel_lower_test.rb +79 -0
  72. data/test/lib/jat/plugins/json_api_maps_cache/json_api_maps_cache_test.rb +107 -0
  73. data/test/lib/jat/plugins/json_api_preloads/json_api_preloads_test.rb +37 -0
  74. data/test/lib/jat/plugins/json_api_preloads/lib/preloads_test.rb +197 -0
  75. data/test/lib/jat/plugins/json_api_validate_params/json_api_validate_params_test.rb +84 -0
  76. data/test/lib/jat/plugins/simple_api/lib/fields_param_parser_test.rb +77 -0
  77. data/test/lib/jat/plugins/simple_api/lib/map_test.rb +133 -0
  78. data/test/lib/jat/plugins/simple_api/lib/response_test.rb +348 -0
  79. data/test/lib/jat/plugins/simple_api/simple_api_test.rb +139 -0
  80. data/test/lib/jat/plugins/simple_api_activerecord/simple_api_activerecord_test.rb +24 -0
  81. data/test/lib/jat/plugins/simple_api_camel_lower/simple_api_camel_lower_test.rb +48 -0
  82. data/test/lib/jat/plugins/simple_api_maps_cache/simple_api_maps_cache_test.rb +95 -0
  83. data/test/lib/jat/plugins/simple_api_preloads/lib/preloads_test.rb +140 -0
  84. data/test/lib/jat/plugins/simple_api_preloads/simple_api_preloads_test.rb +37 -0
  85. data/test/lib/jat/plugins/simple_api_validate_params/simple_api_validate_params_test.rb +89 -0
  86. data/test/lib/jat/plugins/to_str/to_str_test.rb +52 -0
  87. data/test/lib/jat/plugins/types/types_test.rb +79 -0
  88. data/test/lib/jat/utils/enum_deep_dup_test.rb +31 -0
  89. data/test/lib/jat/utils/enum_deep_freeze_test.rb +28 -0
  90. data/test/lib/jat_test.rb +143 -0
  91. data/test/lib/plugin_test.rb +49 -0
  92. data/test/support/activerecord.rb +24 -0
  93. data/test/test_helper.rb +13 -0
  94. data/test/test_plugin.rb +56 -0
  95. metadata +243 -11
data/lib/jat.rb CHANGED
@@ -1,186 +1,111 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'jat/attributes'
4
- require 'jat/config'
5
- require 'jat/error'
6
- require 'jat/map'
7
- require 'jat/map/construct'
8
- require 'jat/opts'
9
- require 'jat/preloads'
10
- require 'jat/preload_handler'
11
- require 'jat/response'
12
- require 'jat/utils/preloads_to_hash'
3
+ require_relative "jat/attribute"
4
+ require_relative "jat/config"
5
+ require_relative "jat/plugins"
13
6
 
14
7
  # Main namespace
15
8
  class Jat
9
+ FROZEN_EMPTY_HASH = {}.freeze
10
+ FROZEN_EMPTY_ARRAY = [].freeze
11
+
12
+ # A generic exception used by Jat.
13
+ class Error < StandardError; end
14
+
15
+ @config = Config.new({plugins: []})
16
+
16
17
  module ClassMethods
18
+ attr_reader :config
19
+
17
20
  def inherited(subclass)
18
- subclass.extend DSLClassMethods
19
- subclass.include DSLInstanceMethods
20
- copy_to(subclass)
21
+ # Initialize config
22
+ config_class = Class.new(self::Config)
23
+ config_class.jat_class = subclass
24
+ subclass.const_set(:Config, config_class)
25
+ subclass.instance_variable_set(:@config, subclass::Config.new(config.opts))
26
+
27
+ # Initialize attribute class
28
+ attribute_class = Class.new(self::Attribute)
29
+ attribute_class.jat_class = subclass
30
+ subclass.const_set(:Attribute, attribute_class)
31
+
32
+ # Assign same attributes
33
+ attributes.each_value do |attribute|
34
+ params = attribute.params
35
+ subclass.attribute(params[:name], **params[:opts], &params[:block])
36
+ end
21
37
 
22
38
  super
23
39
  end
24
40
 
25
- def config
26
- @config ||= Config.new(self)
27
- end
41
+ def plugin(name, **opts)
42
+ return if plugin_used?(name)
28
43
 
29
- def config=(config)
30
- @config = config
31
- end
44
+ plugin = Plugins.find_plugin(name)
32
45
 
33
- def attributes
34
- @attributes ||= Attributes.new
35
- end
46
+ # We split loading of plugin to three methods - before_load, load, after_load:
47
+ #
48
+ # - **before_load** usually used to check requirements and to load additional plugins
49
+ # - **load** usually used to include plugin modules
50
+ # - **after_load** usually used to add config options
51
+ plugin.before_load(self, **opts) if plugin.respond_to?(:before_load)
52
+ plugin.load(self, **opts) if plugin.respond_to?(:load)
53
+ plugin.after_load(self, **opts) if plugin.respond_to?(:after_load)
36
54
 
37
- # Used to validate provided params (fields, include)
38
- def full_map
39
- @full_map ||= Map::Construct.new(self, :all).to_h
40
- end
55
+ # Store attached plugins, so we can check it is loaded later
56
+ config[:plugins] << (plugin.respond_to?(:plugin_name) ? plugin.plugin_name : plugin)
41
57
 
42
- def exposed_map
43
- @exposed_map ||= Map::Construct.new(self, :exposed).to_h
58
+ plugin
44
59
  end
45
60
 
46
- def clear
47
- @full_map = nil
48
- @exposed_map = nil
49
- end
61
+ def plugin_used?(plugin)
62
+ plugin_name =
63
+ case plugin
64
+ when Module then plugin.respond_to?(:plugin_name) ? plugin.plugin_name : plugin
65
+ else plugin
66
+ end
50
67
 
51
- def refresh
52
- attributes.refresh
53
- clear
68
+ config[:plugins].include?(plugin_name)
54
69
  end
55
70
 
56
- def copy_to(subclass)
57
- subclass.type(@type) if defined?(@type)
58
- config.copy_to(subclass)
59
- attributes.copy_to(subclass)
60
- end
61
- end
62
-
63
- module DSLClassMethods
64
71
  def call
65
72
  self
66
73
  end
67
74
 
68
- def to_h(object, context = {})
69
- new.to_h(object, context)
70
- end
71
-
72
- def to_str(object, context = {})
73
- new.to_str(object, context)
74
- end
75
-
76
- def type(new_type = nil)
77
- return @type || raise(Error, "#{self} has no defined type") unless new_type
78
-
79
- new_type = new_type.to_sym
80
- define_method(:type) { new_type }
81
- @type = new_type
75
+ def to_h(object, context = nil)
76
+ new(context || {}).to_h(object)
82
77
  end
83
78
 
84
- def id(key: nil, &block)
85
- raise Error, "Key and block can't be provided together" if key && block
86
- raise Error, 'Key or block must be provided' if !key && !block
87
-
88
- block ||= proc { |obj| obj.public_send(key) }
89
- define_method(:id, &block)
79
+ def attributes
80
+ @attributes ||= {}
90
81
  end
91
82
 
92
83
  def attribute(name, **opts, &block)
93
- add_attribute(name: name, opts: opts, block: block)
84
+ new_attr = self::Attribute.new(name: name, opts: opts, block: block)
85
+ attributes[new_attr.name] = new_attr
94
86
  end
95
87
 
96
88
  def relationship(name, serializer:, **opts, &block)
97
- opts[:serializer] = serializer
98
- add_attribute(name: name, opts: opts, block: block)
99
- end
100
-
101
- private
102
-
103
- def add_attribute(params)
104
- opts = Opts.new(self, params)
105
-
106
- Attribute.new(opts).tap do |attribute|
107
- attributes << attribute
108
- add_method(attribute)
109
- clear
110
- end
111
- end
112
-
113
- def add_method(attribute)
114
- block = attribute.block
115
- return unless block
116
-
117
- name = attribute.original_name
118
- # Warning-free method redefinition
119
- remove_method(name) if method_defined?(name)
120
- define_method(name, &block)
89
+ attribute(name, serializer: serializer, **opts, &block)
121
90
  end
122
91
  end
123
92
 
124
- # :reek:ModuleInitialize
125
- module DSLInstanceMethods
126
- attr_reader :_context
127
-
128
- def initialize(context = {}, full_map = nil)
129
- @_context = context.dup
130
- @_full_map = full_map
131
- end
132
-
133
- def to_h(object, context = {})
134
- _reinitialize(context)
135
-
136
- Response.new(self, object).to_h
137
- end
138
-
139
- def to_str(object, context = {})
140
- _reinitialize(context)
141
- Response.new(self, object).to_str
142
- end
143
-
144
- def id(object)
145
- object.id
146
- end
147
-
148
- def _preloads
149
- Preloads.new(_full_map).for(self.class)
150
- end
151
-
152
- def _copy_to(nested_serializer)
153
- nested_serializer.().new(_context, _full_map)
154
- end
93
+ module InstanceMethods
94
+ attr_reader :context
155
95
 
156
- def _full_map
157
- @_full_map ||= begin
158
- params = _context[:params]
159
- fields = params && (params[:fields] || params['fields'])
160
- includes = params && (params[:include] || params['include'])
161
- Map.(self.class, fields, includes)
162
- end
96
+ def initialize(context = {})
97
+ @context = context
163
98
  end
164
99
 
165
- def _map
166
- @_map ||= _full_map.fetch(type)
100
+ def to_h(_object)
101
+ raise Error, "Method #to_h must be implemented by plugin"
167
102
  end
168
103
 
169
- private
170
-
171
- def _reinitialize(context)
172
- new_params = context[:params]
173
- old_params = _context[:params]
174
-
175
- # maps depend on params, so we should clear them when params changed
176
- if new_params != old_params
177
- @_full_map = nil
178
- @_map = nil
179
- end
180
-
181
- @_context = _context.merge!(context)
104
+ def config
105
+ self.class.config
182
106
  end
183
107
  end
184
108
 
185
109
  extend ClassMethods
110
+ include InstanceMethods
186
111
  end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe Jat::Attribute do
6
+ let(:jat_class) { Class.new(Jat) }
7
+ let(:attribute_class) { jat_class::Attribute }
8
+
9
+ describe ".jat_class=" do
10
+ it "assigns @jat_class" do
11
+ attribute_class.jat_class = :foo
12
+ assert_equal :foo, attribute_class.instance_variable_get(:@jat_class)
13
+ end
14
+ end
15
+
16
+ describe ".jat_class" do
17
+ it "returns self @jat_class" do
18
+ assert_same jat_class, attribute_class.instance_variable_get(:@jat_class)
19
+ assert_same jat_class, attribute_class.jat_class
20
+ end
21
+ end
22
+
23
+ describe ".inspect" do
24
+ it "returns self name" do
25
+ assert_equal "#{jat_class}::Attribute", attribute_class.inspect
26
+ end
27
+ end
28
+
29
+ describe "#initialize" do
30
+ it "deeply copies provided params" do
31
+ params = {name: :foo, opts: {include: {foo: :bar}}, block: -> {}}
32
+
33
+ attribute = attribute_class.new(**params)
34
+ assert_equal attribute.params, params
35
+ refute_same attribute.params, params
36
+ refute_same attribute.opts, params[:opts]
37
+ end
38
+ end
39
+
40
+ describe "#name" do
41
+ it "symbolizes name" do
42
+ attribute = attribute_class.new(name: "foo")
43
+ assert_equal :foo, attribute.name
44
+ end
45
+ end
46
+
47
+ describe "#key" do
48
+ it "returns same as #name when key not provided" do
49
+ attribute = attribute_class.new(name: "foo")
50
+ assert_equal :foo, attribute.key
51
+ end
52
+
53
+ it "returns symbolized key option" do
54
+ attribute = attribute_class.new(name: "foo", opts: {key: "bar"})
55
+ assert_equal :bar, attribute.key
56
+ end
57
+ end
58
+
59
+ describe "#exposed?" do
60
+ it "returns provided value" do
61
+ attribute = attribute_class.new(name: "foo", opts: {exposed: false})
62
+ assert_equal false, attribute.exposed?
63
+ end
64
+
65
+ it "returns true when all keys are exposed by config" do
66
+ jat_class.config[:exposed] = :all
67
+ attribute = attribute_class.new(name: "foo")
68
+ assert_equal true, attribute.exposed?
69
+ end
70
+
71
+ it "returns false when no keys are exposed by config" do
72
+ jat_class.config[:exposed] = :none
73
+ attribute = attribute_class.new(name: "foo")
74
+ assert_equal false, attribute.exposed?
75
+ end
76
+
77
+ it "returns false when serializer exists and config[:exposed] is default" do
78
+ jat_class.config[:exposed] = :default
79
+ attribute = attribute_class.new(name: "foo", opts: {serializer: jat_class})
80
+ assert_equal false, attribute.exposed?
81
+ end
82
+
83
+ it "returns true when serializer not exists and config[:exposed] is default" do
84
+ jat_class.config[:exposed] = :default
85
+ attribute = attribute_class.new(name: "foo")
86
+ assert_equal true, attribute.exposed?
87
+ end
88
+ end
89
+
90
+ describe "#many?" do
91
+ it "returns nil when no key provided" do
92
+ attribute = attribute_class.new(name: "foo")
93
+ assert_nil attribute.many?
94
+ end
95
+
96
+ it "returns provided data" do
97
+ attribute = attribute_class.new(name: "foo", opts: {many: false})
98
+ assert_equal false, attribute.many?
99
+ assert_equal false, attribute.instance_variable_get(:@many)
100
+ assert_same attribute.instance_variable_get(:@many), attribute.many?
101
+ end
102
+ end
103
+
104
+ describe "#relation?" do
105
+ it "returns false when no serializer key" do
106
+ attribute = attribute_class.new(name: "foo")
107
+ assert_equal false, attribute.relation?
108
+ end
109
+
110
+ it "returns true with serializer key" do
111
+ attribute = attribute_class.new(name: "foo", opts: {serializer: jat_class})
112
+ assert_equal true, attribute.relation?
113
+ end
114
+ end
115
+
116
+ describe "#serializer" do
117
+ it "returns nil when no serializer key" do
118
+ attribute = attribute_class.new(name: "foo")
119
+ assert_nil attribute.serializer
120
+ end
121
+
122
+ it "returns provided serializer" do
123
+ attribute = attribute_class.new(name: "foo", opts: {serializer: jat_class})
124
+ assert_same jat_class, attribute.serializer
125
+ end
126
+ end
127
+
128
+ describe "#block" do
129
+ it "returns provided block" do
130
+ block = proc { |object, context| [object, context] }
131
+ attribute = attribute_class.new(name: "foo", block: block)
132
+ assert_equal ["OBJECT", "CONTEXT"], attribute.value("OBJECT", "CONTEXT")
133
+ end
134
+
135
+ it "returns provided block when block was without params" do
136
+ block = proc { "RESULT" }
137
+ attribute = attribute_class.new(name: "foo", block: block)
138
+ assert_equal "RESULT", attribute.value("OBJECT", "CONTEXT")
139
+ end
140
+
141
+ it "returns provided block when block was with one param" do
142
+ block = proc { |object| object }
143
+ attribute = attribute_class.new(name: "foo", block: block)
144
+ assert_equal "OBJECT", attribute.value("OBJECT", "CONTEXT")
145
+ end
146
+
147
+ it "constructs block that calls current key method on object" do
148
+ attribute = attribute_class.new(name: "foo", opts: {key: :length})
149
+ assert_equal 3, attribute.value([1, 2, 3], nil)
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe Jat::Config do
6
+ let(:jat_class) { Class.new(Jat) }
7
+ let(:config) { jat_class.config }
8
+
9
+ describe ".jat_class=" do
10
+ it "assigns @jat_class" do
11
+ config.class.jat_class = :foo
12
+ assert_equal :foo, config.class.instance_variable_get(:@jat_class)
13
+ end
14
+ end
15
+
16
+ describe ".jat_class" do
17
+ it "returns self @jat_class" do
18
+ assert_same jat_class, config.class.instance_variable_get(:@jat_class)
19
+ assert_same jat_class, config.class.jat_class
20
+ end
21
+ end
22
+
23
+ describe ".inspect" do
24
+ it "returns self name" do
25
+ assert_equal "#{jat_class}::Config", config.class.inspect
26
+ end
27
+ end
28
+
29
+ describe "#initialize" do
30
+ it "deeply copies provided opts" do
31
+ opts = {foo: {bar: {bazz: :bazz2}}}
32
+
33
+ config = Jat::Config.new(opts)
34
+ assert_equal config.opts, opts
35
+ refute_same config.opts[:foo], opts[:foo]
36
+ refute_same config.opts[:foo][:bar], opts[:foo][:bar]
37
+ end
38
+ end
39
+
40
+ describe "#[]=" do
41
+ it "adds options" do
42
+ config = Jat::Config.new
43
+ config[:foo] = :bar
44
+
45
+ assert_equal :bar, config.opts[:foo]
46
+ end
47
+ end
48
+
49
+ describe "#[]" do
50
+ it "reads options" do
51
+ config = Jat::Config.new
52
+ config[:foo] = :bar
53
+
54
+ assert_equal :bar, config[:foo]
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::ActiverecordPreloads" do
6
+ let(:jat_class) do
7
+ api_test = api_test()
8
+
9
+ Class.new(Jat) do
10
+ include api_test
11
+ plugin(:_activerecord_preloads)
12
+ end
13
+ end
14
+
15
+ let(:api_test) do
16
+ Module.new do
17
+ def to_h(object)
18
+ object
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "InstanceMethods" do
24
+ it "adds preloads to object when calling to_h" do
25
+ object = "OBJ"
26
+ preloads = "PRELOADS"
27
+ jat = jat_class.new
28
+ jat.expects(:preloads).returns(preloads)
29
+
30
+ Jat::Plugins::ActiverecordPreloads::Preloader
31
+ .expects(:preload)
32
+ .with(object, preloads).returns("OBJ_WITH_PRELOADS")
33
+
34
+ assert_equal("OBJ_WITH_PRELOADS", jat.to_h(object))
35
+ end
36
+
37
+ it "skips preloadings for nil" do
38
+ object = nil
39
+ jat = jat_class.new
40
+
41
+ assert_same object, jat.to_h(object)
42
+ end
43
+
44
+ it "skips preloadings for empty array" do
45
+ object = []
46
+ jat = jat_class.new
47
+
48
+ assert_same object, jat.to_h(object)
49
+ end
50
+
51
+ it "skips preloadings when nothing to preload" do
52
+ object = "OBJECT"
53
+ jat = jat_class.new
54
+ jat.expects(:preloads).returns({})
55
+
56
+ assert_same object, jat.to_h(object)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+ require "support/activerecord"
5
+
6
+ describe "Jat::Plugins::ActiverecordPreloads" do
7
+ before { Jat::Plugins.find_plugin(:_activerecord_preloads) }
8
+
9
+ describe "Preloader" do
10
+ let(:described_class) { plugin::Preloader }
11
+ let(:plugin) { Jat::Plugins::ActiverecordPreloads }
12
+
13
+ describe ".handlers" do
14
+ it "returns memorized array of handlers" do
15
+ assert_equal [
16
+ plugin::ActiverecordRelation,
17
+ plugin::ActiverecordObject,
18
+ plugin::ActiverecordArray
19
+ ], described_class.handlers
20
+
21
+ assert_same described_class.handlers, described_class.handlers
22
+ end
23
+ end
24
+
25
+ describe ".preload" do
26
+ it "raises error when can't find appropriate handler" do
27
+ preloads = {}
28
+
29
+ object = nil
30
+ err = assert_raises(Jat::Error) { described_class.preload(object, {}) }
31
+ assert_equal "Can't preload #{preloads.inspect} to #{object.inspect}", err.message
32
+
33
+ object = []
34
+ err = assert_raises(Jat::Error) { described_class.preload(object, {}) }
35
+ assert_equal "Can't preload #{preloads.inspect} to #{object.inspect}", err.message
36
+
37
+ object = 123
38
+ err = assert_raises(Jat::Error) { described_class.preload(object, {}) }
39
+ assert_equal "Can't preload #{preloads.inspect} to #{object.inspect}", err.message
40
+
41
+ object = [AR::User.create!, AR::Comment.create!]
42
+ err = assert_raises(Jat::Error) { described_class.preload(object, {}) }
43
+ assert_equal "Can't preload #{preloads.inspect} to #{object.inspect}", err.message
44
+ end
45
+
46
+ it "preloads data to activerecord object" do
47
+ user = AR::User.create!
48
+
49
+ result = described_class.preload(user, {comments: {}})
50
+
51
+ assert_same result, user
52
+ assert_equal true, user.association(:comments).loaded?
53
+ end
54
+
55
+ it "preloads data to activerecord array" do
56
+ user = AR::User.create!
57
+
58
+ users = [user]
59
+ result = described_class.preload(users, {comments: {}})
60
+
61
+ assert_same result, users
62
+ assert_equal true, result[0].association(:comments).loaded?
63
+ end
64
+
65
+ it "preloads data to activerecord relation" do
66
+ user = AR::User.create!
67
+
68
+ result = described_class.preload(AR::User.where(id: user.id), {comments: {}})
69
+
70
+ assert_equal result, [user]
71
+ assert_equal true, result[0].association(:comments).loaded?
72
+ end
73
+
74
+ it "preloads data to loaded activerecord relation" do
75
+ user = AR::User.create!
76
+
77
+ result = described_class.preload(AR::User.where(id: user.id).load, {comments: {}})
78
+
79
+ assert_equal result, [user]
80
+ assert_equal true, result[0].association(:comments).loaded?
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::LowerCamelCase" do
6
+ let(:jat_class) do
7
+ new_class = Class.new(Jat)
8
+ new_class.plugin(:_lower_camel_case)
9
+ new_class
10
+ end
11
+
12
+ describe "Attribute" do
13
+ describe "#name" do
14
+ it "returns name in lower_camel_case case" do
15
+ attribute = jat_class.attribute(:foo)
16
+ assert :foo, attribute.name
17
+
18
+ attribute = jat_class.attribute(:foo_bar)
19
+ assert :fooBar, attribute.name
20
+
21
+ attribute = jat_class.attribute(:foo_bar_bazz)
22
+ assert :fooBarBazz, attribute.name
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::Preloads" do
6
+ let(:jat_class) do
7
+ Class.new(Jat) { plugin(:_preloads) }
8
+ end
9
+
10
+ def attribute(name, opts)
11
+ jat_class.attribute(name, **opts)
12
+ end
13
+
14
+ describe "AttributeMethods" do
15
+ it "saves @preloads and @preloads_path after first access" do
16
+ attribute = attribute(:foo, preload: :bar)
17
+
18
+ assert_same attribute.preloads, attribute.preloads
19
+ assert_same attribute.preloads_path, attribute.preloads_path
20
+ end
21
+
22
+ describe "#preloads" do
23
+ it "returns formatted data provided by user" do
24
+ assert_equal({}, attribute(:foo, preload: {}).preloads)
25
+ assert_equal({}, attribute(:foo, preload: []).preloads)
26
+ assert_equal({some: {}}, attribute(:foo, preload: :some).preloads)
27
+ assert_equal({some: {data: {}}}, attribute(:foo, preload: {some: :data}).preloads)
28
+ end
29
+
30
+ it "preloads main key when serializer exists and preloads are not" do
31
+ assert_equal({foo: {}}, attribute(:foo, serializer: jat_class).preloads)
32
+ assert_equal({bar: {}}, attribute(:foo, key: :bar, serializer: jat_class).preloads)
33
+ end
34
+
35
+ it "returns nil when requested to preload nil or false" do
36
+ assert_nil attribute(:foo, serializer: jat_class, preload: nil).preloads
37
+ assert_nil attribute(:foo, key: :bar, serializer: jat_class, preload: false).preloads
38
+ end
39
+
40
+ it "removes bang (!) from preloads" do
41
+ assert_equal({foo: {}}, attribute(:foo, preload: :foo!).preloads)
42
+ end
43
+ end
44
+
45
+ describe "#preloads_path" do
46
+ it "returns path to main resource provided by user" do
47
+ assert_equal([], attribute(:foo, preload: nil).preloads_path)
48
+ assert_equal([], attribute(:foo, preload: {}).preloads_path)
49
+ assert_equal([], attribute(:foo, preload: []).preloads_path)
50
+ assert_equal([:some], attribute(:foo, preload: :some).preloads_path)
51
+ assert_equal(%i[some data], attribute(:foo, preload: {some: :data}).preloads_path)
52
+ end
53
+
54
+ it "show path to main key when serializer exists and preloads are not" do
55
+ assert_equal([:foo], attribute(:foo, serializer: jat_class).preloads_path)
56
+ assert_equal([:bar], attribute(:foo, key: :bar, serializer: jat_class).preloads_path)
57
+
58
+ # serializer with empty preloads provided
59
+ assert_equal([], attribute(:foo, serializer: jat_class, preload: nil).preloads_path)
60
+ assert_equal([], attribute(:foo, key: :bar, serializer: jat_class, preload: false).preloads_path)
61
+ end
62
+
63
+ it "removes bang (!) and construct path to this preload" do
64
+ assert_equal([:some], attribute(:foo, preload: {some!: :data}).preloads_path)
65
+ end
66
+ end
67
+ end
68
+ end