arel-extensions 1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4847138fb20c8ca58e5bf419b595e1cf9e4dc809
4
+ data.tar.gz: 54565109b15574583361a153a2558bdb5deac376
5
+ SHA512:
6
+ metadata.gz: d934dc0afa953e09db3837747ebc919ae473901f6da32033a76635261eda113c75504a7ac98c861b48983993c2e0dace2f439f31d18542b62e01ce30b1d66d74
7
+ data.tar.gz: f568ff754c5f16fca13c73925353ffe9aae53fcd1cdfa8da74dafebabef5110c0308135375241c8c82e7bb2f420229da4ec41bdc3d9b99e055215d387a988ae6
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jon Bracy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,216 @@
1
+ # Arel Extensions
2
+
3
+ Adds support for missing SQL operators and functions to Arel for ActiveRecord.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'arel-extensions', require: 'arel/extensions'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install arel-extensions
18
+
19
+ ## Usage
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.
23
+
24
+ * [Querying PostgreSQL datatypes](docs/querying.md)
25
+
26
+ ## Arrays
27
+
28
+ * [@> - Array Contains operator](#---array-contains-operator)
29
+ * [<@ - Array Contained By operator](#---array-contined-by-operator)
30
+ * [&& - Array Overlap operator](#---array-overlap-operator)
31
+
32
+ ### && - Array Overlap operator
33
+
34
+ PostgreSQL implements the `&&` operator, known as the overlap operator,
35
+ for arrays. The overlap operator returns `t` (true) when two arrays have
36
+ one or more elements in common.
37
+
38
+ ```sql
39
+ ARRAY[1,2,3] && ARRAY[4,5,6]
40
+ -- f
41
+
42
+ ARRAY[1,2,3] && ARRAY[3,5,6]
43
+ -- t
44
+ ```
45
+
46
+ Postgres\_ext extends the `ActiveRecord::Relation.where` method similar
47
+ to the Rails 4.0 not clause. The easiest way to make a overlap query
48
+ would be:
49
+
50
+ ```ruby
51
+ User.where.overlap(:nick_names => ['Bob', 'Fred'])
52
+ ```
53
+
54
+ Postgres\_ext defines `overlap`, an [Arel](https://github.com/rails/arel)
55
+ predicate for the `&&` operator. This is utilized by the `where.overlap`
56
+ call above.
57
+
58
+ ```ruby
59
+ user_arel = User.arel_table
60
+
61
+ # Execute the query
62
+ User.where(user_arel[:tags].overlap(['one','two']))
63
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"tags\" && '{one,two}'
64
+ ```
65
+
66
+ ### @> - Array Contains operator
67
+
68
+ PostgreSQL has a contains (`@>`) operator for querying whether all the
69
+ elements of an array are within another.
70
+
71
+ ```sql
72
+ ARRAY[1,2,3] @> ARRAY[3,4]
73
+ -- f
74
+
75
+ ARRAY[1,2,3] @> ARRAY[2,3]
76
+ -- t
77
+ ```
78
+
79
+ Postgres\_ext extends the `ActiveRecord::Relation.where` method by
80
+ adding a `contains` method. To make a contains query, you can do:
81
+
82
+ ```ruby
83
+ User.where.contains(:nick_names => ['Bob', 'Fred'])
84
+ ```
85
+
86
+ Postgres\_ext overrides `contains`, an [Arel](https://github.com/rails/arel)
87
+ predicate, to use the `@>` operator for arrays. This is utilized by the
88
+ `where.contains` call above.
89
+
90
+ ```ruby
91
+ user_arel = User.arel_table
92
+
93
+ # Execute the query
94
+ User.where(user_arel[:tags].contains(['one','two']))
95
+ # => SELECT "users".* FROM "users" WHERE "users"."tags" @> '{"one","two"}'
96
+ ```
97
+
98
+ ### ANY or ALL functions
99
+
100
+ When querying array columns, you have the ability to see if a predicate
101
+ apply's to either *any* element in the array, or *all* elements of the
102
+ array. The syntax for these predicates are slightly different then the
103
+ normal `where` syntax in PostgreSQL. To see if an array contains the
104
+ string `'test'` in any location, you would write the following in SQL
105
+
106
+ ```sql
107
+ SELECT *
108
+ FROM users
109
+ WHERE 'test' = ANY(users.tags)
110
+ ```
111
+
112
+ Notice that the column is on the right hand side of the predicate,
113
+ instead of the left, because we have to call the `ANY` function on that
114
+ column.
115
+
116
+ Postgres\_ext provides a `ActiveRecord::Relation.where.any()` method. The
117
+ easiest way to make a ANY query would be:
118
+
119
+ ```ruby
120
+ User.where.any(:nick_names => 'Bob')
121
+ ```
122
+
123
+ There is also an `ActiveRecord::Relation.where.all()` call as well. This
124
+ method utilizes the following code to create the query:
125
+
126
+ We can generate the above query using [Arel](https://github.com/rails/arel)
127
+ and generating the Node manually. We would use the following to
128
+ accompish this:
129
+
130
+ ```ruby
131
+ user_arel = User.arel_table
132
+
133
+ # Execute the query
134
+ User.where(user_arel[:tags].any('test'))
135
+ #=> SELECT \"users\".* FROM \"users\" WHERE 'test' = ANY(\"users\".\"tags\")
136
+ ```
137
+
138
+ The ALL version of this same predicate can be generated by swapping
139
+ `#any()` for `#all()`.
140
+
141
+ ## INET/CIDR Queries
142
+
143
+ PostgreSQL defines the `<<`, or contained within operator for INET and
144
+ CIDR datatypes. The `<<` operator returns `t` (true) if a INET or CIDR
145
+ address is contained within the given subnet.
146
+
147
+ ```sql
148
+ inet '192.168.1.6' << inet '10.0.0.0/24'
149
+ -- f
150
+
151
+ inet '192.168.1.6' << inet '192.168.1.0/24'
152
+ -- t
153
+ ```
154
+
155
+ In addition to contained within, there is also:
156
+
157
+ * `<<=` - Contained within or equals
158
+ * `>>` - Contains
159
+ * `>>=` - Contains or equals
160
+
161
+ Postgres\_ext extends the `ActiveRecord::Relation.where` method similar
162
+ to the Rails 4.0 not clause. The easiest way to make a overlap query
163
+ would be:
164
+
165
+ ```ruby
166
+ User.where.contained_within(:ip => '192.168.1.1/24')
167
+ User.where.contained_within_or_equals(:ip => '192.168.1.1/24')
168
+ User.where.contains(:ip => '192.168.1.14')
169
+ User.where.contains_or_equals(:ip => '192.168.1.14')
170
+ ```
171
+
172
+ Postgres\_ext defines `contained_within`, an [Arel](https://github.com/rails/arel)
173
+ predicate for the `<<` operator. This is utilized by the
174
+ methods above.
175
+
176
+ ```ruby
177
+ user_arel = User.arel_table
178
+
179
+ # Execute the query
180
+ User.where(user_arel[:ip_address].contained_within('127.0.0.1/24'))
181
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" << '127.0.0.1/24'
182
+ User.where(user_arel[:ip_address].contained_within_or_equals('127.0.0.1/24'))
183
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" <<= '127.0.0.1/24'
184
+ User.where(user_arel[:ip_address].contains('127.0.0.1'))
185
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" >> '127.0.0.1'
186
+ User.where(user_arel[:ip_address].contains_or_equals('127.0.0.1'))
187
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" >>= '127.0.0.1'
188
+ ```
189
+
190
+ ## Developing
191
+
192
+ To work on postgres\_ext locally, follow these steps:
193
+
194
+ 1. Run `bundle install`, this will install (almost) all the development
195
+ dependencies
196
+ 2. Run `gem install byebug` (not a declared dependency to not break CI)
197
+ 3. Run `bundle exec rake db:setup`, this will set up the `.env` file necessary to run
198
+ the tests and set up the database
199
+ 4. Run `bundle exec rake db:create`, this will create the test database
200
+ 5. Run `bundle exec rake db:migrate`, this will set up the database tables required
201
+ by the test
202
+ 6. Run `BUNDLE_GEMFILE='gemfiles/Gemfile.activerecord-4.0.x' bundle install --quiet` to create the Gemfile.lock for 4.0.
203
+ 7. Run `BUNDLE_GEMFILE='gemfiles/Gemfile.activerecord-4.1.x' bundle install --quiet` to create the Gemfile.lock for 4.1.
204
+ 8. Run `bundle exec rake test:all` to run tests against all supported versions of Active Record
205
+
206
+ ## Authors
207
+
208
+ Dan McClain [twitter](http://twitter.com/_danmcclain) [github](http://github.com/danmcclain)
209
+
210
+
211
+
212
+
213
+
214
+ Change.arel_table[:diff].has_key?(:in_review)
215
+ Change.arel_table[:diff].has_keys?(:in_review, :cached_at)
216
+ Change.arel_table[:diff].has_any_key?(:in_review, :nokey)
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = 'arel-extensions'
3
+ gem.version = '1.0.0'
4
+
5
+ gem.authors = ["Jon Bracy"]
6
+ gem.email = ["jonbracy@gmail.com"]
7
+ gem.summary = %q{Adds support for missing SQL operators and functions to Arel}
8
+ gem.homepage = 'https://github.com/malomalo/arel-extensions'
9
+ gem.licenses = ['MIT']
10
+
11
+ gem.files = `git ls-files`.split("\n")
12
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
+ gem.require_paths = ["lib"]
14
+
15
+ gem.add_dependency 'arel', '>= 7.0.0'
16
+
17
+ gem.add_development_dependency 'rake'
18
+ gem.add_development_dependency 'minitest'
19
+ end
@@ -0,0 +1,20 @@
1
+ module Arel
2
+ module ArrayPredications
3
+
4
+ def contains(*values)
5
+ values = values[0] if values.size == 1 && values[0].is_a?(Array)
6
+ Arel::Nodes::Contains.new(self, values)
7
+ end
8
+
9
+ def contained_by(*values)
10
+ values = values[0] if values.size == 1 && values[0].is_a?(Array)
11
+ Arel::Nodes::ContainedBy.new(self, values)
12
+ end
13
+
14
+ def overlaps(*values)
15
+ values = values[0] if values.size == 1 && values[0].is_a?(Array)
16
+ Arel::Nodes::Overlaps.new(self, values)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ module Arel
2
+ module Attributes
3
+ class Key < Attribute
4
+ def able_to_type_cast?
5
+ false
6
+ end
7
+
8
+ def table_name
9
+ nil
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path('../array_predications', __FILE__)
2
+ require File.expand_path('../nodes/overlaps', __FILE__)
3
+ require File.expand_path('../nodes/contains', __FILE__)
4
+ Arel::Attributes::Attribute.include(Arel::ArrayPredications)
5
+
6
+
7
+ require File.expand_path('../attributes/key', __FILE__)
8
+ require File.expand_path('../nodes/has_any_key', __FILE__)
9
+ require File.expand_path('../nodes/has_key', __FILE__)
10
+ require File.expand_path('../nodes/has_keys', __FILE__)
11
+ require File.expand_path('../json_predications', __FILE__)
12
+ Arel::Attributes::Attribute.include(Arel::JSONPredications)
13
+
14
+ if defined?(Arel::Visitors::PostgreSQL)
15
+ require File.expand_path('../visitors/postgresql_extensions', __FILE__)
16
+ end
@@ -0,0 +1,23 @@
1
+ module Arel
2
+ module JSONPredications
3
+
4
+ def key(key)
5
+ Arel::Attributes::Key.new(self, key)
6
+ end
7
+ alias :[] :key
8
+ alias :index :key
9
+
10
+ def has_key(key)
11
+ Arel::Nodes::HasKey.new(self, key)
12
+ end
13
+
14
+ def has_keys(*keys)
15
+ Arel::Nodes::HasKeys.new(self, keys)
16
+ end
17
+
18
+ def has_any_key(*keys)
19
+ Arel::Nodes::HasAnyKeys.new(self, keys)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+ module Arel
2
+ module Nodes
3
+ class Contains < Binary
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module Arel
2
+ module Nodes
3
+ class HasAnyKeys < Binary
4
+ # ?|
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Arel
2
+ module Nodes
3
+ class HasKey < Binary
4
+ # ?
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Arel
2
+ module Nodes
3
+ class HasKeys < Binary
4
+ # ?&
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ module Arel
2
+ module Nodes
3
+ class Overlaps < Binary
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,45 @@
1
+ module Arel
2
+ module Visitors
3
+ class PostgreSQL
4
+ private
5
+
6
+ def visit_Arel_Nodes_Contains o, collector
7
+ visit o.left, collector
8
+ collector << ' @> '
9
+ collector << quote(o.left.type_cast_for_database(o.right))
10
+ end
11
+
12
+ def visit_Arel_Nodes_ContainedBy o, collector
13
+ visit o.left, collector
14
+ collector << ' <@ '
15
+ collector << quote(o.left.type_cast_for_database(o.right))
16
+ end
17
+
18
+ def visit_Arel_Nodes_Overlaps o, collector
19
+ visit o.left, collector
20
+ collector << ' && '
21
+ collector << quote(o.left.type_cast_for_database(o.right))
22
+ end
23
+
24
+ def visit_Arel_Attributes_Key(o, collector, last_key = true)
25
+ if o.relation.is_a?(Arel::Attributes::Key)
26
+ visit_Arel_Attributes_Key(o.relation, collector, false)
27
+ if last_key
28
+ collector << o.name.to_s
29
+ collector << "}'"
30
+ else
31
+ collector << o.name.to_s
32
+ collector << "."
33
+ end
34
+ else
35
+ visit(o.relation, collector)
36
+ collector << "\#>>'{" << o.name.to_s
37
+ if !last_key
38
+ collector << "."
39
+ end
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: arel-extensions
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jon Bracy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: arel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - jonbracy@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE
63
+ - README.md
64
+ - arel-extensions.gemspec
65
+ - lib/arel/array_predications.rb
66
+ - lib/arel/attributes/key.rb
67
+ - lib/arel/extensions.rb
68
+ - lib/arel/json_predications.rb
69
+ - lib/arel/nodes/contains.rb
70
+ - lib/arel/nodes/has_any_key.rb
71
+ - lib/arel/nodes/has_key.rb
72
+ - lib/arel/nodes/has_keys.rb
73
+ - lib/arel/nodes/overlaps.rb
74
+ - lib/arel/visitors/postgresql_extensions.rb
75
+ homepage: https://github.com/malomalo/arel-extensions
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.5.1
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Adds support for missing SQL operators and functions to Arel
99
+ test_files: []