active_record_extended 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +87 -15
- data/lib/active_record_extended.rb +2 -1
- data/lib/active_record_extended/active_record.rb +2 -9
- data/lib/active_record_extended/active_record/relation_patch.rb +21 -4
- data/lib/active_record_extended/arel.rb +2 -0
- data/lib/active_record_extended/arel/aggregate_function_name.rb +40 -0
- data/lib/active_record_extended/arel/nodes.rb +32 -41
- data/lib/active_record_extended/arel/predications.rb +4 -1
- data/lib/active_record_extended/arel/sql_literal.rb +16 -0
- data/lib/active_record_extended/arel/visitors/postgresql_decorator.rb +40 -1
- data/lib/active_record_extended/query_methods/any_of.rb +10 -8
- data/lib/active_record_extended/query_methods/either.rb +1 -1
- data/lib/active_record_extended/query_methods/inet.rb +7 -3
- data/lib/active_record_extended/query_methods/json.rb +156 -50
- data/lib/active_record_extended/query_methods/select.rb +118 -0
- data/lib/active_record_extended/query_methods/unionize.rb +14 -43
- data/lib/active_record_extended/query_methods/where_chain.rb +14 -6
- data/lib/active_record_extended/query_methods/window.rb +93 -0
- data/lib/active_record_extended/query_methods/with_cte.rb +102 -35
- data/lib/active_record_extended/utilities/order_by.rb +77 -0
- data/lib/active_record_extended/utilities/support.rb +178 -0
- data/lib/active_record_extended/version.rb +1 -1
- data/spec/query_methods/any_of_spec.rb +40 -40
- data/spec/query_methods/array_query_spec.rb +14 -14
- data/spec/query_methods/either_spec.rb +14 -14
- data/spec/query_methods/hash_query_spec.rb +11 -11
- data/spec/query_methods/inet_query_spec.rb +33 -31
- data/spec/query_methods/json_spec.rb +42 -27
- data/spec/query_methods/select_spec.rb +115 -0
- data/spec/query_methods/unionize_spec.rb +56 -56
- data/spec/query_methods/window_spec.rb +51 -0
- data/spec/query_methods/with_cte_spec.rb +22 -12
- data/spec/spec_helper.rb +1 -1
- data/spec/sql_inspections/any_of_sql_spec.rb +12 -12
- data/spec/sql_inspections/arel/aggregate_function_name_spec.rb +41 -0
- data/spec/sql_inspections/arel/array_spec.rb +7 -7
- data/spec/sql_inspections/arel/inet_spec.rb +7 -7
- data/spec/sql_inspections/contains_sql_queries_spec.rb +14 -14
- data/spec/sql_inspections/either_sql_spec.rb +11 -11
- data/spec/sql_inspections/json_sql_spec.rb +44 -8
- data/spec/sql_inspections/unionize_sql_spec.rb +27 -27
- data/spec/sql_inspections/window_sql_spec.rb +98 -0
- data/spec/sql_inspections/with_cte_sql_spec.rb +52 -23
- data/spec/support/models.rb +24 -4
- metadata +31 -20
- data/lib/active_record_extended/patch/5_0/predicate_builder_decorator.rb +0 -87
- data/lib/active_record_extended/utilities.rb +0 -141
@@ -3,112 +3,113 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
5
|
RSpec.describe "Active Record Union Methods" do
|
6
|
-
let!(:
|
7
|
-
let!(:
|
8
|
-
let!(:
|
9
|
-
let!(:
|
10
|
-
let!(:
|
6
|
+
let!(:user_one) { User.create!(number: 8) }
|
7
|
+
let!(:user_two) { User.create!(number: 10) }
|
8
|
+
let!(:user_three) { User.create!(number: 1) }
|
9
|
+
let!(:user_one_pl) { ProfileL.create!(user: user_one, likes: 100) }
|
10
|
+
let!(:user_two_pl) { ProfileL.create!(user: user_two, likes: 200) }
|
11
11
|
|
12
12
|
shared_examples_for "standard set of errors" do
|
13
|
-
let(:
|
14
|
-
let(:
|
13
|
+
let(:user_one_query) { User.select(:id).where(id: user_one.id) }
|
14
|
+
let(:user_two_query) { User.select(:id, :tags).where(id: user_two.id) }
|
15
15
|
let(:misaligned_cmd) { raise("required to override this 'let' statement") }
|
16
16
|
let(:lacking_union_cmd) { raise("required to override this 'let' statement") }
|
17
17
|
|
18
18
|
it "should raise an error if the select statements do not align" do
|
19
19
|
expect { misaligned_cmd.to_a }.to(
|
20
|
-
raise_error(ActiveRecord::StatementInvalid, /each [[:alpha:]]+ query must have the same number of columns/)
|
20
|
+
raise_error(ActiveRecord::StatementInvalid, /each [[:alpha:]]+ query must have the same number of columns/)
|
21
21
|
)
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should raise an argument error if there are less then two union statements" do
|
25
25
|
expect { lacking_union_cmd.to_a }.to(
|
26
|
-
raise_error(ArgumentError, "You are required to provide 2 or more unions to join!")
|
26
|
+
raise_error(ArgumentError, "You are required to provide 2 or more unions to join!")
|
27
27
|
)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
describe ".union" do
|
32
32
|
it_behaves_like "standard set of errors" do
|
33
|
-
let!(:misaligned_cmd) {
|
34
|
-
let!(:lacking_union_cmd) {
|
33
|
+
let!(:misaligned_cmd) { User.union(user_one_query, user_two_query) }
|
34
|
+
let!(:lacking_union_cmd) { User.union(user_one_query) }
|
35
35
|
end
|
36
36
|
|
37
37
|
it "should return two users that match the where conditions" do
|
38
|
-
query =
|
39
|
-
expect(query).to match_array([
|
38
|
+
query = User.union(User.where(id: user_one.id), User.where(id: user_three.id))
|
39
|
+
expect(query).to match_array([user_one, user_three])
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should allow joins on union statements" do
|
43
|
-
query =
|
44
|
-
expect(query).to match_array([
|
43
|
+
query = User.union(User.where(id: user_one.id), User.joins(:profile_l).where.not(id: user_one.id))
|
44
|
+
expect(query).to match_array([user_one, user_two])
|
45
45
|
end
|
46
46
|
|
47
47
|
it "should eliminate duplicate results" do
|
48
|
-
expected_ids =
|
49
|
-
query =
|
48
|
+
expected_ids = User.pluck(:id)
|
49
|
+
query = User.union(User.select(:id), User.select(:id))
|
50
50
|
expect(query.pluck(:id)).to have_attributes(size: expected_ids.size).and(match_array(expected_ids))
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
54
|
describe ".union.all" do
|
55
55
|
it_behaves_like "standard set of errors" do
|
56
|
-
let!(:misaligned_cmd) {
|
57
|
-
let!(:lacking_union_cmd) {
|
56
|
+
let!(:misaligned_cmd) { User.union.all(user_one_query, user_two_query) }
|
57
|
+
let!(:lacking_union_cmd) { User.union.all(user_one_query) }
|
58
58
|
end
|
59
59
|
|
60
60
|
it "should keep duplicate results from each union statement" do
|
61
|
-
expected_ids =
|
62
|
-
query =
|
61
|
+
expected_ids = User.pluck(:id) * 2
|
62
|
+
query = User.union.all(User.select(:id), User.select(:id))
|
63
63
|
expect(query.pluck(:id)).to have_attributes(size: expected_ids.size).and(match_array(expected_ids))
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
describe ".union.except" do
|
68
68
|
it_behaves_like "standard set of errors" do
|
69
|
-
let!(:misaligned_cmd) {
|
70
|
-
let!(:lacking_union_cmd) {
|
69
|
+
let!(:misaligned_cmd) { User.union.except(user_one_query, user_two_query) }
|
70
|
+
let!(:lacking_union_cmd) { User.union.except(user_one_query) }
|
71
71
|
end
|
72
72
|
|
73
73
|
it "should eliminate records that match a given except statement" do
|
74
|
-
query =
|
75
|
-
expect(query).to match_array([
|
74
|
+
query = User.union.except(User.select(:id), User.select(:id).where(id: user_one.id))
|
75
|
+
expect(query).to match_array([user_two, user_three])
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
79
|
describe "union.intersect" do
|
80
80
|
it_behaves_like "standard set of errors" do
|
81
|
-
let!(:misaligned_cmd) {
|
82
|
-
let!(:lacking_union_cmd) {
|
81
|
+
let!(:misaligned_cmd) { User.union.intersect(user_one_query, user_two_query) }
|
82
|
+
let!(:lacking_union_cmd) { User.union.intersect(user_one_query) }
|
83
83
|
end
|
84
84
|
|
85
85
|
it "should find records with similar attributes" do
|
86
|
-
ProfileL.create!(
|
86
|
+
ProfileL.create!(user: user_three, likes: 120)
|
87
87
|
|
88
88
|
query =
|
89
|
-
|
90
|
-
|
91
|
-
|
89
|
+
User.union.intersect(
|
90
|
+
User.select(:id, "profile_ls.likes").joins(:profile_l).where(profile_ls: { likes: 100 }),
|
91
|
+
User.select(:id, "profile_ls.likes").joins(:profile_l).where("profile_ls.likes < 150")
|
92
92
|
)
|
93
93
|
|
94
|
-
expect(query.pluck(:id)).to have_attributes(size: 1).and(eq([
|
95
|
-
expect(query.first.likes).to eq(
|
94
|
+
expect(query.pluck(:id)).to have_attributes(size: 1).and(eq([user_one_pl.id]))
|
95
|
+
expect(query.first.likes).to eq(user_one_pl.likes)
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
99
|
describe "union.as" do
|
100
100
|
let(:query) do
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
User
|
102
|
+
.select("happy_users.id")
|
103
|
+
.union(User.where(id: user_one.id), User.where(id: user_three.id))
|
104
|
+
.union_as(:happy_users)
|
104
105
|
end
|
105
106
|
|
106
|
-
it "should return two
|
107
|
+
it "should return two users" do
|
107
108
|
expect(query.size).to eq(2)
|
108
109
|
end
|
109
110
|
|
110
|
-
it "should return two
|
111
|
-
expect(query.map(&:id)).to match_array([
|
111
|
+
it "should return two userss id's" do
|
112
|
+
expect(query.map(&:id)).to match_array([user_one.id, user_three.id])
|
112
113
|
end
|
113
114
|
|
114
115
|
it "should alias the tables being union'd but still allow for accessing table methods" do
|
@@ -120,43 +121,42 @@ RSpec.describe "Active Record Union Methods" do
|
|
120
121
|
|
121
122
|
describe "union.order_union" do
|
122
123
|
it "should order the .union commands" do
|
123
|
-
query =
|
124
|
-
expect(query).to eq([
|
124
|
+
query = User.union(User.where(id: user_one.id), User.where(id: user_three.id)).order_union(id: :desc)
|
125
|
+
expect(query).to eq([user_three, user_one])
|
125
126
|
end
|
126
127
|
|
127
128
|
it "should order the .union.all commands" do
|
128
129
|
query =
|
129
|
-
|
130
|
-
|
131
|
-
|
130
|
+
User.union.all(
|
131
|
+
User.where(id: user_one.id),
|
132
|
+
User.where(id: user_three.id)
|
132
133
|
).order_union(id: :desc)
|
133
134
|
|
134
|
-
expect(query).to eq([
|
135
|
+
expect(query).to eq([user_three, user_one])
|
135
136
|
end
|
136
137
|
|
137
138
|
it "should order the union.except commands" do
|
138
|
-
query =
|
139
|
-
expect(query).to eq([
|
139
|
+
query = User.union.except(User.order(id: :asc), User.where(id: user_one.id)).order_union(id: :desc)
|
140
|
+
expect(query).to eq([user_three, user_two])
|
140
141
|
end
|
141
142
|
|
142
143
|
it "should order the .union.intersect commands" do
|
143
144
|
query =
|
144
|
-
|
145
|
-
|
146
|
-
|
145
|
+
User.union.intersect(
|
146
|
+
User.where("id < ?", user_three.id),
|
147
|
+
User.where("id >= ?", user_one.id)
|
147
148
|
).order_union(id: :desc)
|
148
149
|
|
149
|
-
expect(query).to eq([
|
150
|
+
expect(query).to eq([user_two, user_one])
|
150
151
|
end
|
151
152
|
end
|
152
153
|
|
153
154
|
describe "union.reorder_union" do
|
154
155
|
it "should replace the ordering with the new parameters" do
|
155
|
-
|
156
|
-
|
157
|
-
initial_ordering = [
|
158
|
-
query =
|
159
|
-
.order_union(id: :desc)
|
156
|
+
user_a = User.create!(number: 1)
|
157
|
+
user_b = User.create!(number: 10)
|
158
|
+
initial_ordering = [user_b, user_a]
|
159
|
+
query = User.union(User.where(id: user_a.id), User.where(id: user_b.id)).order_union(id: :desc)
|
160
160
|
|
161
161
|
expect(query).to eq(initial_ordering)
|
162
162
|
expect(query.reorder_union(number: :asc)).to eq(initial_ordering.reverse)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe "Active Record Window Function Query Methods" do
|
6
|
+
let!(:user_one) { User.create! }
|
7
|
+
let!(:user_two) { User.create! }
|
8
|
+
|
9
|
+
let!(:tag_one) { Tag.create!(user: user_one, tag_number: 1) }
|
10
|
+
let!(:tag_two) { Tag.create!(user: user_two, tag_number: 2) }
|
11
|
+
|
12
|
+
let!(:tag_three) { Tag.create!(user: user_one, tag_number: 3) }
|
13
|
+
let!(:tag_four) { Tag.create!(user: user_two, tag_number: 4) }
|
14
|
+
|
15
|
+
let(:tag_group1) { [tag_one, tag_three] }
|
16
|
+
let(:tag_group2) { [tag_two, tag_four] }
|
17
|
+
|
18
|
+
describe ".window_select" do
|
19
|
+
context "when using ROW_NUMBER() ordered in asc" do
|
20
|
+
let(:base_query) do
|
21
|
+
Tag.define_window(:w).partition_by(:user_id, order_by: :tag_number).select(:id)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return tag_one with r_id 1 and tag_three with r_id 2" do
|
25
|
+
results = base_query.select_window(:row_number, over: :w, as: :r_id).group_by(&:id)
|
26
|
+
tag_group1.each.with_index { |tag, idx| expect(results[tag.id].first.r_id).to eq(idx + 1) }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return tag_two with r_id 1 and tag_four with r_id 2" do
|
30
|
+
results = base_query.select_window(:row_number, over: :w, as: :r_id).group_by(&:id)
|
31
|
+
tag_group2.each.with_index { |tag, idx| expect(results[tag.id].first.r_id).to eq(idx + 1) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when using ROW_NUMBER() ordered in desc" do
|
36
|
+
let(:base_query) do
|
37
|
+
Tag.define_window(:w).partition_by(:user_id, order_by: { tag_number: :desc }).select(:id)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return tag_one with r_id 2 and tag_three with r_id 1" do
|
41
|
+
results = base_query.select_window(:row_number, over: :w, as: :r_id).group_by(&:id)
|
42
|
+
tag_group1.reverse_each.with_index { |tag, idx| expect(results[tag.id].first.r_id).to eq(idx + 1) }
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return tag_two with r_id 2 and tag_four with r_id 1" do
|
46
|
+
results = base_query.select_window(:row_number, over: :w, as: :r_id).group_by(&:id)
|
47
|
+
tag_group2.reverse_each.with_index { |tag, idx| expect(results[tag.id].first.r_id).to eq(idx + 1) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -3,25 +3,25 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
5
|
RSpec.describe "Active Record With CTE Query Methods" do
|
6
|
-
let!(:
|
7
|
-
let!(:
|
8
|
-
let!(:profile_one) { ProfileL.create!(
|
9
|
-
let!(:profile_two) { ProfileL.create!(
|
6
|
+
let!(:user_one) { User.create! }
|
7
|
+
let!(:user_two) { User.create! }
|
8
|
+
let!(:profile_one) { ProfileL.create!(user_id: user_one.id, likes: 200) }
|
9
|
+
let!(:profile_two) { ProfileL.create!(user_id: user_two.id, likes: 500) }
|
10
10
|
|
11
11
|
describe ".with/1" do
|
12
12
|
context "when using as a standalone query" do
|
13
13
|
it "should only return a person with less than 300 likes" do
|
14
|
-
query =
|
15
|
-
|
14
|
+
query = User.with(profile: ProfileL.where("likes < 300"))
|
15
|
+
.joins("JOIN profile ON profile.id = users.id")
|
16
16
|
|
17
|
-
expect(query).to match_array([
|
17
|
+
expect(query).to match_array([user_one])
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should return anyone with likes greater than or equal to 200" do
|
21
|
-
query =
|
22
|
-
|
21
|
+
query = User.with(profile: ProfileL.where("likes >= 200"))
|
22
|
+
.joins("JOIN profile ON profile.id = users.id")
|
23
23
|
|
24
|
-
expect(query).to match_array([
|
24
|
+
expect(query).to match_array([user_one, user_two])
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -31,9 +31,19 @@ RSpec.describe "Active Record With CTE Query Methods" do
|
|
31
31
|
|
32
32
|
it "will maintain the CTE table when merging into existing AR queries" do
|
33
33
|
sub_query = ProfileL.with(version_controls: VersionControl.where.contains(source: { help: "me" }))
|
34
|
-
query =
|
34
|
+
query = User.joins(profile_l: :version).merge(sub_query)
|
35
35
|
|
36
|
-
expect(query).to match_array([
|
36
|
+
expect(query).to match_array([user_one])
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should contain a unique list of ordered CTE keys when merging in multiple children" do
|
40
|
+
x = User.with(profile: ProfileL.where("likes < 300"))
|
41
|
+
y = User.with(profile: ProfileL.where("likes > 400"))
|
42
|
+
z = y.merge(x).joins("JOIN profile ON profile.id = users.id") # Y should reject X's CTE (FIFO)
|
43
|
+
query = User.with(my_profile: z).joins("JOIN my_profile ON my_profile.id = users.id")
|
44
|
+
|
45
|
+
expect(query.cte.with_keys).to eq([:profile, :my_profile])
|
46
|
+
expect(query).to match_array([user_two])
|
37
47
|
end
|
38
48
|
end
|
39
49
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -13,7 +13,7 @@ end
|
|
13
13
|
ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"])
|
14
14
|
|
15
15
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require File.expand_path(f) }
|
16
|
-
Dir["#{File.dirname(__FILE__)}/**/*examples.rb"].each { |f| require f }
|
16
|
+
Dir["#{File.dirname(__FILE__)}/**/*examples.rb"].sort.each { |f| require f }
|
17
17
|
|
18
18
|
RSpec.configure do |config|
|
19
19
|
# Enable flags like --only-failures and --next-failure
|
@@ -3,30 +3,30 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
5
|
RSpec.describe "Any / None of SQL Queries" do
|
6
|
-
let(:equal_query) { '"
|
7
|
-
let(:or_query) { 'OR "
|
8
|
-
let(:equal_or) { equal_query
|
9
|
-
let(:join_query) { /INNER JOIN
|
6
|
+
let(:equal_query) { '"users"."personal_id" = 1' }
|
7
|
+
let(:or_query) { 'OR "users"."personal_id" = 2' }
|
8
|
+
let(:equal_or) { "#{equal_query} #{or_query}" }
|
9
|
+
let(:join_query) { /INNER JOIN "tags" ON "tags"."user_id" = "users"."id/ }
|
10
10
|
|
11
11
|
describe "where.any_of/1" do
|
12
12
|
it "should group different column arguments into nested or conditions" do
|
13
|
-
query =
|
13
|
+
query = User.where.any_of({ personal_id: 1 }, { id: 2 }, { personal_id: 2 }).to_sql
|
14
14
|
expect(query).to match_regex(/WHERE \(\(.+ = 1 OR .+ = 2\) OR .+ = 2\)/)
|
15
15
|
end
|
16
16
|
|
17
17
|
it "Should assign where clause predicates for standard queries" do
|
18
|
-
query =
|
18
|
+
query = User.where.any_of({ personal_id: 1 }, { personal_id: 2 }).to_sql
|
19
19
|
expect(query).to include(equal_or)
|
20
20
|
|
21
|
-
personal_one =
|
22
|
-
personal_two =
|
23
|
-
query =
|
21
|
+
personal_one = User.where(personal_id: 1)
|
22
|
+
personal_two = User.where(personal_id: 2)
|
23
|
+
query = User.where.any_of(personal_one, personal_two).to_sql
|
24
24
|
expect(query).to include(equal_or)
|
25
25
|
end
|
26
26
|
|
27
27
|
it "Joining queries should be added to the select statement" do
|
28
|
-
|
29
|
-
query =
|
28
|
+
user_two_tag = User.where(personal_id: 1).joins(:hm_tags)
|
29
|
+
query = User.where.any_of(user_two_tag).to_sql
|
30
30
|
expect(query).to match_regex(join_query)
|
31
31
|
expect(query).to include(equal_query)
|
32
32
|
end
|
@@ -34,7 +34,7 @@ RSpec.describe "Any / None of SQL Queries" do
|
|
34
34
|
|
35
35
|
describe "where.none_of/1" do
|
36
36
|
it "Should surround the query in a WHERE NOT clause" do
|
37
|
-
query =
|
37
|
+
query = User.where.none_of({ personal_id: 1 }, { id: 2 }, { personal_id: 2 }).to_sql
|
38
38
|
expect(query).to match_regex(/WHERE.+NOT \(\(.+ = 1 OR .+ = 2\) OR .+ = 2\)/)
|
39
39
|
end
|
40
40
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Arel::Nodes::AggregateFunctionName do
|
6
|
+
describe "Custom Aggregate function" do
|
7
|
+
it "constructs an aggregate function based on a given name" do
|
8
|
+
query = described_class.new("MY_CUSTOM_AGG", [Arel.sql("id == me")])
|
9
|
+
expect(query.to_sql).to eq("MY_CUSTOM_AGG(id == me)")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can append multiple expressions" do
|
13
|
+
query = described_class.new("MY_CUSTOM_AGG", [Arel.sql("id == me"), Arel.sql("id == you")])
|
14
|
+
expect(query.to_sql).to eq("MY_CUSTOM_AGG(id == me, id == you)")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can append a distinct clause inside the aggregate" do
|
18
|
+
query = described_class.new("MY_CUSTOM_AGG", [Arel.sql("id == me")], true)
|
19
|
+
expect(query.to_sql).to eq("MY_CUSTOM_AGG(DISTINCT id == me)")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "can append an order by clause when providing a ordering expression" do
|
23
|
+
order_expr = Arel.sql("id").desc
|
24
|
+
query = described_class.new("MY_CUSTOM_AGG", [Arel.sql("id == me")], true).order_by([order_expr])
|
25
|
+
expect(query.to_sql).to eq("MY_CUSTOM_AGG(DISTINCT id == me ORDER BY id DESC)")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "can append multiple ordering clauses" do
|
29
|
+
expr = Arel.sql("id").desc
|
30
|
+
other_expr = Arel.sql("name").asc
|
31
|
+
query = described_class.new("MY_CUSTOM_AGG", [Arel.sql("id == me")], true).order_by([expr, other_expr])
|
32
|
+
expect(query.to_sql).to eq("MY_CUSTOM_AGG(DISTINCT id == me ORDER BY id DESC, name ASC)")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "can be aliased" do
|
36
|
+
alias_as = Arel.sql("new_name")
|
37
|
+
query = described_class.new("MY_CUSTOM_AGG", [Arel.sql("id == me")], true).as(alias_as)
|
38
|
+
expect(query.to_sql).to eq("MY_CUSTOM_AGG(DISTINCT id == me) AS new_name")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
5
|
RSpec.describe "Array Column Predicates" do
|
6
|
-
let(:arel_table) {
|
6
|
+
let(:arel_table) { User.arel_table }
|
7
7
|
|
8
8
|
describe "Array Overlap" do
|
9
9
|
it "converts Arel overlap statement" do
|
@@ -17,7 +17,7 @@ RSpec.describe "Array Column Predicates" do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it "works with count (and other predicates)" do
|
20
|
-
expect(
|
20
|
+
expect(User.where(arel_table[:tag_ids].overlap([1, 2])).count).to eq 0
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -33,31 +33,31 @@ RSpec.describe "Array Column Predicates" do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
it "works with count (and other predicates)" do
|
36
|
-
expect(
|
36
|
+
expect(User.where(arel_table[:tag_ids].contains([1, 2])).count).to eq 0
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
describe "Any Array Element" do
|
41
41
|
it "creates any predicates that contain a string value" do
|
42
42
|
query = arel_table.where(arel_table[:tags].any("tag")).to_sql
|
43
|
-
expect(query).to match_regex(/'tag' = ANY\("
|
43
|
+
expect(query).to match_regex(/'tag' = ANY\("users"\."tags"\)/)
|
44
44
|
end
|
45
45
|
|
46
46
|
it "creates any predicates that contain a integer value" do
|
47
47
|
query = arel_table.where(arel_table[:tags].any(2)).to_sql
|
48
|
-
expect(query).to match_regex(/2 = ANY\("
|
48
|
+
expect(query).to match_regex(/2 = ANY\("users"\."tags"\)/)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
describe "All Array Elements" do
|
53
53
|
it "create all predicates that contain a string value" do
|
54
54
|
query = arel_table.where(arel_table[:tags].all("tag")).to_sql
|
55
|
-
expect(query).to match_regex(/'tag' = ALL\("
|
55
|
+
expect(query).to match_regex(/'tag' = ALL\("users"\."tags"\)/)
|
56
56
|
end
|
57
57
|
|
58
58
|
it "create all predicates that contain a interger value" do
|
59
59
|
query = arel_table.where(arel_table[:tags].all(2)).to_sql
|
60
|
-
expect(query).to match_regex(/2 = ALL\("
|
60
|
+
expect(query).to match_regex(/2 = ALL\("users"\."tags"\)/)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|