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,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Active Record WINDOW Query inspection" do
6
- describe "#define_window" do
7
- context "when there is a single defined window" do
8
- it "should only contain a single defined window statement at the bottom" do
9
- query = Tag.define_window(:w_test).partition_by(:user_id).to_sql
10
- expect(query).to eq('SELECT "tags".* FROM "tags" WINDOW w_test AS (PARTITION BY user_id)')
11
- end
12
-
13
- it "should return a single defined window with a defined ORDER BY" do
14
- query = Tag.define_window(:w_test).partition_by(:user_id, order_by: { tags: { user_id: :desc } }).to_sql
15
- expect(query).to end_with("WINDOW w_test AS (PARTITION BY user_id ORDER BY tags.user_id DESC)")
16
- end
17
-
18
- it "should place the window function below the WHERE and GROUP BY statements" do
19
- query = Tag.define_window(:w_test).partition_by(:user_id).where(id: 1).group(:user_id).to_sql
20
- expect(query).to eq('SELECT "tags".* FROM "tags" WHERE "tags"."id" = 1 GROUP BY "tags"."user_id" WINDOW w_test AS (PARTITION BY user_id)')
21
- end
22
- end
23
-
24
- context "when there are multiple defined windows" do
25
- it "should only contain a single defined window statement at the bottom" do
26
- query =
27
- Tag
28
- .define_window(:test).partition_by(:user_id)
29
- .define_window(:other_window).partition_by(:id)
30
- .to_sql
31
-
32
- expect(query).to end_with("WINDOW test AS (PARTITION BY user_id), other_window AS (PARTITION BY id)")
33
- end
34
-
35
- it "should contain each windows order by statements" do
36
- query =
37
- Tag
38
- .define_window(:test).partition_by(:user_id, order_by: :id)
39
- .define_window(:other_window).partition_by(:id, order_by: { tags: :user_id })
40
- .to_sql
41
-
42
- expect(query).to end_with("WINDOW test AS (PARTITION BY user_id ORDER BY id), other_window AS (PARTITION BY id ORDER BY tags.user_id ASC)")
43
- end
44
- end
45
- end
46
-
47
- describe "#window_select" do
48
- let(:query_base) { Tag.define_window(:w).partition_by(:user_id, order_by: :id) }
49
- let(:expected_end) { "WINDOW w AS (PARTITION BY user_id ORDER BY id)" }
50
-
51
- context "when using no argument window methods" do
52
- [:row_to_number, :rank, :dense_rank, :percent_rank, :cume_dist].each do |window_function|
53
- context "#{window_function.to_s.upcase}()" do
54
- let(:expected_function) { "#{window_function.to_s.upcase}()" }
55
- let(:query) do
56
- query_base.select_window(window_function, over: :w, as: :window_response).to_sql
57
- end
58
-
59
- it "appends the function to the select query" do
60
- expected_start = "SELECT (#{expected_function} OVER w) AS \"window_response\""
61
- expect(query).to start_with(expected_start).and(end_with(expected_end))
62
- end
63
- end
64
- end
65
- end
66
-
67
- context "when using an argument based window method" do
68
- let(:argument_list) { ["a", 1, :sauce] }
69
-
70
- { ntile: 1, lag: 2, lead: 3, first_value: 1, last_value: 1, nth_value: 2 }.each_pair do |window_function, arg_count|
71
- context "#{window_function.to_s.upcase}/#{arg_count}" do
72
- let(:arguments) { argument_list.first(arg_count) }
73
- let(:expected_function) { "#{window_function.to_s.upcase}(#{arguments.join(', ')})" }
74
- let(:query) do
75
- query_base.select_window(window_function, *arguments, over: :w, as: :window_response).to_sql
76
- end
77
-
78
- it "appends the function to the select query" do
79
- expected_start = "SELECT (#{expected_function} OVER w) AS \"window_response\""
80
- expect(query).to start_with(expected_start).and(end_with(expected_end))
81
- end
82
- end
83
- end
84
- end
85
-
86
- context "when not providing a partition by value" do
87
- it "should construct a window function" do
88
- query =
89
- Tag
90
- .define_window(:no_args).partition_by(order_by: { tag_number: :desc })
91
- .select_window(:row_number, over: :no_args, as: :my_row)
92
- .to_sql
93
-
94
- expect(query).to eq("SELECT (ROW_NUMBER() OVER no_args) AS \"my_row\" FROM \"tags\" WINDOW no_args AS (ORDER BY tag_number DESC)")
95
- end
96
- end
97
- end
98
- end
@@ -1,95 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Active Record WITH CTE tables" do
6
- let(:with_personal_query) { /WITH.+personal_id_one.+AS \(SELECT.+users.+FROM.+WHERE.+users.+personal_id.+ = 1\)/ }
7
-
8
- it "should contain WITH statement that creates the CTE table" do
9
- query = User.with(personal_id_one: User.where(personal_id: 1))
10
- .joins("JOIN personal_id_one ON personal_id_one.id = users.id")
11
- .to_sql
12
- expect(query).to match_regex(with_personal_query)
13
- end
14
-
15
- it "will maintain the CTE table when merging" do
16
- query = User.all
17
- .merge(User.with(personal_id_one: User.where(personal_id: 1)))
18
- .joins("JOIN personal_id_one ON personal_id_one.id = users.id")
19
- .to_sql
20
-
21
- expect(query).to match_regex(with_personal_query)
22
- end
23
-
24
- it "will pipe Children CTE's into the Parent relation" do
25
- personal_id_one_query = User.where(personal_id: 1)
26
- personal_id_two_query = User.where(personal_id: 2)
27
-
28
- sub_query = personal_id_two_query.with(personal_id_one: personal_id_one_query)
29
- query = User.all.with(personal_id_two: sub_query)
30
- expected_order = User.with(
31
- personal_id_one: personal_id_one_query,
32
- personal_id_two: personal_id_two_query
33
- )
34
-
35
- expect(query.to_sql).to eq(expected_order.to_sql)
36
- end
37
-
38
- context "when multiple CTE's" do
39
- let(:chained_with) do
40
- User.with(personal_id_one: User.where(personal_id: 1))
41
- .with(personal_id_two: User.where(personal_id: 2))
42
- .joins("JOIN personal_id_one ON personal_id_one.id = users.id")
43
- .joins("JOIN personal_id_two ON personal_id_two.id = users.id")
44
- .to_sql
45
- end
46
-
47
- let(:with_arguments) do
48
- User.with(personal_id_one: User.where(personal_id: 1), personal_id_two: User.where(personal_id: 2))
49
- .joins("JOIN personal_id_one ON personal_id_one.id = users.id")
50
- .joins("JOIN personal_id_two ON personal_id_two.id = users.id")
51
- .to_sql
52
- end
53
-
54
- it "Should only contain a single WITH statement" do
55
- expect(with_arguments.scan(/WITH/).count).to eq(1)
56
- expect(with_arguments.scan(/AS/).count).to eq(2)
57
- end
58
-
59
- it "Should only contain a single WITH statement when chaining" do
60
- expect(chained_with.scan(/WITH/).count).to eq(1)
61
- expect(chained_with.scan(/AS/).count).to eq(2)
62
- end
63
- end
64
-
65
- context "when chaining the recursive method" do
66
- let(:with_recursive_personal_query) do
67
- /WITH.+RECURSIVE.+personal_id_one.+AS \(SELECT.+users.+FROM.+WHERE.+users.+personal_id.+ = 1\)/
68
- end
69
-
70
- let(:with_recursive) do
71
- User.with
72
- .recursive(personal_id_one: User.where(personal_id: 1))
73
- .joins("JOIN personal_id_one ON personal_id_one.id = users.id")
74
- .to_sql
75
- end
76
-
77
- it "generates an expression with recursive" do
78
- query = User.with
79
- .recursive(personal_id_one: User.where(personal_id: 1))
80
- .joins("JOIN personal_id_one ON personal_id_one.id = users.id")
81
- .to_sql
82
-
83
- expect(query).to match_regex(with_recursive_personal_query)
84
- end
85
-
86
- it "will maintain the CTE table when merging" do
87
- sub_query = User.with.recursive(personal_id_one: User.where(personal_id: 1))
88
- query = User.merge(sub_query)
89
- .joins("JOIN personal_id_one ON personal_id_one.id = users.id")
90
- .to_sql
91
-
92
- expect(query).to match_regex(with_recursive_personal_query)
93
- end
94
- end
95
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "database_cleaner"
4
-
5
- DatabaseCleaner.strategy = :truncation
6
-
7
- RSpec.configure do |config|
8
- config.before do
9
- DatabaseCleaner.start
10
- end
11
-
12
- config.after do
13
- DatabaseCleaner.clean
14
- end
15
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class ApplicationRecord < ActiveRecord::Base
4
- self.abstract_class = true
5
- end
6
-
7
- class User < ApplicationRecord
8
- has_many :groups_users, class_name: "GroupsUser"
9
- has_many :groups, through: :groups_users, dependent: :destroy
10
- has_many :hm_tags, class_name: "Tag"
11
- has_one :profile_l, class_name: "ProfileL"
12
- has_one :profile_r, class_name: "ProfileR"
13
- # attributes
14
- # t.string "tags", array: true
15
- # t.integer "number", default: 0
16
- # t.string "name"
17
- # t.integer "personal_id"
18
- # t.hstore "data"
19
- # t.jsonb "jsonb_data"
20
- # t.inet "ip"
21
- # t.cidr "subnet"
22
- #
23
- end
24
-
25
- class StiRecord < ApplicationRecord
26
- # t.string "type"
27
- end
28
-
29
- class AdminSti < StiRecord; end
30
-
31
- module Namespaced
32
- def self.table_name_prefix
33
- "namespaced_"
34
- end
35
-
36
- class Record < ApplicationRecord
37
- # attributes
38
- # t.inet :ip
39
- # t.cidr :subnet
40
- #
41
- end
42
- end
43
-
44
- class Tag < ApplicationRecord
45
- belongs_to :user
46
- # attributes: tag_number
47
- end
48
-
49
- class ProfileL < ApplicationRecord
50
- belongs_to :user
51
- has_one :version, as: :versionable, class_name: "VersionControl"
52
- # attributes
53
- # t.integer :likes
54
- #
55
- end
56
-
57
- class ProfileR < ApplicationRecord
58
- belongs_to :user
59
- has_one :version, as: :versionable, class_name: "VersionControl"
60
- # attributes
61
- # t.integer :dislikes
62
- #
63
- end
64
-
65
- class VersionControl < ApplicationRecord
66
- belongs_to :versionable, polymorphic: true, optional: false
67
- # attributes
68
- # t.jsonb :source, default: {}, null: false
69
- #
70
- end
71
-
72
- class Group < ApplicationRecord
73
- has_many :groups_users, class_name: "GroupsUser"
74
- has_many :users, through: :groups_users, dependent: :destroy
75
- end
76
-
77
- class GroupsUser < ApplicationRecord
78
- belongs_to :user
79
- belongs_to :group
80
- end