jat 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +21 -0
  4. data/jat.gemspec +37 -0
  5. data/lib/jat/attribute.rb +85 -0
  6. data/lib/jat/config.rb +38 -0
  7. data/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads.rb +29 -0
  8. data/lib/jat/plugins/_activerecord_preloads/lib/preloader.rb +89 -0
  9. data/lib/jat/plugins/_json_api_activerecord/_json_api_activerecord.rb +22 -0
  10. data/lib/jat/plugins/_json_api_activerecord/lib/preloads.rb +84 -0
  11. data/lib/jat/plugins/_preloads/_preloads.rb +53 -0
  12. data/lib/jat/plugins/_preloads/lib/format_user_preloads.rb +52 -0
  13. data/lib/jat/plugins/_preloads/lib/preloads_with_path.rb +78 -0
  14. data/lib/jat/plugins/cache/cache.rb +39 -0
  15. data/lib/jat/plugins/camel_lower/camel_lower.rb +18 -0
  16. data/lib/jat/plugins/json_api/json_api.rb +207 -0
  17. data/lib/jat/plugins/json_api/lib/construct_traversal_map.rb +91 -0
  18. data/lib/jat/plugins/json_api/lib/map.rb +54 -0
  19. data/lib/jat/plugins/json_api/lib/params/fields/parse.rb +27 -0
  20. data/lib/jat/plugins/json_api/lib/params/fields/validate.rb +55 -0
  21. data/lib/jat/plugins/json_api/lib/params/fields.rb +23 -0
  22. data/lib/jat/plugins/json_api/lib/params/include/parse.rb +55 -0
  23. data/lib/jat/plugins/json_api/lib/params/include/validate.rb +29 -0
  24. data/lib/jat/plugins/json_api/lib/params/include.rb +49 -0
  25. data/lib/jat/plugins/json_api/lib/presenters/document_links_presenter.rb +48 -0
  26. data/lib/jat/plugins/json_api/lib/presenters/document_meta_presenter.rb +48 -0
  27. data/lib/jat/plugins/json_api/lib/presenters/jsonapi_presenter.rb +48 -0
  28. data/lib/jat/plugins/json_api/lib/presenters/links_presenter.rb +48 -0
  29. data/lib/jat/plugins/json_api/lib/presenters/meta_presenter.rb +48 -0
  30. data/lib/jat/plugins/json_api/lib/presenters/relationship_links_presenter.rb +53 -0
  31. data/lib/jat/plugins/json_api/lib/presenters/relationship_meta_presenter.rb +53 -0
  32. data/lib/jat/plugins/json_api/lib/response.rb +239 -0
  33. data/lib/jat/plugins/json_api/lib/traversal_map.rb +34 -0
  34. data/lib/jat/plugins/simple_api/lib/construct_traversal_map.rb +45 -0
  35. data/lib/jat/plugins/simple_api/lib/map.rb +29 -0
  36. data/lib/jat/plugins/simple_api/lib/params/parse.rb +68 -0
  37. data/lib/jat/plugins/simple_api/lib/response.rb +134 -0
  38. data/lib/jat/plugins/simple_api/simple_api.rb +65 -0
  39. data/lib/jat/plugins/to_str/to_str.rb +44 -0
  40. data/lib/jat/plugins.rb +39 -0
  41. data/lib/jat/presenter.rb +51 -0
  42. data/lib/jat/utils/enum_deep_dup.rb +29 -0
  43. data/lib/jat/utils/enum_deep_freeze.rb +19 -0
  44. data/lib/jat.rb +66 -144
  45. data/test/lib/jat/attribute_test.rb +142 -0
  46. data/test/lib/jat/config_test.rb +57 -0
  47. data/test/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads_test.rb +40 -0
  48. data/test/lib/jat/plugins/_activerecord_preloads/lib/preloader_test.rb +98 -0
  49. data/test/lib/jat/plugins/_json_api_activerecord/_json_api_activerecord_test.rb +29 -0
  50. data/test/lib/jat/plugins/_json_api_activerecord/lib/preloads_test.rb +191 -0
  51. data/test/lib/jat/plugins/_preloads/_preloads_test.rb +68 -0
  52. data/test/lib/jat/plugins/_preloads/lib/format_user_preloads_test.rb +47 -0
  53. data/test/lib/jat/plugins/_preloads/lib/preloads_with_path_test.rb +33 -0
  54. data/test/lib/jat/plugins/cache/cache_test.rb +82 -0
  55. data/test/lib/jat/plugins/camel_lower/camel_lower_test.rb +78 -0
  56. data/test/lib/jat/plugins/json_api/json_api_test.rb +154 -0
  57. data/test/lib/jat/plugins/json_api/lib/construct_traversal_map_test.rb +119 -0
  58. data/test/lib/jat/plugins/json_api/lib/map_test.rb +117 -0
  59. data/test/lib/jat/plugins/json_api/lib/params/fields/parse_test.rb +24 -0
  60. data/test/lib/jat/plugins/json_api/lib/params/fields/validate_test.rb +47 -0
  61. data/test/lib/jat/plugins/json_api/lib/params/fields_test.rb +37 -0
  62. data/test/lib/jat/plugins/json_api/lib/params/include/parse_test.rb +46 -0
  63. data/test/lib/jat/plugins/json_api/lib/params/include/validate_test.rb +51 -0
  64. data/test/lib/jat/plugins/json_api/lib/params/include_test.rb +41 -0
  65. data/test/lib/jat/plugins/json_api/lib/presenters/document_links_presenter_test.rb +69 -0
  66. data/test/lib/jat/plugins/json_api/lib/presenters/document_meta_presenter_test.rb +69 -0
  67. data/test/lib/jat/plugins/json_api/lib/presenters/jsonapi_presenter_test.rb +69 -0
  68. data/test/lib/jat/plugins/json_api/lib/presenters/links_presenter_test.rb +69 -0
  69. data/test/lib/jat/plugins/json_api/lib/presenters/meta_presenter_test.rb +69 -0
  70. data/test/lib/jat/plugins/json_api/lib/presenters/relationship_links_presenter_test.rb +75 -0
  71. data/test/lib/jat/plugins/json_api/lib/presenters/relationship_meta_presenter_test.rb +75 -0
  72. data/test/lib/jat/plugins/json_api/lib/response_test.rb +489 -0
  73. data/test/lib/jat/plugins/json_api/lib/traversal_map_test.rb +58 -0
  74. data/test/lib/jat/plugins/simple_api/lib/construct_traversal_map_test.rb +100 -0
  75. data/test/lib/jat/plugins/simple_api/lib/map_test.rb +56 -0
  76. data/test/lib/jat/plugins/simple_api/lib/params/parse_test.rb +71 -0
  77. data/test/lib/jat/plugins/simple_api/lib/response_test.rb +342 -0
  78. data/test/lib/jat/plugins/simple_api/simple_api_test.rb +81 -0
  79. data/test/lib/jat/plugins/to_str/to_str_test.rb +52 -0
  80. data/test/lib/jat/presenter_test.rb +61 -0
  81. data/test/lib/jat/utils/enum_deep_dup_test.rb +31 -0
  82. data/test/lib/jat/utils/enum_deep_freeze_test.rb +28 -0
  83. data/test/lib/jat_test.rb +120 -0
  84. data/test/lib/plugin_test.rb +49 -0
  85. data/test/support/activerecord.rb +24 -0
  86. data/test/test_helper.rb +16 -0
  87. data/test/test_plugin.rb +59 -0
  88. metadata +240 -11
