mr 0.35.2

Sign up to get free protection for your applications and to get access to all the features.
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