active_record_extended 2.2.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -3
  3. data/lib/active_record_extended/arel/aggregate_function_name.rb +0 -0
  4. data/lib/active_record_extended/arel/nodes.rb +0 -0
  5. data/lib/active_record_extended/arel/predications.rb +0 -0
  6. data/lib/active_record_extended/arel/{sql_literal.rb → sql_literal_patch.rb} +2 -2
  7. data/lib/active_record_extended/arel/visitors/postgresql_decorator.rb +0 -0
  8. data/lib/active_record_extended/arel.rb +1 -1
  9. data/lib/active_record_extended/patch/array_handler_patch.rb +22 -0
  10. data/lib/active_record_extended/patch/relation_patch.rb +67 -0
  11. data/lib/active_record_extended/patch/where_clause_patch.rb +13 -0
  12. data/lib/active_record_extended/query_methods/any_of.rb +0 -0
  13. data/lib/active_record_extended/query_methods/either.rb +1 -3
  14. data/lib/active_record_extended/query_methods/{select.rb → foster_select.rb} +4 -4
  15. data/lib/active_record_extended/query_methods/inet.rb +0 -0
  16. data/lib/active_record_extended/query_methods/json.rb +2 -2
  17. data/lib/active_record_extended/query_methods/unionize.rb +2 -2
  18. data/lib/active_record_extended/query_methods/where_chain.rb +94 -92
  19. data/lib/active_record_extended/query_methods/window.rb +3 -3
  20. data/lib/active_record_extended/query_methods/with_cte.rb +1 -1
  21. data/lib/active_record_extended/utilities/order_by.rb +1 -1
  22. data/lib/active_record_extended/utilities/support.rb +1 -1
  23. data/lib/active_record_extended/version.rb +1 -1
  24. data/lib/active_record_extended.rb +55 -4
  25. metadata +15 -16
  26. data/lib/active_record_extended/active_record/relation_patch.rb +0 -62
  27. data/lib/active_record_extended/active_record.rb +0 -25
  28. data/lib/active_record_extended/patch/5_2/where_clause.rb +0 -11
  29. data/lib/active_record_extended/predicate_builder/array_handler_decorator.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f8d2f193f9e0e50c6e83e462c1df30a9b948779ebf3e00f64c735f165bdb5f3
4
- data.tar.gz: 0ee6d70e9b6714c6ab3431da2df340ff63fca28bc0ceb6fc2c3e45593b9e87e0
3
+ metadata.gz: b59ef27069d870b734f0494db168936d5536493fd1346469f7a85d9b43bc7655
4
+ data.tar.gz: f0e25e53250ec9d562bb75ec06e7d02deda48a9996b8a03e4fb5afac2d113abc
5
5
  SHA512:
