pg_saurus 3.3.0 → 3.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95526ab7651625ecb8d454074e855cbddb574524
4
- data.tar.gz: a44975a7e86b74893dbec2ded843a2a82b80780c
3
+ metadata.gz: bfdd2685401333873ea9a135aae494ceadae569c
4
+ data.tar.gz: f9655837b68a589bf27decdf20c2f4601bd71536
5
5
  SHA512:
6
- metadata.gz: edde7148883c2b70be2f90ec6894fd4cabb644c6e981af6a224c8842ab9f6b221e2a4e4c624f396d4f54b0249d09fbd2eee79666fd2e815fbdb1d78f910e773b
7
- data.tar.gz: ab9d11096b351eb872a7c8a16e5569ccce00a657863a4293987d34a5f844c3c19f9df540f2b7466a3a07544d172ed2f5a9299e9ce83a4ee3b3e62f54a14322c5
6
+ metadata.gz: 56a742d9ee24d6c27e5057aa87a9fb9034670e0e577a8ef66128850a489321019d0e5016ad0160f54a2e01dc3c8be66f992dc692d94e6d8c0f8734c6be250ed5
7
+ data.tar.gz: 4c047507f0762b571c64aec2a85a000d779bab42f98aed65652fe2e918f5f25291ea5cf62f0aa3a918d04cf5557958432281cfdae8e477247bf15f3dc97f3eea
data/README.markdown CHANGED
@@ -11,6 +11,7 @@ An ActiveRecord extension to get more from PostgreSQL:
11
11
  * [Enhancements to the Rails 4.2 foreign key support](#foreign-keys).
12
12
  * Use [partial indexes](#partial-indexes).
13
13
  * Use [indexes on expressions](#indexes-on-expressions).
14
+ * Use [indexes with custom ops classes](#indexes-with-operator-classes).
14
15
  * [Run index creation concurrently](#concurrent-index-creation).
15
16
  * Create/drop [views](#views).
16
17
  * Create/drop [functions](#functions).
@@ -241,6 +242,18 @@ create_extension 'fuzzystrmatch'
241
242
  add_index(:comments, 'dmetaphone(author)', using: 'gist')
242
243
  ```
243
244
 
245
+ ## Indexes with operator classes
246
+
247
+ Specifying an [operator class on each column of an index](https://www.postgresql.org/docs/10/indexes-opclass.html) is supported.
248
+
249
+ ### Examples
250
+
251
+ Add an index with a custom ops class:
252
+
253
+ ```ruby
254
+ add_index(:books, "title varchar_pattern_ops")
255
+ ```
256
+
244
257
  ## Concurrent index creation
245
258
 
246
259
  PostgreSQL supports concurrent index creation. PgSaurus supports that feature by adding support
@@ -5,6 +5,8 @@ module ActiveRecord
5
5
  # function call
6
6
  FUNCTIONAL_INDEX_REGEXP = /(\w+)\(((?:'.+'(?:::\w+)?, *)*)(\w+)\)/
7
7
 
8
+ # Regexp used to find the operator name
9
+ OPERATOR_REGEXP = /(.+)\s(\w+)$/
8
10
 
9
11
  # Redefine original add_index method to handle :concurrently option.
10
12
  #
@@ -132,24 +134,46 @@ module ActiveRecord
132
134
  # Override super method to provide support for expression column names.
133
135
  def quoted_columns_for_index(column_names, options = {})
134
136
  column_names.map do |name|
135
- if name =~ FUNCTIONAL_INDEX_REGEXP
136
- "#{$1}(#{$2}#{quote_column_name($3)})"
137
- else
138
- quote_column_name(name)
139
- end
137
+ column_name, operator_name = split_column_name(name)
138
+
139
+ result_name = if column_name =~ FUNCTIONAL_INDEX_REGEXP
140
+ "#{$1}(#{$2}#{quote_column_name($3)})"
141
+ else
142
+ quote_column_name(column_name)
143
+ end
144
+
145
+ result_name += " " + operator_name if operator_name
146
+
147
+ result_name
140
148
  end
141
149
  end
142
150
  protected :quoted_columns_for_index
143
151
 
144
152
  # Map an expression to a name appropriate for an index.
145
- def expression_index_name(column_name)
146
- if column_name =~ FUNCTIONAL_INDEX_REGEXP
147
- "#{$1.downcase}_#{$3}"
153
+ def expression_index_name(name)
154
+ column_name, operator_name = split_column_name(name)
155
+
156
+ result_name = if column_name =~ FUNCTIONAL_INDEX_REGEXP
157
+ "#{$1.downcase}_#{$3}"
158
+ else
159
+ column_name
160
+ end
161
+
162
+ result_name += "_" + operator_name if operator_name
163
+
164
+ result_name
165
+ end
166
+ private :expression_index_name
167
+
168
+ # Split column name to name and operator class if possible.
169
+ def split_column_name(name)
170
+ if name =~ OPERATOR_REGEXP
171
+ return $1, $2
148
172
  else
149
- column_name
173
+ return name, nil
150
174
  end
151
175
  end
152
- private :expression_index_name
176
+ private :split_column_name
153
177
  end
154
178
  end
155
179
  end
@@ -71,7 +71,7 @@ module ActiveRecord # :nodoc:
71
71
  schemas = schema ? "ARRAY['#{schema}']" : 'current_schemas(false)'
72
72
 
73
73
  result = query(<<-SQL, name)
74
- SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid, am.amname
74
+ SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid, am.amname, d.indclass
75
75
  FROM pg_class t
76
76
  INNER JOIN pg_index d ON t.oid = d.indrelid
77
77
  INNER JOIN pg_class i ON d.indexrelid = i.oid
@@ -90,11 +90,14 @@ module ActiveRecord # :nodoc:
90
90
  :keys => row[2].split(" "),
91
91
  :definition => row[3],
92
92
  :id => row[4],
93
- :access_method => row[5]
93
+ :access_method => row[5],
94
+ :operators => row[6].split(" ")
94
95
  }
95
96
 
96
97
  column_names = find_column_names(table_name, index)
97
98
 
99
+ operator_names = find_operator_names(column_names, index)
100
+
98
101
  unless column_names.empty?
99
102
  where = find_where_statement(index)
100
103
  lengths = find_lengths(index)
@@ -106,7 +109,8 @@ module ActiveRecord # :nodoc:
106
109
  column_names,
107
110
  lengths,
108
111
  where,
109
- index[:access_method]
112
+ index[:access_method],
113
+ operator_names
110
114
  )
111
115
  end
112
116
  end.compact
@@ -141,6 +145,29 @@ module ActiveRecord # :nodoc:
141
145
  column_names
142
146
  end
143
147
 
148
+ # Find non-default operator class names for columns from index.
149
+ #
150
+ # @param column_names [Array] List of columns from index.
151
+ # @param index [Hash] index index attributes
152
+ # @return [Hash]
153
+ def find_operator_names(column_names, index)
154
+ column_names.each_with_index.inject({}) do |class_names, (column_name, column_index)|
155
+ result = query(<<-SQL, "Classes for columns for index #{index[:name]} for column #{column_name}")
156
+ SELECT op.opcname, op.opcdefault
157
+ FROM pg_opclass op
158
+ WHERE op.oid = #{index[:operators][column_index]};
159
+ SQL
160
+
161
+ row = result.first
162
+
163
+ if row && row[1] == "f"
164
+ class_names[column_name] = row[0]
165
+ end
166
+
167
+ class_names
168
+ end
169
+ end
170
+
144
171
  # Splits only on commas outside of parens
145
172
  def split_expression(expression)
146
173
  result = []
@@ -15,9 +15,15 @@ module ActiveRecord #:nodoc:
15
15
  def indexes(table, stream)
16
16
  if (indexes = @connection.indexes(table)).any?
17
17
  add_index_statements = indexes.map do |index|
18
+ columns = index.columns.map do |column_name|
19
+ column_name += ' ' +index.operators[column_name] if index.operators.key?(column_name)
20
+
21
+ column_name
22
+ end
23
+
18
24
  statement_parts = [
19
25
  ('add_index ' + index.table.inspect),
20
- index.columns.inspect,
26
+ columns.inspect,
21
27
  (':name => ' + index.name.inspect),
22
28
  ]
23
29
  statement_parts << ':unique => true' if index.unique
@@ -3,6 +3,6 @@ module PgSaurus::ConnectionAdapters
3
3
  # Overrides ActiveRecord::ConnectionAdapters::IndexDefinition
4
4
  # with the additional :where parameter.
5
5
  class IndexDefinition < Struct.new( :table, :name, :unique, :columns,
6
- :lengths, :where, :access_method )
6
+ :lengths, :where, :access_method, :operators )
7
7
  end
8
8
  end
@@ -1,4 +1,4 @@
1
1
  module PgSaurus
2
2
  # Version of pg_saurus gem.
3
- VERSION = "3.3.0"
3
+ VERSION = "3.4.0"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_saurus
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Potapov Sergey
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2018-09-06 00:00:00.000000000 Z
16
+ date: 2019-03-14 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: pg