mr 0.35.2

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 (115) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +22 -0
  5. data/README.md +29 -0
  6. data/bench/all.rb +4 -0
  7. data/bench/factory.rb +68 -0
  8. data/bench/fake_record.rb +174 -0
  9. data/bench/model.rb +201 -0
  10. data/bench/read_model.rb +191 -0
  11. data/bench/results/factory.txt +21 -0
  12. data/bench/results/fake_record.txt +37 -0
  13. data/bench/results/model.txt +44 -0
  14. data/bench/results/read_model.txt +46 -0
  15. data/bench/setup.rb +132 -0
  16. data/lib/mr.rb +11 -0
  17. data/lib/mr/after_commit.rb +49 -0
  18. data/lib/mr/after_commit/fake_record.rb +39 -0
  19. data/lib/mr/after_commit/record.rb +48 -0
  20. data/lib/mr/after_commit/record_procs_methods.rb +82 -0
  21. data/lib/mr/factory.rb +82 -0
  22. data/lib/mr/factory/config.rb +240 -0
  23. data/lib/mr/factory/model_factory.rb +103 -0
  24. data/lib/mr/factory/model_stack.rb +28 -0
  25. data/lib/mr/factory/read_model_factory.rb +104 -0
  26. data/lib/mr/factory/record_factory.rb +130 -0
  27. data/lib/mr/factory/record_stack.rb +219 -0
  28. data/lib/mr/fake_query.rb +53 -0
  29. data/lib/mr/fake_record.rb +58 -0
  30. data/lib/mr/fake_record/associations.rb +257 -0
  31. data/lib/mr/fake_record/attributes.rb +168 -0
  32. data/lib/mr/fake_record/persistence.rb +116 -0
  33. data/lib/mr/json_field.rb +180 -0
  34. data/lib/mr/json_field/fake_record.rb +31 -0
  35. data/lib/mr/json_field/record.rb +38 -0
  36. data/lib/mr/model.rb +67 -0
  37. data/lib/mr/model/associations.rb +161 -0
  38. data/lib/mr/model/configuration.rb +67 -0
  39. data/lib/mr/model/fields.rb +177 -0
  40. data/lib/mr/model/persistence.rb +79 -0
  41. data/lib/mr/query.rb +126 -0
  42. data/lib/mr/read_model.rb +83 -0
  43. data/lib/mr/read_model/data.rb +38 -0
  44. data/lib/mr/read_model/fields.rb +218 -0
  45. data/lib/mr/read_model/query_expression.rb +188 -0
  46. data/lib/mr/read_model/querying.rb +214 -0
  47. data/lib/mr/read_model/set_querying.rb +82 -0
  48. data/lib/mr/read_model/subquery.rb +98 -0
  49. data/lib/mr/record.rb +35 -0
  50. data/lib/mr/test_helpers.rb +229 -0
  51. data/lib/mr/type_converter.rb +85 -0
  52. data/lib/mr/version.rb +3 -0
  53. data/log/.gitkeep +0 -0
  54. data/mr.gemspec +29 -0
  55. data/test/helper.rb +21 -0
  56. data/test/support/db.rb +10 -0
  57. data/test/support/factory.rb +13 -0
  58. data/test/support/factory/area.rb +6 -0
  59. data/test/support/factory/comment.rb +14 -0
  60. data/test/support/factory/image.rb +6 -0
  61. data/test/support/factory/user.rb +6 -0
  62. data/test/support/models/area.rb +58 -0
  63. data/test/support/models/comment.rb +60 -0
  64. data/test/support/models/image.rb +53 -0
  65. data/test/support/models/user.rb +96 -0
  66. data/test/support/read_model/querying.rb +150 -0
  67. data/test/support/read_models/comment_with_user_data.rb +27 -0
  68. data/test/support/read_models/set_data.rb +49 -0
  69. data/test/support/read_models/subquery_data.rb +41 -0
  70. data/test/support/read_models/user_with_area_data.rb +15 -0
  71. data/test/support/schema.rb +39 -0
  72. data/test/support/setup_test_db.rb +10 -0
  73. data/test/system/factory/model_factory_tests.rb +87 -0
  74. data/test/system/factory/model_stack_tests.rb +30 -0
  75. data/test/system/factory/record_factory_tests.rb +84 -0
  76. data/test/system/factory/record_stack_tests.rb +51 -0
  77. data/test/system/factory_tests.rb +32 -0
  78. data/test/system/read_model_tests.rb +199 -0
  79. data/test/system/with_model_tests.rb +275 -0
  80. data/test/unit/after_commit/fake_record_tests.rb +110 -0
  81. data/test/unit/after_commit/record_procs_methods_tests.rb +177 -0
  82. data/test/unit/after_commit/record_tests.rb +134 -0
  83. data/test/unit/after_commit_tests.rb +113 -0
  84. data/test/unit/factory/config_tests.rb +651 -0
  85. data/test/unit/factory/model_factory_tests.rb +473 -0
  86. data/test/unit/factory/model_stack_tests.rb +97 -0
  87. data/test/unit/factory/read_model_factory_tests.rb +195 -0
  88. data/test/unit/factory/record_factory_tests.rb +446 -0
  89. data/test/unit/factory/record_stack_tests.rb +549 -0
  90. data/test/unit/factory_tests.rb +213 -0
  91. data/test/unit/fake_query_tests.rb +137 -0
  92. data/test/unit/fake_record/associations_tests.rb +585 -0
  93. data/test/unit/fake_record/attributes_tests.rb +265 -0
  94. data/test/unit/fake_record/persistence_tests.rb +239 -0
  95. data/test/unit/fake_record_tests.rb +106 -0
  96. data/test/unit/json_field/fake_record_tests.rb +75 -0
  97. data/test/unit/json_field/record_tests.rb +80 -0
  98. data/test/unit/json_field_tests.rb +302 -0
  99. data/test/unit/model/associations_tests.rb +346 -0
  100. data/test/unit/model/configuration_tests.rb +92 -0
  101. data/test/unit/model/fields_tests.rb +278 -0
  102. data/test/unit/model/persistence_tests.rb +114 -0
  103. data/test/unit/model_tests.rb +137 -0
  104. data/test/unit/query_tests.rb +300 -0
  105. data/test/unit/read_model/data_tests.rb +56 -0
  106. data/test/unit/read_model/fields_tests.rb +416 -0
  107. data/test/unit/read_model/query_expression_tests.rb +381 -0
  108. data/test/unit/read_model/querying_tests.rb +613 -0
  109. data/test/unit/read_model/set_querying_tests.rb +149 -0
  110. data/test/unit/read_model/subquery_tests.rb +242 -0
  111. data/test/unit/read_model_tests.rb +187 -0
  112. data/test/unit/record_tests.rb +45 -0
  113. data/test/unit/test_helpers_tests.rb +431 -0
  114. data/test/unit/type_converter_tests.rb +207 -0
  115. metadata +285 -0
