arel-extensions 8.0.2 → 9.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/README.md +83 -2
  4. data/ext/arel/nodes/ascending.rb +2 -0
  5. data/ext/arel/nodes/descending.rb +2 -0
  6. data/ext/arel/order_predications.rb +2 -0
  7. data/lib/active_record/query_methods.rb +33 -31
  8. data/lib/arel/array_predications.rb +2 -0
  9. data/lib/arel/attributes/cast.rb +2 -0
  10. data/lib/arel/attributes/key.rb +2 -0
  11. data/lib/arel/extensions/version.rb +3 -1
  12. data/lib/arel/extensions.rb +2 -0
  13. data/lib/arel/gis_predications.rb +2 -0
  14. data/lib/arel/json_predications.rb +2 -0
  15. data/lib/arel/nodes/binary_value.rb +2 -0
  16. data/lib/arel/nodes/contained_by.rb +2 -0
  17. data/lib/arel/nodes/excludes.rb +2 -0
  18. data/lib/arel/nodes/geometry.rb +2 -0
  19. data/lib/arel/nodes/has_any_key.rb +2 -0
  20. data/lib/arel/nodes/has_key.rb +2 -0
  21. data/lib/arel/nodes/has_keys.rb +2 -0
  22. data/lib/arel/nodes/hex_encoded_binary_value.rb +2 -0
  23. data/lib/arel/nodes/intersects.rb +2 -0
  24. data/lib/arel/nodes/random.rb +2 -0
  25. data/lib/arel/nodes/relation.rb +2 -0
  26. data/lib/arel/nodes/ts_match.rb +2 -0
  27. data/lib/arel/nodes/ts_query.rb +2 -0
  28. data/lib/arel/nodes/ts_rank.rb +2 -0
  29. data/lib/arel/nodes/ts_rank_cd.rb +2 -0
  30. data/lib/arel/nodes/ts_vector.rb +2 -0
  31. data/lib/arel/nodes/within.rb +2 -0
  32. data/lib/arel/ts_predications.rb +2 -0
  33. data/lib/arel/visitors/postgresql_extensions.rb +2 -0
  34. data/lib/arel/visitors/sunstone_extensions.rb +2 -0
  35. data/lib/arel/visitors/to_sql_extensions.rb +2 -0
  36. metadata +15 -45
  37. data/.github/workflows/ci.yml +0 -212
  38. data/.gitignore +0 -3
  39. data/Gemfile +0 -5
  40. data/Rakefile +0 -14
  41. data/arel-extensions.gemspec +0 -29
  42. data/test/binary_value_test.rb +0 -23
  43. data/test/database.rb +0 -51
  44. data/test/gis_test.rb +0 -23
  45. data/test/order_test.rb +0 -83
  46. data/test/sunstone_test.rb +0 -149
  47. data/test/test_helper.rb +0 -210
  48. data/test/ts_test.rb +0 -151
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f10fd80539653570d9ea7333fa9f9aef21e29ccdb9f9a976fa178e106c1f3c66
4
- data.tar.gz: 02efc9b543b5325e61899a590982207378482592f13a91ccb121d94a621a1966
3
+ metadata.gz: 2cac2b9e201296fa2c9e058f38cd0acf4835b134f2f98bb74f245af78b58f02c
4
+ data.tar.gz: 8b4be319b4037c1dfb2c54d6d9314a6add237ac60ec1fe2e6e1f0d396d67d1bb
5
5
  SHA512:
