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.
- checksums.yaml +7 -0
- data/Gemfile +16 -0
- data/README.md +718 -0
- data/Rakefile +18 -0
- data/lib/babik.rb +122 -0
- data/lib/babik/database.rb +16 -0
- data/lib/babik/queryset.rb +154 -0
- data/lib/babik/queryset/components/aggregation.rb +172 -0
- data/lib/babik/queryset/components/limit.rb +22 -0
- data/lib/babik/queryset/components/order.rb +161 -0
- data/lib/babik/queryset/components/projection.rb +118 -0
- data/lib/babik/queryset/components/select_related.rb +78 -0
- data/lib/babik/queryset/components/sql_renderer.rb +99 -0
- data/lib/babik/queryset/components/where.rb +43 -0
- data/lib/babik/queryset/lib/association/foreign_association_chain.rb +97 -0
- data/lib/babik/queryset/lib/association/select_related_association_chain.rb +32 -0
- data/lib/babik/queryset/lib/condition.rb +103 -0
- data/lib/babik/queryset/lib/field.rb +34 -0
- data/lib/babik/queryset/lib/join/association_joiner.rb +39 -0
- data/lib/babik/queryset/lib/join/join.rb +86 -0
- data/lib/babik/queryset/lib/selection/config.rb +19 -0
- data/lib/babik/queryset/lib/selection/foreign_selection.rb +39 -0
- data/lib/babik/queryset/lib/selection/local_selection.rb +40 -0
- data/lib/babik/queryset/lib/selection/operation/base.rb +126 -0
- data/lib/babik/queryset/lib/selection/operation/date.rb +178 -0
- data/lib/babik/queryset/lib/selection/operation/operations.rb +201 -0
- data/lib/babik/queryset/lib/selection/operation/regex.rb +58 -0
- data/lib/babik/queryset/lib/selection/path/foreign_path.rb +50 -0
- data/lib/babik/queryset/lib/selection/path/local_path.rb +44 -0
- data/lib/babik/queryset/lib/selection/path/path.rb +23 -0
- data/lib/babik/queryset/lib/selection/select_related_selection.rb +38 -0
- data/lib/babik/queryset/lib/selection/selection.rb +19 -0
- data/lib/babik/queryset/lib/update/assignment.rb +108 -0
- data/lib/babik/queryset/mixins/aggregatable.rb +17 -0
- data/lib/babik/queryset/mixins/bounded.rb +38 -0
- data/lib/babik/queryset/mixins/clonable.rb +52 -0
- data/lib/babik/queryset/mixins/countable.rb +44 -0
- data/lib/babik/queryset/mixins/deletable.rb +13 -0
- data/lib/babik/queryset/mixins/distinguishable.rb +27 -0
- data/lib/babik/queryset/mixins/filterable.rb +51 -0
- data/lib/babik/queryset/mixins/limitable.rb +88 -0
- data/lib/babik/queryset/mixins/lockable.rb +31 -0
- data/lib/babik/queryset/mixins/none.rb +16 -0
- data/lib/babik/queryset/mixins/projectable.rb +34 -0
- data/lib/babik/queryset/mixins/related_selector.rb +28 -0
- data/lib/babik/queryset/mixins/set_operations.rb +32 -0
- data/lib/babik/queryset/mixins/sortable.rb +49 -0
- data/lib/babik/queryset/mixins/sql_renderizable.rb +17 -0
- data/lib/babik/queryset/mixins/updatable.rb +14 -0
- data/lib/babik/queryset/templates/default/delete/main.sql.erb +14 -0
- data/lib/babik/queryset/templates/default/select/components/aggregation.sql.erb +5 -0
- data/lib/babik/queryset/templates/default/select/components/from.sql.erb +16 -0
- data/lib/babik/queryset/templates/default/select/components/from_set.sql.erb +3 -0
- data/lib/babik/queryset/templates/default/select/components/from_table.sql.erb +2 -0
- data/lib/babik/queryset/templates/default/select/components/limit.sql.erb +10 -0
- data/lib/babik/queryset/templates/default/select/components/order_by.sql.erb +9 -0
- data/lib/babik/queryset/templates/default/select/components/projection.sql.erb +7 -0
- data/lib/babik/queryset/templates/default/select/components/select_related.sql.erb +26 -0
- data/lib/babik/queryset/templates/default/select/components/where.sql.erb +39 -0
- data/lib/babik/queryset/templates/default/select/main.sql.erb +42 -0
- data/lib/babik/queryset/templates/default/update/main.sql.erb +15 -0
- data/lib/babik/queryset/templates/mssql/select/components/limit.sql.erb +8 -0
- data/lib/babik/queryset/templates/mssql/select/components/order_by.sql.erb +21 -0
- data/lib/babik/queryset/templates/mysql2/delete/main.sql.erb +15 -0
- data/lib/babik/queryset/templates/mysql2/update/main.sql.erb +18 -0
- data/lib/babik/queryset/templates/sqlite3/select/components/from_set.sql.erb +5 -0
- data/test/config/db/schema.rb +83 -0
- data/test/config/models/bad_post.rb +5 -0
- data/test/config/models/bad_tag.rb +5 -0
- data/test/config/models/category.rb +4 -0
- data/test/config/models/geozone.rb +6 -0
- data/test/config/models/group.rb +5 -0
- data/test/config/models/group_user.rb +5 -0
- data/test/config/models/post.rb +24 -0
- data/test/config/models/post_tag.rb +5 -0
- data/test/config/models/tag.rb +5 -0
- data/test/config/models/user.rb +6 -0
- data/test/delete/delete_test.rb +60 -0
- data/test/delete/foreign_conditions_delete_test.rb +57 -0
- data/test/delete/local_conditions_delete_test.rb +20 -0
- data/test/enable_coverage.rb +17 -0
- data/test/lib/selection/operation/log/test-queries.log +1 -0
- data/test/lib/selection/operation/test_date.rb +131 -0
- data/test/lib/selection/operation/test_regex.rb +55 -0
- data/test/other/clone_test.rb +129 -0
- data/test/other/escape_test.rb +21 -0
- data/test/other/inverse_of_required_test.rb +33 -0
- data/test/select/aggregate_test.rb +151 -0
- data/test/select/bounds_test.rb +46 -0
- data/test/select/count_test.rb +147 -0
- data/test/select/distinct_test.rb +38 -0
- data/test/select/exclude_test.rb +72 -0
- data/test/select/filter_from_object_test.rb +125 -0
- data/test/select/filter_test.rb +207 -0
- data/test/select/for_update_test.rb +19 -0
- data/test/select/foreign_selection_test.rb +60 -0
- data/test/select/get_test.rb +40 -0
- data/test/select/limit_test.rb +109 -0
- data/test/select/local_selection_test.rb +24 -0
- data/test/select/lookup_test.rb +208 -0
- data/test/select/none_test.rb +40 -0
- data/test/select/order_test.rb +165 -0
- data/test/select/project_test.rb +107 -0
- data/test/select/select_related_test.rb +124 -0
- data/test/select/subquery_test.rb +50 -0
- data/test/set_operations/basic_usage_test.rb +121 -0
- data/test/test_helper.rb +55 -0
- data/test/update/update_test.rb +93 -0
- metadata +278 -0
@@ -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
|