active_record_extended 2.0.3 → 2.2.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -9
  3. data/lib/active_record_extended/active_record/relation_patch.rb +16 -4
  4. data/lib/active_record_extended/active_record.rb +6 -6
  5. data/lib/active_record_extended/arel/nodes.rb +1 -1
  6. data/lib/active_record_extended/arel/visitors/postgresql_decorator.rb +16 -12
  7. data/lib/active_record_extended/query_methods/any_of.rb +1 -1
  8. data/lib/active_record_extended/query_methods/either.rb +5 -3
  9. data/lib/active_record_extended/query_methods/unionize.rb +3 -3
  10. data/lib/active_record_extended/query_methods/where_chain.rb +5 -1
  11. data/lib/active_record_extended/query_methods/with_cte.rb +2 -2
  12. data/lib/active_record_extended/version.rb +1 -1
  13. metadata +11 -59
  14. data/lib/active_record_extended/patch/5_1/where_clause.rb +0 -11
  15. data/spec/active_record_extended_spec.rb +0 -7
  16. data/spec/query_methods/any_of_spec.rb +0 -131
  17. data/spec/query_methods/array_query_spec.rb +0 -64
  18. data/spec/query_methods/either_spec.rb +0 -70
  19. data/spec/query_methods/hash_query_spec.rb +0 -45
  20. data/spec/query_methods/inet_query_spec.rb +0 -112
  21. data/spec/query_methods/json_spec.rb +0 -157
  22. data/spec/query_methods/select_spec.rb +0 -115
  23. data/spec/query_methods/unionize_spec.rb +0 -165
  24. data/spec/query_methods/window_spec.rb +0 -51
  25. data/spec/query_methods/with_cte_spec.rb +0 -50
  26. data/spec/spec_helper.rb +0 -28
  27. data/spec/sql_inspections/any_of_sql_spec.rb +0 -41
  28. data/spec/sql_inspections/arel/aggregate_function_name_spec.rb +0 -41
  29. data/spec/sql_inspections/arel/array_spec.rb +0 -63
  30. data/spec/sql_inspections/arel/inet_spec.rb +0 -66
  31. data/spec/sql_inspections/contains_sql_queries_spec.rb +0 -47
  32. data/spec/sql_inspections/either_sql_spec.rb +0 -71
  33. data/spec/sql_inspections/json_sql_spec.rb +0 -82
  34. data/spec/sql_inspections/unionize_sql_spec.rb +0 -124
  35. data/spec/sql_inspections/window_sql_spec.rb +0 -98
  36. data/spec/sql_inspections/with_cte_sql_spec.rb +0 -95
  37. data/spec/support/database_cleaner.rb +0 -15
  38. data/spec/support/models.rb +0 -80
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Active Record Either Methods" do
6
- let!(:one) { User.create! }
7
- let!(:two) { User.create! }
8
- let!(:three) { User.create! }
9
- let!(:profile_l) { ProfileL.create!(user_id: one.id, likes: 100) }
10
- let!(:profile_r) { ProfileR.create!(user_id: two.id, dislikes: 50) }
11
-
12
- describe ".either_join/2" do
13
- it "Should only only return records that belong to profile L or profile R" do
14
- query = User.either_join(:profile_l, :profile_r)
15
- expect(query).to include(one, two)
16
- expect(query).to_not include(three)
17
- end
18
-
19
- context "Alias .either_joins/2" do
20
- it "Should only only return records that belong to profile L or profile R" do
21
- query = User.either_joins(:profile_l, :profile_r)
22
- expect(query).to include(one, two)
23
- expect(query).to_not include(three)
24
- end
25
- end
26
-
27
- context "Through association .either_joins/2" do
28
- let!(:four) { User.create! }
29
- let!(:group) { Group.create!(users: [four]) }
30
-
31
- it "Should only only return records that belong to profile L or has group" do
32
- query = User.either_joins(:profile_l, :groups)
33
- expect(query).to include(one, four)
34
- expect(query).to_not include(three, two)
35
- end
36
- end
37
- end
38
-
39
- describe ".either_order/2" do
40
- it "Should not exclude anyone who does not have a relationship" do
41
- query = User.either_order(:asc, profile_l: :likes, profile_r: :dislikes)
42
- expect(query.count).to eq(3)
43
- expect(query[0]).to eq(two)
44
- expect(query[1]).to eq(one)
45
- expect(query[2]).to eq(three)
46
- end
47
-
48
- it "Should order users based on their likes and dislikes in ascended order" do
49
- query = User.either_order(:asc, profile_l: :likes, profile_r: :dislikes).where(id: [one.id, two.id])
50
- expect(query.count).to eq(2)
51
- expect(query.first).to eq(two)
52
- expect(query.last).to eq(one)
53
- end
54
-
55
- it "Should order users based on their likes and dislikes in descending order" do
56
- query = User.either_order(:desc, profile_l: :likes, profile_r: :dislikes).where(id: [one.id, two.id])
57
- expect(query.first).to eq(one)
58
- expect(query.last).to eq(two)
59
- end
60
-
61
- context "Alias .either_order/2" do
62
- it "Should order users based on their likes and dislikes in ascended order" do
63
- query = User.either_orders(:asc, profile_l: :likes, profile_r: :dislikes).where(id: [one.id, two.id])
64
- expect(query.count).to eq(2)
65
- expect(query.first).to eq(two)
66
- expect(query.last).to eq(one)
67
- end
68
- end
69
- end
70
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Active Record Hash Related Query Methods" do
6
- let!(:one) { User.create!(data: { nickname: "george" }, jsonb_data: { payment: "zip" }) }
7
- let!(:two) { User.create!(data: { nickname: "dan" }, jsonb_data: { payment: "zipper" }) }
8
- let!(:three) { User.create!(data: { nickname: "georgey" }) }
9
-
10
- describe "#contains" do
11
- context "HStore Column Type" do
12
- it "returns records that contain hash elements in joined tables" do
13
- tag_one = Tag.create!(user_id: one.id)
14
- tag_two = Tag.create!(user_id: two.id)
15
-
16
- query = Tag.joins(:user).where.contains(users: { data: { nickname: "george" } })
17
- expect(query).to include(tag_one)
18
- expect(query).to_not include(tag_two)
19
- end
20
-
21
- it "returns records that contain hash value" do
22
- query = User.where.contains(data: { nickname: "george" })
23
- expect(query).to include(one)
24
- expect(query).to_not include(two, three)
25
- end
26
- end
27
-
28
- context "JSONB Column Type" do
29
- it "returns records that contains a json hashed value" do
30
- query = User.where.contains(jsonb_data: { payment: "zip" })
31
- expect(query).to include(one)
32
- expect(query).to_not include(two, three)
33
- end
34
-
35
- it "returns records that contain jsonb elements in joined tables" do
36
- tag_one = Tag.create!(user_id: one.id)
37
- tag_two = Tag.create!(user_id: two.id)
38
-
39
- query = Tag.joins(:user).where.contains(users: { jsonb_data: { payment: "zip" } })
40
- expect(query).to include(tag_one)
41
- expect(query).to_not include(tag_two)
42
- end
43
- end
44
- end
45
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Active Record Inet Query Methods" do
6
- before { stub_const("User", Namespaced::Record) }
7
-
8
- describe "#inet_contained_within" do
9
- let!(:local_1) { User.create!(ip: "127.0.0.1") }
10
- let!(:local_44) { User.create!(ip: "127.0.0.44") }
11
- let!(:local_99_1) { User.create!(ip: "127.0.99.1") }
12
- let!(:local_range) { User.create!(ip: "127.0.0.1/10") }
13
-
14
- it "Should return users who have an IP within the 127.0.0.1/24 range" do
15
- query = User.where.inet_contained_within(ip: "127.0.0.1/24")
16
- expect(query).to include(local_1, local_44)
17
- expect(query).to_not include(local_99_1, local_range)
18
- end
19
-
20
- it "Should return all users who have an IP within the 127.0.0.1/16 range" do
21
- query = User.where.inet_contained_within(ip: "127.0.0.1/16")
22
- expect(query).to include(local_1, local_44, local_99_1)
23
- expect(query).to_not include(local_range)
24
- end
25
- end
26
-
27
- describe "inet_contained_within_or_equals" do
28
- let!(:local_1) { User.create!(ip: "127.0.0.1/10") }
29
- let!(:local_44) { User.create!(ip: "127.0.0.44/32") }
30
- let!(:local_99_1) { User.create!(ip: "127.0.99.1") }
31
-
32
- it "Should find records that contain a matching submask" do
33
- query = User.where.inet_contained_within_or_equals(ip: "127.0.0.44/32")
34
- expect(query).to include(local_44)
35
- expect(query).to_not include(local_1, local_99_1)
36
- end
37
-
38
- it "Should find records that are within range of a given submask" do
39
- query = User.where.inet_contained_within_or_equals(ip: "127.0.0.1/16")
40
- expect(query).to include(local_44, local_99_1)
41
- expect(query).to_not include(local_1)
42
-
43
- query = User.where.inet_contained_within_or_equals(ip: "127.0.0.1/8")
44
- expect(query).to include(local_1, local_44, local_99_1)
45
- end
46
- end
47
-
48
- describe "#inet_contains_or_equals" do
49
- let!(:local_1) { User.create!(ip: "127.0.0.1/10") }
50
- let!(:local_44) { User.create!(ip: "127.0.0.44/24") }
51
- let!(:local_99_1) { User.create!(ip: "127.0.99.1") }
52
-
53
- it "Should find records with submask ranges that contain a given IP" do
54
- query = User.where.inet_contains_or_equals(ip: "127.0.255.255")
55
- expect(query).to include(local_1)
56
- expect(query).to_not include(local_44, local_99_1)
57
-
58
- query = User.where.inet_contains_or_equals(ip: "127.0.0.255")
59
- expect(query).to include(local_1, local_44)
60
- expect(query).to_not include(local_99_1)
61
- end
62
-
63
- it "Finds records when querying with a submasked value" do
64
- query = User.where.inet_contains_or_equals(ip: "127.0.0.1/10")
65
- expect(query).to include(local_1)
66
- expect(query).to_not include(local_44, local_99_1)
67
-
68
- query = User.where.inet_contains_or_equals(ip: "127.0.0.1/32")
69
- expect(query).to include(local_1, local_44)
70
- expect(query).to_not include(local_99_1)
71
- end
72
- end
73
-
74
- describe "#inet_contains" do
75
- let!(:local_1) { User.create!(ip: "127.0.0.1/10") }
76
- let!(:local_44) { User.create!(ip: "127.0.0.44/24") }
77
-
78
- it "Should find records that the given IP falls within" do
79
- query = User.where.inet_contains(ip: "127.0.0.1")
80
- expect(query).to include(local_1, local_44)
81
- end
82
-
83
- it "Should not find records when querying with a submasked value" do
84
- query = User.where.inet_contains(ip: "127.0.0.0/8")
85
- expect(query).to be_empty
86
- end
87
- end
88
-
89
- describe "#inet_contains_or_is_contained_within" do
90
- let!(:local_1) { User.create!(ip: "127.0.0.1/24") }
91
- let!(:local_44) { User.create!(ip: "127.0.22.44/8") }
92
- let!(:local_99_1) { User.create!(ip: "127.0.99.1") }
93
-
94
- it "should find records where the records contain the given IP" do
95
- query = User.where.inet_contains_or_is_contained_within(ip: "127.0.255.80")
96
- expect(query).to include(local_44)
97
- expect(query).to_not include(local_1, local_99_1)
98
-
99
- query = User.where.inet_contains_or_is_contained_within(ip: "127.0.0.80")
100
- expect(query).to include(local_1, local_44)
101
- expect(query).to_not include(local_99_1)
102
- end
103
-
104
- it "Should find records that the where query contains a valid range" do
105
- query = User.where.inet_contains_or_is_contained_within(ip: "127.0.0.80/8")
106
- expect(query).to include(local_1, local_44, local_99_1)
107
-
108
- query = User.where.inet_contains_or_is_contained_within(ip: "127.0.0.80/16")
109
- expect(query).to include(local_1, local_44, local_99_1)
110
- end
111
- end
112
- end
@@ -1,157 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe "Active Record JSON methods" do
4
- let!(:user_one) { User.create! }
5
- let!(:user_two) { User.create! }
6
-
7
- describe ".select_row_to_json" do
8
- let!(:tag_one) { Tag.create!(user: user_one, tag_number: 2) }
9
- let!(:tag_two) { Tag.create!(user: user_two, tag_number: 5) }
10
- let(:sub_query) { Tag.select(:tag_number).where("tags.user_id = users.id") }
11
-
12
- it "should nest a json object in the query results" do
13
- query = User.select(:id).select_row_to_json(sub_query, as: :results).where(id: user_one.id)
14
- expect(query.size).to eq(1)
15
- expect(query.take.results).to be_a(Hash).and(match("tag_number" => 2))
16
- end
17
-
18
- # ugh wording here sucks, brain is fried.
19
- it "accepts a block for appending additional scopes to the middle-top level" do
20
- query = User.select(:id).select_row_to_json(sub_query, key: :tag_row, as: :results) do |scope|
21
- scope.where("tag_row.tag_number = 5")
22
- end
23
-
24
- expect(query.size).to eq(2)
25
- query.each do |result|
26
- if result.id == user_one.id
27
- expect(result.results).to be_blank
28
- else
29
- expect(result.results).to be_present.and(match("tag_number" => 5))
30
- end
31
- end
32
- end
33
-
34
- it "accepts a scope-block without arguments" do
35
- query = User.select(:id).select_row_to_json(sub_query, key: :tag_row, as: :results) do
36
- where("tag_row.tag_number = 5")
37
- end
38
-
39
- expect(query.size).to eq(2)
40
- query.each do |result|
41
- if result.id == user_one.id
42
- expect(result.results).to be_blank
43
- else
44
- expect(result.results).to be_present.and(match("tag_number" => 5))
45
- end
46
- end
47
- end
48
-
49
- it "allows for casting results in an aggregate-able Array function" do
50
- query = User.select(:id).select_row_to_json(sub_query, key: :tag_row, as: :results, cast_with: :array)
51
- expect(query.take.results).to be_a(Array).and(be_present)
52
- expect(query.take.results.first).to be_a(Hash)
53
- end
54
-
55
- it "raises an error if a from clause key is missing" do
56
- expect do
57
- User.select(:id).select_row_to_json(key: :tag_row, as: :results)
58
- end.to raise_error(ArgumentError)
59
- end
60
- end
61
-
62
- describe ".json_build_object" do
63
- let(:sub_query) do
64
- User.select_row_to_json(from: User.select(:id), cast_with: :array, as: :ids).where(id: user_one.id)
65
- end
66
-
67
- it "defaults the column alias if one is not provided" do
68
- query = User.json_build_object(:personal, sub_query)
69
- expect(query.size).to eq(1)
70
- expect(query.take.results).to match(
71
- "personal" => match("ids" => match_array([{ "id" => user_one.id }, { "id" => user_two.id }]))
72
- )
73
- end
74
-
75
- it "allows for re-aliasing the default 'results' column" do
76
- query = User.json_build_object(:personal, sub_query, as: :cool_dudes)
77
- expect(query.take).to respond_to(:cool_dudes)
78
- end
79
- end
80
-
81
- describe ".jsonb_build_object" do
82
- let(:sub_query) { User.select(:id, :number).where(id: user_one.id) }
83
-
84
- it "defaults the column alias if one is not provided" do
85
- query = User.jsonb_build_object(:personal, sub_query)
86
- expect(query.size).to eq(1)
87
- expect(query.take.results).to be_a(Hash).and(be_present)
88
- expect(query.take.results).to match("personal" => match("id" => user_one.id, "number" => user_one.number))
89
- end
90
-
91
- it "allows for re-aliasing the default 'results' column" do
92
- query = User.jsonb_build_object(:personal, sub_query, as: :cool_dudes)
93
- expect(query.take).to respond_to(:cool_dudes)
94
- end
95
-
96
- it "allows for custom value statement" do
97
- query = User.jsonb_build_object(
98
- :personal,
99
- sub_query.where.not(id: user_one),
100
- value: "COALESCE(array_agg(\"personal\"), '{}')",
101
- as: :cool_dudes
102
- )
103
-
104
- expect(query.take.cool_dudes["personal"]).to be_a(Array).and(be_empty)
105
- end
106
-
107
- it "will raise a warning if the value doesn't include a double quoted input" do
108
- expect do
109
- User.jsonb_build_object(
110
- :personal,
111
- sub_query.where.not(id: user_one),
112
- value: "COALESCE(array_agg(personal), '{}')",
113
- as: :cool_dudes
114
- )
115
- end.to output.to_stderr
116
- end
117
- end
118
-
119
- describe "Json literal builds" do
120
- let(:original_hash) { { p: 1, b: "three", x: 3.14 } }
121
- let(:hash_as_array_objs) { original_hash.to_a.flatten }
122
-
123
- shared_examples_for "literal builds" do
124
- let(:method) { raise "You are expected to over ride this!" }
125
-
126
- it "will accept a hash arguments that will return itself" do
127
- query = User.send(method.to_sym, original_hash)
128
- expect(query.take.results).to be_a(Hash).and(be_present)
129
- expect(query.take.results).to match(original_hash.stringify_keys)
130
- end
131
-
132
- it "will accept a standard array of key values" do
133
- query = User.send(method.to_sym, hash_as_array_objs)
134
- expect(query.take.results).to be_a(Hash).and(be_present)
135
- expect(query.take.results).to match(original_hash.stringify_keys)
136
- end
137
-
138
- it "will accept a splatted array of key-values" do
139
- query = User.send(method.to_sym, *hash_as_array_objs)
140
- expect(query.take.results).to be_a(Hash).and(be_present)
141
- expect(query.take.results).to match(original_hash.stringify_keys)
142
- end
143
- end
144
-
145
- describe ".json_build_literal" do
146
- it_behaves_like "literal builds" do
147
- let!(:method) { :json_build_literal }
148
- end
149
- end
150
-
151
- describe ".jsonb_build_literal" do
152
- it_behaves_like "literal builds" do
153
- let!(:method) { :jsonb_build_literal }
154
- end
155
- end
156
- end
157
- end
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Active Record Select Methods" do
6
- let(:numbers) { (1..10).to_a }
7
-
8
- describe ".foster_select" do
9
- context "with an aggregate function" do
10
- context "agg_array" do
11
- let(:number_set) { numbers.sample(6).to_enum }
12
- let!(:users) { Array.new(6) { User.create!(number: number_set.next, ip: "127.0.0.1") } }
13
- let!(:tags) { users.flat_map { |u| Array.new(2) { Tag.create!(user: u, tag_number: numbers.sample) } } }
14
-
15
- it "can accept a subquery" do
16
- subquery = Tag.select("count(*)").joins("JOIN users u ON tags.user_id = u.id").where("u.ip = users.ip")
17
- query =
18
- User.foster_select(tag_count: [subquery, { cast_with: :array_agg, distinct: true }])
19
- .joins(:hm_tags)
20
- .group(:ip)
21
- .take
22
-
23
- expect(query.tag_count).to eq([tags.size])
24
- end
25
-
26
- it "can be ordered" do
27
- query = User.foster_select(
28
- asc_ordered_numbers: [:number, { cast_with: :array_agg, order_by: { number: :asc } }],
29
- desc_ordered_numbers: [:number, { cast_with: :array_agg, order_by: { number: :desc } }]
30
- ).take
31
-
32
- expect(query.asc_ordered_numbers).to eq(number_set.to_a.sort)
33
- expect(query.desc_ordered_numbers).to eq(number_set.to_a.sort.reverse)
34
- end
35
-
36
- it "works with joined relations" do
37
- query =
38
- User.foster_select(tag_numbers: { tags: :tag_number, cast_with: :array_agg })
39
- .joins(:hm_tags)
40
- .take
41
- expect(query.tag_numbers).to match_array(Tag.pluck(:tag_number))
42
- end
43
- end
44
-
45
- context "bool_[and|or]" do
46
- let!(:users) do
47
- enum_numbers = numbers.to_enum
48
- Array.new(6) { User.create!(number: enum_numbers.next, ip: "127.0.0.1") }
49
- end
50
-
51
- it "will return a boolean expression" do
52
- query = User.foster_select(
53
- truthly_expr: ["users.number > 0", { cast_with: :bool_and }],
54
- falsey_expr: ["users.number > 200", { cast_with: :bool_and }],
55
- other_true_expr: ["users.number > 4", { cast_with: :bool_or }],
56
- other_false_expr: ["users.number > 6", { cast_with: :bool_or }]
57
- ).take
58
-
59
- expect(query.truthly_expr).to be_truthy
60
- expect(query.falsey_expr).to be_falsey
61
- expect(query.other_true_expr).to be_truthy
62
- expect(query.other_false_expr).to be_falsey
63
- end
64
- end
65
-
66
- context "with math functions: sum|max|min|avg" do
67
- before { 2.times.flat_map { |i| Array.new(2) { |j| User.create!(number: (i + 1) * j + 3) } } }
68
-
69
- it "max" do
70
- query = User.foster_select(max_num: [:number, { cast_with: :max }]).take
71
- expect(query.max_num).to eq(5)
72
- end
73
-
74
- it "min" do
75
- query = User.foster_select(max_num: [:number, { cast_with: :min }]).take
76
- expect(query.max_num).to eq(3)
77
- end
78
-
79
- it "sum" do
80
- query = User.foster_select(
81
- num_sum: [:number, { cast_with: :sum }],
82
- distinct_sum: [:number, { cast_with: :sum, distinct: true }]
83
- ).take
84
-
85
- expect(query.num_sum).to eq(15)
86
- expect(query.distinct_sum).to eq(12)
87
- end
88
-
89
- it "avg" do
90
- query = User.foster_select(
91
- num_avg: [:number, { cast_with: :avg }],
92
- distinct_avg: [:number, { cast_with: :avg, distinct: true }]
93
- ).take
94
-
95
- expect(query.num_avg).to eq(3.75)
96
- expect(query.distinct_avg).to eq(4.0)
97
- end
98
- end
99
- end
100
-
101
- context "with standard select items" do
102
- let!(:user) { User.create!(name: "Test") }
103
-
104
- it "works with no alias" do
105
- query = User.foster_select(:name).take
106
- expect(query.name).to eq(user.name)
107
- end
108
-
109
- it "works with alias" do
110
- query = User.foster_select(my_name: :name).take
111
- expect(query.my_name).to eq(user.name)
112
- end
113
- end
114
- end
115
- end
@@ -1,165 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Active Record Union Methods" do
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
-
12
- shared_examples_for "standard set of errors" do
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
- let(:misaligned_cmd) { raise("required to override this 'let' statement") }
16
- let(:lacking_union_cmd) { raise("required to override this 'let' statement") }
17
-
18
- it "should raise an error if the select statements do not align" do
19
- expect { misaligned_cmd.to_a }.to(
20
- raise_error(ActiveRecord::StatementInvalid, /each [[:alpha:]]+ query must have the same number of columns/)
21
- )
22
- end
23
-
24
- it "should raise an argument error if there are less then two union statements" do
25
- expect { lacking_union_cmd.to_a }.to(
26
- raise_error(ArgumentError, "You are required to provide 2 or more unions to join!")
27
- )
28
- end
29
- end
30
-
31
- describe ".union" do
32
- it_behaves_like "standard set of errors" do
33
- let!(:misaligned_cmd) { User.union(user_one_query, user_two_query) }
34
- let!(:lacking_union_cmd) { User.union(user_one_query) }
35
- end
36
-
37
- it "should return two users that match the where conditions" do
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
- end
41
-
42
- it "should allow joins on union statements" do
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
- end
46
-
47
- it "should eliminate duplicate results" do
48
- expected_ids = User.pluck(:id)
49
- query = User.union(User.select(:id), User.select(:id))
50
- expect(query.pluck(:id)).to have_attributes(size: expected_ids.size).and(match_array(expected_ids))
51
- end
52
- end
53
-
54
- describe ".union.all" do
55
- it_behaves_like "standard set of errors" do
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
- end
59
-
60
- it "should keep duplicate results from each union statement" do
61
- expected_ids = User.pluck(:id) * 2
62
- query = User.union.all(User.select(:id), User.select(:id))
63
- expect(query.pluck(:id)).to have_attributes(size: expected_ids.size).and(match_array(expected_ids))
64
- end
65
- end
66
-
67
- describe ".union.except" do
68
- it_behaves_like "standard set of errors" do
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
- end
72
-
73
- it "should eliminate records that match a given except statement" do
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
- end
77
- end
78
-
79
- describe "union.intersect" do
80
- it_behaves_like "standard set of errors" do
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
- end
84
-
85
- it "should find records with similar attributes" do
86
- ProfileL.create!(user: user_three, likes: 120)
87
-
88
- query =
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
- )
93
-
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
- end
97
- end
98
-
99
- describe "union.as" do
100
- let(:query) do
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)
105
- end
106
-
107
- it "should return two users" do
108
- expect(query.size).to eq(2)
109
- end
110
-
111
- it "should return two userss id's" do
112
- expect(query.map(&:id)).to match_array([user_one.id, user_three.id])
113
- end
114
-
115
- it "should alias the tables being union'd but still allow for accessing table methods" do
116
- query.each do |happy_person|
117
- expect(happy_person).to respond_to(:profile_l)
118
- end
119
- end
120
- end
121
-
122
- describe "union.order_union" do
123
- it "should order the .union commands" do
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])
126
- end
127
-
128
- it "should order the .union.all commands" do
129
- query =
130
- User.union.all(
131
- User.where(id: user_one.id),
132
- User.where(id: user_three.id)
133
- ).order_union(id: :desc)
134
-
135
- expect(query).to eq([user_three, user_one])
136
- end
137
-
138
- it "should order the union.except commands" do
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])
141
- end
142
-
143
- it "should order the .union.intersect commands" do
144
- query =
145
- User.union.intersect(
146
- User.where("id < ?", user_three.id),
147
- User.where("id >= ?", user_one.id)
148
- ).order_union(id: :desc)
149
-
150
- expect(query).to eq([user_two, user_one])
151
- end
152
- end
153
-
154
- describe "union.reorder_union" do
155
- it "should replace the ordering with the new parameters" do
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
-
161
- expect(query).to eq(initial_ordering)
162
- expect(query.reorder_union(number: :asc)).to eq(initial_ordering.reverse)
163
- end
164
- end
165
- end