@@ -0,0 +1,149 @@
1
+ require 'assert'
2
+ require 'mr/read_model/set_querying'
3
+
4
+ require 'ardb/relation_spy'
5
+ require 'much-plugin'
6
+ require 'mr/fake_record'
7
+ require 'mr/read_model/query_expression'
8
+ require 'test/support/read_model/querying'
9
+
10
+ module MR::ReadModel::SetQuerying
11
+
12
+ class UnitTests < Assert::Context
13
+ include MR::ReadModel::Querying::TestHelpers
14
+
15
+ desc "MR::ReadModel::SetQuerying"
16
+ setup do
17
+ @read_model_class = Class.new do
18
+ include MR::ReadModel::SetQuerying
19
+ end
20
+ end
21
+ subject{ @read_model_class }
22
+
23
+ should have_imeths :relation
24
+ should have_imeths :union, :union_all
25
+ should have_imeths :intersect, :intersect_all
26
+ should have_imeths :except, :except_all
27
+
28
+ should "use much-plugin" do
29
+ assert_includes MuchPlugin, MR::ReadModel::SetQuerying
30
+ end
31
+
32
+ should "mixin read model querying mixin" do
33
+ assert_includes MR::ReadModel::Querying, subject
34
+ end
35
+
36
+ should "return a set querying relation using `relation`" do
37
+ relation = subject.relation
38
+ assert_instance_of MR::ReadModel::SetQuerying::Relation, relation
39
+ assert_same relation, subject.relation
40
+ end
41
+
42
+ end
43
+
44
+ class WithFromRecordClassTests < UnitTests
45
+ setup do
46
+ @ar_relation_spy = Ardb::RelationSpy.new
47
+ Assert.stub(FakeTestRecord, :scoped){ @ar_relation_spy }
48
+ @read_model_class.from FakeTestRecord
49
+ @relation = @read_model_class.relation
50
+ end
51
+
52
+ should "add a union to the relation using `union`" do
53
+ union_proc = proc{ read_model FakeTestRecord }
54
+ subject.union(&union_proc)
55
+ assert_set_expression_added @relation, :union, union_proc
56
+ end
57
+
58
+ should "add a union all to the relation using `union_all`" do
59
+ union_all_proc = proc{ read_model FakeTestRecord }
60
+ subject.union_all(&union_all_proc)
61
+ assert_set_expression_added @relation, :union_all, union_all_proc
62
+ end
63
+
64
+ should "add a intersect to the relation using `intersect`" do
65
+ intersect_proc = proc{ read_model FakeTestRecord }
66
+ subject.intersect(&intersect_proc)
67
+ assert_set_expression_added @relation, :intersect, intersect_proc
68
+ end
69
+
70
+ should "add a intersect all to the relation using `intersect_all`" do
71
+ intersect_all_proc = proc{ read_model FakeTestRecord }
72
+ subject.intersect_all(&intersect_all_proc)
73
+ assert_set_expression_added @relation, :intersect_all, intersect_all_proc
74
+ end
75
+
76
+ should "add a except to the relation using `except`" do
77
+ except_proc = proc{ read_model FakeTestRecord }
78
+ subject.except(&except_proc)
79
+ assert_set_expression_added @relation, :except, except_proc
80
+ end
81
+
82
+ should "add a except all to the relation using `except_all`" do
83
+ except_all_proc = proc{ read_model FakeTestRecord }
84
+ subject.except_all(&except_all_proc)
85
+ assert_set_expression_added @relation, :except_all, except_all_proc
86
+ end
87
+
88
+ should "raise an argument error when any set method isn't provided a block" do
89
+ assert_raises(ArgumentError){ subject.union }
90
+ assert_raises(ArgumentError){ subject.union_all }
91
+ assert_raises(ArgumentError){ subject.intersect }
92
+ assert_raises(ArgumentError){ subject.intersect_all }
93
+ assert_raises(ArgumentError){ subject.except }
94
+ assert_raises(ArgumentError){ subject.except_all }
95
+ end
96
+
97
+ end
98
+
99
+ class RelationTests < UnitTests
100
+ desc "Relation"
101
+ setup do
102
+ @relation_class = Relation
103
+ @relation = @relation_class.new
104
+ end
105
+ subject{ @relation }
106
+
107
+ should have_readers :set_expressions
108
+ should have_imeths :build_sql
109
+
110
+ should "not have any set expressions by default" do
111
+ assert_equal [], subject.set_expressions
112
+ end
113
+
114
+ should "know how to build its sql" do
115
+ Factory.integer(3).times.each do
116
+ column = Factory.string
117
+
118
+ @relation.set_expressions << Factory.read_model_set_expression do
119
+ select{ |p| p ? p['column'] : column }
120
+ from FakeTestRecord
121
+ end
122
+ end
123
+
124
+ built_sql = Factory.text
125
+ relation_spy = Ardb::RelationSpy.new
126
+ Assert.stub(relation_spy, :to_sql){ built_sql }
127
+ Assert.stub(subject, :build_for_all){ relation_spy }
128
+
129
+ exp = @relation.set_expressions.inject(built_sql){ |s, e| e.combine_sql(s) }
130
+ assert_equal exp, subject.build_sql
131
+
132
+ params = { Factory.string => Factory.string }
133
+ exp = @relation.set_expressions.inject(built_sql) do |s, e|
134
+ e.combine_sql(s, params)
135
+ end
136
+ assert_equal exp, subject.build_sql(params)
137
+ end
138
+
139
+ end
140
+
141
+ class FakeTestRecord
142
+ include MR::FakeRecord
143
+
144
+ def self.scoped
145
+ Ardb::RelationSpy.new
146
+ end
147
+ end
148
+
149
+ end
@@ -0,0 +1,242 @@
1
+ require 'assert'
2
+ require 'mr/read_model/subquery'
3
+
4
+ require 'ardb/relation_spy'
5
+ require 'mr/fake_record'
6
+ require 'mr/read_model/set_querying'
7
+ require 'test/support/read_model/querying'
8
+
9
+ module MR::ReadModel
10
+
11
+ class UnitTests < Assert::Context
12
+ include Querying::TestHelpers
13
+ desc "MR::ReadModel"
14
+ setup do
15
+ @column = column = Factory.string
16
+ @subquery_block = proc do
17
+ read_model do
18
+ select column
19
+ from FakeTestRecord
20
+ end
21
+ end
22
+
23
+ @subquery_with_params_block = proc do
24
+ read_model do
25
+ select{ |params| params['column'] }
26
+ from FakeTestRecord
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ class SubqueryTests < UnitTests
34
+ desc "Subquery"
35
+ setup do
36
+ @subquery_class = Class.new{ include MR::ReadModel::Subquery }
37
+
38
+ @subquery = @subquery_class.new(&@subquery_block)
39
+ end
40
+ subject{ @subquery }
41
+
42
+ should have_readers :read_model_class
43
+ should have_imeths :read_model, :build_sql
44
+
45
+ should "know its read model class" do
46
+ read_model_class = subject.read_model_class
47
+ assert_includes MR::ReadModel, read_model_class
48
+ assert_includes MR::ReadModel::SetQuerying, read_model_class
49
+ relation_spy = read_model_class.relation
50
+ assert_static_expression_added relation_spy, :select, @column
51
+ end
52
+
53
+ should "build the subquery's SQL using `build_sql`" do
54
+ exp = "(#{subject.read_model_class.relation.build_for_all.to_sql})"
55
+ assert_equal exp, subject.build_sql
56
+
57
+ subquery = @subquery_class.new(&@subquery_with_params_block)
58
+ params = { 'column' => Factory.string }
59
+ exp = "(#{subquery.read_model_class.build_sql(params)})"
60
+ assert_equal exp, subquery.build_sql(params)
61
+ end
62
+
63
+ end
64
+
65
+ class AliasSubqueryTests < UnitTests
66
+ desc "AliasSubquery"
67
+ setup do
68
+ @subquery_class = Class.new{ include MR::ReadModel::AliasSubquery }
69
+ end
70
+ subject{ @subquery_class }
71
+
72
+ should "be a MR subquery" do
73
+ assert_includes MR::ReadModel::Subquery, subject
74
+ end
75
+
76
+ end
77
+
78
+ class AliasSubqueryInitTests < AliasSubqueryTests
79
+ desc "when init"
80
+ setup do
81
+ @subquery = @subquery_class.new(&@subquery_block)
82
+ end
83
+ subject{ @subquery }
84
+
85
+ should have_imeths :alias_sql, :as, :build_sql
86
+
87
+ should "know its default alias sql" do
88
+ assert_equal "", subject.alias_sql
89
+ end
90
+
91
+ should "allow changing its alias sql using `as`" do
92
+ alias_name = Factory.string
93
+ subject.as(alias_name)
94
+ assert_equal "AS #{alias_name}", subject.alias_sql
95
+ end
96
+
97
+ should "raise an argument error if passing a blank alias" do
98
+ assert_raises(ArgumentError){ subject.as(nil) }
99
+ assert_raises(ArgumentError){ subject.as('') }
100
+ assert_raises(ArgumentError){ subject.as(' ') }
101
+ end
102
+
103
+ should "build the subquery's SQL using `build_sql`" do
104
+ alias_name = Factory.string
105
+ subject.as(alias_name)
106
+ exp = "(#{subject.read_model_class.build_sql}) #{subject.alias_sql}"
107
+ assert_equal exp, subject.build_sql
108
+
109
+ subquery = @subquery_class.new(&@subquery_with_params_block)
110
+ subquery.as(alias_name)
111
+ params = { 'column' => Factory.string }
112
+ exp = "(#{subquery.read_model_class.build_sql(params)}) #{subquery.alias_sql}"
113
+ assert_equal exp, subquery.build_sql(params)
114
+ end
115
+
116
+ should "raise an invalid subquery error if an alias hasn't been set" do
117
+ assert_raises(InvalidSubqueryError){ subject.build_sql }
118
+ end
119
+
120
+ end
121
+
122
+ class FromSubqueryTests < UnitTests
123
+ desc "FromSubquery"
124
+ setup do
125
+ @subquery_class = MR::ReadModel::FromSubquery
126
+ end
127
+ subject{ @subquery_class }
128
+
129
+ should "be a MR alias subquery" do
130
+ assert_includes MR::ReadModel::AliasSubquery, subject
131
+ end
132
+
133
+ end
134
+
135
+ class FromSubqueryInitTests < FromSubqueryTests
136
+ desc "when init"
137
+ setup do
138
+ @subquery = @subquery_class.new(&@subquery_block)
139
+ end
140
+ subject{ @subquery }
141
+
142
+ should have_imeths :record_class
143
+
144
+ should "know its record class" do
145
+ assert_equal FakeTestRecord, subject.record_class
146
+
147
+ subquery_block = @subquery_block
148
+ subquery = @subquery_class.new do
149
+ read_model{ from_subquery(&subquery_block) }
150
+ end
151
+ assert_equal FakeTestRecord, subquery.record_class
152
+ end
153
+
154
+ end
155
+
156
+ class JoinSubqueryTests < UnitTests
157
+ desc "JoinSubquery"
158
+ setup do
159
+ @subquery_class = MR::ReadModel::JoinSubquery
160
+ end
161
+ subject{ @subquery_class }
162
+
163
+ should "be a MR alias subquery" do
164
+ assert_includes MR::ReadModel::AliasSubquery, subject
165
+ end
166
+
167
+ should "know its join sql constants" do
168
+ assert_equal 'JOIN', subject::DEFAULT_JOIN_SQL
169
+
170
+ exp = {
171
+ :inner => "INNER JOIN",
172
+ :left => "LEFT OUTER JOIN",
173
+ :right => "RIGHT OUTER JOIN",
174
+ :full => "FULL OUTER JOIN"
175
+ }
176
+ assert_equal exp, subject::JOIN_SQL
177
+ assert_equal subject::DEFAULT_JOIN_SQL, subject::JOIN_SQL[Factory.string]
178
+ end
179
+
180
+ end
181
+
182
+ class JoinSubqueryInitTests < JoinSubqueryTests
183
+ desc "when init"
184
+ setup do
185
+ @type = if Factory.boolean
186
+ @subquery_class::JOIN_SQL.keys.sample
187
+ else
188
+ Factory.string
189
+ end
190
+
191
+ @subquery = @subquery_class.new(@type, &@subquery_block)
192
+ end
193
+ subject{ @subquery }
194
+
195
+ should have_readers :join_sql
196
+ should have_imeths :conditions_sql, :on, :build_sql
197
+
198
+ should "know its join sql" do
199
+ assert_equal @subquery_class::JOIN_SQL[@type], subject.join_sql
200
+ end
201
+
202
+ should "know its default conditions sql" do
203
+ assert_equal "", subject.conditions_sql
204
+ end
205
+
206
+ should "allow changing its conditions sql using `on`" do
207
+ conditions = Factory.string
208
+ subject.on(conditions)
209
+ assert_equal "ON #{conditions}", subject.conditions_sql
210
+ end
211
+
212
+ should "build the subquery's SQL using `build_sql`" do
213
+ alias_name = Factory.string
214
+ subject.as(alias_name)
215
+ conditions = Factory.string
216
+ subject.on(conditions)
217
+ exp = "#{subject.join_sql} " \
218
+ "(#{subject.read_model_class.relation.build_for_all.to_sql}) " \
219
+ "#{subject.alias_sql} #{subject.conditions_sql}"
220
+ assert_equal exp, subject.build_sql
221
+
222
+ subquery = @subquery_class.new(@type, &@subquery_with_params_block)
223
+ subquery.as(alias_name)
224
+ subquery.on(conditions)
225
+ params = { 'column' => Factory.string }
226
+ exp = "#{subquery.join_sql} " \
227
+ "(#{subquery.read_model_class.build_sql(params)}) " \
228
+ "#{subquery.alias_sql} #{subquery.conditions_sql}"
229
+ assert_equal exp, subquery.build_sql(params)
230
+ end
231
+
232
+ end
233
+
234
+ class FakeTestRecord
235
+ include MR::FakeRecord
236
+
237
+ def self.scoped
238
+ Ardb::RelationSpy.new
239
+ end
240
+ end
241
+
242
+ end
@@ -0,0 +1,187 @@
1
+ require 'assert'
2
+ require 'mr/read_model'
3
+
4
+ require 'much-plugin'
5
+ require 'mr/read_model/data'
6
+ require 'mr/read_model/fields'
7
+ require 'mr/read_model/querying'
8
+
9
+ module MR::ReadModel
10
+
11
+ class UnitTests < Assert::Context
12
+ desc "MR::ReadModel"
13
+ setup do
14
+ @read_model_class = Class.new do
15
+ include MR::ReadModel
16
+ end
17
+ end
18
+ subject{ MR::ReadModel }
19
+
20
+ should have_imeths :add_select_for_field
21
+
22
+ should "use much-plugin" do
23
+ assert_includes MuchPlugin, MR::ReadModel
24
+ end
25
+
26
+ should "know how to add a select for a field with column SQL" do
27
+ field_name = Factory.string
28
+ column_sql = Factory.string
29
+ MR::ReadModel.add_select_for_field(@read_model_class, field_name, column_sql)
30
+
31
+ assert_equal 1, @read_model_class.relation.query_expressions.size
32
+ expression = @read_model_class.relation.query_expressions.first
33
+ assert_equal :select, expression.type
34
+ exp = "#{column_sql} AS #{field_name}"
35
+ assert_equal exp, expression.args.first
36
+ end
37
+
38
+ should "know how to add a select for a field with a column SQL block" do
39
+ field_name = Factory.string
40
+ MR::ReadModel.add_select_for_field(@read_model_class, field_name){ |sql| sql }
41
+
42
+ assert_equal 1, @read_model_class.relation.query_expressions.size
43
+ expression = @read_model_class.relation.query_expressions.first
44
+ assert_equal :select, expression.type
45
+
46
+ column_sql = Factory.string
47
+ exp = "#{column_sql} AS #{field_name}"
48
+ assert_equal exp, expression.block.call(column_sql)
49
+ end
50
+
51
+ end
52
+
53
+ class MixinTests < UnitTests
54
+ desc "mixed in"
55
+ setup do
56
+ @struct_class = Class.new{ include MR::ReadModelStruct }
57
+
58
+ @add_select_for_field_called_with = nil
59
+ Assert.stub(MR::ReadModel, :add_select_for_field) do |*args, &block|
60
+ @add_select_for_field_called_with = args + [block]
61
+ Assert.stub_send(MR::ReadModel, :add_select_for_field, *args, &block)
62
+ end
63
+ end
64
+ subject{ @read_model_class }
65
+
66
+ should have_imeths :field, :json_struct_list, :json_struct_obj
67
+
68
+ should "use the mr read model struct mixin" do
69
+ assert_includes MR::ReadModelStruct, subject
70
+ end
71
+
72
+ should "use the mr read model querying mixin" do
73
+ assert_includes MR::ReadModel::Querying, subject
74
+ end
75
+
76
+ should "know how to add fields with a select" do
77
+ field_name = Factory.string
78
+ column_sql = Factory.string
79
+ column_sql_block = proc{ |sql| sql }
80
+ subject.field(field_name, :string, column_sql, &column_sql_block)
81
+
82
+ field = subject.fields.find(field_name)
83
+ assert_instance_of MR::ReadModel::Field, field
84
+ assert_equal :string, field.type
85
+ assert_respond_to field.name, subject.new
86
+
87
+ exp = [subject, field_name, column_sql, column_sql_block]
88
+ assert_equal exp, @add_select_for_field_called_with
89
+ end
90
+
91
+ should "know how to add json struct lists with a select" do
92
+ field_name = Factory.string
93
+ column_sql = Factory.string
94
+ column_sql_block = proc{ |sql| sql }
95
+ subject.json_struct_list(field_name, @struct_class, column_sql, &column_sql_block)
96
+
97
+ field = subject.json_struct_lists.find{ |f| f.name == field_name }
98
+ assert_instance_of MR::ReadModel::JsonStructListField, field
99
+ assert_equal @struct_class, field.struct_class
100
+ assert_respond_to field.name, subject.new
101
+
102
+ exp = [subject, field_name, column_sql, column_sql_block]
103
+ assert_equal exp, @add_select_for_field_called_with
104
+ end
105
+
106
+ should "know how to add json struct objs with a select" do
107
+ field_name = Factory.string
108
+ column_sql = Factory.string
109
+ column_sql_block = proc{ |sql| sql }
110
+ subject.json_struct_obj(field_name, @struct_class, column_sql, &column_sql_block)
111
+
112
+ field = subject.json_struct_objs.find{ |f| f.name == field_name }
113
+ assert_instance_of MR::ReadModel::JsonStructObjField, field
114
+ assert_equal @struct_class, field.struct_class
115
+ assert_respond_to field.name, subject.new
116
+
117
+ exp = [subject, field_name, column_sql, column_sql_block]
118
+ assert_equal exp, @add_select_for_field_called_with
119
+ end
120
+
121
+ end
122
+
123
+ class ReadModelStructTests < Assert::Context
124
+ desc "MR::ReadModelStruct"
125
+ setup do
126
+ @read_model_struct_class = Class.new do
127
+ include MR::ReadModelStruct
128
+ end
129
+ end
130
+ subject{ @read_model_struct_class }
131
+
132
+ should "use much-plugin" do
133
+ assert_includes MuchPlugin, MR::ReadModelStruct
134
+ end
135
+
136
+ should "use the mr read model data mixin" do
137
+ assert_includes MR::ReadModel::Data, subject
138
+ end
139
+
140
+ should "use the mr read model fields mixin" do
141
+ assert_includes MR::ReadModel::Fields, subject
142
+ end
143
+
144
+ end
145
+
146
+ class ReadModelStructInitTests < ReadModelStructTests
147
+ desc "when init"
148
+ setup do
149
+ @read_model_struct_class.class_eval do
150
+ field :name, :string
151
+ end
152
+
153
+ @data = { 'name' => Factory.string }
154
+ @read_model = @read_model_struct_class.new(@data)
155
+ end
156
+ subject{ @read_model }
157
+
158
+ should "set its data" do
159
+ assert_equal @data['name'], subject.name
160
+ end
161
+
162
+ should "not error when initialized without data" do
163
+ read_model_struct = @read_model_struct_class.new
164
+ assert_nil read_model_struct.name
165
+ end
166
+
167
+ should "be comparable" do
168
+ matching_struct = @read_model_struct_class.new(@data)
169
+ assert_equal matching_struct, subject
170
+
171
+ data = Factory.boolean ? { 'name' => Factory.string } : {}
172
+ not_matching_struct = @read_model_struct_class.new(data)
173
+ assert_not_equal not_matching_struct, subject
174
+ end
175
+
176
+ should "know its inspect" do
177
+ object_hex = (subject.object_id << 1).to_s(16)
178
+ values_inspect = @read_model_struct_class.fields.map do |field|
179
+ "#{field.ivar_name}=#{field.read(@data).inspect}"
180
+ end.join(' ')
181
+ exp = "#<#{@read_model_struct_class}:0x#{object_hex} #{values_inspect}>"
182
+ assert_equal exp, subject.inspect
183
+ end
184
+
185
+ end
186
+
187
+ end