active_record_extended 0.7.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "JSON Methods SQL Queries" do
6
+ let(:single_with) { /^WITH .all_others. AS(?!.*WITH \w?)/mi }
7
+ let(:override_with) { /^WITH .all_others. AS \(.+WHERE .people.\..id. = 10\)/mi }
8
+
9
+ describe ".select_row_to_json" do
10
+ context "when a subquery contains a CTE table" do
11
+ let(:cte_person) { Person.with(all_others: Person.where.not(id: 1)).where(id: 2) }
12
+
13
+ it "should push the CTE to the callee's level" do
14
+ query = Person.select_row_to_json(cte_person, as: :results).to_sql
15
+ expect(query).to match_regex(single_with)
16
+ end
17
+
18
+ it "should favor the parents CTE table if names collide" do
19
+ query = Person.with(all_others: Person.where(id: 10))
20
+ query = query.select_row_to_json(cte_person, as: :results).to_sql
21
+
22
+ expect(query).to match_regex(single_with)
23
+ expect(query).to match_regex(override_with)
24
+ end
25
+ end
26
+ end
27
+
28
+ describe ".json_build_object" do
29
+ context "when a subquery contains a CTE table" do
30
+ let(:cte_person) { Person.with(all_others: Person.where.not(id: 1)).where(id: 2) }
31
+
32
+ it "should push the CTE to the callee's level" do
33
+ query = Person.json_build_object(:peoples, cte_person).to_sql
34
+ expect(query).to match_regex(single_with)
35
+ end
36
+
37
+ it "should favor the parents CTE table if names collide" do
38
+ query = Person.with(all_others: Person.where(id: 10))
39
+ query = query.json_build_object(:peoples, cte_person).to_sql
40
+
41
+ expect(query).to match_regex(single_with)
42
+ expect(query).to match_regex(override_with)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Union SQL Queries" do
6
+ let(:person) { Person.where(id: 1) }
7
+ let(:other_person) { Person.where("id = 2") }
8
+
9
+ shared_examples_for "unions" do
10
+ it { is_expected.to eq("( (#{person.to_sql}) #{described_union} (#{other_person.to_sql}) )") }
11
+ end
12
+
13
+ shared_examples_for "piping nest CTE tables" do
14
+ let(:cte_person) { Person.with(all_others: Person.where.not(id: 1)).where(id: 2) }
15
+ let(:method) { raise "Required to override this method!" }
16
+ let(:single_with) { /^WITH .all_others. AS(?!.*WITH \w?)/mi }
17
+ let(:override_with) { /^WITH .all_others. AS \(.+WHERE .people.\..id. = 10\)/mi }
18
+
19
+ it "should push the CTE to the callee's level" do
20
+ query = Person.send(method.to_sym, cte_person, other_person).to_sql
21
+ expect(query).to match_regex(single_with)
22
+ end
23
+
24
+ it "should favor the parents CTE table if names collide" do
25
+ query = Person.with(all_others: Person.where(id: 10))
26
+ query = query.send(method.to_sym, cte_person, other_person).to_sql
27
+
28
+ expect(query).to match_regex(single_with)
29
+ expect(query).to match_regex(override_with)
30
+ end
31
+ end
32
+
33
+ describe ".union" do
34
+ let!(:described_union) { "UNION" }
35
+ subject(:described_method) { Person.union(person, other_person).to_union_sql }
36
+ it_behaves_like "unions"
37
+ it_behaves_like "piping nest CTE tables" do
38
+ let!(:method) { :union }
39
+ end
40
+ end
41
+
42
+ describe ".union.all" do
43
+ let!(:described_union) { "UNION ALL" }
44
+ subject(:described_method) { Person.union.all(person, other_person).to_union_sql }
45
+ it_behaves_like "unions"
46
+ it_behaves_like "piping nest CTE tables" do
47
+ let!(:method) { :union_all }
48
+ end
49
+ end
50
+
51
+ describe ".union.except" do
52
+ let!(:described_union) { "EXCEPT" }
53
+ subject(:described_method) { Person.union.except(person, other_person).to_union_sql }
54
+ it_behaves_like "unions"
55
+ it_behaves_like "piping nest CTE tables" do
56
+ let!(:method) { :union_except }
57
+ end
58
+ end
59
+
60
+ describe "union.intersect" do
61
+ let!(:described_union) { "INTERSECT" }
62
+ subject(:described_method) { Person.union.intersect(person, other_person).to_union_sql }
63
+ it_behaves_like "unions"
64
+ it_behaves_like "piping nest CTE tables" do
65
+ let!(:method) { :union_intersect }
66
+ end
67
+ end
68
+
69
+ describe "union.as" do
70
+ context "when a union.as has been called" do
71
+ subject(:described_method) do
72
+ Person.select("happy_people.id").union(person, other_person).union.as(:happy_people).to_sql
73
+ end
74
+
75
+ it "should alias the union from clause to 'happy_people'" do
76
+ expect(described_method).to match_regex(/FROM \(+.+\) UNION \(.+\)+ happy_people$/)
77
+ expect(described_method).to match_regex(/^SELECT happy_people\.id FROM.+happy_people$/)
78
+ end
79
+ end
80
+
81
+ context "when user.as hasn't been called" do
82
+ subject(:described_method) { Person.select(:id).union(person, other_person).to_sql }
83
+
84
+ it "should retain the actual class calling table name as the union alias" do
85
+ expect(described_method).to match_regex(/FROM \(+.+\) UNION \(.+\)+ people$/)
86
+ expect(described_method).to match_regex(/^SELECT \"people\"\.\"id\" FROM.+people$/)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "union.order" do
92
+ context "when rendering with .to_union_sql" do
93
+ subject(:described_method) { Person.union(person, other_person).union.order(:id, name: :desc).to_union_sql }
94
+
95
+ it "Should append an 'ORDER BY' to the end of the union statements" do
96
+ expect(described_method).to match_regex(/^\(+.+\) UNION \(.+\) \) ORDER BY id, name DESC$/)
97
+ end
98
+ end
99
+
100
+ context "when rendering with .to_sql" do
101
+ subject(:described_method) { Person.union(person, other_person).union.order(:id, name: :desc).to_sql }
102
+
103
+ it "Should append an 'ORDER BY' to the end of the union statements" do
104
+ expect(described_method).to match_regex(/FROM \(+.+\) UNION \(.+\) \) ORDER BY id, name DESC\) people$/)
105
+ end
106
+ end
107
+
108
+ context "when a there are multiple union statements" do
109
+ let(:query_regex) { /(?<=\)\s(ORDER BY)) id/ }
110
+
111
+ it "should only append an order by to the very end of a union statements" do
112
+ query = Person.union.order(id: :asc, tags: :desc)
113
+ .union(person.order(id: :asc, tags: :desc))
114
+ .union(person.order(:id, :tags))
115
+ .union(other_person.order(id: :desc, tags: :desc))
116
+ .to_union_sql
117
+
118
+ index = query.index(query_regex)
119
+ expect(index).to be_truthy
120
+ expect(query[index..-1]).to eq(" id ASC, tags DESC")
121
+ end
122
+ end
123
+ end
124
+ end
@@ -1,25 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Person < ActiveRecord::Base
3
+ class ApplicationRecord < ActiveRecord::Base
4
+ self.abstract_class = true
5
+ end
6
+
7
+ class Person < ApplicationRecord
4
8
  has_many :hm_tags, class_name: "Tag"
