postgres_ext 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -8,7 +8,11 @@ rvm:
8
8
  before_script:
9
9
  - psql -c 'create database postgres_ext_test;' -U postgres
10
10
  - cp spec/dummy/config/database.yml.example spec/dummy/config/database.yml
11
+ - RAILS_ENV=test rake db:migrate
11
12
 
12
13
  notifications:
13
14
  email:
14
15
  - git@danmcclain.net
16
+ campfire:
17
+ rooms:
18
+ - secure: "yVESPleawl+fzvnzXw/W7rULyCjMEq3gPc3cEqcqM2SBBtEIDNXto2zoTAoR\nC5yqhijr+UtmVMsI7CxVK3XvfkmCJZN9P4DP0uas8XYx5DsSabCdPN0h3pka\nbaDCMCInU5QF4WswL2iuyLsOJeKDRwxh09adsHi1HpMgf0nTKPA="
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## 0.2.0
2
+
3
+ * Introduces extensions to `ActiveRecord::Relation.where` to simplify
4
+ Array and INET/CIDR queries - Dan McClain (@danmcclain)
5
+ * Fixes `where(:array => [1,2])` to use equailty instead of IN clauses
6
+ - Dan McClain (@danmcclain)
7
+ * Adds Arel predicates for more network comparisons - Patrick Muldoon
8
+ (@doon)
9
+ * Adds support for citext in migrations/schema.rb - Jonathan Younger
10
+ (@daikini)
11
+ * Fixes text character encoding for text columns - Andy Monat (@amonat)
12
+ * Cleans up alias_method_chains for better interoperability - Raido
13
+ Paaslepp (@legendetm)
14
+ * Doc updates - Dan McClain, Caleb Woods (@danmcclain @calebwoods)
15
+
16
+ ## 0.1.0
17
+
18
+ * Performs PostgreSQL version check before attempting to dumpe
19
+ extensions - Dan McClain (@danmcclain)
20
+ * Fixes issues with schema dumper when indexes have no index_opclass -
21
+ Mario Visic (@mariovisic)
22
+
1
23
  ## 0.0.10
2
24
 
3
25
  * Fixes parsing of number arrays when they are set from a string array - Alexey Noskov (@alno)
