babik 0.1.0

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