postgres_ext 2.1.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +13 -22
- data/CHANGELOG.md +45 -0
- data/README.md +13 -0
- data/Rakefile +83 -7
- data/docs/querying.md +76 -6
- data/lib/postgres_ext/active_record/relation/predicate_builder.rb +2 -2
- data/lib/postgres_ext/active_record/relation/query_methods.rb +44 -11
- data/lib/postgres_ext/arel/predications.rb +10 -0
- data/lib/postgres_ext/arel/visitors/to_sql.rb +1 -1
- data/lib/postgres_ext/version.rb +1 -1
- data/postgres_ext.gemspec +4 -2
- data/test/arel/array_test.rb +92 -0
- data/{spec/arel/inet_spec.rb → test/arel/inet_test.rb} +6 -6
- data/{spec/queries/array_queries_spec.rb → test/queries/array_queries_test.rb} +22 -14
- data/test/queries/common_table_expression_test.rb +49 -0
- data/{spec/queries/contains_querie_spec.rb → test/queries/contains_test.rb} +5 -5
- data/test/queries/sanity_test.rb +32 -0
- data/test/queries/window_functions_test.rb +64 -0
- data/test/test_helper.rb +38 -0
- metadata +74 -150
- data/spec/arel/array_spec.rb +0 -77
- data/spec/arel/rank_spec.rb +0 -0
- data/spec/dummy/.gitignore +0 -15
- data/spec/dummy/README.rdoc +0 -261
- data/spec/dummy/Rakefile +0 -7
- data/spec/dummy/app/assets/images/rails.png +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +0 -15
- data/spec/dummy/app/assets/stylesheets/application.css +0 -13
- data/spec/dummy/app/controllers/application_controller.rb +0 -3
- data/spec/dummy/app/helpers/application_helper.rb +0 -2
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/person.rb +0 -2
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/config/application.rb +0 -56
- data/spec/dummy/config/boot.rb +0 -6
- data/spec/dummy/config/database.yml.example +0 -14
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -33
- data/spec/dummy/config/environments/production.rb +0 -68
- data/spec/dummy/config/environments/test.rb +0 -33
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/inflections.rb +0 -15
- data/spec/dummy/config/initializers/mime_types.rb +0 -5
- data/spec/dummy/config/initializers/secret_token.rb +0 -7
- data/spec/dummy/config/initializers/session_store.rb +0 -8
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/config/locales/en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -58
- data/spec/dummy/db/migrate/20120501163758_create_people.rb +0 -15
- data/spec/dummy/db/schema.rb +0 -31
- data/spec/dummy/db/seeds.rb +0 -7
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/tasks/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -25
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/index.html +0 -241
- data/spec/dummy/public/robots.txt +0 -5
- data/spec/dummy/script/rails +0 -6
- data/spec/dummy/spec/factories/people.rb +0 -7
- data/spec/dummy/test/fixtures/.gitkeep +0 -0
- data/spec/dummy/test/functional/.gitkeep +0 -0
- data/spec/dummy/test/integration/.gitkeep +0 -0
- data/spec/dummy/test/performance/browsing_test.rb +0 -12
- data/spec/dummy/test/test_helper.rb +0 -13
- data/spec/dummy/test/unit/.gitkeep +0 -0
- data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/dummy/vendor/plugins/.gitkeep +0 -0
- data/spec/queries/common_table_expression_spec.rb +0 -36
- data/spec/queries/sanity_spec.rb +0 -17
- data/spec/queries/window_functions_spec.rb +0 -54
- data/spec/spec_helper.rb +0 -36
@@ -21,5 +21,15 @@ module Arel
|
|
21
21
|
def overlap(other)
|
22
22
|
Nodes::Overlap.new self, other
|
23
23
|
end
|
24
|
+
|
25
|
+
def any(other)
|
26
|
+
any_tags_function = Arel::Nodes::NamedFunction.new('ANY', [self])
|
27
|
+
Arel::Nodes::Equality.new(other, any_tags_function)
|
28
|
+
end
|
29
|
+
|
30
|
+
def all(other)
|
31
|
+
any_tags_function = Arel::Nodes::NamedFunction.new('ALL', [self])
|
32
|
+
Arel::Nodes::Equality.new(other, any_tags_function)
|
33
|
+
end
|
24
34
|
end
|
25
35
|
end
|
@@ -4,7 +4,7 @@ module Arel
|
|
4
4
|
module Visitors
|
5
5
|
class ToSql
|
6
6
|
def visit_Array o, a
|
7
|
-
column = a.relation.engine.columns.find { |col| col.name == a.name.to_s } if a
|
7
|
+
column = a.relation.engine.connection.columns(a.relation.name).find { |col| col.name == a.name.to_s } if a
|
8
8
|
if column && column.respond_to?(:array) && column.array
|
9
9
|
quoted o, a
|
10
10
|
else
|
data/lib/postgres_ext/version.rb
CHANGED
data/postgres_ext.gemspec
CHANGED
@@ -20,10 +20,12 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.add_dependency 'arel', '~> 4.0.1'
|
21
21
|
gem.add_dependency 'pg_array_parser', '~> 0.0.9'
|
22
22
|
|
23
|
-
gem.add_development_dependency '
|
24
|
-
gem.add_development_dependency '
|
23
|
+
gem.add_development_dependency 'rake', '~> 10.1.0'
|
24
|
+
gem.add_development_dependency 'minitest'
|
25
|
+
gem.add_development_dependency 'm'
|
25
26
|
gem.add_development_dependency 'bourne', '~> 1.3.0'
|
26
27
|
gem.add_development_dependency 'database_cleaner'
|
28
|
+
gem.add_development_dependency 'dotenv'
|
27
29
|
if RUBY_PLATFORM =~ /java/
|
28
30
|
gem.add_development_dependency 'activerecord-jdbcpostgresql-adapter', '1.3.0.beta2'
|
29
31
|
else
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'Array Column Predicates' do
|
4
|
+
let(:arel_table) { Person.arel_table }
|
5
|
+
describe 'Array Any' do
|
6
|
+
context 'string value' do
|
7
|
+
it 'creates any predicates' do
|
8
|
+
arel_table.where(arel_table[:tags].any('tag')).to_sql.must_match /'tag' = ANY\("people"\."tags"\)/
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'integer value' do
|
13
|
+
it 'creates any predicates' do
|
14
|
+
arel_table.where(arel_table[:tag_ids].any(1)).to_sql.must_match /1 = ANY\("people"\."tag_ids"\)/
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'Array All' do
|
20
|
+
context 'string value' do
|
21
|
+
it 'creates all predicates' do
|
22
|
+
arel_table.where(arel_table[:tags].all('tag')).to_sql.must_match /'tag' = ALL\("people"\."tags"\)/
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'integer value' do
|
27
|
+
it 'creates all predicates' do
|
28
|
+
arel_table.where(arel_table[:tag_ids].all(1)).to_sql.must_match /1 = ALL\("people"\."tag_ids"\)/
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'Array Overlap' do
|
34
|
+
it 'converts Arel overlap statement' do
|
35
|
+
arel_table.where(arel_table[:tags].overlap(['tag','tag 2'])).to_sql.must_match /&& '\{"tag","tag 2"\}'/
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'converts Arel overlap statement' do
|
39
|
+
arel_table.where(arel_table[:tag_ids].overlap([1,2])).to_sql.must_match /&& '\{1,2\}'/
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'works with count (and other predicates)' do
|
43
|
+
Person.where(arel_table[:tag_ids].overlap([1,2])).count.must_equal 0
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns matched records' do
|
47
|
+
one = Person.create!(:tags => ['one'])
|
48
|
+
two = Person.create!(:tags => ['two'])
|
49
|
+
|
50
|
+
query = arel_table.where(arel_table[:tags].overlap(['one'])).project(Arel.sql('*'))
|
51
|
+
Person.find_by_sql(query.to_sql).must_include(one)
|
52
|
+
|
53
|
+
query = arel_table.where(arel_table[:tags].overlap(['two'])).project(Arel.sql('*'))
|
54
|
+
Person.find_by_sql(query.to_sql).must_include(two)
|
55
|
+
|
56
|
+
query = arel_table.where(arel_table[:tags].overlap(['two','one'])).project(Arel.sql('*'))
|
57
|
+
Person.find_by_sql(query.to_sql).must_include(two)
|
58
|
+
Person.find_by_sql(query.to_sql).must_include(one)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'Array Contains' do
|
63
|
+
it 'converts Arel contains statement and escapes strings' do
|
64
|
+
arel_table.where(arel_table[:tags].contains(['tag','tag 2'])).to_sql.must_match /@> '\{"tag","tag 2"\}'/
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'converts Arel contains statement with numbers' do
|
68
|
+
arel_table.where(arel_table[:tag_ids].contains([1,2])).to_sql.must_match /@> '\{1,2\}'/
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'works with count (and other predicates)' do
|
72
|
+
Person.where(arel_table[:tag_ids].contains([1,2])).count.must_equal 0
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'returns matched records' do
|
76
|
+
one = Person.create!(:tags => ['one', 'two', 'three'])
|
77
|
+
two = Person.create!(:tags => ['one', 'three'])
|
78
|
+
|
79
|
+
query = arel_table.where(arel_table[:tags].contains(['one', 'two'])).project(Arel.sql('*'))
|
80
|
+
Person.find_by_sql(query.to_sql).must_include one
|
81
|
+
Person.find_by_sql(query.to_sql).wont_include two
|
82
|
+
|
83
|
+
query = arel_table.where(arel_table[:tags].contains(['one', 'three'])).project(Arel.sql('*'))
|
84
|
+
Person.find_by_sql(query.to_sql).must_include one
|
85
|
+
Person.find_by_sql(query.to_sql).must_include two
|
86
|
+
|
87
|
+
query = arel_table.where(arel_table[:tags].contains(['two'])).project(Arel.sql('*'))
|
88
|
+
Person.find_by_sql(query.to_sql).must_include one
|
89
|
+
Person.find_by_sql(query.to_sql).wont_include two
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
describe 'INET related AREL functions' do
|
4
4
|
describe 'quoting IPAddr in sql statement' do
|
5
5
|
it 'properly converts IPAddr to quoted strings when passed as an argument to a where clause' do
|
6
|
-
Person.where(:ip => IPAddr.new('127.0.0.1')).to_sql.
|
6
|
+
Person.where(:ip => IPAddr.new('127.0.0.1')).to_sql.must_include("'127.0.0.1/32'")
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
@@ -11,7 +11,7 @@ describe 'INET related AREL functions' do
|
|
11
11
|
it 'converts Arel contained_within statements to <<' do
|
12
12
|
arel_table = Person.arel_table
|
13
13
|
|
14
|
-
arel_table.where(arel_table[:ip].contained_within(IPAddr.new('127.0.0.1/24'))).to_sql.
|
14
|
+
arel_table.where(arel_table[:ip].contained_within(IPAddr.new('127.0.0.1/24'))).to_sql.must_match /<< '127.0.0.0\/24'/
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -19,14 +19,14 @@ describe 'INET related AREL functions' do
|
|
19
19
|
it 'converts Arel contained_within_or_equals statements to <<=' do
|
20
20
|
arel_table = Person.arel_table
|
21
21
|
|
22
|
-
arel_table.where(arel_table[:ip].contained_within_or_equals(IPAddr.new('127.0.0.1/24'))).to_sql.
|
22
|
+
arel_table.where(arel_table[:ip].contained_within_or_equals(IPAddr.new('127.0.0.1/24'))).to_sql.must_match /<<= '127.0.0.0\/24'/
|
23
23
|
end
|
24
24
|
end
|
25
25
|
describe 'contains (>>) operator' do
|
26
26
|
it 'converts Arel contains statements to >>' do
|
27
27
|
arel_table = Person.arel_table
|
28
28
|
|
29
|
-
arel_table.where(arel_table[:ip].contains(IPAddr.new('127.0.0.1/24'))).to_sql.
|
29
|
+
arel_table.where(arel_table[:ip].contains(IPAddr.new('127.0.0.1/24'))).to_sql.must_match />> '127.0.0.0\/24'/
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -34,7 +34,7 @@ describe 'INET related AREL functions' do
|
|
34
34
|
it 'converts Arel contains_or_equals statements to >>=' do
|
35
35
|
arel_table = Person.arel_table
|
36
36
|
|
37
|
-
arel_table.where(arel_table[:ip].contains_or_equals(IPAddr.new('127.0.0.1/24'))).to_sql.
|
37
|
+
arel_table.where(arel_table[:ip].contains_or_equals(IPAddr.new('127.0.0.1/24'))).to_sql.must_match />>= '127.0.0.0\/24'/
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
describe 'Array queries' do
|
4
4
|
let(:equality_regex) { %r{\"people\"\.\"tags\" = '\{\"working\"\}'} }
|
@@ -10,63 +10,71 @@ describe 'Array queries' do
|
|
10
10
|
describe '.where(:array_column => [])' do
|
11
11
|
it 'returns an array string instead of IN ()' do
|
12
12
|
query = Person.where(:tags => ['working']).to_sql
|
13
|
-
query.
|
13
|
+
query.must_match equality_regex
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.where(joins: { array_column: [] })' do
|
18
|
+
it 'returns an array string instead of IN ()' do
|
19
|
+
skip
|
20
|
+
query = Person.joins(:hm_tags).where(tags: { categories: ['working'] }).to_sql
|
21
|
+
query.must_match equality_regex
|
14
22
|
end
|
15
23
|
end
|
16
24
|
|
17
25
|
describe '.where.overlap(:column => value)' do
|
18
26
|
it 'generates the appropriate where clause' do
|
19
27
|
query = Person.where.overlap(:tag_ids => [1,2])
|
20
|
-
query.to_sql.
|
28
|
+
query.to_sql.must_match overlap_regex
|
21
29
|
end
|
22
30
|
|
23
31
|
it 'allows chaining' do
|
24
32
|
query = Person.where.overlap(:tag_ids => [1,2]).where(:tags => ['working']).to_sql
|
25
33
|
|
26
|
-
query.
|
27
|
-
query.
|
34
|
+
query.must_match overlap_regex
|
35
|
+
query.must_match equality_regex
|
28
36
|
end
|
29
37
|
end
|
30
38
|
|
31
39
|
describe '.where.contains(:column => value)' do
|
32
40
|
it 'generates the appropriate where clause' do
|
33
41
|
query = Person.where.contains(:tag_ids => [1,2])
|
34
|
-
query.to_sql.
|
42
|
+
query.to_sql.must_match contains_regex
|
35
43
|
end
|
36
44
|
|
37
45
|
it 'allows chaining' do
|
38
46
|
query = Person.where.contains(:tag_ids => [1,2]).where(:tags => ['working']).to_sql
|
39
47
|
|
40
|
-
query.
|
41
|
-
query.
|
48
|
+
query.must_match contains_regex
|
49
|
+
query.must_match equality_regex
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
45
53
|
describe '.where.any(:column => value)' do
|
46
54
|
it 'generates the appropriate where clause' do
|
47
55
|
query = Person.where.any(:tag_ids => 2)
|
48
|
-
query.to_sql.
|
56
|
+
query.to_sql.must_match any_regex
|
49
57
|
end
|
50
58
|
|
51
59
|
it 'allows chaining' do
|
52
60
|
query = Person.where.any(:tag_ids => 2).where(:tags => ['working']).to_sql
|
53
61
|
|
54
|
-
query.
|
55
|
-
query.
|
62
|
+
query.must_match any_regex
|
63
|
+
query.must_match equality_regex
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
59
67
|
describe '.where.all(:column => value)' do
|
60
68
|
it 'generates the appropriate where clause' do
|
61
69
|
query = Person.where.all(:tag_ids => 2)
|
62
|
-
query.to_sql.
|
70
|
+
query.to_sql.must_match all_regex
|
63
71
|
end
|
64
72
|
|
65
73
|
it 'allows chaining' do
|
66
74
|
query = Person.where.all(:tag_ids => 2).where(:tags => ['working']).to_sql
|
67
75
|
|
68
|
-
query.
|
69
|
-
query.
|
76
|
+
query.must_match all_regex
|
77
|
+
query.must_match equality_regex
|
70
78
|
end
|
71
79
|
end
|
72
80
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'Common Table Expression queries' do
|
4
|
+
describe '.with(common_table_expression_hash)' do
|
5
|
+
it 'generates an expression with the CTE' do
|
6
|
+
query = Person.with(lucky_number_seven: Person.where(lucky_number: 7)).joins('JOIN lucky_number_seven ON lucky_number_seven.id = people.id')
|
7
|
+
query.to_sql.must_equal 'WITH lucky_number_seven AS (SELECT "people".* FROM "people" WHERE "people"."lucky_number" = 7) SELECT "people".* FROM "people" JOIN lucky_number_seven ON lucky_number_seven.id = people.id'
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'generates an expression with multiple CTEs' do
|
11
|
+
query = Person.with(lucky_number_seven: Person.where(lucky_number: 7), lucky_number_three: Person.where(lucky_number: 3)).joins('JOIN lucky_number_seven ON lucky_number_seven.id = people.id').joins('JOIN lucky_number_three ON lucky_number_three.id = people.id')
|
12
|
+
query.to_sql.must_equal 'WITH lucky_number_seven AS (SELECT "people".* FROM "people" WHERE "people"."lucky_number" = 7), lucky_number_three AS (SELECT "people".* FROM "people" WHERE "people"."lucky_number" = 3) SELECT "people".* FROM "people" JOIN lucky_number_seven ON lucky_number_seven.id = people.id JOIN lucky_number_three ON lucky_number_three.id = people.id'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'generates an expression with multiple with calls' do
|
16
|
+
query = Person.with(lucky_number_seven: Person.where(lucky_number: 7)).with(lucky_number_three: Person.where(lucky_number: 3)).joins('JOIN lucky_number_seven ON lucky_number_seven.id = people.id').joins('JOIN lucky_number_three ON lucky_number_three.id = people.id')
|
17
|
+
query.to_sql.must_equal 'WITH lucky_number_seven AS (SELECT "people".* FROM "people" WHERE "people"."lucky_number" = 7), lucky_number_three AS (SELECT "people".* FROM "people" WHERE "people"."lucky_number" = 3) SELECT "people".* FROM "people" JOIN lucky_number_seven ON lucky_number_seven.id = people.id JOIN lucky_number_three ON lucky_number_three.id = people.id'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'generates an expression with recursive' do
|
21
|
+
query = Person.with.recursive(lucky_number_seven: Person.where(lucky_number: 7)).joins('JOIN lucky_number_seven ON lucky_number_seven.id = people.id')
|
22
|
+
query.to_sql.must_equal 'WITH RECURSIVE lucky_number_seven AS (SELECT "people".* FROM "people" WHERE "people"."lucky_number" = 7) SELECT "people".* FROM "people" JOIN lucky_number_seven ON lucky_number_seven.id = people.id'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'accepts Arel::SelectMangers' do
|
26
|
+
arel_table = Arel::Table.new 'test'
|
27
|
+
arel_manager = arel_table.project arel_table[:foo]
|
28
|
+
|
29
|
+
query = Person.with(testing: arel_manager)
|
30
|
+
query.to_sql.must_equal 'WITH testing AS (SELECT "test"."foo" FROM "test") SELECT "people".* FROM "people"'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.from_cte(common_table_expression_hash)' do
|
35
|
+
it 'generates an expression with the CTE as the main table' do
|
36
|
+
query = Person.from_cte('lucky_number_seven', Person.where(lucky_number: 7)).where(id: 5)
|
37
|
+
query.to_sql.must_equal 'WITH lucky_number_seven AS (SELECT "people".* FROM "people" WHERE "people"."lucky_number" = 7) SELECT "lucky_number_seven".* FROM "lucky_number_seven" WHERE "lucky_number_seven"."id" = 5'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns instances of the model' do
|
41
|
+
3.times { Person.create! lucky_number: 7 }
|
42
|
+
3.times { Person.create! lucky_number: 3 }
|
43
|
+
people = Person.from_cte('lucky_number_seven', Person.where(lucky_number: 7))
|
44
|
+
|
45
|
+
people.count.must_equal 3
|
46
|
+
people.first.lucky_number.must_equal 7
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
describe 'Contains queries' do
|
4
4
|
let(:contained_within_regex) { %r{\"people\"\.\"ip\" << '127.0.0.1/24'} }
|
@@ -9,28 +9,28 @@ describe 'Contains queries' do
|
|
9
9
|
describe '.where.contained_within(:column, value)' do
|
10
10
|
it 'generates the appropriate where clause' do
|
11
11
|
query = Person.where.contained_within(:ip => '127.0.0.1/24')
|
12
|
-
query.to_sql.
|
12
|
+
query.to_sql.must_match contained_within_regex
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
describe '.where.contained_within_or_equals(:column, value)' do
|
17
17
|
it 'generates the appropriate where clause' do
|
18
18
|
query = Person.where.contained_within_or_equals(:ip => '127.0.0.1/24')
|
19
|
-
query.to_sql.
|
19
|
+
query.to_sql.must_match contained_within_equals_regex
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
describe '.where.contains(:column, value)' do
|
24
24
|
it 'generates the appropriate where clause' do
|
25
25
|
query = Person.where.contains(:ip => '127.0.0.1')
|
26
|
-
query.to_sql.
|
26
|
+
query.to_sql.must_match contains_regex
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
describe '.where.contained_within_or_equals(:column, value)' do
|
31
31
|
it 'generates the appropriate where clause' do
|
32
32
|
query = Person.where.contains_or_equals(:ip => '127.0.0.1')
|
33
|
-
query.to_sql.
|
33
|
+
query.to_sql.must_match contains_equals_regex
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'Ensure that we don\'t stomp on Active Record\'s queries' do
|
4
|
+
describe '.where' do
|
5
|
+
it 'generates IN clauses for non array columns' do
|
6
|
+
query = Person.where(:id => [1,2,3]).to_sql
|
7
|
+
|
8
|
+
query.must_match /IN \(1, 2, 3\)/
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'generates IN clauses for non array columns' do
|
12
|
+
query = Person.where(:id => []).to_sql
|
13
|
+
|
14
|
+
query.must_match /WHERE 1=0/
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.where(joins: { column: [] })' do
|
19
|
+
it 'generates IN clause for non array columns' do
|
20
|
+
query = Person.joins(:hm_tags).where(tags: { id: ['working'] }).to_sql
|
21
|
+
query.must_match /WHERE "tags"\."id" IN \('working'\)/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#habtm_association_ids=' do
|
26
|
+
it 'properly deletes records through HABTM association method' do
|
27
|
+
person = Person.create(habtm_tag_ids: [Tag.create.id])
|
28
|
+
person.update_attributes(habtm_tag_ids: [])
|
29
|
+
person.habtm_tag_ids.must_be_empty
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'Window functions' do
|
4
|
+
describe 'ranked' do
|
5
|
+
it 'uses the order when no order is passed to ranked' do
|
6
|
+
query = Person.order(lucky_number: :desc).ranked
|
7
|
+
query.to_sql.must_equal 'SELECT "people".*, rank() OVER (ORDER BY "people"."lucky_number" DESC) FROM "people" ORDER BY "people"."lucky_number" DESC'
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'uses the order when no order is passed to ranked, swapped calls' do
|
11
|
+
query = Person.ranked.order(lucky_number: :desc)
|
12
|
+
query.to_sql.must_equal 'SELECT "people".*, rank() OVER (ORDER BY "people"."lucky_number" DESC) FROM "people" ORDER BY "people"."lucky_number" DESC'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'uses the rank value when there is an order passed to it' do
|
16
|
+
query = Person.ranked(lucky_number: :desc)
|
17
|
+
query.to_sql.must_equal 'SELECT "people".*, rank() OVER (ORDER BY "people"."lucky_number" DESC) FROM "people"'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'uses the rank value when a symbol passed to it' do
|
21
|
+
query = Person.ranked(:lucky_number)
|
22
|
+
query.to_sql.must_equal 'SELECT "people".*, rank() OVER (ORDER BY "people"."lucky_number" ASC) FROM "people"'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'uses the rank value when a string passed to it' do
|
26
|
+
query = Person.ranked('ORDER BY lucky_number DESC')
|
27
|
+
query.to_sql.must_equal 'SELECT "people".*, rank() OVER (ORDER BY lucky_number DESC) FROM "people"'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'combines the order and rank' do
|
31
|
+
query = Person.ranked(lucky_number: :desc).order(id: :asc)
|
32
|
+
query.to_sql.must_equal 'SELECT "people".*, rank() OVER (ORDER BY "people"."lucky_number" DESC) FROM "people" ORDER BY "people"."id" ASC'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'executes the query with the rank' do
|
36
|
+
Person.create!
|
37
|
+
Person.create!
|
38
|
+
|
39
|
+
ranked_people = Person.ranked(:id)
|
40
|
+
ranked_people[0].rank.must_equal 1
|
41
|
+
ranked_people[1].rank.must_equal 2
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'does not apply the rank when performing a count' do
|
45
|
+
query = Person.ranked(lucky_number: :desc).count
|
46
|
+
query.must_equal 0
|
47
|
+
|
48
|
+
Person.create!
|
49
|
+
|
50
|
+
query = Person.ranked(lucky_number: :desc).count
|
51
|
+
query.must_equal 1
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'does not apply the rank when checking presence' do
|
55
|
+
query = Person.ranked(lucky_number: :desc).present?
|
56
|
+
query.must_equal false
|
57
|
+
|
58
|
+
Person.create!
|
59
|
+
|
60
|
+
query = Person.ranked(lucky_number: :desc).present?
|
61
|
+
query.must_equal true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|