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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56c4be1e6e48ce5c2c7430545666c5a972d8355539d9f4eacd606bfb8919eb2c
4
- data.tar.gz: d4ceaaaa423fc093cec3fb463ec2e2a54f9eba2f7f8b13ca0f2c55b45b4b38d1
3
+ metadata.gz: df4c51db1e23fe823d4f551b4b44eb607133b431f0970286b0e3b3a576c6ad42
4
+ data.tar.gz: cd2558c39e0224d6fc9719dc7ceb27a45ed0e98da7141ed620287f95ce4a6062
5
5
  SHA512:
6
- metadata.gz: 1d5132209987cef0e73351c8343121998a107fad83d29d0e4b9f44fff72254b8c3f97f8b3ac237eb54f6aeb2b53254f5d93c4b63a0bc3597084e848795be9ce2
7
- data.tar.gz: a9f707ddb4b0734e9fa8e62403e8787859e464e2b0d288dc6b51ab15abf235e1420398cbe7292de7987b42463572c96028f28dcd84cde16658df67a809ef65f5
6
+ metadata.gz: 520880c113c258caaa12a3ef2f83b92f1f7d6e71b03beaab5acd03050267071f2025b268f8156eb70206ad84887a13195717d76e328e10832257433a6963421e
7
+ data.tar.gz: 8ba91e9f95d7f77541d5f956811b4c61e9e04a2e8ecbe8cc12cff6fe79ead72ce7233699f7d89de53fcd67f1aa1a932ea2d31bbc144adc7943cd119e1f8e748b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- active_record_extended (0.5.0.beta1)
4
+ active_record_extended (0.5.0.beta2)
5
5
  activerecord (>= 5.0, < 6.0)
6
6
  ar_outer_joins (~> 0.2)
7
7
  pg (~> 0.18)
data/README.md CHANGED
@@ -1,6 +1,25 @@
1
1
  [![Build Status](https://travis-ci.com/GeorgeKaraszi/ActiveRecordExtended.svg?branch=master)](https://travis-ci.com/GeorgeKaraszi/ActiveRecordExtended) [![Maintainability](https://api.codeclimate.com/v1/badges/98ecffc0239417098cbc/maintainability)](https://codeclimate.com/github/GeorgeKaraszi/active_record_extended/maintainability)
2
2
 
3
- # Active Record Extended
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
@@ -61,6 +61,8 @@ namespace :db do
61
61
  t.integer "personal_id"
62
62
  t.hstore "data"
63
63
  t.jsonb "jsonb_data"
64
+ t.inet "ip"
65
+ t.cidr "subnet"
64
66
  t.datetime "created_at"
65
67
  t.datetime "updated_at"
66
68
  end
@@ -34,21 +34,23 @@ module Arel
34
34
  end
35
35
  end
36
36
 
37
- class ContainsEquals < Arel::Nodes::Binary
38
- def operator
39
- :">>="
37
+ module Inet
38
+ class ContainsEquals < Arel::Nodes::Binary
39
+ def operator
40
+ :">>="
41
+ end
40
42
  end
41
- end
42
43
 
43
- class ContainedWithin < Arel::Nodes::Binary
44
- def operator
45
- :<<
44
+ class ContainedWithin < Arel::Nodes::Binary
45
+ def operator
46
+ :<<
47
+ end
46
48
  end
47
- end
48
49
 
49
- class ContainedWithinEquals < Arel::Nodes::Binary
50
- def operator
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 overlap(other)
8
- Nodes::Overlap.new(self, Nodes.build_quoted(other, self))
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 contains(other)
12
- Nodes::Contains.new self, Nodes.build_quoted(other, self)
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 contained_within(other)
16
- Nodes::ContainedWithin.new self, Nodes.build_quoted(other, self)
17
+ def overlap(other)
18
+ Nodes::Overlap.new(self, Nodes.build_quoted(other, self))
17
19
  end
18
20
 
19
- def contained_within_or_equals(other)
20
- Nodes::ContainedWithinEquals.new self, Nodes.build_quoted(other, self)
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 contains_or_equals(other)
28
- Nodes::ContainsEquals.new self, Nodes.build_quoted(other, self)
30
+ def inet_contained_within(other)
31
+ Nodes::Inet::ContainedWithin.new self, Nodes.build_quoted(other, self)
29
32
  end
30
33
 
31
- def any(other)
32
- any_tags_function = Arel::Nodes::NamedFunction.new("ANY", [self])
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 all(other)
37
- any_tags_function = Arel::Nodes::NamedFunction.new("ALL", [self])
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 visit_Arel_Nodes_ContainsEquals(object, collector)
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordExtended
4
- VERSION = "0.5.0.beta1"
4
+ VERSION = "0.5.0.beta2"
5
5
  end
@@ -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.overlap(tags: [8, 2])
28
- expect(query).to include(one, three)
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.beta1
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-26 00:00:00.000000000 Z
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