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,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