6
- metadata.gz: 282ad3881cb0ed581dbe1aa0dd605dbc33cb7182d560a015f2de5a57a1ca49f3db8e5b5515229d527130e6f7f35321105bface3669edb15340b1bb76e333d7c4
7
- data.tar.gz: c7b38bca14c8ed07faba4f2996a18c455b85dec7def64e184c1a8dc9defa86681c1650b9097112264248c66580685f2f90825e9cf04d981e48b47333e091bde2
6
+ metadata.gz: ffad0b652cbaac828d25ed1dbbd6e5e5479f6905bf776785090f9b76fe33fefb750fcbce7c329bbcaf077f1f5401b9817e830d89efab130feca3500bbc97c1f8
7
+ data.tar.gz: b0f77a0248242cc50e7f87ebd813e90c4e57bf1cfd28e35190ee93fa4ce2ae50878dd6e7f153dc017a692f13d147a9a9f8378ba9583d7705c2b71566fb20e29c
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/active_record_extended.svg)](https://badge.fury.io/rb/active_record_extended)
2
- [![Build Status](https://travis-ci.com/GeorgeKaraszi/ActiveRecordExtended.svg?branch=master)](https://travis-ci.com/GeorgeKaraszi/ActiveRecordExtended)
2
+ [![Build Status](https://github.com/GeorgeKaraszi/ActiveRecordExtended/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/GeorgeKaraszi/ActiveRecordExtended/actions/workflows/test.yml?query=branch%3Amaster+)
3
3
  [![Maintainability](https://api.codeclimate.com/v1/badges/98ecffc0239417098cbc/maintainability)](https://codeclimate.com/github/GeorgeKaraszi/active_record_extended/maintainability)
4
4
  [![Test Coverage](https://api.codeclimate.com/v1/badges/f22154211bb3a8feb89f/test_coverage)](https://codeclimate.com/github/GeorgeKaraszi/ActiveRecordExtended/test_coverage)
5
5
  ## Index
@@ -55,7 +55,7 @@ This package is designed align and work with any officially supported Ruby and R
55
55
  - Minimum Ruby Version: 2.5.x **(EOL warning!)**
56
56
  - Minimum Rails Version: 5.2.x **(EOL warning!)**
57
57
  - Minimum Postgres Version: 10.x **(EOL warning!)**
58
- - Latest Ruby supported: 3.0.x
58
+ - Latest Ruby supported: 3.1.x
59
59
  - Latest Rails supported: 7.0.x
60
60
  - Postgres: 10-current(14) (probably works with most older versions to a certain point)
61
61
 
@@ -412,12 +412,27 @@ If any or all of your json sub-queries include a CTE, read the [Subquery CTE Got
412
412
  #### Row To JSON
413
413
  [Postgres 'ROW_TO_JSON' function](https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-CREATION-TABLE)
414
414
 
415
- The implementation of the`.row_to_json/2` method is designed to be used with sub-queries. As a means for taking complex
415
+ The implementation of the`.select_row_to_json/2` method is designed to be used with sub-queries. As a means for taking complex
416
416
  query logic and transform them into a single or multiple json responses. These responses are required to be assigned
417
417
  to an aliased column on the parent(callee) level.
418
418
 
419
419
  While quite the mouthful of an explanation. The implementation of combining unrelated or semi-related queries is quite smooth(imo).
420
420
 
421
+ **Arguments:**
422
+ - `from` [String, Arel, or ActiveRecord::Relation]: A subquery that can be nested into a `ROW_TO_JSON` clause
423
+
424
+ **Options:**
425
+ - `as` [Symbol or String] (default="results"): What the column will be aliased to
426
+ - `key` [Symbol or String] (default=[random letter]): Internal query alias name.
427
+ * This is useful if you would like to add additional mid-level predicate clauses
428
+ - `cast_with` [Symbol or Array\<Symbol>]:
429
+ * `:to_jsonb`
430
+ * `:array`
431
+ * `:array_agg`
432
+ * `:distinct` (auto applies `:array_agg` & `:to_jsonb`)
433
+ - `order_by` [Symbol or Hash]: Applies an ordering operation (similar to ActiveRecord #order)
434
+ * **Note**: this option will be ignored if you need to order a DISTINCT Aggregated Array.
435
+
421
436
  ```ruby
422
437
  physical_cat = Category.create!(name: "Physical")
423
438
  products = 3.times.map { Product.create! }
File without changes
File without changes
@@ -5,7 +5,7 @@ require "arel/nodes/sql_literal"
5
5
  # CTE alias fix for Rails 6.1
6
6
  module Arel
7
7
  module Nodes
8
- module SqlLiteralDecorator
8
+ module SqlLiteralPatch
9
9
  def name
10
10
  self
11
11
  end
@@ -13,4 +13,4 @@ module Arel
13
13
  end
14
14
  end
15
15
 
16
- Arel::Nodes::SqlLiteral.prepend(Arel::Nodes::SqlLiteralDecorator)
16
+ Arel::Nodes::SqlLiteral.prepend(Arel::Nodes::SqlLiteralPatch)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record_extended/arel/nodes"
4
- require "active_record_extended/arel/sql_literal"
4
+ require "active_record_extended/arel/sql_literal_patch"
5
5
  require "active_record_extended/arel/aggregate_function_name"
6
6
  require "active_record_extended/arel/predications"
7
7
  require "active_record_extended/arel/visitors/postgresql_decorator"
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/relation/predicate_builder"
4
+ require "active_record/relation/predicate_builder/array_handler"
5
+
6
+ module ActiveRecordExtended
7
+ module Patch
8
+ module ArrayHandlerPatch
9
+ def call(attribute, value)
10
+ cache = ActiveRecord::Base.connection.schema_cache
11
+ if cache.data_source_exists?(attribute.relation.name)
12
+ column = cache.columns(attribute.relation.name).detect { |col| col.name.to_s == attribute.name.to_s }
13
+ return attribute.eq(value) if column.try(:array)
14
+ end
15
+
16
+ super(attribute, value)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ ActiveRecord::PredicateBuilder::ArrayHandler.prepend(ActiveRecordExtended::Patch::ArrayHandlerPatch)
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecordExtended
4
+ module Patch
5
+ module RelationPatch
6
+ module QueryDelegation
7
+ AR_EX_QUERY_METHODS = (
8
+ [
9
+ :with, :define_window, :select_window, :foster_select,
10
+ :either_join, :either_joins, :either_order, :either_orders
11
+ ] +
12
+ ActiveRecordExtended::QueryMethods::Unionize::UNIONIZE_METHODS +
13
+ ActiveRecordExtended::QueryMethods::Json::JSON_QUERY_METHODS
14
+ ).freeze
15
+
16
+ delegate(*AR_EX_QUERY_METHODS, to: :all)
17
+ end
18
+
19
+ module Merger
20
+ def merge
21
+ merge_ctes!
22
+ merge_union!
23
+ merge_windows!
24
+ super
25
+ end
26
+
27
+ def merge_union!
28
+ return if other.unionize_storage.empty?
29
+
30
+ relation.union_values += other.union_values
31
+ relation.union_operations += other.union_operations
32
+ relation.union_ordering_values += other.union_ordering_values
33
+ end
34
+
35
+ def merge_windows!
36
+ return unless other.window_values?
37
+
38
+ relation.window_values |= other.window_values
39
+ end
40
+
41
+ def merge_ctes!
42
+ return unless other.with_values?
43
+
44
+ if other.recursive_value? && !relation.recursive_value?
45
+ relation.with!.recursive(other.cte)
46
+ else
47
+ relation.with!(other.cte)
48
+ end
49
+ end
50
+ end
51
+
52
+ module ArelBuildPatch
53
+ def build_arel(*aliases)
54
+ super.tap do |arel|
55
+ build_windows(arel) if window_values?
56
+ build_unions(arel) if union_values?
57
+ build_with(arel) if with_values?
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ ActiveRecord::Relation.prepend(ActiveRecordExtended::Patch::RelationPatch::ArelBuildPatch)
66
+ ActiveRecord::Relation::Merger.prepend(ActiveRecordExtended::Patch::RelationPatch::Merger)
67
+ ActiveRecord::Base.extend(ActiveRecordExtended::Patch::RelationPatch::QueryDelegation)
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecordExtended
4
+ module Patch
5
+ module WhereClausePatch
6
+ def modified_predicates(&block)
7
+ ActiveRecord::Relation::WhereClause.new(predicates.map(&block))
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ ActiveRecord::Relation::WhereClause.prepend(ActiveRecordExtended::Patch::WhereClausePatch)
File without changes
@@ -60,6 +60,4 @@ module ActiveRecordExtended
60
60
  end
61
61
  end
62
62
 
63
- ActiveSupport.on_load :active_record do
64
- extend(ActiveRecordExtended::QueryMethods::Either)
65
- end
63
+ ActiveRecord::Relation.prepend(ActiveRecordExtended::QueryMethods::Either)
@@ -2,10 +2,10 @@
2
2
 
3
3
  module ActiveRecordExtended
4
4
  module QueryMethods
5
- module Select
5
+ module FosterSelect
6
6
  class SelectHelper
7
- include ::ActiveRecordExtended::Utilities::Support
8
- include ::ActiveRecordExtended::Utilities::OrderBy
7
+ include ActiveRecordExtended::Utilities::Support
8
+ include ActiveRecordExtended::Utilities::OrderBy
9
9
 
10
10
  AGGREGATE_ONE_LINERS = /^(exists|sum|max|min|avg|count|jsonb?_agg|(bit|bool)_(and|or)|xmlagg|array_agg)$/.freeze
11
11
 
@@ -115,4 +115,4 @@ module ActiveRecordExtended
115
115
  end
116
116
  end
117
117
 
118
- ActiveRecord::Relation.prepend(ActiveRecordExtended::QueryMethods::Select)
118
+ ActiveRecord::Relation.prepend(ActiveRecordExtended::QueryMethods::FosterSelect)
File without changes
@@ -12,8 +12,8 @@ module ActiveRecordExtended
12
12
  ].freeze
13
13
 
14
14
  class JsonChain
15
- include ::ActiveRecordExtended::Utilities::Support
16
- include ::ActiveRecordExtended::Utilities::OrderBy
15
+ include ActiveRecordExtended::Utilities::Support
16
+ include ActiveRecordExtended::Utilities::OrderBy
17
17
 
18
18
  DEFAULT_ALIAS = '"results"'
19
19
  TO_JSONB_OPTIONS = [:array_agg, :distinct, :to_jsonb].to_set.freeze
@@ -7,8 +7,8 @@ module ActiveRecordExtended
7
7
  UNIONIZE_METHODS = [:union, :union_all, :union_except, :union_intersect].freeze
8
8
 
9
9
  class UnionChain
10
- include ::ActiveRecordExtended::Utilities::Support
11
- include ::ActiveRecordExtended::Utilities::OrderBy
10
+ include ActiveRecordExtended::Utilities::Support
11
+ include ActiveRecordExtended::Utilities::OrderBy
12
12
 
13
13
  def initialize(scope)
14
14
  @scope = scope
@@ -1,119 +1,121 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordExtended
4
- module WhereChain
5
- # Finds Records that have an array column that contain any a set of values
6
- # User.where.overlap(tags: [1,2])
7
- # # SELECT * FROM users WHERE tags && {1,2}
8
- def overlaps(opts, *rest)
9
- substitute_comparisons(opts, rest, Arel::Nodes::Overlaps, "overlap")
10
- end
11
- alias overlap overlaps
12
-
13
- # Finds Records that contain an element in an array column
14
- # User.where.any(tags: 3)
15
- # # SELECT user.* FROM user WHERE 3 = ANY(user.tags)
16
- def any(opts, *rest)
17
- equality_to_function("ANY", opts, rest)
18
- end
4
+ module QueryMethods
5
+ module WhereChain
6
+ # Finds Records that have an array column that contain any a set of values
7
+ # User.where.overlap(tags: [1,2])
8
+ # # SELECT * FROM users WHERE tags && {1,2}
9
+ def overlaps(opts, *rest)
10
+ substitute_comparisons(opts, rest, Arel::Nodes::Overlaps, "overlap")
11
+ end
12
+ alias overlap overlaps
19
13
 
20
- # Finds Records that contain a single matchable array element
21
- # User.where.all(tags: 3)
22
- # # SELECT user.* FROM user WHERE 3 = ALL(user.tags)
23
- def all(opts, *rest)
24
- equality_to_function("ALL", opts, rest)
25
- end
14
+ # Finds Records that contain an element in an array column
15
+ # User.where.any(tags: 3)
16
+ # # SELECT user.* FROM user WHERE 3 = ANY(user.tags)
17
+ def any(opts, *rest)
18
+ equality_to_function("ANY", opts, rest)
19
+ end
26
20
 
27
- # Finds Records that contains a nested set elements
28
- #
29
- # Array Column Type:
30
- # User.where.contains(tags: [1, 3])
31
- # # SELECT user.* FROM user WHERE user.tags @> {1,3}
32
- #
33
- # HStore Column Type:
34
- # User.where.contains(data: { nickname: 'chainer' })
35
- # # SELECT user.* FROM user WHERE user.data @> 'nickname' => 'chainer'
36
- #
37
- # JSONB Column Type:
38
- # User.where.contains(data: { nickname: 'chainer' })
39
- # # SELECT user.* FROM user WHERE user.data @> {'nickname': 'chainer'}
40
- #
41
- # This can also be used along side joined tables
42
- #
43
- # JSONB Column Type Example:
44
- # Tag.joins(:user).where.contains(user: { data: { nickname: 'chainer' } })
45
- # # SELECT tags.* FROM tags INNER JOIN user on user.id = tags.user_id WHERE user.data @> { nickname: 'chainer' }
46
- #
47
- def contains(opts, *rest)
48
- if ActiveRecordExtended::AR_VERSION_GTE_6_1
49
- return substitute_comparisons(opts, rest, Arel::Nodes::Contains, "contains")
21
+ # Finds Records that contain a single matchable array element
22
+ # User.where.all(tags: 3)
23
+ # # SELECT user.* FROM user WHERE 3 = ALL(user.tags)
24
+ def all(opts, *rest)
25
+ equality_to_function("ALL", opts, rest)
50
26
  end
51
27
 
52
- build_where_chain(opts, rest) do |arel|
53
- case arel
54
- when Arel::Nodes::In, Arel::Nodes::Equality
55
- column = left_column(arel) || column_from_association(arel)
28
+ # Finds Records that contains a nested set elements
29
+ #
30
+ # Array Column Type:
31
+ # User.where.contains(tags: [1, 3])
32
+ # # SELECT user.* FROM user WHERE user.tags @> {1,3}
33
+ #
34
+ # HStore Column Type:
35
+ # User.where.contains(data: { nickname: 'chainer' })
36
+ # # SELECT user.* FROM user WHERE user.data @> 'nickname' => 'chainer'
37
+ #
38
+ # JSONB Column Type:
39
+ # User.where.contains(data: { nickname: 'chainer' })
40
+ # # SELECT user.* FROM user WHERE user.data @> {'nickname': 'chainer'}
41
+ #
42
+ # This can also be used along side joined tables
43
+ #
44
+ # JSONB Column Type Example:
45
+ # Tag.joins(:user).where.contains(user: { data: { nickname: 'chainer' } })
46
+ # # SELECT tags.* FROM tags INNER JOIN user on user.id = tags.user_id WHERE user.data @> { nickname: 'chainer' }
47
+ #
48
+ def contains(opts, *rest)
49
+ if ActiveRecordExtended::AR_VERSION_GTE_6_1
50
+ return substitute_comparisons(opts, rest, Arel::Nodes::Contains, "contains")
51
+ end
56
52
 
57
- if [:hstore, :jsonb].include?(column.type)
58
- Arel::Nodes::ContainsHStore.new(arel.left, arel.right)
59
- elsif column.try(:array)
60
- Arel::Nodes::ContainsArray.new(arel.left, arel.right)
53
+ build_where_chain(opts, rest) do |arel|
54
+ case arel
55
+ when Arel::Nodes::In, Arel::Nodes::Equality
56
+ column = left_column(arel) || column_from_association(arel)
57
+
58
+ if [:hstore, :jsonb].include?(column.type)
59
+ Arel::Nodes::ContainsHStore.new(arel.left, arel.right)
60
+ elsif column.try(:array)
61
+ Arel::Nodes::ContainsArray.new(arel.left, arel.right)
62
+ else
63
+ raise ArgumentError.new("Invalid argument for .where.contains(), got #{arel.class}")
64
+ end
61
65
  else
62
66
  raise ArgumentError.new("Invalid argument for .where.contains(), got #{arel.class}")
63
67
  end
64
- else
65
- raise ArgumentError.new("Invalid argument for .where.contains(), got #{arel.class}")
66
68
  end
67
69
  end
68
- end
69
70
 
70
- private
71
+ private
71
72
 
72
- def matchable_column?(col, arel)
73
- col.name == arel.left.name.to_s || col.name == arel.left.relation.name.to_s
74
- end
73
+ def matchable_column?(col, arel)
74
+ col.name == arel.left.name.to_s || col.name == arel.left.relation.name.to_s
75
+ end
75
76
 
76
- def column_from_association(arel)
77
- assoc = assoc_from_related_table(arel)
78
- assoc.klass.columns.detect { |col| matchable_column?(col, arel) } if assoc
79
- end
77
+ def column_from_association(arel)
78
+ assoc = assoc_from_related_table(arel)
79
+ assoc.klass.columns.detect { |col| matchable_column?(col, arel) } if assoc
80
+ end
80
81
 
81
- def assoc_from_related_table(arel)
82
- @scope.klass.reflect_on_association(arel.left.relation.name.to_sym) ||
83
- @scope.klass.reflect_on_association(arel.left.relation.name.singularize.to_sym)
84
- end
82
+ def assoc_from_related_table(arel)
83
+ @scope.klass.reflect_on_association(arel.left.relation.name.to_sym) ||
84
+ @scope.klass.reflect_on_association(arel.left.relation.name.singularize.to_sym)
85
+ end
85
86
 
86
- def left_column(arel)
87
- @scope.klass.columns_hash[arel.left.name] || @scope.klass.columns_hash[arel.left.relation.name]
88
- end
87
+ def left_column(arel)
88
+ @scope.klass.columns_hash[arel.left.name] || @scope.klass.columns_hash[arel.left.relation.name]
89
+ end
89
90
 
90
- def equality_to_function(function_name, opts, rest)
91
- build_where_chain(opts, rest) do |arel|
92
- case arel
93
- when Arel::Nodes::Equality
94
- Arel::Nodes::Equality.new(arel.right, Arel::Nodes::NamedFunction.new(function_name, [arel.left]))
95
- else
96
- raise ArgumentError.new("Invalid argument for .where.#{function_name.downcase}(), got #{arel.class}")
91
+ def equality_to_function(function_name, opts, rest)
92
+ build_where_chain(opts, rest) do |arel|
93
+ case arel
94
+ when Arel::Nodes::Equality
95
+ Arel::Nodes::Equality.new(arel.right, Arel::Nodes::NamedFunction.new(function_name, [arel.left]))
96
+ else
97
+ raise ArgumentError.new("Invalid argument for .where.#{function_name.downcase}(), got #{arel.class}")
98
+ end
97
99
  end
98
100
  end
99
- end
100
101
 
101
- def substitute_comparisons(opts, rest, arel_node_class, method)
102
- build_where_chain(opts, rest) do |arel|
103
- case arel
104
- when Arel::Nodes::In, Arel::Nodes::Equality
105
- arel_node_class.new(arel.left, arel.right)
106
- else
107
- raise ArgumentError.new("Invalid argument for .where.#{method}(), got #{arel.class}")
102
+ def substitute_comparisons(opts, rest, arel_node_class, method)
103
+ build_where_chain(opts, rest) do |arel|
104
+ case arel
105
+ when Arel::Nodes::In, Arel::Nodes::Equality
106
+ arel_node_class.new(arel.left, arel.right)
107
+ else
108
+ raise ArgumentError.new("Invalid argument for .where.#{method}(), got #{arel.class}")
109
+ end
108
110
  end
109
111
  end
110
- end
111
112
 
112
- def build_where_clause_for(scope, opts, rest)
113
- if ActiveRecordExtended::AR_VERSION_GTE_6_1
114
- scope.send(:build_where_clause, opts, rest)
115
- else
116
- scope.send(:where_clause_factory).build(opts, rest)
113
+ def build_where_clause_for(scope, opts, rest)
114
+ if ActiveRecordExtended::AR_VERSION_GTE_6_1
115
+ scope.send(:build_where_clause, opts, rest)
116
+ else
117
+ scope.send(:where_clause_factory).build(opts, rest)
118
+ end
117
119
  end
118
120
  end
119
121
  end
@@ -122,7 +124,7 @@ end
122
124
  module ActiveRecord
123
125
  module QueryMethods
124
126
  class WhereChain
125
- prepend ActiveRecordExtended::WhereChain
127
+ prepend ActiveRecordExtended::QueryMethods::WhereChain
126
128
 
127
129
  def build_where_chain(opts, rest, &block)
128
130
  where_clause = build_where_clause_for(@scope, opts, rest)
@@ -4,8 +4,8 @@ module ActiveRecordExtended
4
4
  module QueryMethods
5
5
  module Window
6
6
  class DefineWindowChain
7
- include ::ActiveRecordExtended::Utilities::Support
8
- include ::ActiveRecordExtended::Utilities::OrderBy
7
+ include ActiveRecordExtended::Utilities::Support
8
+ include ActiveRecordExtended::Utilities::OrderBy
9
9
 
10
10
  def initialize(scope, window_name)
11
11
  @scope = scope
@@ -24,7 +24,7 @@ module ActiveRecordExtended
24
24
  end
25
25
 
26
26
  class WindowSelectBuilder
27
- include ::ActiveRecordExtended::Utilities::Support
27
+ include ActiveRecordExtended::Utilities::Support
28
28
 
29
29
  def initialize(window_function, args, window_name)
30
30
  @window_function = window_function
@@ -4,7 +4,7 @@ module ActiveRecordExtended
4
4
  module QueryMethods
5
5
  module WithCTE
6
6
  class WithCTE
7
- include ::ActiveRecordExtended::Utilities::Support
7
+ include ActiveRecordExtended::Utilities::Support
8
8
  include Enumerable
9
9
  extend Forwardable
10
10
 
@@ -49,7 +49,7 @@ module ActiveRecordExtended
49
49
  obj.each_pair do |o_key, o_value|
50
50
  new_hash["#{tbl_or_col}.#{o_key}"] = o_value
51
51
  end
52
- elsif ::ActiveRecord::QueryMethods::VALID_DIRECTIONS.include?(obj)
52
+ elsif ActiveRecord::QueryMethods::VALID_DIRECTIONS.include?(obj)
53
53
  new_hash[tbl_or_col] = obj
54
54
  elsif obj.nil?
55
55
  new_hash[tbl_or_col.to_s] = :asc
@@ -113,7 +113,7 @@ module ActiveRecordExtended
113
113
  case value.to_s
114
114
  # Ignore keys that contain double quotes or a Arel.star (*)[all columns]
115
115
  # or if a table has already been explicitly declared (ex: users.id)
116
- when "*", /((^".+"$)|(^[[:alpha:]]+\.[[:alnum:]]+))/
116
+ when "*", /((^".+"$)|(^[[:alpha:]]+\.[[:alnum:]]+)|\(.+\))/
117
117
  value
118
118
  else
119
119
  PG::Connection.quote_ident(value.to_s)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordExtended
4
- VERSION = "2.2.0"
4
+ VERSION = "3.0.0"
5
5
  end
@@ -1,10 +1,61 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record_extended/version"
4
- require "active_record_extended/utilities/support"
5
- require "active_record_extended/utilities/order_by"
6
- require "active_record_extended/active_record"
7
- require "active_record_extended/arel"
4
+
5
+ require "active_record"
6
+ require "active_record/relation"
7
+ require "active_record/relation/merger"
8
+ require "active_record/relation/query_methods"
8
9
 
9
10
  module ActiveRecordExtended
11
+ extend ActiveSupport::Autoload
12
+
13
+ AR_VERSION_GTE_6_1 = Gem::Requirement.new(">= 6.1").satisfied_by?(ActiveRecord.gem_version)
14
+
15
+ module Utilities
16
+ extend ActiveSupport::Autoload
17
+
18
+ eager_autoload do
19
+ autoload :OrderBy
20
+ autoload :Support
21
+ end
22
+ end
23
+
24
+ module Patch
25
+ extend ActiveSupport::Autoload
26
+
27
+ eager_autoload do
28
+ autoload :ArrayHandlerPatch
29
+ autoload :RelationPatch
30
+ autoload :WhereClausePatch
31
+ end
32
+ end
33
+
34
+ module QueryMethods
35
+ extend ActiveSupport::Autoload
36
+
37
+ eager_autoload do
38
+ autoload :AnyOf
39
+ autoload :Either
40
+ autoload :FosterSelect
41
+ autoload :Inet
42
+ autoload :Json
43
+ autoload :Unionize
44
+ autoload :WhereChain
45
+ autoload :Window
46
+ autoload :WithCTE
47
+ end
48
+ end
49
+
50
+ def self.eager_load!
51
+ super
52
+ ActiveRecordExtended::Utilities.eager_load!
53
+ ActiveRecordExtended::Patch.eager_load!
54
+ ActiveRecordExtended::QueryMethods.eager_load!
55
+ end
56
+ end
57
+
58
+ ActiveSupport.on_load(:active_record) do
59
+ require "active_record_extended/arel"
60
+ ActiveRecordExtended.eager_load!
10
61
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_extended
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Protacio-Karaszi
8
8
  - Dan McClain
9
9
  - Olivier El Mekki
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-07-28 00:00:00.000000000 Z
13
+ date: 2022-08-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: '1.16'
69
+ version: '2.2'
70
70
  - - "<"
71
71
  - !ruby/object:Gem::Version
72
72
  version: '3.0'
@@ -76,7 +76,7 @@ dependencies:
76
76
  requirements:
77
77
  - - ">="
78
78
  - !ruby/object:Gem::Version
79
- version: '1.16'
79
+ version: '2.2'
80
80
  - - "<"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.0'
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '1.6'
89
+ version: '2.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '1.6'
96
+ version: '2.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -147,21 +147,20 @@ extra_rdoc_files: []
147
147
  files:
148
148
  - README.md
149
149
  - lib/active_record_extended.rb
150
- - lib/active_record_extended/active_record.rb
151
- - lib/active_record_extended/active_record/relation_patch.rb
152
150
  - lib/active_record_extended/arel.rb
153
151
  - lib/active_record_extended/arel/aggregate_function_name.rb
154
152
  - lib/active_record_extended/arel/nodes.rb
155
153
  - lib/active_record_extended/arel/predications.rb
156
- - lib/active_record_extended/arel/sql_literal.rb
154
+ - lib/active_record_extended/arel/sql_literal_patch.rb
157
155
  - lib/active_record_extended/arel/visitors/postgresql_decorator.rb
158
- - lib/active_record_extended/patch/5_2/where_clause.rb
159
- - lib/active_record_extended/predicate_builder/array_handler_decorator.rb
156
+ - lib/active_record_extended/patch/array_handler_patch.rb
157
+ - lib/active_record_extended/patch/relation_patch.rb
158
+ - lib/active_record_extended/patch/where_clause_patch.rb
160
159
  - lib/active_record_extended/query_methods/any_of.rb
161
160
  - lib/active_record_extended/query_methods/either.rb
161
+ - lib/active_record_extended/query_methods/foster_select.rb
162
162
  - lib/active_record_extended/query_methods/inet.rb
163
163
  - lib/active_record_extended/query_methods/json.rb
164
- - lib/active_record_extended/query_methods/select.rb
165
164
  - lib/active_record_extended/query_methods/unionize.rb
166
165
  - lib/active_record_extended/query_methods/where_chain.rb
167
166
  - lib/active_record_extended/query_methods/window.rb
@@ -174,7 +173,7 @@ licenses:
174
173
  - MIT
175
174
  metadata:
176
175
  rubygems_mfa_required: 'true'
177
- post_install_message:
176
+ post_install_message:
178
177
  rdoc_options: []
179
178
  require_paths:
180
179
  - lib
@@ -189,8 +188,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
188
  - !ruby/object:Gem::Version
190
189
  version: '0'
191
190
  requirements: []
192
- rubygems_version: 3.2.15
193
- signing_key:
191
+ rubygems_version: 3.3.7
192
+ signing_key:
194
193
  specification_version: 4
195
194
  summary: Adds extended functionality to Activerecord Postgres implementation
196
195
  test_files: []
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_record_extended/query_methods/window"
4
- require "active_record_extended/query_methods/unionize"
5
- require "active_record_extended/query_methods/json"
6
-
7
- module ActiveRecordExtended
8
- module RelationPatch
9
- module QueryDelegation
10
- delegate :with, :define_window, :select_window, :foster_select, to: :all
11
- delegate(*::ActiveRecordExtended::QueryMethods::Unionize::UNIONIZE_METHODS, to: :all)
12
- delegate(*::ActiveRecordExtended::QueryMethods::Json::JSON_QUERY_METHODS, to: :all)
13
- end
14
-
15
- module Merger
16
- def merge
17
- merge_ctes!
18
- merge_union!
19
- merge_windows!
20
- super
21
- end
22
-
23
- def merge_union!
24
- return if other.unionize_storage.empty?
25
-
26
- relation.union_values += other.union_values
27
- relation.union_operations += other.union_operations
28
- relation.union_ordering_values += other.union_ordering_values
29
- end
30
-
31
- def merge_windows!
32
- return unless other.window_values?
33
-
34
- relation.window_values |= other.window_values
35
- end
36
-
37
- def merge_ctes!
38
- return unless other.with_values?
39
-
40
- if other.recursive_value? && !relation.recursive_value?
41
- relation.with!(:chain).recursive(other.cte)
42
- else
43
- relation.with!(other.cte)
44
- end
45
- end
46
- end
47
-
48
- module ArelBuildPatch
49
- def build_arel(*aliases)
50
- super.tap do |arel|
51
- build_windows(arel) if window_values?
52
- build_unions(arel) if union_values?
53
- build_with(arel) if with_values?
54
- end
55
- end
56
- end
57
- end
58
- end
59
-
60
- ActiveRecord::Relation.prepend(ActiveRecordExtended::RelationPatch::ArelBuildPatch)
61
- ActiveRecord::Relation::Merger.prepend(ActiveRecordExtended::RelationPatch::Merger)
62
- ActiveRecord::Querying.prepend(ActiveRecordExtended::RelationPatch::QueryDelegation)
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_record"
4
- require "active_record/relation"
5
- require "active_record/relation/merger"
6
- require "active_record/relation/query_methods"
7
-
8
- module ActiveRecordExtended
9
- # TODO: Deprecate <= AR 6.0 methods & routines
10
- AR_VERSION_GTE_6_1 = Gem::Requirement.new(">= 6.1").satisfied_by?(ActiveRecord.gem_version)
11
- end
12
-
13
- require "active_record_extended/predicate_builder/array_handler_decorator"
14
-
15
- require "active_record_extended/active_record/relation_patch"
16
-
17
- require "active_record_extended/query_methods/where_chain"
18
- require "active_record_extended/query_methods/with_cte"
19
- require "active_record_extended/query_methods/unionize"
20
- require "active_record_extended/query_methods/any_of"
21
- require "active_record_extended/query_methods/either"
22
- require "active_record_extended/query_methods/inet"
23
- require "active_record_extended/query_methods/json"
24
- require "active_record_extended/query_methods/select"
25
- require "active_record_extended/patch/5_2/where_clause"
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActiveRecordExtended
4
- module WhereClause
5
- def modified_predicates(&block)
6
- ::ActiveRecord::Relation::WhereClause.new(predicates.map(&block))
7
- end
8
- end
9
- end
10
-
11
- ActiveRecord::Relation::WhereClause.prepend(ActiveRecordExtended::WhereClause)
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_record/relation/predicate_builder"
4
- require "active_record/relation/predicate_builder/array_handler"
5
-
6
- module ActiveRecordExtended
7
- module ArrayHandlerDecorator
8
- def call(attribute, value)
9
- cache = ActiveRecord::Base.connection.schema_cache
10
- if cache.data_source_exists?(attribute.relation.name)
11
- column = cache.columns(attribute.relation.name).detect { |col| col.name.to_s == attribute.name.to_s }
12
- return attribute.eq(value) if column.try(:array)
13
- end
14
-
15
- super(attribute, value)
16
- end
17
- end
18
- end
19
-
20
- ActiveRecord::PredicateBuilder::ArrayHandler.prepend(ActiveRecordExtended::ArrayHandlerDecorator)