active_record_extended 1.1.0 → 2.0.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 +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
|