active_record_extended 0.5.0.beta1 → 0.5.0.beta2
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +208 -1
- data/Rakefile +2 -0
- data/lib/active_record_extended/arel/nodes.rb +13 -11
- data/lib/active_record_extended/arel/predications.rb +17 -16
- data/lib/active_record_extended/arel/visitors/postgresql_decorator.rb +9 -9
- data/lib/active_record_extended/query_methods/inet.rb +84 -0
- data/lib/active_record_extended/query_methods/where_chain.rb +0 -12
- data/lib/active_record_extended/version.rb +1 -1
- data/spec/query_methods/array_query_spec.rb +3 -3
- data/spec/query_methods/inet_query_spec.rb +97 -0
- data/spec/sql_inspections/arel/inet_spec.rb +51 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df4c51db1e23fe823d4f551b4b44eb607133b431f0970286b0e3b3a576c6ad42
|
4
|
+
data.tar.gz: cd2558c39e0224d6fc9719dc7ceb27a45ed0e98da7141ed620287f95ce4a6062
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 520880c113c258caaa12a3ef2f83b92f1f7d6e71b03beaab5acd03050267071f2025b268f8156eb70206ad84887a13195717d76e328e10832257433a6963421e
|
7
|
+
data.tar.gz: 8ba91e9f95d7f77541d5f956811b4c61e9e04a2e8ecbe8cc12cff6fe79ead72ce7233699f7d89de53fcd67f1aa1a932ea2d31bbc144adc7943cd119e1f8e748b
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,25 @@
|
|
1
1
|
[](https://travis-ci.com/GeorgeKaraszi/ActiveRecordExtended) [](https://codeclimate.com/github/GeorgeKaraszi/active_record_extended/maintainability)
|
2
2
|
|
3
|
-
|
3
|
+
## Index
|
4
|
+
- [Description and history](#description-and-history)
|
5
|
+
- [Installation](#installation)
|
6
|
+
- [Useage](#usage)
|
7
|
+
- [Query Methods](#query-methods)
|
8
|
+
- [Any](#any)
|
9
|
+
- [All](#all)
|
10
|
+
- [Contains](#contains)
|
11
|
+
- [Overlap](#overlap)
|
12
|
+
- [Inet / IP Address](#inet--ip-address)
|
13
|
+
- [Inet Contains](#inet-contains)
|
14
|
+
- [Inet Contains or Equals](#inet-contains-or-equals)
|
15
|
+
- [Inet Contained Within](#inet-contained-within)
|
16
|
+
- [Inet Contained Within or Equals](#inet-contained-within-or-equals)
|
17
|
+
- [Conditional Methods](#conditional-methods)
|
18
|
+
- [Any_of / None_of](#any_of--none_of)
|
19
|
+
- [Either Join](#either-join)
|
20
|
+
- [Either Order](#either-order)
|
21
|
+
|
22
|
+
## Description and History
|
4
23
|
|
5
24
|
Active Record Extended is the continuation of maintaining and improving the work done by **Dan McClain**, the original author of [postgres_ext](https://github.com/DavyJonesLocker/postgres_ext).
|
6
25
|
|
@@ -9,6 +28,194 @@ The only problem is that this has created a wild west of environments of sorts.
|
|
9
28
|
|
10
29
|
Active Record Extended is intended to be a supporting community that will maintain compatibility for the foreseeable future.
|
11
30
|
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
### Query Methods
|
35
|
+
|
36
|
+
#### Any
|
37
|
+
[Postgres 'ANY' expression](https://www.postgresql.org/docs/10/static/functions-comparisons.html#id-1.5.8.28.16)
|
38
|
+
|
39
|
+
In Postgres the `ANY` expression is used for gather record's that have an Array column type that contain a single matchable value within its array.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
alice = Person.create!(tags: [1])
|
43
|
+
bob = Person.create!(tags: [1, 2])
|
44
|
+
randy = Person.create!(tags: [3])
|
45
|
+
|
46
|
+
Person.where.any(tags: 1) #=> [alice, bob]
|
47
|
+
|
48
|
+
```
|
49
|
+
|
50
|
+
This only accepts a single value. So querying for example multiple tag numbers `[1,2]` will return nothing.
|
51
|
+
|
52
|
+
|
53
|
+
#### All
|
54
|
+
[Postgres 'ALL' expression](https://www.postgresql.org/docs/10/static/functions-comparisons.html#id-1.5.8.28.17)
|
55
|
+
|
56
|
+
In Postgres the `ALL` expression is used for gather record's that have an Array column type that contains only a **single** and matchable element.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
alice = Person.create!(tags: [1])
|
60
|
+
bob = Person.create!(tags: [1, 2])
|
61
|
+
randy = Person.create!(tags: [3])
|
62
|
+
|
63
|
+
Person.where.all(tags: 1) #=> [alice]
|
64
|
+
|
65
|
+
```
|
66
|
+
|
67
|
+
This only accepts a single value to a given attribute. So querying for example multiple tag numbers `[1,2]` will return nothing.
|
68
|
+
|
69
|
+
#### Contains
|
70
|
+
[Postgres '@>' (Array type) Contains expression](https://www.postgresql.org/docs/10/static/functions-array.html)
|
71
|
+
|
72
|
+
[Postgres '@>' (JSONB/HSTORE type) Contains expression](https://www.postgresql.org/docs/10/static/functions-json.html#FUNCTIONS-JSONB-OP-TABLE)
|
73
|
+
|
74
|
+
|
75
|
+
The `contains/1` method is used for finding any elements in an `Array`, `JSONB`, or `HSTORE` column type.
|
76
|
+
That contains all of the provided values.
|
77
|
+
|
78
|
+
Array Type:
|
79
|
+
```ruby
|
80
|
+
alice = Person.create!(tags: [1, 4])
|
81
|
+
bob = Person.create!(tags: [3, 1])
|
82
|
+
randy = Person.create!(tags: [4, 1])
|
83
|
+
|
84
|
+
Person.where.contains(tags: [1, 4]) #=> [alice, randy]
|
85
|
+
```
|
86
|
+
|
87
|
+
HSTORE / JSONB Type:
|
88
|
+
```ruby
|
89
|
+
alice = Person.create!(data: { nickname: "ARExtend" })
|
90
|
+
bob = Person.create!(data: { nickname: "ARExtended" })
|
91
|
+
randy = Person.create!(data: { nickname: "ARExtended" })
|
92
|
+
|
93
|
+
Person.where.contains(data: { nickname: "ARExtended" }) #=> [bob, randy]
|
94
|
+
```
|
95
|
+
|
96
|
+
#### Overlap
|
97
|
+
[Postgres && (overlap) Expression](https://www.postgresql.org/docs/10/static/functions-array.html)
|
98
|
+
|
99
|
+
The `overlap/1` method will match an Array column type that contains any of the provided values within its column.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
alice = Person.create!(tags: [1, 4])
|
103
|
+
bob = Person.create!(tags: [3, 4])
|
104
|
+
randy = Person.create!(tags: [4, 8])
|
105
|
+
|
106
|
+
Person.where.overlap(tags: [4]) #=> [alice, bob, randy]
|
107
|
+
Person.where.overlap(tags: [1, 8]) #=> [alice, randy]
|
108
|
+
Person.where.overlap(tags: [1, 3, 8]) #=> [alice, bob, randy]
|
109
|
+
|
110
|
+
```
|
111
|
+
|
112
|
+
#### Inet / IP Address
|
113
|
+
##### Inet Contains
|
114
|
+
[Postgres >> (contains) Network Expression](https://www.postgresql.org/docs/current/static/functions-net.html)
|
115
|
+
|
116
|
+
The `inet_contains` method works by taking a column(inet type) that has a submask prepended to it.
|
117
|
+
And tries to find related records that fall within a given IP's range.
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
alice = Person.create!(ip: "127.0.0.1/16")
|
121
|
+
bob = Person.create!(ip: "192.168.0.1/16")
|
122
|
+
|
123
|
+
Person.where.inet_contains(ip: "127.0.0.254") #=> [alice]
|
124
|
+
Person.where.inet_contains(ip: "192.168.20.44") #=> [bob]
|
125
|
+
Person.where.inet_contains(ip: "192.255.1.1") #=> []
|
126
|
+
```
|
127
|
+
|
128
|
+
##### Inet Contains or Equals
|
129
|
+
[Postgres >>= (contains or equals) Network Expression](https://www.postgresql.org/docs/current/static/functions-net.html)
|
130
|
+
|
131
|
+
The `inet_contains_or_equals` method works much like the [Inet Contains](#inet-contains) method, but will also accept a submask range.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
alice = Person.create!(ip: "127.0.0.1/10")
|
135
|
+
bob = Person.create!(ip: "127.0.0.44/24")
|
136
|
+
|
137
|
+
Person.where.inet_contains_or_equals(ip: "127.0.0.1/16") #=> [alice]
|
138
|
+
Person.where.inet_contains_or_equals(ip: "127.0.0.1/10") #=> [alice]
|
139
|
+
Person.where.inet_contains_or_equals(ip: "127.0.0.1/32") #=> [alice, bob]
|
140
|
+
```
|
141
|
+
|
142
|
+
##### Inet Contained Within
|
143
|
+
[Postgres << (contained within) Network Expression](https://www.postgresql.org/docs/current/static/functions-net.html)
|
144
|
+
|
145
|
+
For the `inet_contained_within` method, we try to find IP's that fall within a submasking range we provide.
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
alice = Person.create!(ip: "127.0.0.1")
|
149
|
+
bob = Person.create!(ip: "127.0.0.44")
|
150
|
+
randy = Person.create!(ip: "127.0.55.20")
|
151
|
+
|
152
|
+
Person.where.inet_contained_within(ip: "127.0.0.1/24") #=> [alice, bob]
|
153
|
+
Person.where.inet_contained_within(ip: "127.0.0.1/16") #=> [alice, bob, randy]
|
154
|
+
```
|
155
|
+
|
156
|
+
##### Inet Contained Within or Equals
|
157
|
+
[Postgres <<= (contained within or equals) Network Expression](https://www.postgresql.org/docs/current/static/functions-net.html)
|
158
|
+
|
159
|
+
The `inet_contained_within_or_equals` method works much like the [Inet Contained Within](#inet-contained-within) method, but will also accept a submask range.
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
alice = Person.create!(ip: "127.0.0.1/10")
|
163
|
+
bob = Person.create!(ip: "127.0.0.44/32")
|
164
|
+
randy = Person.create!(ip: "127.0.99.1")
|
165
|
+
|
166
|
+
Person.where.inet_contained_within_or_equals(ip: "127.0.0.44/32") #=> [bob]
|
167
|
+
Person.where.inet_contained_within_or_equals(ip: "127.0.0.1/16") #=> [bob, randy]
|
168
|
+
Person.where.inet_contained_within_or_equals(ip: "127.0.0.44/8") #=> [alice, bob, randy]
|
169
|
+
```
|
170
|
+
|
171
|
+
|
172
|
+
### Conditional Methods
|
173
|
+
#### Any_of / None_of
|
174
|
+
`any_of/1` simplifies the process of finding records that require multiple `or` conditions.
|
175
|
+
|
176
|
+
`none_of/1` is the inverse of `any_of/1`. It'll find records where none of the contains are matched.
|
177
|
+
|
178
|
+
Both accepts An array of: ActiveRecord Objects, Query Strings, and basic attribute names.
|
179
|
+
|
180
|
+
Querying With Attributes:
|
181
|
+
```ruby
|
182
|
+
alice = Person.create!(uid: 1)
|
183
|
+
bob = Person.create!(uid: 2)
|
184
|
+
randy = Person.create!(uid: 3)
|
185
|
+
|
186
|
+
Person.where.any_of({ uid: 1 }, { uid: 2 }) #=> [alice, bob]
|
187
|
+
```
|
188
|
+
|
189
|
+
Querying With ActiveRecord Objects:
|
190
|
+
```ruby
|
191
|
+
alice = Person.create!(uid: 1)
|
192
|
+
bob = Person.create!(uid: 2)
|
193
|
+
randy = Person.create!(uid: 3)
|
194
|
+
|
195
|
+
uid_one = Person.where(uid: 1)
|
196
|
+
uid_two = Person.where(uid: 2)
|
197
|
+
|
198
|
+
Person.where.any_of(uid_one, uid_two) #=> [alice, bob]
|
199
|
+
```
|
200
|
+
|
201
|
+
Querying with Joined Relationships:
|
202
|
+
```ruby
|
203
|
+
alice = Person.create!(uid: 1)
|
204
|
+
bob = Person.create!(uid: 2)
|
205
|
+
randy = Person.create!(uid: 3)
|
206
|
+
tag_alice = Tag.create!(person_id: alice.id)
|
207
|
+
tag_bob = Tag.create!(person_id: person_two.id)
|
208
|
+
tag_randy = Tag.create!(person_id: person_three.id)
|
209
|
+
|
210
|
+
bob_tag_query = Tag.where(people: { id: two.id }).includes(:person)
|
211
|
+
randy_tag_query = Tag.where(people: { id: three.id }).joins(:person)
|
212
|
+
|
213
|
+
Tag.joins(:person).where.any_of(bob_tag_query, randy_tag_query) #=> [tag_bob, tag_randy] (with person table joined)
|
214
|
+
```
|
215
|
+
|
216
|
+
#### Either Join
|
217
|
+
#### Either Order
|
218
|
+
|
12
219
|
## Installation
|
13
220
|
|
14
221
|
Add this line to your application's Gemfile:
|
data/Rakefile
CHANGED
@@ -34,21 +34,23 @@ module Arel
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
module Inet
|
38
|
+
class ContainsEquals < Arel::Nodes::Binary
|
39
|
+
def operator
|
40
|
+
:">>="
|
41
|
+
end
|
40
42
|
end
|
41
|
-
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
44
|
+
class ContainedWithin < Arel::Nodes::Binary
|
45
|
+
def operator
|
46
|
+
:<<
|
47
|
+
end
|
46
48
|
end
|
47
|
-
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
class ContainedWithinEquals < Arel::Nodes::Binary
|
51
|
+
def operator
|
52
|
+
:"<<="
|
53
|
+
end
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
@@ -4,38 +4,39 @@ require "arel/predications"
|
|
4
4
|
|
5
5
|
module Arel
|
6
6
|
module Predications
|
7
|
-
def
|
8
|
-
Nodes::
|
7
|
+
def any(other)
|
8
|
+
any_tags_function = Arel::Nodes::NamedFunction.new("ANY", [self])
|
9
|
+
Arel::Nodes::Equality.new(Nodes.build_quoted(other, self), any_tags_function)
|
9
10
|
end
|
10
11
|
|
11
|
-
def
|
12
|
-
Nodes::
|
12
|
+
def all(other)
|
13
|
+
all_tags_function = Arel::Nodes::NamedFunction.new("ALL", [self])
|
14
|
+
Arel::Nodes::Equality.new(Nodes.build_quoted(other, self), all_tags_function)
|
13
15
|
end
|
14
16
|
|
15
|
-
def
|
16
|
-
Nodes::
|
17
|
+
def overlap(other)
|
18
|
+
Nodes::Overlap.new(self, Nodes.build_quoted(other, self))
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
20
|
-
Nodes::
|
21
|
+
def contains(other)
|
22
|
+
Nodes::Contains.new self, Nodes.build_quoted(other, self)
|
21
23
|
end
|
24
|
+
alias inet_contains contains
|
22
25
|
|
23
26
|
def contained_in_array(other)
|
24
27
|
Nodes::ContainedInArray.new self, Nodes.build_quoted(other, self)
|
25
28
|
end
|
26
29
|
|
27
|
-
def
|
28
|
-
Nodes::
|
30
|
+
def inet_contained_within(other)
|
31
|
+
Nodes::Inet::ContainedWithin.new self, Nodes.build_quoted(other, self)
|
29
32
|
end
|
30
33
|
|
31
|
-
def
|
32
|
-
|
33
|
-
Arel::Nodes::Equality.new(Nodes.build_quoted(other, self), any_tags_function)
|
34
|
+
def inet_contained_within_or_equals(other)
|
35
|
+
Nodes::Inet::ContainedWithinEquals.new self, Nodes.build_quoted(other, self)
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
37
|
-
|
38
|
-
Arel::Nodes::Equality.new(Nodes.build_quoted(other, self), any_tags_function)
|
38
|
+
def inet_contains_or_equals(other)
|
39
|
+
Nodes::Inet::ContainsEquals.new self, Nodes.build_quoted(other, self)
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
@@ -35,14 +35,6 @@ module ActiveRecordExtended
|
|
35
35
|
infix_value object, collector, " @> "
|
36
36
|
end
|
37
37
|
|
38
|
-
def visit_Arel_Nodes_ContainedWithin(object, collector)
|
39
|
-
infix_value object, collector, " << "
|
40
|
-
end
|
41
|
-
|
42
|
-
def visit_Arel_Nodes_ContainedWithinEquals(object, collector)
|
43
|
-
infix_value object, collector, " <<= "
|
44
|
-
end
|
45
|
-
|
46
38
|
def visit_Arel_Nodes_ContainedInHStore(object, collector)
|
47
39
|
infix_value object, collector, " <@ "
|
48
40
|
end
|
@@ -51,7 +43,15 @@ module ActiveRecordExtended
|
|
51
43
|
infix_value object, collector, " <@ "
|
52
44
|
end
|
53
45
|
|
54
|
-
def
|
46
|
+
def visit_Arel_Nodes_Inet_ContainedWithin(object, collector)
|
47
|
+
infix_value object, collector, " << "
|
48
|
+
end
|
49
|
+
|
50
|
+
def visit_Arel_Nodes_Inet_ContainedWithinEquals(object, collector)
|
51
|
+
infix_value object, collector, " <<= "
|
52
|
+
end
|
53
|
+
|
54
|
+
def visit_Arel_Nodes_Inet_ContainsEquals(object, collector)
|
55
55
|
infix_value object, collector, " >>= "
|
56
56
|
end
|
57
57
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordExtended
|
4
|
+
module QueryMethods
|
5
|
+
module Inet
|
6
|
+
def contained_within(opts, *rest)
|
7
|
+
ActiveSupport::Deprecation.warn("#contained_within will soon be deprecated for version 1.0 release. "\
|
8
|
+
"Please use #inet_contained_within instead.", caller(1))
|
9
|
+
inet_contained_within(opts, *rest)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Finds matching inet column records that fall within a given submasked IP range
|
13
|
+
#
|
14
|
+
# Column(inet) << "127.0.0.1/24"
|
15
|
+
#
|
16
|
+
# User.where.inet_contained_within(ip: "127.0.0.1/16")
|
17
|
+
# #=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip\" << '127.0.0.1/16'"
|
18
|
+
#
|
19
|
+
# User.where.inet_contained_within(ip: IPAddr.new("192.168.2.0/24"))
|
20
|
+
# #=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip\" << '192.168.2.0/24'"
|
21
|
+
#
|
22
|
+
def inet_contained_within(opts, *rest)
|
23
|
+
substitute_comparisons(opts, rest, Arel::Nodes::Inet::ContainedWithin, "inet_contained_within")
|
24
|
+
end
|
25
|
+
|
26
|
+
def contained_within_or_equals(opts, *rest)
|
27
|
+
ActiveSupport::Deprecation.warn("#contained_within_or_equals will soon be deprecated for version 1.0 release. "\
|
28
|
+
"Please use #inet_contained_within_or_equals instead.", caller(1))
|
29
|
+
inet_contained_within_or_equals(opts, *rest)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Finds matching inet column records that fall within a given submasked IP range and also finds records that also
|
33
|
+
# contain a submasking field that fall within range too.
|
34
|
+
#
|
35
|
+
# Column(inet) <<= "127.0.0.1/24"
|
36
|
+
#
|
37
|
+
# User.where.inet_contained_within_or_equals(ip: "127.0.0.1/16")
|
38
|
+
# #=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip\" <<= '127.0.0.44/32'"
|
39
|
+
#
|
40
|
+
# User.where.inet_contained_within_or_equals(ip: IPAddr.new("192.168.2.0/24"))
|
41
|
+
# #=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip\" <<= '192.168.2.0/24'"
|
42
|
+
#
|
43
|
+
def inet_contained_within_or_equals(opts, *rest)
|
44
|
+
substitute_comparisons(opts, rest, Arel::Nodes::Inet::ContainedWithinEquals, "inet_contained_within_or_equals")
|
45
|
+
end
|
46
|
+
|
47
|
+
def contains_or_equals(opts, *rest)
|
48
|
+
ActiveSupport::Deprecation.warn("#contains_or_equals will soon be deprecated for version 1.0 release. "\
|
49
|
+
"Please use #inet_contains_or_equals instead.", caller(1))
|
50
|
+
inet_contains_or_equals(opts, *rest)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Finds records that contain a submask and the supplied IP address falls within its range.
|
54
|
+
#
|
55
|
+
# Column(inet) >>= "127.0.0.1/24"
|
56
|
+
#
|
57
|
+
# User.where.inet_contained_within_or_equals(ip: "127.0.255.255")
|
58
|
+
# #=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip\" >>= '127.0.255.255'"
|
59
|
+
#
|
60
|
+
# User.where.inet_contained_within_or_equals(ip: IPAddr.new("127.0.0.255"))
|
61
|
+
# #=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip\" >>= '127.0.0.255/32'"
|
62
|
+
#
|
63
|
+
def inet_contains_or_equals(opts, *rest)
|
64
|
+
substitute_comparisons(opts, rest, Arel::Nodes::Inet::ContainsEquals, "inet_contains_or_equals")
|
65
|
+
end
|
66
|
+
|
67
|
+
# Strictly finds records that contain a submask and the supplied IP address falls within its range.
|
68
|
+
#
|
69
|
+
# Column(inet) >>= "127.0.0.1"
|
70
|
+
#
|
71
|
+
# User.where.inet_contained_within_or_equals(ip: "127.0.255.255")
|
72
|
+
# #=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip\" >> '127.0.255.255'"
|
73
|
+
#
|
74
|
+
# User.where.inet_contained_within_or_equals(ip: IPAddr.new("127.0.0.255"))
|
75
|
+
# #=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip\" >> '127.0.0.255/32'"
|
76
|
+
#
|
77
|
+
def inet_contains(opts, *rest)
|
78
|
+
substitute_comparisons(opts, rest, Arel::Nodes::Contains, "inet_contains")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
ActiveRecord::QueryMethods::WhereChain.prepend(ActiveRecordExtended::QueryMethods::Inet)
|
@@ -9,18 +9,6 @@ module ActiveRecordExtended
|
|
9
9
|
substitute_comparisons(opts, rest, Arel::Nodes::Overlap, "overlap")
|
10
10
|
end
|
11
11
|
|
12
|
-
def contained_within(opts, *rest)
|
13
|
-
substitute_comparisons(opts, rest, Arel::Nodes::ContainedWithin, "contained_within")
|
14
|
-
end
|
15
|
-
|
16
|
-
def contained_within_or_equals(opts, *rest)
|
17
|
-
substitute_comparisons(opts, rest, Arel::Nodes::ContainedWithinEquals, "contained_within_or_equals")
|
18
|
-
end
|
19
|
-
|
20
|
-
def contains_or_equals(opts, *rest)
|
21
|
-
substitute_comparisons(opts, rest, Arel::Nodes::ContainsEquals, "contains_or_equals")
|
22
|
-
end
|
23
|
-
|
24
12
|
# Finds Records that contain an element in an array column
|
25
13
|
# User.where.any(tags: 3)
|
26
14
|
# # SELECT user.* FROM user WHERE 3 = ANY(user.tags)
|
@@ -24,9 +24,9 @@ RSpec.describe "Active Record Array Query Methods" do
|
|
24
24
|
expect(query).to include(one, two)
|
25
25
|
expect(query).to_not include(three)
|
26
26
|
|
27
|
-
query = Person.where.
|
28
|
-
expect(query).to include(
|
29
|
-
expect(query).to_not include(two)
|
27
|
+
query = Person.where.contains(tags: [8, 2])
|
28
|
+
expect(query).to include(three)
|
29
|
+
expect(query).to_not include(one, two)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe "Active Record Inet Query Methods" do
|
6
|
+
describe "Deprecation Notices" do
|
7
|
+
%i[contained_within contained_within_or_equals contains_or_equals].each do |method|
|
8
|
+
it "Should display a deprecation warning for #{method}" do
|
9
|
+
new_method = "inet_#{method}".to_sym
|
10
|
+
warning_msg = "##{method} will soon be deprecated for version 1.0 release. Please use ##{new_method} instead."
|
11
|
+
expect_any_instance_of(ActiveRecordExtended::QueryMethods::Inet).to receive(new_method)
|
12
|
+
expect { Person.where.send(method, nil) }.to output(Regexp.new(warning_msg)).to_stderr
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#inet_contained_within" do
|
18
|
+
let!(:local_1) { Person.create!(ip: "127.0.0.1") }
|
19
|
+
let!(:local_44) { Person.create!(ip: "127.0.0.44") }
|
20
|
+
let!(:local_99_1) { Person.create!(ip: "127.0.99.1") }
|
21
|
+
let!(:local_range) { Person.create!(ip: "127.0.0.1/10") }
|
22
|
+
|
23
|
+
it "Should return people who have an IP within the 127.0.0.1/24 range" do
|
24
|
+
query = Person.where.inet_contained_within(ip: "127.0.0.1/24")
|
25
|
+
expect(query).to include(local_1, local_44)
|
26
|
+
expect(query).to_not include(local_99_1, local_range)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "Should return all users who have an IP within the 127.0.0.1/16 range" do
|
30
|
+
query = Person.where.inet_contained_within(ip: "127.0.0.1/16")
|
31
|
+
expect(query).to include(local_1, local_44, local_99_1)
|
32
|
+
expect(query).to_not include(local_range)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "contained_within_or_equals" do
|
37
|
+
let!(:local_1) { Person.create!(ip: "127.0.0.1/10") }
|
38
|
+
let!(:local_44) { Person.create!(ip: "127.0.0.44/32") }
|
39
|
+
let!(:local_99_1) { Person.create!(ip: "127.0.99.1") }
|
40
|
+
|
41
|
+
it "Should find records that contain a matching submask" do
|
42
|
+
query = Person.where.inet_contained_within_or_equals(ip: "127.0.0.44/32")
|
43
|
+
expect(query).to include(local_44)
|
44
|
+
expect(query).to_not include(local_1, local_99_1)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "Should find records that are within range of a given submask" do
|
48
|
+
query = Person.where.inet_contained_within_or_equals(ip: "127.0.0.1/16")
|
49
|
+
expect(query).to include(local_44, local_99_1)
|
50
|
+
expect(query).to_not include(local_1)
|
51
|
+
|
52
|
+
query = Person.where.inet_contained_within_or_equals(ip: "127.0.0.1/8")
|
53
|
+
expect(query).to include(local_1, local_44, local_99_1)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#inet_contains_or_equals" do
|
58
|
+
let!(:local_1) { Person.create!(ip: "127.0.0.1/10") }
|
59
|
+
let!(:local_44) { Person.create!(ip: "127.0.0.44/24") }
|
60
|
+
let!(:local_99_1) { Person.create!(ip: "127.0.99.1") }
|
61
|
+
|
62
|
+
it "Should find records with submask ranges that contain a given IP" do
|
63
|
+
query = Person.where.inet_contains_or_equals(ip: "127.0.255.255")
|
64
|
+
expect(query).to include(local_1)
|
65
|
+
expect(query).to_not include(local_44, local_99_1)
|
66
|
+
|
67
|
+
query = Person.where.inet_contains_or_equals(ip: "127.0.0.255")
|
68
|
+
expect(query).to include(local_1, local_44)
|
69
|
+
expect(query).to_not include(local_99_1)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "Finds records when querying with a submasked value" do
|
73
|
+
query = Person.where.inet_contains_or_equals(ip: "127.0.0.1/10")
|
74
|
+
expect(query).to include(local_1)
|
75
|
+
expect(query).to_not include(local_44, local_99_1)
|
76
|
+
|
77
|
+
query = Person.where.inet_contains_or_equals(ip: "127.0.0.1/32")
|
78
|
+
expect(query).to include(local_1, local_44)
|
79
|
+
expect(query).to_not include(local_99_1)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#inet_contains" do
|
84
|
+
let!(:local_1) { Person.create!(ip: "127.0.0.1/10") }
|
85
|
+
let!(:local_44) { Person.create!(ip: "127.0.0.44/24") }
|
86
|
+
|
87
|
+
it "Should find records that the given IP falls within" do
|
88
|
+
query = Person.where.inet_contains(ip: "127.0.0.1")
|
89
|
+
expect(query).to include(local_1, local_44)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "Should not find records when querying with a submasked value" do
|
93
|
+
query = Person.where.inet_contains(ip: "127.0.0.0/8")
|
94
|
+
expect(query).to be_empty
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe "Inet Column Predicates" do
|
6
|
+
let(:arel_table) { Person.arel_table }
|
7
|
+
|
8
|
+
describe "#inet_contained_within" do
|
9
|
+
it "converts Arel inet contained within statement" do
|
10
|
+
query = arel_table.where(arel_table[:ip].inet_contained_within(IPAddr.new("127.0.0.1"))).to_sql
|
11
|
+
expect(query).to match_regex(%r{<< '127\.0\.0\.1/32'})
|
12
|
+
end
|
13
|
+
|
14
|
+
it "works with count" do
|
15
|
+
expect(Person.where(arel_table[:ip].inet_contained_within(IPAddr.new("127.0.0.1"))).count).to eq(0)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#inet_contained_within_or_equals" do
|
20
|
+
it "converts Arel inet contained within statement" do
|
21
|
+
query = arel_table.where(arel_table[:ip].inet_contained_within_or_equals(IPAddr.new("127.0.0.1"))).to_sql
|
22
|
+
expect(query).to match_regex(%r{<<= '127\.0\.0\.1/32'})
|
23
|
+
end
|
24
|
+
|
25
|
+
it "works with count" do
|
26
|
+
expect(Person.where(arel_table[:ip].inet_contained_within_or_equals(IPAddr.new("127.0.0.1"))).count).to eq(0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#inet_contains_or_equals" do
|
31
|
+
it "converts Arel inet contained within statement" do
|
32
|
+
query = arel_table.where(arel_table[:ip].inet_contains_or_equals(IPAddr.new("127.0.0.1"))).to_sql
|
33
|
+
expect(query).to match_regex(%r{>>= '127\.0\.0\.1/32'})
|
34
|
+
end
|
35
|
+
|
36
|
+
it "works with count" do
|
37
|
+
expect(Person.where(arel_table[:ip].inet_contains_or_equals(IPAddr.new("127.0.0.1"))).count).to eq(0)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#inet_contains" do
|
42
|
+
it "converts Arel inet contained within statement" do
|
43
|
+
query = arel_table.where(arel_table[:ip].inet_contains("127.0.0.1")).to_sql
|
44
|
+
expect(query).to match_regex(/>> '127\.0\.0\.1'/)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "works with count" do
|
48
|
+
expect(Person.where(arel_table[:ip].inet_contains("127.0.0.1")).count).to eq(0)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
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.5.0.
|
4
|
+
version: 0.5.0.beta2
|
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-05-
|
13
|
+
date: 2018-05-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -160,6 +160,7 @@ files:
|
|
160
160
|
- lib/active_record_extended/predicate_builder/array_handler_decorator.rb
|
161
161
|
- lib/active_record_extended/query_methods/any_of.rb
|
162
162
|
- lib/active_record_extended/query_methods/either.rb
|
163
|
+
- lib/active_record_extended/query_methods/inet.rb
|
163
164
|
- lib/active_record_extended/query_methods/where_chain.rb
|
164
165
|
- lib/active_record_extended/version.rb
|
165
166
|
- spec/active_record_extended_spec.rb
|
@@ -167,9 +168,11 @@ files:
|
|
167
168
|
- spec/query_methods/array_query_spec.rb
|
168
169
|
- spec/query_methods/either_spec.rb
|
169
170
|
- spec/query_methods/hash_query_spec.rb
|
171
|
+
- spec/query_methods/inet_query_spec.rb
|
170
172
|
- spec/spec_helper.rb
|
171
173
|
- spec/sql_inspections/any_of_sql_spec.rb
|
172
174
|
- spec/sql_inspections/arel/array_spec.rb
|
175
|
+
- spec/sql_inspections/arel/inet_spec.rb
|
173
176
|
- spec/sql_inspections/contains_sql_queries_spec.rb
|
174
177
|
- spec/sql_inspections/either_sql_spec.rb
|
175
178
|
- spec/support/database_cleaner.rb
|
@@ -204,9 +207,11 @@ test_files:
|
|
204
207
|
- spec/query_methods/array_query_spec.rb
|
205
208
|
- spec/query_methods/either_spec.rb
|
206
209
|
- spec/query_methods/hash_query_spec.rb
|
210
|
+
- spec/query_methods/inet_query_spec.rb
|
207
211
|
- spec/spec_helper.rb
|
208
212
|
- spec/sql_inspections/any_of_sql_spec.rb
|
209
213
|
- spec/sql_inspections/arel/array_spec.rb
|
214
|
+
- spec/sql_inspections/arel/inet_spec.rb
|
210
215
|
- spec/sql_inspections/contains_sql_queries_spec.rb
|
211
216
|
- spec/sql_inspections/either_sql_spec.rb
|
212
217
|
- spec/support/database_cleaner.rb
|