babik 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|