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,150 @@
1
+ require 'mr/read_model/query_expression'
2
+
3
+ module MR; end
4
+ module MR::ReadModel; end
5
+ module MR::ReadModel::Querying
6
+
7
+ module TestHelpers
8
+ module_function
9
+
10
+ def assert_static_expression_added(relation, type, *args)
11
+ with_backtrace(caller) do
12
+ assert_equal 1, relation.query_expressions.size
13
+ expression = relation.query_expressions.first
14
+ assert_static_expression expression, type, args
15
+ end
16
+ end
17
+
18
+ def assert_dynamic_expression_added(relation, type, block)
19
+ with_backtrace(caller) do
20
+ assert_equal 1, relation.query_expressions.size
21
+ expression = relation.query_expressions.first
22
+ assert_dynamic_expression expression, type, block
23
+ end
24
+ end
25
+
26
+ def assert_static_merge_expression_added(relation, type, *args)
27
+ with_backtrace(caller) do
28
+ assert_equal 1, relation.query_expressions.size
29
+ expression = relation.query_expressions.first
30
+ assert_static_merge_expression expression, type, args
31
+ end
32
+ end
33
+
34
+ def assert_dynamic_merge_expression_added(relation, type, block)
35
+ with_backtrace(caller) do
36
+ assert_equal 1, relation.query_expressions.size
37
+ expression = relation.query_expressions.first
38
+ assert_dynamic_merge_expression expression, type, block
39
+ end
40
+ end
41
+
42
+ def assert_inner_join_subquery_added(relation, block)
43
+ with_backtrace(caller) do
44
+ assert_join_subquery_added(relation, :inner, block)
45
+ end
46
+ end
47
+
48
+ def assert_left_outer_join_subquery_added(relation, block)
49
+ with_backtrace(caller) do
50
+ assert_join_subquery_added(relation, :left, block)
51
+ end
52
+ end
53
+
54
+ def assert_right_outer_join_subquery_added(relation, block)
55
+ with_backtrace(caller) do
56
+ assert_join_subquery_added(relation, :right, block)
57
+ end
58
+ end
59
+
60
+ def assert_full_outer_join_subquery_added(relation, block)
61
+ with_backtrace(caller) do
62
+ assert_join_subquery_added(relation, :full, block)
63
+ end
64
+ end
65
+
66
+ def assert_join_subquery_added(relation, type, block)
67
+ assert_equal 1, relation.query_expressions.size
68
+ expression = relation.query_expressions.first
69
+ expected_class = MR::ReadModel::SubqueryExpression
70
+ assert_instance_of expected_class, expression
71
+ assert_join_subquery_expression expression, type, block
72
+ end
73
+
74
+ def assert_set_expression_added(relation, operator, block)
75
+ with_backtrace(caller) do
76
+ assert_equal 1, relation.set_expressions.size
77
+ expression = relation.set_expressions.first
78
+ expression_class = MR::ReadModel::SetExpression
79
+ assert_instance_of expression_class, expression
80
+ exp = expression_class::OPERATOR_SQL[operator]
81
+ assert_equal exp, expression.operator_sql
82
+ assert_equal block, expression.read_model_block
83
+ end
84
+ end
85
+
86
+ def assert_static_expression(expression, type, args)
87
+ expected_class = MR::ReadModel::StaticQueryExpression
88
+ assert_instance_of expected_class, expression
89
+ assert_equal type, expression.type
90
+ assert_equal [*args], expression.args
91
+ end
92
+
93
+ def assert_dynamic_expression(expression, type, block)
94
+ expected_class = MR::ReadModel::DynamicQueryExpression
95
+ assert_instance_of expected_class, expression
96
+ assert_equal type, expression.type
97
+ assert_equal block, expression.block
98
+ end
99
+
100
+ def assert_merge_expression(expression, type)
101
+ expected_class = MR::ReadModel::MergeQueryExpression
102
+ assert_instance_of expected_class, expression
103
+ assert_equal expression.type, type
104
+ end
105
+
106
+ def assert_static_merge_expression(expression, type, args)
107
+ assert_merge_expression expression, type
108
+ assert_static_expression expression.query_expression, :merge, args
109
+ end
110
+
111
+ def assert_dynamic_merge_expression(expression, type, block)
112
+ assert_merge_expression expression, type
113
+ assert_dynamic_expression expression.query_expression, :merge, block
114
+ end
115
+
116
+ def assert_subquery_expression(expression, type)
117
+ expected_class = MR::ReadModel::SubqueryExpression
118
+ assert_kind_of expected_class, expression
119
+ assert_equal type, expression.subquery_type
120
+ end
121
+
122
+ def assert_join_subquery_expression(expression, type, block)
123
+ assert_subquery_expression expression, :joins
124
+ assert_includes type, expression.subquery_args
125
+ assert_equal block, expression.subquery_block
126
+ end
127
+
128
+ def assert_expression_applied(relation_spy, type, *args)
129
+ with_backtrace(caller) do
130
+ message = "couldn't find an applied #{type} expression " \
131
+ "with #{args.inspect} args"
132
+ assert_not_nil find_applied(relation_spy, type, args), message
133
+ end
134
+ end
135
+
136
+ def assert_not_expression_applied(relation_spy, type, *args)
137
+ with_backtrace(caller) do
138
+ message = "found an applied #{type} expression " \
139
+ "with #{args.inspect} args"
140
+ assert_nil find_applied(relation_spy, type, args), message
141
+ end
142
+ end
143
+
144
+ def find_applied(relation_spy, type, args)
145
+ relation_spy.applied.find{ |e| e.type == type && e.args == args }
146
+ end
147
+
148
+ end
149
+
150
+ end
@@ -0,0 +1,27 @@
1
+ require 'mr'
2
+ require 'test/support/models/comment'
3
+ require 'test/support/models/user'
4
+
5
+ class CommentWithUserData
6
+ include MR::ReadModel
7
+
8
+ field :comment_id, :primary_key, 'comments.id'
9
+ field :comment_created_at, :datetime, 'comments.created_at'
10
+ field :user_name, :string, 'users.name'
11
+ field :user_number, :integer, 'users.number'
12
+ field :user_salary, :decimal, 'users.salary'
13
+ field :user_started_on, :date, 'users.started_on'
14
+ field :user_dob, :timestamp, 'users.dob'
15
+ field :image_data, :binary, 'images.data'
16
+ field :area_active, :boolean, 'areas.active'
17
+ field :area_meeting_time, :time, 'areas.meeting_time'
18
+ field :area_description, :text, 'areas.description'
19
+ field :area_percentage, :float, 'areas.percentage'
20
+ from CommentRecord
21
+ joins "INNER JOIN users ON " \
22
+ "'#{UserRecord}' = comments.parent_type AND " \
23
+ "users.id = comments.parent_id " \
24
+ "INNER JOIN images ON images.user_id = users.id " \
25
+ "INNER JOIN areas ON areas.id = users.area_id"
26
+
27
+ end
@@ -0,0 +1,49 @@
1
+ require 'mr'
2
+ require 'test/support/models/area'
3
+
4
+ class SetData
5
+ include MR::ReadModel
6
+
7
+ field :id, :primary_key, 'filtered_areas.id'
8
+ field :name, :string, 'filtered_areas.name'
9
+
10
+ from_subquery do
11
+ read_model do
12
+
13
+ select 'areas.id, areas.name'
14
+ from AreaRecord
15
+ where do |params|
16
+ AreaRecord.where("areas.name LIKE ?", "#{params[:match_start]}%")
17
+ end
18
+
19
+ union do
20
+ select 'areas.id, areas.name'
21
+ from AreaRecord
22
+ where do |params|
23
+ AreaRecord.where("areas.name LIKE ?", "#{params[:other_match_start]}%")
24
+ end
25
+ end
26
+
27
+ intersect do
28
+ select 'areas.id, areas.name'
29
+ from AreaRecord
30
+ where do |params|
31
+ AreaRecord.where("areas.name LIKE ?", "%#{params[:match_end]}")
32
+ end
33
+ end
34
+
35
+ except do
36
+ select 'areas.id, areas.name'
37
+ from AreaRecord
38
+ where do |params|
39
+ AreaRecord.where("areas.name LIKE ?", "%#{params[:non_match]}%")
40
+ end
41
+ end
42
+
43
+ end
44
+ as 'filtered_areas'
45
+ end
46
+
47
+ find_attr 'filtered_areas.id'
48
+
49
+ end
@@ -0,0 +1,41 @@
1
+ require 'mr'
2
+ require 'test/support/models/area'
3
+ require 'test/support/models/comment'
4
+ require 'test/support/models/user'
5
+
6
+ class SubqueryData
7
+ include MR::ReadModel
8
+
9
+ field :area_id, :primary_key, 'my_areas.id'
10
+ field :user_id, :primary_key, 'my_users.id'
11
+ field :comment_id, :primary_key, 'my_comments.id'
12
+
13
+ from_subquery do
14
+ read_model do
15
+ select '*'
16
+ from AreaRecord
17
+ end
18
+ as 'my_areas'
19
+ end
20
+
21
+ inner_join_subquery do
22
+ read_model do
23
+ from UserRecord
24
+ where{ |args| UserRecord.where(:started_on => args[:started_on]) }
25
+ end
26
+ as 'my_users'
27
+ on 'my_users.area_id = my_areas.id'
28
+ end
29
+ left_join_subquery do
30
+ read_model do
31
+ from CommentRecord
32
+ where CommentRecord.where(:parent_type => UserRecord.to_s)
33
+ end
34
+ as 'my_comments'
35
+ on "my_comments.parent_type = '#{UserRecord}' AND " \
36
+ "my_comments.parent_id = my_users.id"
37
+ end
38
+
39
+ find_attr 'my_areas.id'
40
+
41
+ end
@@ -0,0 +1,15 @@
1
+ require 'mr'
2
+ require 'test/support/models/user'
3
+
4
+ class UserWithAreaData
5
+ include MR::ReadModel
6
+
7
+ field :user_id, :primary_key, 'users.id'
8
+ field :user_name, :string, 'users.name'
9
+ field :area_id, :primary_key, 'areas.id'
10
+ field :area_name, :string, 'areas.name'
11
+ from UserRecord
12
+ joins :area
13
+ where{ |area_id| UserRecord.where("areas.id = ?", area_id) }
14
+
15
+ end
@@ -0,0 +1,39 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+
3
+ create_table :areas do |t|
4
+ t.string :name
5
+ t.boolean :active
6
+ t.float :ratio
7
+ t.text :description
8
+ t.float :percentage
9
+ t.time :meeting_time
10
+ end
11
+
12
+ create_table :users do |t|
13
+ t.string :name
14
+ t.integer :number
15
+ t.decimal :salary
16
+ t.date :started_on
17
+ t.timestamp :dob
18
+ t.integer :area_id, :null => false
19
+ t.integer :benchmark_area_id
20
+ end
21
+
22
+ create_table :images do |t|
23
+ t.string :file_path
24
+ t.binary :data
25
+ t.integer :user_id, :null => false
26
+ t.integer :benchmark_user_id
27
+ end
28
+
29
+ create_table :comments do |t|
30
+ t.text :body
31
+ t.string :parent_type, :null => false
32
+ t.integer :parent_id, :null => false
33
+ t.datetime :created_at
34
+ t.integer :created_by_id
35
+ t.string :benchmark_parent_type
36
+ t.integer :benchmark_parent_id
37
+ end
38
+
39
+ end
@@ -0,0 +1,10 @@
1
+ require 'ardb'
2
+ ENV['ARDB_DB_FILE'] = 'test/support/db'
3
+ Ardb.init
4
+
5
+ require 'ardb/test_helpers'
6
+ Ardb::TestHelpers.reset_db
7
+
8
+ require 'ardb/db_tests'
9
+ class DbTests < Ardb::DbTests
10
+ end
@@ -0,0 +1,87 @@
1
+ require 'assert'
2
+ require 'mr/factory/model_factory'
3
+
4
+ require 'mr/test_helpers'
5
+ require 'test/support/setup_test_db'
6
+ require 'test/support/models/area'
7
+ require 'test/support/models/user'
8
+
9
+ class MR::Factory::ModelFactory
10
+
11
+ class SystemTests < DbTests
12
+ include MR::TestHelpers
13
+
14
+ desc "MR::Factory::Model"
15
+ setup do
16
+ @factory_class = MR::Factory::ModelFactory
17
+ end
18
+
19
+ end
20
+
21
+ class BuildingRealModelTests < SystemTests
22
+ setup do
23
+ @factory = @factory_class.new(User, UserRecord)
24
+ end
25
+ subject{ @factory }
26
+
27
+ should "build a model with it's fields set using `model`" do
28
+ user = subject.model
29
+ assert_instance_of User, user
30
+ assert_instance_of UserRecord, user.record
31
+ assert_true user.new?
32
+ assert_kind_of String, user.name
33
+ assert_kind_of Integer, user.number
34
+ assert_kind_of Date, user.started_on
35
+ assert_kind_of Time, user.dob
36
+ assert_true user.salary.kind_of?(Float) || user.salary.kind_of?(BigDecimal)
37
+ assert_nil user.area_id
38
+ end
39
+
40
+ should "build a model and save it using `saved_model`" do
41
+ area_factory = @factory_class.new(Area, AreaRecord)
42
+ area = area_factory.model.tap(&:save)
43
+
44
+ user = subject.saved_model(:area => area)
45
+ assert_instance_of User, user
46
+ assert_false user.new?
47
+ end
48
+
49
+ should "build a model stack using `stack`" do
50
+ assert_instance_of MR::Factory::ModelStack, subject.stack
51
+ end
52
+
53
+ end
54
+
55
+ class BuildingFakeModelTests < SystemTests
56
+ setup do
57
+ @factory = @factory_class.new(User, FakeUserRecord)
58
+ end
59
+ subject{ @factory }
60
+
61
+ should "build a model with it's fields set using `model`" do
62
+ user = subject.model
63
+ assert_instance_of User, user
64
+ assert_instance_of FakeUserRecord, user.record
65
+ assert_true user.new?
66
+ assert_kind_of String, user.name
67
+ assert_kind_of Integer, user.number
68
+ assert_kind_of Date, user.started_on
69
+ assert_kind_of Time, user.dob
70
+ assert_true user.salary.kind_of?(Float) || user.salary.kind_of?(BigDecimal)
71
+ assert_nil user.area_id
72
+ end
73
+
74
+ should "build a model and save it using `saved_model`" do
75
+ user = subject.saved_model
76
+ assert_instance_of User, user
77
+ assert_false user.new?
78
+ assert_not_model_saved user
79
+ end
80
+
81
+ should "build a model stack for an instance using `stack`" do
82
+ assert_instance_of MR::Factory::ModelStack, subject.stack
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,30 @@
1
+ require 'assert'
2
+ require 'mr/factory/model_stack'
3
+
4
+ require 'test/support/setup_test_db'
5
+ require 'test/support/models/comment'
6
+
7
+ class MR::Factory::ModelStack
8
+
9
+ class SystemTests < DbTests
10
+ desc "MR::Factory::ModelStack"
11
+ setup do
12
+ @comment = Comment.new(:parent_type => 'UserRecord')
13
+ @factory_config = MR::Factory::RecordFactory::Config.new(@comment.class)
14
+
15
+ @model_stack = MR::Factory::ModelStack.new(@comment, @factory_config)
16
+ end
17
+ subject{ @model_stack }
18
+
19
+ should "build an instance of the model with all belongs to associations set" do
20
+ assert_instance_of Comment, @comment
21
+ assert_true @comment.new?
22
+ assert_instance_of User, @comment.parent
23
+ assert_true @comment.parent.new?
24
+ assert_instance_of Area, @comment.parent.area
25
+ assert_true @comment.parent.area.new?
26
+ end
27
+
28
+ end
29
+
30
+ end