babik 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +16 -0
  3. data/README.md +718 -0
  4. data/Rakefile +18 -0
  5. data/lib/babik.rb +122 -0
  6. data/lib/babik/database.rb +16 -0
  7. data/lib/babik/queryset.rb +154 -0
  8. data/lib/babik/queryset/components/aggregation.rb +172 -0
  9. data/lib/babik/queryset/components/limit.rb +22 -0
  10. data/lib/babik/queryset/components/order.rb +161 -0
  11. data/lib/babik/queryset/components/projection.rb +118 -0
  12. data/lib/babik/queryset/components/select_related.rb +78 -0
  13. data/lib/babik/queryset/components/sql_renderer.rb +99 -0
  14. data/lib/babik/queryset/components/where.rb +43 -0
  15. data/lib/babik/queryset/lib/association/foreign_association_chain.rb +97 -0
  16. data/lib/babik/queryset/lib/association/select_related_association_chain.rb +32 -0
  17. data/lib/babik/queryset/lib/condition.rb +103 -0
  18. data/lib/babik/queryset/lib/field.rb +34 -0
  19. data/lib/babik/queryset/lib/join/association_joiner.rb +39 -0
  20. data/lib/babik/queryset/lib/join/join.rb +86 -0
  21. data/lib/babik/queryset/lib/selection/config.rb +19 -0
  22. data/lib/babik/queryset/lib/selection/foreign_selection.rb +39 -0
  23. data/lib/babik/queryset/lib/selection/local_selection.rb +40 -0
  24. data/lib/babik/queryset/lib/selection/operation/base.rb +126 -0
  25. data/lib/babik/queryset/lib/selection/operation/date.rb +178 -0
  26. data/lib/babik/queryset/lib/selection/operation/operations.rb +201 -0
  27. data/lib/babik/queryset/lib/selection/operation/regex.rb +58 -0
  28. data/lib/babik/queryset/lib/selection/path/foreign_path.rb +50 -0
  29. data/lib/babik/queryset/lib/selection/path/local_path.rb +44 -0
  30. data/lib/babik/queryset/lib/selection/path/path.rb +23 -0
  31. data/lib/babik/queryset/lib/selection/select_related_selection.rb +38 -0
  32. data/lib/babik/queryset/lib/selection/selection.rb +19 -0
  33. data/lib/babik/queryset/lib/update/assignment.rb +108 -0
  34. data/lib/babik/queryset/mixins/aggregatable.rb +17 -0
  35. data/lib/babik/queryset/mixins/bounded.rb +38 -0
  36. data/lib/babik/queryset/mixins/clonable.rb +52 -0
  37. data/lib/babik/queryset/mixins/countable.rb +44 -0
  38. data/lib/babik/queryset/mixins/deletable.rb +13 -0
  39. data/lib/babik/queryset/mixins/distinguishable.rb +27 -0
  40. data/lib/babik/queryset/mixins/filterable.rb +51 -0
  41. data/lib/babik/queryset/mixins/limitable.rb +88 -0
  42. data/lib/babik/queryset/mixins/lockable.rb +31 -0
  43. data/lib/babik/queryset/mixins/none.rb +16 -0
  44. data/lib/babik/queryset/mixins/projectable.rb +34 -0
  45. data/lib/babik/queryset/mixins/related_selector.rb +28 -0
  46. data/lib/babik/queryset/mixins/set_operations.rb +32 -0
  47. data/lib/babik/queryset/mixins/sortable.rb +49 -0
  48. data/lib/babik/queryset/mixins/sql_renderizable.rb +17 -0
  49. data/lib/babik/queryset/mixins/updatable.rb +14 -0
  50. data/lib/babik/queryset/templates/default/delete/main.sql.erb +14 -0
  51. data/lib/babik/queryset/templates/default/select/components/aggregation.sql.erb +5 -0
  52. data/lib/babik/queryset/templates/default/select/components/from.sql.erb +16 -0
  53. data/lib/babik/queryset/templates/default/select/components/from_set.sql.erb +3 -0
  54. data/lib/babik/queryset/templates/default/select/components/from_table.sql.erb +2 -0
  55. data/lib/babik/queryset/templates/default/select/components/limit.sql.erb +10 -0
  56. data/lib/babik/queryset/templates/default/select/components/order_by.sql.erb +9 -0
  57. data/lib/babik/queryset/templates/default/select/components/projection.sql.erb +7 -0
  58. data/lib/babik/queryset/templates/default/select/components/select_related.sql.erb +26 -0
  59. data/lib/babik/queryset/templates/default/select/components/where.sql.erb +39 -0
  60. data/lib/babik/queryset/templates/default/select/main.sql.erb +42 -0
  61. data/lib/babik/queryset/templates/default/update/main.sql.erb +15 -0
  62. data/lib/babik/queryset/templates/mssql/select/components/limit.sql.erb +8 -0
  63. data/lib/babik/queryset/templates/mssql/select/components/order_by.sql.erb +21 -0
  64. data/lib/babik/queryset/templates/mysql2/delete/main.sql.erb +15 -0
  65. data/lib/babik/queryset/templates/mysql2/update/main.sql.erb +18 -0
  66. data/lib/babik/queryset/templates/sqlite3/select/components/from_set.sql.erb +5 -0
  67. data/test/config/db/schema.rb +83 -0
  68. data/test/config/models/bad_post.rb +5 -0
  69. data/test/config/models/bad_tag.rb +5 -0
  70. data/test/config/models/category.rb +4 -0
  71. data/test/config/models/geozone.rb +6 -0
  72. data/test/config/models/group.rb +5 -0
  73. data/test/config/models/group_user.rb +5 -0
  74. data/test/config/models/post.rb +24 -0
  75. data/test/config/models/post_tag.rb +5 -0
  76. data/test/config/models/tag.rb +5 -0
  77. data/test/config/models/user.rb +6 -0
  78. data/test/delete/delete_test.rb +60 -0
  79. data/test/delete/foreign_conditions_delete_test.rb +57 -0
  80. data/test/delete/local_conditions_delete_test.rb +20 -0
  81. data/test/enable_coverage.rb +17 -0
  82. data/test/lib/selection/operation/log/test-queries.log +1 -0
  83. data/test/lib/selection/operation/test_date.rb +131 -0
  84. data/test/lib/selection/operation/test_regex.rb +55 -0
  85. data/test/other/clone_test.rb +129 -0
  86. data/test/other/escape_test.rb +21 -0
  87. data/test/other/inverse_of_required_test.rb +33 -0
  88. data/test/select/aggregate_test.rb +151 -0
  89. data/test/select/bounds_test.rb +46 -0
  90. data/test/select/count_test.rb +147 -0
  91. data/test/select/distinct_test.rb +38 -0
  92. data/test/select/exclude_test.rb +72 -0
  93. data/test/select/filter_from_object_test.rb +125 -0
  94. data/test/select/filter_test.rb +207 -0
  95. data/test/select/for_update_test.rb +19 -0
  96. data/test/select/foreign_selection_test.rb +60 -0
  97. data/test/select/get_test.rb +40 -0
  98. data/test/select/limit_test.rb +109 -0
  99. data/test/select/local_selection_test.rb +24 -0
  100. data/test/select/lookup_test.rb +208 -0
  101. data/test/select/none_test.rb +40 -0
  102. data/test/select/order_test.rb +165 -0
  103. data/test/select/project_test.rb +107 -0
  104. data/test/select/select_related_test.rb +124 -0
  105. data/test/select/subquery_test.rb +50 -0
  106. data/test/set_operations/basic_usage_test.rb +121 -0
  107. data/test/test_helper.rb +55 -0
  108. data/test/update/update_test.rb +93 -0
  109. metadata +278 -0