6
- metadata.gz: 4da172777f5c26a8eafcc82faef85510967381601e67c6d8259229be3097aaa483ad8f57bddb3d42733b95a805ace1f40f84aa2a89777a4fe33f9b2647669e85
7
- data.tar.gz: 40873247a7c72bd997f424df0ebf1e421f158046967929ef4d11ae932e1d10422b26fe78feb56a86086b2eb261d20e118dbbe848f10a862d04fae8701bb4340f
6
+ metadata.gz: 36818826669a7004657c3362908fc8c11bb683fabbf93183dde33cb4a933ce3e5bd41da637cfd2c48906fab72d8ed22992802aa44daa69d7919cc3ccc62faffe
7
+ data.tar.gz: 17ae44d0099f00b6193f3e94aaa50830556e191d728bc3580b4164fae8f4b6b9f808cea2d3925ffe73cd5a30ea5501be6d393b428e23b01d6b4ee63dfd9d5d32
data/CHANGELOG.md ADDED
@@ -0,0 +1,41 @@
1
+ ## [9.0.0] - Unreleased
2
+
3
+ ### Changed
4
+ - Switched to independent Semantic Versioning. Prior releases tracked the Rails
5
+ major/minor line; the version number no longer maps to a Rails version.
6
+ - Require Ruby >= 3.3.
7
+ - Require ActiveRecord >= 8.0, < 9.0 (dropped support for Rails older than 8.0).
8
+
9
+ ### Added
10
+ - `gem.description` and gemspec `metadata` (source, changelog, MFA-required).
11
+
12
+ ### Packaging
13
+ - Slimmed the published gem to `lib`, `ext`, `LICENSE`, and `README.md`; removed
14
+ the deprecated `test_files` declaration.
15
+
16
+ ### Documentation
17
+ - Documented the features arel-extensions adds (DISTINCT ON, NULLS ordering,
18
+ array/JSON predicates, full-text search, GIS, binary values) in the README.
19
+ - Documented that the GIS predicates (`#intersects`, `#within`) require the
20
+ optional `rgeo` gem unless passed an Arel node.
21
+
22
+ ## Earlier releases
23
+
24
+ Prior versions tracked the matching Rails release. See the Git tags for details:
25
+
26
+ - [8.1.0] - 2025-12-22
27
+ - [8.0.0] - 2025-01-27
28
+ - [7.0.1] - 2023-05-31
29
+ - [7.0.0] - 2022-12-07
30
+ - [6.1.0] - 2021-01-14
31
+ - [6.0.0.7] - 2019-11-04
32
+ - [6.0.0.2] - 2019-08-12
33
+
34
+ [9.0.0]: https://github.com/malomalo/arel-extensions/compare/v8.1.0...master
35
+ [8.1.0]: https://github.com/malomalo/arel-extensions/releases/tag/v8.1.0
36
+ [8.0.0]: https://github.com/malomalo/arel-extensions/releases/tag/v8.0.0
37
+ [7.0.1]: https://github.com/malomalo/arel-extensions/releases/tag/v7.0.1
38
+ [7.0.0]: https://github.com/malomalo/arel-extensions/releases/tag/v7.0.0
39
+ [6.1.0]: https://github.com/malomalo/arel-extensions/releases/tag/v6.1.0
40
+ [6.0.0.7]: https://github.com/malomalo/arel-extensions/releases/tag/v6.0.0.7
41
+ [6.0.0.2]: https://github.com/malomalo/arel-extensions/releases/tag/v6.0.0.2
data/README.md CHANGED
@@ -18,5 +18,86 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- Just `require 'arel-extensions'` and use Arel/ActiveRecord as you normally would!
22
- arel-extensions extends ActiveRecord's query methods in both Arel and ActiveRecord.
21
+ Just `require 'arel-extensions'` and use `Arel` / `ActiveRecord` as you normally
22
+ would.
23
+
24
+ It adds the methods and nodes below to `Arel::Attributes::Attribute` and to
25
+ `ActiveRecord` relations. Most operators generate PostgreSQL-specific SQL.
26
+
27
+ Attribute-level helpers are used through an Arel attribute, e.g.
28
+ `Model.arel_table[:column]`, typically inside `where` or `order`.
29
+
30
+ ## What it adds
31
+
32
+ ### `DISTINCT ON` (ActiveRecord)
33
+
34
+ Added to relations (and as a class method via `Model.distinct_on`):
35
+
36
+ ```ruby
37
+ User.distinct_on(:email) # SELECT DISTINCT ON (users.email) ...
38
+ User.distinct_on(:a, :b) # DISTINCT ON (users.a, users.b)
39
+ ```
40
+
41
+ `uniq_on` is an alias of `distinct_on`.
42
+
43
+ ### Ordering with NULLS FIRST / LAST
44
+
45
+ ```ruby
46
+ col = User.arel_table[:name]
47
+ User.order(col.asc(:nulls_last)) # ... ORDER BY users.name ASC NULLS LAST
48
+ User.order(col.desc(:nulls_first)) # ... ORDER BY users.name DESC NULLS FIRST
49
+ ```
50
+
51
+ A `RANDOM()` ordering node is also provided.
52
+
53
+ ### Array predicates
54
+
55
+ ```ruby
56
+ tags = Post.arel_table[:tags]
57
+ tags.contained_by(other) # tags <@ other
58
+ tags.excludes(other) # NOT (tags @> other)
59
+ ```
60
+
61
+ ### JSON / JSONB predicates
62
+
63
+ ```ruby
64
+ data = User.arel_table[:data]
65
+
66
+ data.key('name') # data #>'{name}' (aliases: data['name'], data.index('name'))
67
+ data.dig('address', 'zip') # data #>'{address,zip}'
68
+ data.has_key('name') # data ? 'name'
69
+ data.has_keys('a', 'b') # data ?& array['a','b']
70
+ data.has_any_key('a', 'b') # data ?| array['a','b']
71
+ data.cast_as('int') # (data)::int
72
+ ```
73
+
74
+ ### Full-text search
75
+
76
+ ```ruby
77
+ body = Article.arel_table[:body]
78
+ body.ts_query('quick & fox') # to_tsvector(body) @@ to_tsquery('quick & fox')
79
+ body.ts_query('quick & fox', 'english')
80
+ ```
81
+
82
+ Nodes for `to_tsvector`, `to_tsquery`, `@@` (`TSMatch`), `ts_rank`, and
83
+ `ts_rank_cd` are available for building ranking expressions.
84
+
85
+ ### GIS predicates (optional)
86
+
87
+ ```ruby
88
+ area = Place.arel_table[:area]
89
+ area.intersects(value) # ST_Intersects(area, value)
90
+ area.within(value) # ST_Within(area, value)
91
+ ```
92
+
93
+ `value` may be an Arel node, an RGeo geometry, a WKT/WKB string, or a GeoJSON
94
+ hash. Anything other than an Arel node requires the
95
+ [`rgeo`](https://github.com/rgeo/rgeo) gem, so add it to your Gemfile if you use
96
+ these:
97
+
98
+ gem 'rgeo'
99
+
100
+ ### Binary values
101
+
102
+ `BinaryValue` and `HexEncodedBinaryValue` nodes for embedding binary data
103
+ (escaped `bytea` and `\x`-encoded hex, respectively).
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class Ascending < Ordering
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class Descending < Ordering
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Ordering with :nulls_last, :nulls_first options
2
4
  module Arel
3
5
  module OrderPredications
@@ -1,47 +1,49 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_record'
2
4
  require 'active_record/relation'
3
5
  require 'active_record/querying'
4
6
  require 'active_record/relation/query_methods'
5
7
 
6
- module ActiveRecord::QueryMethods
7
- def distinct_on_values
8
- @values["distinct_on_values"] || []
9
- end
10
-
11
- def distinct_on_values=(value)
12
- @values["distinct_on_values"] = value
13
- end
8
+ module ActiveRecord
9
+ # Prepended onto ActiveRecord::QueryMethods rather than reopening it, so
10
+ # these methods don't appear in QueryMethods.public_instance_methods(false)
11
+ # -- which Rails' QueryingMethodsDelegationTest asserts against -- while
12
+ # relations still respond to them.
13
+ module DistinctOn
14
+ def distinct_on_values
15
+ @values["distinct_on_values"] || []
16
+ end
14
17
 
15
- def distinct_on(*fields)
16
- spawn.distinct_on!(*fields)
17
- end
18
- alias uniq_on distinct_on
18
+ def distinct_on_values=(value)
19
+ @values["distinct_on_values"] = value
20
+ end
19
21
 
20
- def distinct_on!(*fields)
21
- fields.flatten!
22
- self.distinct_on_values = fields.map { |x| x.is_a?(Arel::Attributes::Attribute) ? x : klass.arel_table[x] }
23
- self
24
- end
25
- alias uniq_on! distinct_on!
22
+ def distinct_on(*fields)
23
+ spawn.distinct_on!(*fields)
24
+ end
25
+ alias uniq_on distinct_on
26
26
 
27
- private
28
-
29
- if ActiveRecord.version >= "7.2"
30
- def build_arel_with_distinct_on(connection, aliases = nil)
31
- arel = build_arel_without_distinct_on(connection, aliases)
32
- arel.distinct_on(self.distinct_on_values) if !self.distinct_on_values.empty?
33
- arel
27
+ def distinct_on!(*fields)
28
+ fields.flatten!
29
+ self.distinct_on_values = fields.map { |x| x.is_a?(Arel::Attributes::Attribute) ? x : klass.arel_table[x] }
30
+ self
34
31
  end
35
- else
36
- def build_arel_with_distinct_on(aliases = nil)
37
- arel = build_arel_without_distinct_on(aliases)
32
+ alias uniq_on! distinct_on!
33
+
34
+ private
35
+
36
+ # Version-agnostic: forward whatever build_arel receives (its signature
37
+ # varies across Rails versions) to the original via super, then apply
38
+ # the accumulated distinct_on values.
39
+ def build_arel(*args)
40
+ arel = super
38
41
  arel.distinct_on(self.distinct_on_values) if !self.distinct_on_values.empty?
39
42
  arel
40
43
  end
41
44
  end
42
- alias_method :build_arel_without_distinct_on, :build_arel
43
- alias_method :build_arel, :build_arel_with_distinct_on
44
45
  end
45
46
 
47
+ ActiveRecord::QueryMethods.prepend(ActiveRecord::DistinctOn)
46
48
  ActiveRecord::Querying.delegate :distinct_on, to: :all
47
- ActiveRecord::Querying.delegate :distinct_on!, to: :all
49
+ ActiveRecord::Querying.delegate :uniq_on, to: :all
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module ArrayPredications
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Attributes
3
5
  class Cast < Attribute
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Attributes
3
5
  class Key < Attribute
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Extensions
3
- VERSION = '8.0.2'
5
+ VERSION = '9.0.0'
4
6
  end
5
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "arel"
2
4
  require File.expand_path('../nodes/binary_value', __FILE__)
3
5
  require File.expand_path('../nodes/hex_encoded_binary_value', __FILE__)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module GISPredications
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module JSONPredications
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class BinaryValue < Arel::Nodes::Unary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class ContainedBy < InfixOperation
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class Excludes < Binary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class Geometry < Arel::Nodes::Unary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class HasAnyKey < Binary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class HasKey < Binary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class HasKeys < Binary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class HexEncodedBinaryValue < Arel::Nodes::Unary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class Intersects < Binary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class RandomOrdering < Arel::Nodes::Node
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Attributes
3
5
  class Relation < Attribute
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class TSMatch < Binary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class TSQuery < Arel::Nodes::Node
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class TSRank < Arel::Nodes::Node
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class TSRankCD < Arel::Nodes::Node
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class TSVector < Arel::Nodes::Node
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Nodes
3
5
  class Within < Binary
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module TSPredications
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Visitors
3
5
  class PostgreSQL
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Visitors
3
5
  class Sunstone
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Arel
2
4
  module Visitors
3
5
  class ToSql
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arel-extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.2
4
+ version: 9.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Bracy
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-01-27 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activerecord
@@ -16,7 +15,7 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 7.0.0
18
+ version: 8.0.0
20
19
  - - "<"
21
20
  - !ruby/object:Gem::Version
22
21
  version: '9.0'
@@ -26,24 +25,10 @@ dependencies:
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- version: 7.0.0
28
+ version: 8.0.0
30
29
  - - "<"
31
30
  - !ruby/object:Gem::Version
32
31
  version: '9.0'
33
- - !ruby/object:Gem::Dependency
34
- name: bundler
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: '0'
40
- type: :development
41
- prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: '0'
47
32
  - !ruby/object:Gem::Dependency
48
33
  name: debug
49
34
  requirement: !ruby/object:Gem::Requirement
@@ -170,20 +155,18 @@ dependencies:
170
155
  - - ">="
171
156
  - !ruby/object:Gem::Version
172
157
  version: '8.0'
173
- description:
158
+ description: Extends Arel and ActiveRecord with SQL operators and functions that aren't
159
+ available out of the box, including array and JSON predicates, PostgreSQL full-text
160
+ search (tsvector/tsquery), GIS/geometry predicates, and additional ordering helpers.
174
161
  email:
175
162
  - jonbracy@gmail.com
176
163
  executables: []
177
164
  extensions: []
178
165
  extra_rdoc_files: []
179
166
  files:
180
- - ".github/workflows/ci.yml"
181
- - ".gitignore"
182
- - Gemfile
167
+ - CHANGELOG.md
183
168
  - LICENSE
184
169
  - README.md
185
- - Rakefile
186
- - arel-extensions.gemspec
187
170
  - ext/arel/nodes/ascending.rb
188
171
  - ext/arel/nodes/descending.rb
189
172
  - ext/arel/order_predications.rb
@@ -216,18 +199,13 @@ files:
216
199
  - lib/arel/visitors/postgresql_extensions.rb
217
200
  - lib/arel/visitors/sunstone_extensions.rb
218
201
  - lib/arel/visitors/to_sql_extensions.rb
219
- - test/binary_value_test.rb
220
- - test/database.rb
221
- - test/gis_test.rb
222
- - test/order_test.rb
223
- - test/sunstone_test.rb
224
- - test/test_helper.rb
225
- - test/ts_test.rb
226
202
  homepage: https://github.com/malomalo/arel-extensions
227
203
  licenses:
228
204
  - MIT
229
- metadata: {}
230
- post_install_message:
205
+ metadata:
206
+ source_code_uri: https://github.com/malomalo/arel-extensions
207
+ changelog_uri: https://github.com/malomalo/arel-extensions/blob/master/CHANGELOG.md
208
+ rubygems_mfa_required: 'true'
231
209
  rdoc_options: []
232
210
  require_paths:
233
211
  - lib
@@ -235,22 +213,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
235
213
  requirements:
236
214
  - - ">="
237
215
  - !ruby/object:Gem::Version
238
- version: '0'
216
+ version: '3.3'
239
217
  required_rubygems_version: !ruby/object:Gem::Requirement
240
218
  requirements:
241
219
  - - ">="
242
220
  - !ruby/object:Gem::Version
243
221
  version: '0'
244
222
  requirements: []
245
- rubygems_version: 3.5.21
246
- signing_key:
223
+ rubygems_version: 4.0.11
247
224
  specification_version: 4
248
225
  summary: Adds support for missing SQL operators and functions to Arel
249
- test_files:
250
- - test/binary_value_test.rb
251
- - test/database.rb
252
- - test/gis_test.rb
253
- - test/order_test.rb
254
- - test/sunstone_test.rb
255
- - test/test_helper.rb
256
- - test/ts_test.rb
226
+ test_files: []