@@ -0,0 +1,142 @@
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 = -> {}
131
+ attribute = attribute_class.new(name: "foo", block: block)
132
+ assert_equal block, attribute.block
133
+ end
134
+
135
+ it "constructs block that calls current key method on object" do
136
+ attribute = attribute_class.new(name: "foo", opts: {key: :length})
137
+ presenter = jat_class::Presenter.new([1, 2, 3], {})
138
+
139
+ assert_equal 3, presenter.instance_exec(&attribute.block)
140
+ end
141
+ end
142
+ 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,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::ActiverecordPreloads" do
6
+ let(:jat_class) { Class.new(Jat) { plugin(:_activerecord_preloads) } }
7
+ let(:preloader) { Jat::Plugins::ActiverecordPreloads::Preloader }
8
+
9
+ describe "InstanceMethods" do
10
+ it "adds preloads to object in initialize call" do
11
+ obj = "OBJ"
12
+ preloads = "PRELOADS"
13
+ jat_class.expects(:jat_preloads).with(kind_of(jat_class)).returns(preloads)
14
+ preloader.expects(:preload).with(obj, preloads).returns("OBJ_WITH_PRELOADS")
15
+
16
+ jat = jat_class.new(obj, {})
17
+ assert_equal("OBJ_WITH_PRELOADS", jat.object)
18
+ end
19
+
20
+ it "skips preloadings for nil" do
21
+ object = nil
22
+ jat = jat_class.new(object, {})
23
+ assert_same object, jat.object
24
+ end
25
+
26
+ it "skips preloadings for empty array" do
27
+ object = []
28
+ jat = jat_class.new(object, {})
29
+ assert_same object, jat.object
30
+ end
31
+
32
+ it "skips preloadings when nothing to preload" do
33
+ object = "OBJECT"
34
+ jat_class.expects(:jat_preloads).with(kind_of(jat_class)).returns({})
35
+
36
+ jat = jat_class.new(object, {})
37
+ assert_same object, jat.object
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,98 @@
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.load_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 "resets activerecord object preloaded relations" do
56
+ user = AR::User.create!
57
+ comment = user.comments.create!
58
+ user.comments.to_a && comment.delete # preload comments manually and delete comment
59
+
60
+ described_class.preload(user, {comments: {}})
61
+
62
+ assert_equal true, user.association(:comments).loaded?
63
+ assert_equal [], user.comments
64
+ end
65
+
66
+ it "preloads data to activerecord relation object" do
67
+ user = AR::User.create!
68
+
69
+ result = described_class.preload(AR::User.where(id: user.id), {comments: {}})
70
+
71
+ assert_equal result, [user]
72
+ assert_equal true, result[0].association(:comments).loaded?
73
+ end
74
+
75
+ it "preloads data to activerecord array" do
76
+ user = AR::User.create!
77
+
78
+ users = [user]
79
+ result = described_class.preload(users, {comments: {}})
80
+
81
+ assert_same result, users
82
+ assert_equal true, result[0].association(:comments).loaded?
83
+ end
84
+
85
+ it "resets activerecord array preloaded relations" do
86
+ user = AR::User.create!
87
+ comment = user.comments.create!
88
+ user.comments.to_a && comment.delete # preload comments manually and delete comment
89
+
90
+ users = [user]
91
+ result = described_class.preload(users, {comments: {}})
92
+
93
+ assert_equal true, result[0].association(:comments).loaded?
94
+ assert_equal [], result[0].comments
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::JsonApiActiverecord" do
6
+ before do
7
+ @plugin = Jat::Plugins.load_plugin(:_json_api_activerecord)
8
+ end
9
+
10
+ it "loads other plugins in after_load" do
11
+ jat_class = Class.new(Jat)
12
+ jat_class.expects(:plugin).with(:_preloads, foo: :bar)
13
+ jat_class.expects(:plugin).with(:_activerecord_preloads, foo: :bar)
14
+
15
+ Jat::Plugins.after_load(@plugin, jat_class, foo: :bar)
16
+ end
17
+
18
+ describe "ClassMethods" do
19
+ it "add .jat_preloads method as a delegator to #{@plugin}::Preloads" do
20
+ jat_class = Class.new(Jat)
21
+ jat_class.plugin @plugin
22
+ jat = jat_class.allocate
23
+
24
+ @plugin::Preloads.expects(:call).with(jat).returns("RES")
25
+
26
+ assert_equal "RES", jat_class.jat_preloads(jat)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::JsonApiActiverecord::Preloads" do
6
+ let(:base) { Class.new(Jat) { plugin :json_api, activerecord: true } }
7
+
8
+ let(:user_serializer) { Class.new(base) { type(:user) } }
9
+ let(:profile_serializer) { Class.new(base) { type(:profile) } }
10
+ let(:email_serializer) { Class.new(base) { type(:email) } }
11
+
12
+ let(:jat_user) { user_serializer.allocate }
13
+ let(:jat_profile) { profile_serializer.allocate }
14
+ let(:jat_email) { email_serializer.allocate }
15
+
16
+ let(:described_class) { Jat::Plugins::JsonApiActiverecord::Preloads }
17
+
18
+ def define_map(map)
19
+ jat_user.traversal_map.expects(:current).returns(map)
20
+ end
21
+
22
+ it "returns empty hash when no attributes requested" do
23
+ define_map(user: {attributes: [], relationships: []})
24
+
25
+ result = described_class.call(jat_user)
26
+ assert_equal({}, result)
27
+ end
28
+
29
+ it "returns empty hash when no attributes with preloads requested" do
30
+ user_serializer.attribute :name
31
+ define_map(user: {attributes: [:name], relationships: []})
32
+
33
+ result = described_class.call(jat_user)
34
+ assert_equal({}, result)
35
+ end
36
+
37
+ it "returns preloads for requested attributes" do
38
+ user_serializer.attribute :name, preload: :profile
39
+ define_map(user: {attributes: [:name], relationships: []})
40
+
41
+ result = described_class.call(jat_user)
42
+ assert_equal({profile: {}}, result)
43
+ end
44
+
45
+ it "returns merged preloads for requested attributes" do
46
+ user_serializer.attribute :first_name, preload: :profile
47
+ user_serializer.attribute :phone, preload: {profile: :phones}
48
+ user_serializer.attribute :email, preload: {profile: :emails}
49
+
50
+ define_map(user: {attributes: %i[first_name phone email], relationships: []})
51
+
52
+ result = described_class.call(jat_user)
53
+ assert_equal({profile: {phones: {}, emails: {}}}, result)
54
+ end
55
+
56
+ it "returns no preloads and no nested preloads for relationships when specified preloads is nil" do
57
+ user_serializer.relationship :profile, serializer: profile_serializer, preload: nil
58
+ profile_serializer.attribute :email, preload: :email # should not be preloaded
59
+ define_map(
60
+ user: {attributes: [], relationships: %i[profile]},
61
+ profile: {attributes: %i[email], relationships: []}
62
+ )
63
+
64
+ result = described_class.call(jat_user)
65
+ assert_equal({}, result)
66
+ end
67
+
68
+ it "returns preloads for nested relationships joined to root when specified preloads is {} or []" do
69
+ [{}, []].each do |preloads|
70
+ user_serializer.relationship :profile, serializer: profile_serializer, preload: preloads
71
+ profile_serializer.attribute :email, preload: :email # should be preloaded to root
72
+ define_map(
73
+ user: {attributes: [], relationships: %i[profile]},
74
+ profile: {attributes: %i[email], relationships: []}
75
+ )
76
+
77
+ result = described_class.call(jat_user)
78
+ assert_equal({email: {}}, result)
79
+ end
80
+ end
81
+
82
+ it "returns preloads for relationships" do
83
+ user_serializer.relationship :profile, serializer: profile_serializer
84
+ define_map(
85
+ user: {attributes: [], relationships: %i[profile]},
86
+ profile: {attributes: [], relationships: []}
87
+ )
88
+
89
+ result = described_class.call(jat_user)
90
+ assert_equal({profile: {}}, result)
91
+ end
92
+
93
+ it "returns nested preloads for relationships" do
94
+ user_serializer.relationship :profile, serializer: profile_serializer
95
+ profile_serializer.attribute :email, preload: %i[confirmed_email unconfirmed_email]
96
+
97
+ define_map(
98
+ user: {attributes: [], relationships: %i[profile]},
99
+ profile: {attributes: %i[email], relationships: []}
100
+ )
101
+
102
+ result = described_class.call(jat_user)
103
+ assert_equal({profile: {confirmed_email: {}, unconfirmed_email: {}}}, result)
104
+ end
105
+
106
+ it "preloads nested relationships for nested relationship" do
107
+ user_serializer.relationship :profile, serializer: profile_serializer, preload: {company: :profile}
108
+ profile_serializer.attribute :email, preload: %i[confirmed_email unconfirmed_email]
109
+
110
+ define_map(
111
+ user: {attributes: [], relationships: %i[profile]},
112
+ profile: {attributes: %i[email], relationships: []}
113
+ )
114
+
115
+ result = described_class.call(jat_user)
116
+ assert_equal({company: {profile: {confirmed_email: {}, unconfirmed_email: {}}}}, result)
117
+ end
118
+
119
+ it "preloads nested relationships to main (!) resource" do
120
+ user_serializer.relationship :profile, serializer: profile_serializer, preload: {company!: :profile}
121
+ profile_serializer.attribute :email, preload: %i[confirmed_email unconfirmed_email]
122
+
123
+ define_map(
124
+ user: {attributes: [], relationships: %i[profile]},
125
+ profile: {attributes: %i[email], relationships: []}
126
+ )
127
+
128
+ result = described_class.call(jat_user)
129
+ assert_equal({company: {profile: {}, confirmed_email: {}, unconfirmed_email: {}}}, result)
130
+ end
131
+
132
+ it "raises error if with 2 serializers have recursive preloads" do
133
+ user_serializer.relationship :profile, serializer: profile_serializer, preload: :profile
134
+ profile_serializer.relationship :user, serializer: user_serializer, preload: :user
135
+
136
+ define_map(
137
+ user: {attributes: [], relationships: %i[profile]},
138
+ profile: {attributes: [], relationships: %i[user]}
139
+ )
140
+
141
+ error = assert_raises(Jat::Error) { described_class.call(jat_user) }
142
+ assert_match(/recursive preloads/, error.message)
143
+ end
144
+
145
+ it "raises error if 3 serializers recursive preloads" do
146
+ user_serializer.relationship :profile, serializer: profile_serializer, preload: :profile
147
+ profile_serializer.relationship :email, serializer: email_serializer, preload: :email
148
+ email_serializer.relationship :user, serializer: user_serializer, preload: :user
149
+
150
+ define_map(
151
+ user: {attributes: [], relationships: %i[profile]},
152
+ profile: {attributes: [], relationships: %i[email]},
153
+ email: {attributes: [], relationships: %i[user]}
154
+ )
155
+
156
+ error = assert_raises(Jat::Error) { described_class.call(jat_user) }
157
+ assert_match(/recursive preloads/, error.message)
158
+ end
159
+
160
+ it "does not raises error if 2 serializers preloads same preloads" do
161
+ user_serializer.relationship :profile, serializer: profile_serializer, preload: :profile
162
+ user_serializer.relationship :email, serializer: email_serializer, preload: :email
163
+ profile_serializer.relationship :email, serializer: email_serializer, preload: :email
164
+
165
+ define_map(
166
+ user: {attributes: [], relationships: %i[profile email]},
167
+ profile: {attributes: [], relationships: %i[email]},
168
+ email: {attributes: [], relationships: %i[]}
169
+ )
170
+
171
+ described_class.call(jat_user) # should not raise
172
+ end
173
+
174
+ it "merges preloads the same way regardless of order of preloads" do
175
+ a = Class.new(base) { type(:a) }
176
+ a.attribute :a1, preload: {foo: {bar: {bazz1: {}, bazz: {}}}}
177
+ a.attribute :a2, preload: {foo: {bar: {bazz2: {}, bazz: {last: {}}}}}
178
+
179
+ jat_a1 = a.allocate
180
+ jat_a2 = a.allocate
181
+
182
+ jat_a1.traversal_map.expects(:current).returns(a: {attributes: %i[a1 a2], relationships: %i[]})
183
+ jat_a2.traversal_map.expects(:current).returns(a: {attributes: %i[a2 a1], relationships: %i[]})
184
+
185
+ result1 = described_class.call(jat_a1)
186
+ result2 = described_class.call(jat_a2)
187
+
188
+ assert_equal(result2, result1)
189
+ assert_equal({foo: {bar: {bazz: {last: {}}, bazz1: {}, bazz2: {}}}}, result1)
190
+ end
191
+ 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
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::Preloads::FormatUserPreloads" do
6
+ before { Jat::Plugins.load_plugin(:_preloads) }
7
+
8
+ let(:format) { Jat::Plugins::Preloads::FormatUserPreloads }
9
+
10
+ it "transforms nil to empty hash" do
11
+ preloads = nil
12
+ assert_equal ({}), format.to_hash(preloads)
13
+ end
14
+
15
+ it "transforms false to empty hash" do
16
+ preloads = false
17
+ assert_equal({}, format.to_hash(preloads))
18
+ end
19
+
20
+ it "transforms Symbol" do
21
+ preloads = :foo
22
+ assert_equal({foo: {}}, format.to_hash(preloads))
23
+ end
24
+
25
+ it "transforms String" do
26
+ preloads = "foo"
27
+ assert_equal({foo: {}}, format.to_hash(preloads))
28
+ end
29
+
30
+ it "transforms Hash" do
31
+ preloads = {foo: :bar}
32
+ assert_equal({foo: {bar: {}}}, format.to_hash(preloads))
33
+ end
34
+
35
+ it "transforms Array" do
36
+ preloads = %i[foo bar]
37
+ assert_equal({foo: {}, bar: {}}, format.to_hash(preloads))
38
+ end
39
+
40
+ it "transforms nested hashes and arrays" do
41
+ preloads = [:foo, {"bar" => "bazz"}, ["bazz"]]
42
+ assert_equal({foo: {}, bar: {bazz: {}}, bazz: {}}, format.to_hash(preloads))
43
+
44
+ preloads = {"bar" => "bazz", :foo => [:bar, "bazz"]}
45
+ assert_equal({bar: {bazz: {}}, foo: {bar: {}, bazz: {}}}, format.to_hash(preloads))
46
+ end
47
+ end