5
9
  has_one :profile_l, class_name: "ProfileL"
6
10
  has_one :profile_r, class_name: "ProfileR"
11
+ # attributes
12
+ # t.string "tags", array: true
13
+ # t.integer "number", default: 0
14
+ # t.integer "personal_id"
15
+ # t.hstore "data"
16
+ # t.jsonb "jsonb_data"
17
+ # t.inet "ip"
18
+ # t.cidr "subnet"
19
+ #
7
20
  end
8
21
 
9
- class Tag < ActiveRecord::Base
22
+ class Tag < ApplicationRecord
10
23
  belongs_to :person
24
+ # attributes: tag_number
11
25
  end
12
26
 
13
- class ProfileL < ActiveRecord::Base
27
+ class ProfileL < ApplicationRecord
14
28
  belongs_to :person
15
29
  has_one :version, as: :versionable, class_name: "VersionControl"
30
+ # attributes
31
+ # t.integer :likes
32
+ #
16
33
  end
17
34
 
18
- class ProfileR < ActiveRecord::Base
35
+ class ProfileR < ApplicationRecord
19
36
  belongs_to :person
20
37
  has_one :version, as: :versionable, class_name: "VersionControl"
38
+ # attributes
39
+ # t.integer :dislikes
40
+ #
21
41
  end
22
42
 
