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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +13 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/bench/all.rb +4 -0
- data/bench/factory.rb +68 -0
- data/bench/fake_record.rb +174 -0
- data/bench/model.rb +201 -0
- data/bench/read_model.rb +191 -0
- data/bench/results/factory.txt +21 -0
- data/bench/results/fake_record.txt +37 -0
- data/bench/results/model.txt +44 -0
- data/bench/results/read_model.txt +46 -0
- data/bench/setup.rb +132 -0
- data/lib/mr.rb +11 -0
- data/lib/mr/after_commit.rb +49 -0
- data/lib/mr/after_commit/fake_record.rb +39 -0
- data/lib/mr/after_commit/record.rb +48 -0
- data/lib/mr/after_commit/record_procs_methods.rb +82 -0
- data/lib/mr/factory.rb +82 -0
- data/lib/mr/factory/config.rb +240 -0
- data/lib/mr/factory/model_factory.rb +103 -0
- data/lib/mr/factory/model_stack.rb +28 -0
- data/lib/mr/factory/read_model_factory.rb +104 -0
- data/lib/mr/factory/record_factory.rb +130 -0
- data/lib/mr/factory/record_stack.rb +219 -0
- data/lib/mr/fake_query.rb +53 -0
- data/lib/mr/fake_record.rb +58 -0
- data/lib/mr/fake_record/associations.rb +257 -0
- data/lib/mr/fake_record/attributes.rb +168 -0
- data/lib/mr/fake_record/persistence.rb +116 -0
- data/lib/mr/json_field.rb +180 -0
- data/lib/mr/json_field/fake_record.rb +31 -0
- data/lib/mr/json_field/record.rb +38 -0
- data/lib/mr/model.rb +67 -0
- data/lib/mr/model/associations.rb +161 -0
- data/lib/mr/model/configuration.rb +67 -0
- data/lib/mr/model/fields.rb +177 -0
- data/lib/mr/model/persistence.rb +79 -0
- data/lib/mr/query.rb +126 -0
- data/lib/mr/read_model.rb +83 -0
- data/lib/mr/read_model/data.rb +38 -0
- data/lib/mr/read_model/fields.rb +218 -0
- data/lib/mr/read_model/query_expression.rb +188 -0
- data/lib/mr/read_model/querying.rb +214 -0
- data/lib/mr/read_model/set_querying.rb +82 -0
- data/lib/mr/read_model/subquery.rb +98 -0
- data/lib/mr/record.rb +35 -0
- data/lib/mr/test_helpers.rb +229 -0
- data/lib/mr/type_converter.rb +85 -0
- data/lib/mr/version.rb +3 -0
- data/log/.gitkeep +0 -0
- data/mr.gemspec +29 -0
- data/test/helper.rb +21 -0
- data/test/support/db.rb +10 -0
- data/test/support/factory.rb +13 -0
- data/test/support/factory/area.rb +6 -0
- data/test/support/factory/comment.rb +14 -0
- data/test/support/factory/image.rb +6 -0
- data/test/support/factory/user.rb +6 -0
- data/test/support/models/area.rb +58 -0
- data/test/support/models/comment.rb +60 -0
- data/test/support/models/image.rb +53 -0
- data/test/support/models/user.rb +96 -0
- data/test/support/read_model/querying.rb +150 -0
- data/test/support/read_models/comment_with_user_data.rb +27 -0
- data/test/support/read_models/set_data.rb +49 -0
- data/test/support/read_models/subquery_data.rb +41 -0
- data/test/support/read_models/user_with_area_data.rb +15 -0
- data/test/support/schema.rb +39 -0
- data/test/support/setup_test_db.rb +10 -0
- data/test/system/factory/model_factory_tests.rb +87 -0
- data/test/system/factory/model_stack_tests.rb +30 -0
- data/test/system/factory/record_factory_tests.rb +84 -0
- data/test/system/factory/record_stack_tests.rb +51 -0
- data/test/system/factory_tests.rb +32 -0
- data/test/system/read_model_tests.rb +199 -0
- data/test/system/with_model_tests.rb +275 -0
- data/test/unit/after_commit/fake_record_tests.rb +110 -0
- data/test/unit/after_commit/record_procs_methods_tests.rb +177 -0
- data/test/unit/after_commit/record_tests.rb +134 -0
- data/test/unit/after_commit_tests.rb +113 -0
- data/test/unit/factory/config_tests.rb +651 -0
- data/test/unit/factory/model_factory_tests.rb +473 -0
- data/test/unit/factory/model_stack_tests.rb +97 -0
- data/test/unit/factory/read_model_factory_tests.rb +195 -0
- data/test/unit/factory/record_factory_tests.rb +446 -0
- data/test/unit/factory/record_stack_tests.rb +549 -0
- data/test/unit/factory_tests.rb +213 -0
- data/test/unit/fake_query_tests.rb +137 -0
- data/test/unit/fake_record/associations_tests.rb +585 -0
- data/test/unit/fake_record/attributes_tests.rb +265 -0
- data/test/unit/fake_record/persistence_tests.rb +239 -0
- data/test/unit/fake_record_tests.rb +106 -0
- data/test/unit/json_field/fake_record_tests.rb +75 -0
- data/test/unit/json_field/record_tests.rb +80 -0
- data/test/unit/json_field_tests.rb +302 -0
- data/test/unit/model/associations_tests.rb +346 -0
- data/test/unit/model/configuration_tests.rb +92 -0
- data/test/unit/model/fields_tests.rb +278 -0
- data/test/unit/model/persistence_tests.rb +114 -0
- data/test/unit/model_tests.rb +137 -0
- data/test/unit/query_tests.rb +300 -0
- data/test/unit/read_model/data_tests.rb +56 -0
- data/test/unit/read_model/fields_tests.rb +416 -0
- data/test/unit/read_model/query_expression_tests.rb +381 -0
- data/test/unit/read_model/querying_tests.rb +613 -0
- data/test/unit/read_model/set_querying_tests.rb +149 -0
- data/test/unit/read_model/subquery_tests.rb +242 -0
- data/test/unit/read_model_tests.rb +187 -0
- data/test/unit/record_tests.rb +45 -0
- data/test/unit/test_helpers_tests.rb +431 -0
- data/test/unit/type_converter_tests.rb +207 -0
- 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
|