@@ -0,0 +1,5 @@
1
+
2
+ class PostTag < ActiveRecord::Base
3
+ belongs_to :post, inverse_of: :post_tags
4
+ belongs_to :tag, inverse_of: :post_tags
5
+ end
@@ -0,0 +1,5 @@
1
+
2
+ class Tag < ActiveRecord::Base
3
+ has_many :post_tags
4
+ has_many :posts, through: :post_tags, inverse_of: :tags
5
+ end
@@ -0,0 +1,6 @@
1
+
2
+ class User < ActiveRecord::Base
3
+ belongs_to :zone, foreign_key: 'zone_id', class_name: 'GeoZone', optional: true, inverse_of: :users
4
+ has_many :posts, foreign_key: 'author_id', class_name: 'Post', inverse_of: :author
5
+ has_many :groups, through: :group_users, inverse_of: :users
6
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../test_helper'
5
+
6
+ # Abstract class for Tests of delete method
7
+ class DeleteTest < Minitest::Test
8
+
9
+ def setup
10
+ war_tag = Tag.create!(name: 'war')
11
+ tribes_tag = Tag.create!(name: 'tribes')
12
+ gallic_tag = Tag.create!(name: 'gallic')
13
+ victory_tag = Tag.create!(name: 'victory')
14
+ campaign_tag = Tag.create!(name: 'campaign')
15
+ book_tag = Tag.create!(name: 'book')
16
+ last_book_tag = Tag.create!(name: 'last_book')
17
+
18
+ @caesar = User.create!(first_name: 'Julius', last_name: 'Caesar', email: 'backstabbed@example.com')
19
+ (1..7).each do |book_i|
20
+ post = Post.create!(title: "Commentarii de Bello Gallico #{book_i}", author: @caesar, stars: [book_i, 5].min)
21
+ post.add_tag(war_tag)
22
+ post.add_tag(gallic_tag)
23
+ post.add_tag(tribes_tag)
24
+ post.add_tag(victory_tag)
25
+ post.add_tag(book_tag)
26
+ post.add_tag(campaign_tag)
27
+ end
28
+
29
+ @aulus = User.create!(first_name: 'Aulus', last_name: 'Hirtius', email: 'aulushirtius@example.com')
30
+ last_post = Post.create!(title: 'Commentarii de Bello Gallico 8', author: @aulus)
31
+ last_post.add_tag(war_tag)
32
+ last_post.add_tag(book_tag)
33
+ last_post.add_tag(last_book_tag)
34
+ end
35
+
36
+ def teardown
37
+ Tag.destroy_all
38
+ Post.destroy_all
39
+ User.destroy_all
40
+ end
41
+
42
+ def test_delete_by_local_selection
43
+ User.objects.filter(first_name: 'Julius').delete
44
+ assert_nil User.objects.filter(first_name: 'Julius').first
45
+ assert_equal User.all.count, User.objects.count
46
+ end
47
+
48
+ def test_delete_by_foreign_selection
49
+ Post.objects.filter('author::first_name': 'Julius', title: 'Commentarii de Bello Gallico 2').delete
50
+ assert_nil Post.objects.filter('author::first_name': 'Julius', title: 'Commentarii de Bello Gallico 2').first
51
+ assert_equal 6, @caesar.objects(:posts).count
52
+ end
53
+
54
+ def test_delete_by_instance_foreign_selection
55
+ @caesar.objects(:posts).filter(title: 'Commentarii de Bello Gallico 2').delete
56
+ assert_nil @caesar.objects(:posts).filter(title: 'Commentarii de Bello Gallico 2').first
57
+ assert_equal 6, @caesar.objects(:posts).count
58
+ end
59
+
60
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../test_helper'
5
+ require_relative 'delete_test'
6
+
7
+ # Tests of delete with foreign conditions method
8
+ class ForeignConditionsDeleteTest < DeleteTest
9
+
10
+ def test_delete_from_model
11
+ Post.objects.filter('author::first_name': 'Aulus').delete
12
+ assert_equal 0, Post.objects.filter('author::first_name': 'Aulus').count
13
+ assert_equal false, Post.objects.filter('author::first_name': 'Aulus').exists?
14
+ assert_equal 0, @aulus.objects(:posts).count
15
+ assert_equal false, @aulus.objects(:posts).exists?
16
+ end
17
+
18
+ def test_delete_from_instance
19
+ @aulus.objects(:posts).delete
20
+ assert_equal 0, Post.objects.filter('author::first_name': 'Aulus').count
21
+ assert_equal false, Post.objects.filter('author::first_name': 'Aulus').exists?
22
+ assert_equal 0, @aulus.objects(:posts).count
23
+ assert_equal false, @aulus.objects(:posts).exists?
24
+ end
25
+
26
+ def test_delete_from_model_deep_conditions
27
+ Tag.objects.filter('posts::author::first_name': 'Aulus').delete
28
+ assert_equal 0, Tag.objects.filter('posts::author::first_name': 'Aulus').count
29
+ assert_equal false, Tag.objects.filter('posts::author::first_name': 'Aulus').exists?
30
+ assert_equal 0, @aulus.objects('posts::tags').count
31
+ assert_equal false, @aulus.objects('posts::tags').exists?
32
+ end
33
+
34
+ def test_delete_from_instance_deep_condition_not_matched
35
+ @aulus.objects('posts::tags').filter(name: 'not existing tag').delete
36
+ assert_equal 3, Tag.objects.filter('posts::author::first_name': 'Aulus').count
37
+ assert_equal true, Tag.objects.filter('posts::author::first_name': 'Aulus').exists?
38
+ assert_equal 3, @aulus.objects('posts::tags').count
39
+ assert_equal true, @aulus.objects('posts::tags').exists?
40
+ end
41
+
42
+ def test_delete_from_instance_deep_conditions
43
+ tag_to_delete = 'last_book'
44
+ @aulus.objects('posts::tags').filter(name: tag_to_delete).delete
45
+ assert_equal 2, Tag.objects.filter('posts::author::first_name': 'Aulus').count
46
+ assert_equal true, Tag.objects.filter('posts::author::first_name': 'Aulus').exists?
47
+ Tag.objects.filter('posts::author::first_name': 'Aulus').each do |aulus_tag|
48
+ refute_equal tag_to_delete, aulus_tag.name
49
+ end
50
+ assert_equal 2, @aulus.objects('posts::tags').count
51
+ assert_equal true, @aulus.objects('posts::tags').exists?
52
+ @aulus.objects('posts::tags').each do |aulus_tag|
53
+ refute_equal tag_to_delete, aulus_tag.name
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../test_helper'
5
+ require_relative 'delete_test'
6
+
7
+ # Tests of delete with local conditions method
8
+ class LocalConditionsDeleteTest < DeleteTest
9
+
10
+ def test_deletion_from_model
11
+ User.objects.filter(first_name: 'Aulus').delete
12
+ assert_operator 0, :<, User.objects.count
13
+ User.objects.each do |user|
14
+ refute_equal 'Aulus', user.first_name
15
+ end
16
+ assert_equal 0, User.objects.filter(first_name: 'Aulus').count
17
+ assert_equal false, User.objects.filter(first_name: 'Aulus').exists?
18
+ end
19
+
20
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+ require 'simplecov-console'
5
+
6
+ SimpleCov.formatter = SimpleCov.formatter = SimpleCov::Formatter::Console
7
+ SimpleCov.start do
8
+ add_filter '/doc/'
9
+ add_filter '/test/'
10
+ add_filter '/features/'
11
+ add_filter '/spec/'
12
+ add_filter '/autotest/'
13
+ add_group 'Binaries', '/bin/'
14
+ add_group 'Libraries', '/lib/'
15
+ add_group 'Extensions', '/ext/'
16
+ add_group 'Vendor Libraries', '/vendor/'
17
+ end
@@ -0,0 +1 @@
1
+ # Logfile created on 2018-08-03 20:29:14 +0200 by logger.rb/61378
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../../../../test/test_helper'
5
+
6
+ # Class for testing date lookups
7
+ class DateLookupTest < Minitest::Test
8
+
9
+ def test_abstract_date_operation
10
+ assert_raises NotImplementedError do
11
+ Babik::Selection::Operation::DateOperation.new('my_field', 'equal', 'my_value')
12
+ end
13
+ end
14
+
15
+ def test_year_date_operation
16
+ sql_by_db_adapter = {
17
+ mysql2: 'YEAR(#field)',
18
+ postgresql: 'EXTRACT(YEAR FROM #field)',
19
+ sqlite3: 'strftime(\'%Y\', #field)'
20
+ }
21
+ _test_date_operation('Year', sql_by_db_adapter)
22
+ end
23
+
24
+ def test_quarter_date_operation
25
+ sql_by_db_adapter = {
26
+ mysql2: 'QUARTER(#field)',
27
+ postgresql: 'EXTRACT(QUARTER FROM #field)',
28
+ sqlite3: '(CAST(strftime(\'%m\', #field) AS INTEGER) + 2) / 3'
29
+ }
30
+ _test_date_operation('Quarter', sql_by_db_adapter)
31
+ end
32
+
33
+ def test_month_date_operation
34
+ sql_by_db_adapter = {
35
+ mysql2: 'MONTH(#field)',
36
+ postgresql: 'EXTRACT(MONTH FROM #field)',
37
+ sqlite3: 'strftime(\'%m\', #field)'
38
+ }
39
+ _test_date_operation('Month', sql_by_db_adapter)
40
+ end
41
+
42
+ def test_day_date_operation
43
+ sql_by_db_adapter = {
44
+ mysql2: 'DAYOFMONTH(#field)',
45
+ postgresql: 'EXTRACT(DAY FROM #field)',
46
+ sqlite3: 'strftime(\'%d\', #field)'
47
+ }
48
+ _test_date_operation('Day', sql_by_db_adapter)
49
+ end
50
+
51
+ def test_weekday_date_operation
52
+ sql_by_db_adapter = {
53
+ mysql2: 'DAYOFWEEK(#field) - 1',
54
+ postgresql: 'EXTRACT(DOW FROM #field)',
55
+ sqlite3: 'strftime(\'%w\', #field)'
56
+ }
57
+ _test_date_operation('WeekDay', sql_by_db_adapter)
58
+ end
59
+
60
+ def test_week_date_operation
61
+ sql_by_db_adapter = {
62
+ mysql2: 'WEEK(#field, 3)',
63
+ postgresql: 'EXTRACT(WEEK FROM #field)',
64
+ sqlite3: '(strftime(\'%j\', date(#field, \'-3 days\', \'weekday 4\')) - 1) / 7 + 1'
65
+ }
66
+ _test_date_operation('Week', sql_by_db_adapter)
67
+ end
68
+
69
+ def test_hour_date_operation
70
+ sql_by_db_adapter = {
71
+ mysql2: 'HOUR(#field)',
72
+ postgresql: 'EXTRACT(HOUR FROM #field)',
73
+ sqlite3: 'CAST(strftime(\'%H\', #field) AS INTEGER)'
74
+ }
75
+ _test_date_operation('Hour', sql_by_db_adapter)
76
+ end
77
+
78
+ def test_minute_date_operation
79
+ sql_by_db_adapter = {
80
+ mysql2: 'MINUTE(#field)',
81
+ postgresql: 'EXTRACT(MINUTE FROM #field)',
82
+ sqlite3: 'CAST(strftime(\'%M\', #field) AS INTEGER)'
83
+ }
84
+ _test_date_operation('Minute', sql_by_db_adapter)
85
+ end
86
+
87
+ def test_second_date_operation
88
+ sql_by_db_adapter = {
89
+ mysql2: 'SECOND(#field)',
90
+ postgresql: 'FLOOR(EXTRACT(SECOND FROM #field))',
91
+ sqlite3: 'CAST(strftime(\'%S\', #field) AS INTEGER)'
92
+ }
93
+ _test_date_operation('Second', sql_by_db_adapter)
94
+ end
95
+
96
+ def test_time_date_operation
97
+ sql_by_db_adapter = {
98
+ mysql2: 'DATE_FORMAT(#field, \'%H:%i:%s\')',
99
+ postgresql: 'date_trunc(\'second\', #field::time)',
100
+ sqlite3: 'strftime(\'%H:%M:%S\', #field)'
101
+ }
102
+ _test_date_operation('Time', sql_by_db_adapter)
103
+ end
104
+
105
+ def _test_date_operation(date_operation_name, sql_by_adapter, unimplemented_db_adapters = %w[mssql, oracle])
106
+ date_operation_class = Object.const_get("Babik::Selection::Operation::#{date_operation_name.camelize}")
107
+ _test_date_operation_sql(date_operation_class, sql_by_adapter)
108
+ _test_date_operation_not_implemented(date_operation_class, unimplemented_db_adapters)
109
+ end
110
+
111
+ def _test_date_operation_sql(klass, date_operation_sql_by_db_adapter)
112
+ date_operation = klass.new('my_field', 'equal', 6)
113
+ date_operation_sql_by_db_adapter.each do |db_adapter, date_operation_sql|
114
+ date_operation.stub :db_engine, -> { db_adapter.to_s } do
115
+ assert_equal date_operation_sql, date_operation.sql_function
116
+ end
117
+ end
118
+ end
119
+
120
+ def _test_date_operation_not_implemented(klass, unimplemented_db_adapters)
121
+ date_operation = klass.new('my_field', 'equal', 6)
122
+ unimplemented_db_adapters.each do |unimplemented_db_adapter|
123
+ date_operation.stub :db_engine, -> { unimplemented_db_adapter.to_s } do
124
+ assert_raises NotImplementedError do
125
+ date_operation.sql_function
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../../../../test/test_helper'
5
+
6
+ # Class for testing regex lookups
7
+ class RegexLookupTest < Minitest::Test
8
+
9
+ def test_regex_operator
10
+ sql_by_db_adapter = {
11
+ mysql2: { operator: 'REGEXP', operation: 'my_field REGEXP \'my_value\'' },
12
+ postgresql: { operator: '~', operation: 'my_field ~ \'my_value\'' },
13
+ sqlite3: { operator: 'REGEXP', operation: 'my_field REGEXP \'my_value\'' }
14
+ }
15
+ _test_regex('Regex', sql_by_db_adapter)
16
+ end
17
+
18
+ def test_iregex_operator
19
+ sql_by_db_adapter = {
20
+ mysql2: { operator: 'REGEXP', operation: 'LOWER(my_field) REGEXP \'my_value\'' },
21
+ postgresql: { operator: '~*', operation: 'my_field ~* \'my_value\'' },
22
+ sqlite3: { operator: 'REGEXP', operation: 'my_field REGEXP \'(?i)my_value\'' }
23
+ }
24
+ _test_regex('IRegex', sql_by_db_adapter)
25
+ end
26
+
27
+ def _test_regex(regex_operation_name, sql_by_adapter, unimplemented_db_adapters = %w[mssql, oracle])
28
+ regex_class = Object.const_get("Babik::Selection::Operation::#{regex_operation_name.camelize}")
29
+ _test_regex_sql(regex_class, sql_by_adapter)
30
+ _test_regex_not_implemented(regex_class, unimplemented_db_adapters)
31
+ end
32
+
33
+ def _test_regex_sql(klass, sql_by_db_adapter)
34
+ sql_by_db_adapter.each do |db_adapter, sql|
35
+ Babik::Database.config[:adapter] = db_adapter.to_s
36
+ regex_operation = klass.new('my_field', 'my_value')
37
+ assert_equal db_adapter.to_s, regex_operation.db_engine
38
+ assert_equal sql[:operator], regex_operation.operator, "Failed on checking #{klass} operator on #{db_adapter}"
39
+ assert_equal sql[:operation], regex_operation.sql_operation, "Failed on checking #{klass} operation on #{db_adapter}"
40
+ end
41
+ end
42
+
43
+
44
+ def _test_regex_not_implemented(klass, unimplemented_db_adapters)
45
+ date_operation = klass.new('my_field', 'my_value')
46
+ unimplemented_db_adapters.each do |unimplemented_db_adapter|
47
+ date_operation.stub :db_engine, -> { unimplemented_db_adapter.to_s } do
48
+ assert_raises NotImplementedError do
49
+ date_operation.operator
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../test_helper'
5
+
6
+ # Class for Tests of clone method
7
+ class CloneTest < Minitest::Test
8
+
9
+ def test_filter
10
+ filter = { first_name: 'whatever1' }
11
+ exclusion = { last_name: 'whatever1' }
12
+
13
+ original = User.objects.filter(filter).exclude(exclusion)
14
+ copy = original.clone
15
+
16
+ refute_equal original.object_id, copy.object_id
17
+
18
+ assert_equal original._where.model, copy._where.model
19
+
20
+ refute_equal original._where.inclusion_filters.object_id, copy._where.inclusion_filters.object_id
21
+ refute_equal original._where.inclusion_filters[0].object_id, copy._where.inclusion_filters[0].object_id
22
+
23
+ refute_equal original._where.exclusion_filters.object_id, copy._where.exclusion_filters.object_id
24
+ refute_equal original._where.exclusion_filters[0].object_id, copy._where.exclusion_filters[0].object_id
25
+ end
26
+
27
+ def test_or_filter
28
+ filter = [{ first_name: 'whatever1' }, { first_name: 'whatever2' }]
29
+ exclusion = [{ last_name: 'whatever1' }, { last_name: 'whatever2' }]
30
+
31
+ original = User.objects.filter(filter).exclude(exclusion)
32
+ copy = original.clone
33
+
34
+ refute_equal original.object_id, copy.object_id
35
+
36
+ assert_equal original._where.model, copy._where.model
37
+
38
+ refute_equal original._where.inclusion_filters.object_id, copy._where.inclusion_filters.object_id
39
+ refute_equal original._where.inclusion_filters[0].object_id, copy._where.inclusion_filters[0].object_id
40
+
41
+ refute_equal original._where.exclusion_filters.object_id, copy._where.exclusion_filters.object_id
42
+ refute_equal original._where.exclusion_filters[0].object_id, copy._where.exclusion_filters[0].object_id
43
+ end
44
+
45
+ def test_distinct
46
+ filter = [{ first_name: 'whatever1' }, { first_name: 'whatever2' }]
47
+ exclusion = [{ last_name: 'whatever1' }, { last_name: 'whatever2' }]
48
+
49
+ original = User.objects.filter(filter).exclude(exclusion)
50
+ copy = original.distinct
51
+ copy_undistinct = original.undistinct
52
+
53
+ refute_equal original.object_id, copy.object_id
54
+ refute_equal original.object_id, copy_undistinct.object_id
55
+ refute original.distinct?
56
+ assert copy.distinct?
57
+ refute copy_undistinct.distinct?
58
+ end
59
+
60
+ def test_limit
61
+ filter = [{ first_name: 'whatever1' }, { first_name: 'whatever2' }]
62
+ original = User.objects.filter(filter)
63
+ copy1 = original.limit(2, 10)
64
+ copy2 = original[2..10]
65
+ refute_equal original.object_id, copy1.object_id
66
+ refute_equal original.object_id, copy2.object_id
67
+ refute_equal copy1.object_id, copy2.object_id
68
+ end
69
+
70
+ def test_lockable
71
+ filter = [{ first_name: 'whatever1' }, { first_name: 'whatever2' }]
72
+ original = User.objects.filter(filter)
73
+ copy1 = original.lock
74
+ copy2 = original.for_update
75
+ refute_equal original.object_id, copy1.object_id
76
+ refute_equal original.object_id, copy2.object_id
77
+ refute_equal copy1.object_id, copy2.object_id
78
+ end
79
+
80
+ def test_projectable
81
+ filter = [{ first_name: 'whatever1' }, { first_name: 'whatever2' }]
82
+ original = User.objects.filter(filter)
83
+ copy1 = original.project(:id, :first_name)
84
+ copy2 = original.project(:id, :first_name, :last_name)
85
+ copy3 = copy2.unproject
86
+ refute_equal original.object_id, copy1.object_id
87
+ refute_equal original.object_id, copy2.object_id
88
+ refute_equal original.object_id, copy3.object_id
89
+ refute_equal copy1.object_id, copy2.object_id
90
+ refute_equal copy1.object_id, copy3.object_id
91
+ refute_equal copy2.object_id, copy3.object_id
92
+ end
93
+
94
+ def test_sortable
95
+ filter = [{ first_name: 'whatever1' }, { first_name: 'whatever2' }]
96
+ original = User.objects.filter(filter)
97
+ copy1 = original.order_by(first_name: :ASC)
98
+ copy2 = original.order(id: :ASC)
99
+ copy3 = copy2.order(%i[last_name DESC])
100
+ refute_equal original.object_id, copy1.object_id
101
+ refute_equal original.object_id, copy2.object_id
102
+ refute_equal original.object_id, copy3.object_id
103
+ refute_equal copy1.object_id, copy2.object_id
104
+ refute_equal copy1.object_id, copy3.object_id
105
+ refute_equal copy2.object_id, copy3.object_id
106
+ end
107
+
108
+ def test_deletable
109
+ filter = [{ first_name: 'Julius' }, { first_name: 'Marcus' }]
110
+ names = %w[Julius Marcus Tiberius Pontius Crassus]
111
+ names.each do |name|
112
+ User.create(first_name: name)
113
+ end
114
+ users = User.objects.filter(filter)
115
+ users.delete
116
+
117
+ assert_equal 0, users.count
118
+ assert_equal User.all.count, User.objects.count
119
+
120
+ User.destroy_all
121
+ end
122
+
123
+ def test_clone
124
+ filter = [{ first_name: 'whatever1' }, { first_name: 'whatever2' }]
125
+ original = User.objects.filter(filter)
126
+ original.clone.clone
127
+ end
128
+
129
+ end