23
- class VersionControl < ActiveRecord::Base
43
+ class VersionControl < ApplicationRecord
24
44
  belongs_to :versionable, polymorphic: true, optional: false
45
+ # attributes
46
+ # t.jsonb :source, default: {}, null: false
47
+ #
25
48
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_extended
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Protacio-Karaszi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-09-22 00:00:00.000000000 Z
13
+ date: 2019-03-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -70,16 +70,22 @@ dependencies:
70
70
  name: bundler
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '1.16'
76
+ - - "<"
77
+ - !ruby/object:Gem::Version
78
+ version: '2.1'
76
79
  type: :development
77
80
  prerelease: false
78
81
  version_requirements: !ruby/object:Gem::Requirement
79
82
  requirements:
80
- - - "~>"
83
+ - - ">="
81
84
  - !ruby/object:Gem::Version
82
85
  version: '1.16'
86
+ - - "<"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.1'
83
89
  - !ruby/object:Gem::Dependency
84
90
  name: database_cleaner
85
91
  requirement: !ruby/object:Gem::Requirement
@@ -148,6 +154,7 @@ files:
148
154
  - README.md
149
155
  - lib/active_record_extended.rb
150
156
  - lib/active_record_extended/active_record.rb
157
+ - lib/active_record_extended/active_record/relation_patch.rb
151
158
  - lib/active_record_extended/arel.rb
152
159
  - lib/active_record_extended/arel/nodes.rb
153
160
  - lib/active_record_extended/arel/predications.rb
@@ -159,8 +166,11 @@ files:
159
166
  - lib/active_record_extended/query_methods/any_of.rb
160
167
  - lib/active_record_extended/query_methods/either.rb
161
168
  - lib/active_record_extended/query_methods/inet.rb
169
+ - lib/active_record_extended/query_methods/json.rb
170
+ - lib/active_record_extended/query_methods/unionize.rb
162
171
  - lib/active_record_extended/query_methods/where_chain.rb
163
172
  - lib/active_record_extended/query_methods/with_cte.rb
173
+ - lib/active_record_extended/utilities.rb
164
174
  - lib/active_record_extended/version.rb
165
175
  - spec/active_record_extended_spec.rb
166
176
  - spec/query_methods/any_of_spec.rb
@@ -168,6 +178,8 @@ files:
168
178
  - spec/query_methods/either_spec.rb
169
179
  - spec/query_methods/hash_query_spec.rb
170
180
  - spec/query_methods/inet_query_spec.rb
181
+ - spec/query_methods/json_spec.rb
182
+ - spec/query_methods/unionize_spec.rb
171
183
  - spec/query_methods/with_cte_spec.rb
172
184
  - spec/spec_helper.rb
173
185
  - spec/sql_inspections/any_of_sql_spec.rb
@@ -175,6 +187,8 @@ files:
175
187
  - spec/sql_inspections/arel/inet_spec.rb
176
188
  - spec/sql_inspections/contains_sql_queries_spec.rb
177
189
  - spec/sql_inspections/either_sql_spec.rb
190
+ - spec/sql_inspections/json_sql_spec.rb
191
+ - spec/sql_inspections/unionize_sql_spec.rb
178
192
  - spec/sql_inspections/with_cte_sql_spec.rb
179
193
  - spec/support/database_cleaner.rb
180
194
  - spec/support/models.rb
@@ -209,6 +223,8 @@ test_files:
209
223
  - spec/query_methods/either_spec.rb
210
224
  - spec/query_methods/hash_query_spec.rb
211
225
  - spec/query_methods/inet_query_spec.rb
226
+ - spec/query_methods/json_spec.rb
227
+ - spec/query_methods/unionize_spec.rb
212
228
  - spec/query_methods/with_cte_spec.rb
213
229
  - spec/spec_helper.rb
214
230
  - spec/sql_inspections/any_of_sql_spec.rb
@@ -216,6 +232,8 @@ test_files:
216
232
  - spec/sql_inspections/arel/inet_spec.rb
217
233
  - spec/sql_inspections/contains_sql_queries_spec.rb
218
234
  - spec/sql_inspections/either_sql_spec.rb
235
+ - spec/sql_inspections/json_sql_spec.rb
236
+ - spec/sql_inspections/unionize_sql_spec.rb
219
237
  - spec/sql_inspections/with_cte_sql_spec.rb
220
238
  - spec/support/database_cleaner.rb
221
239
  - spec/support/models.rb