data/README.md CHANGED
@@ -5,10 +5,13 @@ Adds support for missing PostgreSQL data types to ActiveRecord.
5
5
  [![Build Status](https://secure.travis-ci.org/dockyard/postgres_ext.png?branch=master)](http://travis-ci.org/dockyard/postgres_ext)
6
6
  [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/dockyard/postgres_ext)
7
7
 
8
- ## Roadmap
8
+ ## Looking for help? ##
9
9
 
10
- * Arel support for INET, CIDR and Array related where clauses
11
- * Backport HStore code from Rails 4.0
10
+ If it is a bug [please open an issue on
11
+ Github](https://github.com/dockyard/party_foul/issues). If you need help using
12
+ the gem please ask the question on
13
+ [Stack Overflow](http://stackoverflow.com). Be sure to tag the
14
+ question with `DockYard` so we can find it.
12
15
 
13
16
  ## Installation
14
17
 
@@ -29,11 +32,12 @@ Or install it yourself as:
29
32
  Just `require 'postgres_ext'` and use ActiveRecord as you normally would! postgres\_ext extends
30
33
  ActiveRecord's data type handling.
31
34
 
32
- * [Migration/Schema.rb support](#migrationschemarb-support)
33
- * [Type Casting support](#type-casting-support)
34
- * [Querying PostgreSQL datatypes](#querying-postgresql-datatypes)
35
+ * [Migration/Schema.rb support](docs/migrations.md)
36
+ * [Type Casting support](docs/type_casting.md)
37
+ * [Querying PostgreSQL datatypes](docs/querying.md)
38
+ * [Indexes](docs/indexes.md)
35
39
 
36
- ### Usage Notes
40
+ ## Usage Notes
37
41
  Avoid the use of in place operators (ie `Array#<<`). These changes are
38
42
  *not* tracked by Rails ([this issue](https://github.com/rails/rails/issues/6954))
39
43
  explains why). In place modifications also modify the default object.
@@ -64,7 +68,7 @@ The supported way of modifying `a.names`:
64
68
 
65
69
  ```ruby
66
70
  a = Item.new
67
- a.names += 'foo'
71
+ a.names += ['foo']
68
72
 
69
73
  b = Item.new
70
74
  puts b.names
@@ -74,240 +78,8 @@ puts b.names
74
78
  As a result, in place operators are discouraged and will not be
75
79
  supported in postgres\_ext at this time.
76
80
 
77
- ## Migration/Schema.rb support
78
81
 
79
- ### INET
80
82
 
81
- ```ruby
82
- create_table :testing do |t|
83
- t.inet :inet_column
84
- # or
85
- t.inet :inet_column_1, :inet_column_2
86
- # or
87
- t.column :inet_column, :inet
88
- end
89
- ```
90
-
91
- ### CIDR
92
-
93
- ```ruby
94
- create_table :testing do |t|
95
- t.cidr :cidr_column
96
- # or
97
- t.cidr :cidr_column_1, :cidr_column_2
98
- # or
99
- t.column :cidr_column, :cidr
100
- end
101
- ```
102
-
103
- ### MACADDR
104
-
105
- ```ruby
106
- create_table :testing do |t|
107
- t.macaddr :macaddr_column
108
- # or
109
- t.macaddr :macaddr_column_1, :macaddr_column_2
110
- # or
111
- t.column :macaddr_column, :macaddr
112
- end
113
- ```
114
-
115
- ### UUID
116
-
117
- ```ruby
118
- create_table :testing do |t|
119
- t.uuid :uuid_column
120
- # or
121
- t.uuid :uuid_column_1, :uuid_column_2
122
- # or
123
- t.column :uuid_column, :uuid
124
- end
125
- ```
126
-
127
- ### Arrays
128
- Arrays are created from any ActiveRecord supported datatype (including
129
- ones added by postgre\_ext), and respect length constraints
130
-
131
- ```ruby
132
- create_table :testing do |t|
133
- t.integer :int_array, :array => true
134
- # integer[]
135
- t.integer :int_array, :array => true, :limit => 2
136
- # smallint[]
137
- t.string :macaddr_column_1, :array => true, :limit => 30
138
- # char varying(30)[]
139
- end
140
- ```
141
-
142
- ## Type Casting support
143
-
144
- ### INET and CIDR
145
- INET and CIDR values are converted to
146
- [IPAddr](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/ipaddr/rdoc/IPAddr.html)
147
- objects when retrieved from the database, or set as a string.
148
-
149
- ```ruby
150
- create_table :inet_examples do |t|
151
- t.inet :ip_address
152
- end
153
-
154
- class InetExample < ActiveRecord::Base
155
- end
156
-
157
- inetExample = InetExample.new
158
- inetExample.ip_address = '127.0.0.0/24'
159
- inetExample.ip_address
160
- # => #<IPAddr: IPv4:127.0.0.0/255.255.255.0>
161
- inetExample.save
162
-
163
- inet_2 = InetExample.first
164
- inet_2.ip_address
165
- # => #<IPAddr: IPv4:127.0.0.0/255.255.255.0>
166
- ```
167
-
168
- ### Arrays
169
- Array values can be set with Array objects. Any array stored in the
170
- database will be converted to a properly casted array of values on the
171
- way out.
172
-
173
- ```ruby
174
- create_table :people do |t|
175
- t.integer :favorite_numbers, :array => true
176
- end
177
-
178
- class Person < ActiveRecord::Base
179
- end
180
-
181
- person = Person.new
182
- person.favorite_numbers = [1,2,3]
183
- person.favorite_numbers
184
- # => [1,2,3]
185
- person.save
186
-
187
- person_2 = Person.first
188
- person_2.favorite_numbers
189
- # => [1,2,3]
190
- person_2.favorite_numbers.first.class
191
- # => Fixnum
192
- ```
193
-
194
- ## Querying PostgreSQL datatypes
195
-
196
- * [Arrays](#arrays-2)
197
- * [INET/CIDR](#inetcidr)
198
-
199
- ### Arrays
200
-
201
- * [&& - Array Overlap operator](#---array-overlap-operator)
202
- * [ANY or ALL functions](#any-or-all-functions)
203
-
204
- #### && - Array Overlap operator
205
-
206
- PostgreSQL implements the `&&` operator, known as the overlap operator,
207
- for arrays. The overlap operator returns `t` (true) when two arrays have
208
- one or more elements in common.
209
-
210
- ```sql
211
- ARRAY[1,2,3] && ARRAY[4,5,6]
212
- -- f
213
-
214
- ARRAY[1,2,3] && ARRAY[3,5,6]
215
- -- t
216
- ```
217
-
218
- Postgres\_ext defines `array_overlap`, an [Arel](https://github.com/rails/arel)
219
- predicate for the `&&` operator.
220
-
221
- ```ruby
222
- user_arel = User.arel_table
223
-
224
- # Execute the query
225
- User.where(user_arel[:tags].array_overlap(['one','two']))
226
- # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"tags\" && '{one,two}'
227
- ```
228
-
229
- #### ANY or ALL functions
230
-
231
- When querying array columns, you have the ability to see if a predicate
232
- apply's to either *any* element in the array, or *all* elements of the
233
- array. The syntax for these predicates are slightly different then the
234
- normal `where` syntax in PostgreSQL. To see if an array contains the
235
- string `'test'` in any location, you would write the following in SQL
236
-
237
- ```sql
238
- SELECT *
239
- FROM users
240
- WHERE 'test' = ANY(users.tags)
241
- ```
242
-
243
- Notice that the column is on the right hand side of the predicate,
244
- instead of the left, because we have to call the `ANY` function on that
245
- column.
246
-
247
- We can generate the above query using [Arel](https://github.com/rails/arel)
248
- and generating the Node manually. We would use the following to
249
- accompish this:
250
-
251
- ```ruby
252
- user_arel = User.arel_table
253
-
254
- any_tags_function = Arel::Nodes::NamedFunction.new('ANY', [user_arel[:tags]])
255
- predicate = Arel::Nodes::Equality.new('test', any_tags_function)
256
-
257
- # Execute the query
258
- User.where(predicate)
259
- #=> SELECT \"users\".* FROM \"users\" WHERE 'test' = ANY(\"users\".\"tags\")
260
- ```
261
-
262
- The ALL version of this same predicate can be generated by swap `'ANY'`
263
- for `'ALL'` in the named function.
264
-
265
- ### INET/CIDR
266
-
267
- #### `<<` -- Contained within operator
268
-
269
- PostgreSQL defines the `<<`, or contained within operator for INET and
270
- CIDR datatypes. The `<<` operator returns `t` (true) if a INET or CIDR
271
- address is contained within the given subnet.
272
-
273
- ```sql
274
- inet '192.168.1.6' << inet '10.0.0.0/24'
275
- -- f
276
-
277
- inet '192.168.1.6' << inet '192.168.1.0/24'
278
- -- t
279
- ```
280
-
281
- Postgres\_ext defines `contained_within`, an [Arel](https://github.com/rails/arel)
282
- predicate for the `<<` operator.
283
-
284
- ```ruby
285
- user_arel = User.arel_table
286
-
287
- # Execute the query
288
- User.where(user_arel[:ip_address].contained_witin('127.0.0.1/24'))
289
- # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" << '127.0.0.1/24'
290
- ```
291
-
292
- ## Indexes
293
-
294
- ### Index types
295
-
296
- Postgres\_ext allows you to specify index type and index operator
297
- class at index creation.
298
-
299
- ```ruby
300
- add_index :table_name, :column, :index_type => :gin
301
- add_index :table_name, :column, :index_type => :gin, :index_opclass => :gin_trgm_ops
302
- ```
303
-
304
- ### Where clauses
305
-
306
- Postgres\_ext allows you to specify a where clause at index creation.
307
-
308
- ```ruby
309
- add_index :table_name, :column, :where => 'column < 50'
310
- ```
311
83
 
312
84
  ## Authors
313
85
 
data/docs/indexes.md ADDED
@@ -0,0 +1,19 @@
1
+ # Indexes
2
+
3
+ ## Index types
4
+
5
+ Postgres\_ext allows you to specify index type and index operator
6
+ class at index creation.
7
+
8
+ ```ruby
9
+ add_index :table_name, :column, :index_type => :gin
10
+ add_index :table_name, :column, :index_type => :gin, :index_opclass => :gin_trgm_ops
11
+ ```
12
+
13
+ ## Where clauses
14
+
15
+ Postgres\_ext allows you to specify a where clause at index creation.
16
+
17
+ ```ruby
18
+ add_index :table_name, :column, :where => 'column < 50'
19
+ ```
@@ -0,0 +1,76 @@
1
+ # Migration/Schema.rb support
2
+
3
+ ## INET
4
+
5
+ ```ruby
6
+ create_table :testing do |t|
7
+ t.inet :inet_column
8
+ # or
9
+ t.inet :inet_column_1, :inet_column_2
10
+ # or
11
+ t.column :inet_column, :inet
12
+ end
13
+ ```
14
+
15
+ ## CIDR
16
+
17
+ ```ruby
18
+ create_table :testing do |t|
19
+ t.cidr :cidr_column
20
+ # or
21
+ t.cidr :cidr_column_1, :cidr_column_2
22
+ # or
23
+ t.column :cidr_column, :cidr
24
+ end
25
+ ```
26
+
27
+ ## MACADDR
28
+
29
+ ```ruby
30
+ create_table :testing do |t|
31
+ t.macaddr :macaddr_column
32
+ # or
33
+ t.macaddr :macaddr_column_1, :macaddr_column_2
34
+ # or
35
+ t.column :macaddr_column, :macaddr
36
+ end
37
+ ```
38
+
39
+ ## UUID
40
+
41
+ ```ruby
42
+ create_table :testing do |t|
43
+ t.uuid :uuid_column
44
+ # or
45
+ t.uuid :uuid_column_1, :uuid_column_2
46
+ # or
47
+ t.column :uuid_column, :uuid
48
+ end
49
+ ```
50
+
51
+ ## CITEXT
52
+
53
+ ```ruby
54
+ create_table :testing do |t|
55
+ t.citext :citext_column
56
+ # or
57
+ t.citext :citext_column_1, :citext_column_2
58
+ # or
59
+ t.column :citext_column, :citext
60
+ end
61
+ ```
62
+
63
+ ## Arrays
64
+ Arrays are created from any ActiveRecord supported datatype (including
65
+ ones added by postgres\_ext), and respect length constraints
66
+
67
+ ```ruby
68
+ create_table :testing do |t|
69
+ t.integer :int_array, :array => true
70
+ # integer[]
71
+ t.integer :int_array, :array => true, :limit => 2
72
+ # smallint[]
73
+ t.string :macaddr_column_1, :array => true, :limit => 30
74
+ # char varying(30)[]
75
+ end
76
+ ```
data/docs/querying.md ADDED
@@ -0,0 +1,138 @@
1
+ # Querying PostgreSQL datatypes
2
+
3
+ * [Arrays](#arrays)
4
+ * [INET/CIDR](#inetcidr-queries)
5
+
6
+ ## Arrays
7
+
8
+ * [&& - Array Overlap operator](#---array-overlap-operator)
9
+ * [ANY or ALL functions](#any-or-all-functions)
10
+
11
+ ### && - Array Overlap operator
12
+
13
+ PostgreSQL implements the `&&` operator, known as the overlap operator,
14
+ for arrays. The overlap operator returns `t` (true) when two arrays have
15
+ one or more elements in common.
16
+
17
+ ```sql
18
+ ARRAY[1,2,3] && ARRAY[4,5,6]
19
+ -- f
20
+
21
+ ARRAY[1,2,3] && ARRAY[3,5,6]
22
+ -- t
23
+ ```
24
+
25
+ Postgres\_ext extends the `ActiveRecord::Relation.where` method similar
26
+ to the Rails 4.0 not clause. The easiest way to make a overlap query
27
+ would be:
28
+
29
+ ```ruby
30
+ User.where.overlap(:nick_names => ['Bob', 'Fred'])
31
+ ```
32
+
33
+ Postgres\_ext defines `array_overlap`, an [Arel](https://github.com/rails/arel)
34
+ predicate for the `&&` operator. This is utilized by the `where.overlap`
35
+ call above.
36
+
37
+ ```ruby
38
+ user_arel = User.arel_table
39
+
40
+ # Execute the query
41
+ User.where(user_arel[:tags].array_overlap(['one','two']))
42
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"tags\" && '{one,two}'
43
+ ```
44
+
45
+ ### ANY or ALL functions
46
+
47
+ When querying array columns, you have the ability to see if a predicate
48
+ apply's to either *any* element in the array, or *all* elements of the
49
+ array. The syntax for these predicates are slightly different then the
50
+ normal `where` syntax in PostgreSQL. To see if an array contains the
51
+ string `'test'` in any location, you would write the following in SQL
52
+
53
+ ```sql
54
+ SELECT *
55
+ FROM users
56
+ WHERE 'test' = ANY(users.tags)
57
+ ```
58
+
59
+ Notice that the column is on the right hand side of the predicate,
60
+ instead of the left, because we have to call the `ANY` function on that
61
+ column.
62
+
63
+ Postgres\_ext provides a `ActiveRecord::Relation.where.any()` method. The
64
+ easiest way to make a ANY query would be:
65
+
66
+ ```ruby
67
+ User.where.any(:nick_names => 'Bob')
68
+ ```
69
+
70
+ There is also an `ActiveRecord::Relation.where.all()` call as well. This
71
+ method utilizes the following code to create the query:
72
+
73
+ We can generate the above query using [Arel](https://github.com/rails/arel)
74
+ and generating the Node manually. We would use the following to
75
+ accompish this:
76
+
77
+ ```ruby
78
+ user_arel = User.arel_table
79
+
80
+ any_tags_function = Arel::Nodes::NamedFunction.new('ANY', [user_arel[:tags]])
81
+ predicate = Arel::Nodes::Equality.new('test', any_tags_function)
82
+
83
+ # Execute the query
84
+ User.where(predicate)
85
+ #=> SELECT \"users\".* FROM \"users\" WHERE 'test' = ANY(\"users\".\"tags\")
86
+ ```
87
+
88
+ The ALL version of this same predicate can be generated by swap `'ANY'`
89
+ for `'ALL'` in the named function.
90
+
91
+ ## INET/CIDR Queries
92
+
93
+ PostgreSQL defines the `<<`, or contained within operator for INET and
94
+ CIDR datatypes. The `<<` operator returns `t` (true) if a INET or CIDR
95
+ address is contained within the given subnet.
96
+
97
+ ```sql
98
+ inet '192.168.1.6' << inet '10.0.0.0/24'
99
+ -- f
100
+
101
+ inet '192.168.1.6' << inet '192.168.1.0/24'
102
+ -- t
103
+ ```
104
+
105
+ In addition to contained within, there is also:
106
+
107
+ * `<<=` - Contained within or equals
108
+ * `>>` - Contains
109
+ * `>>=` - Contains or equals
110
+
111
+ Postgres\_ext extends the `ActiveRecord::Relation.where` method similar
112
+ to the Rails 4.0 not clause. The easiest way to make a overlap query
113
+ would be:
114
+
115
+ ```ruby
116
+ User.where.contained_within(:ip => '192.168.1.1/24')
117
+ User.where.contained_within_or_equals(:ip => '192.168.1.1/24')
118
+ User.where.contains(:ip => '192.168.1.14')
119
+ User.where.contains_or_equals(:ip => '192.168.1.14')
120
+ ```
121
+
122
+ Postgres\_ext defines `contained_within`, an [Arel](https://github.com/rails/arel)
123
+ predicate for the `<<` operator. This is utilized by the
124
+ methods above.
125
+
126
+ ```ruby
127
+ user_arel = User.arel_table
128
+
129
+ # Execute the query
130
+ User.where(user_arel[:ip_address].contained_within('127.0.0.1/24'))
131
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" << '127.0.0.1/24'
132
+ User.where(user_arel[:ip_address].contained_within_or_equals('127.0.0.1/24'))
133
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" <<= '127.0.0.1/24'
134
+ User.where(user_arel[:ip_address].contains('127.0.0.1'))
135
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" >> '127.0.0.1'
136
+ User.where(user_arel[:ip_address].contains_or_equals('127.0.0.1'))
137
+ # => SELECT \"users\".* FROM \"users\" WHERE \"users\".\"ip_address\" >>= '127.0.0.1'
138
+ ```