pg_search 0.5.7 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.travis.yml +22 -1
- data/CHANGELOG.rdoc +14 -0
- data/Gemfile +12 -8
- data/Guardfile +6 -0
- data/LICENSE +1 -1
- data/README.rdoc +37 -14
- data/lib/pg_search/configuration.rb +9 -5
- data/lib/pg_search/features/feature.rb +2 -0
- data/lib/pg_search/features/trigram.rb +18 -8
- data/lib/pg_search/features/tsearch.rb +18 -11
- data/lib/pg_search/migration/templates/add_pg_search_associated_against_support_functions.rb.erb +2 -2
- data/lib/pg_search/migration/templates/add_pg_search_dmetaphone_support_functions.rb.erb +4 -4
- data/lib/pg_search/normalizer.rb +19 -11
- data/lib/pg_search/scope_options.rb +22 -6
- data/lib/pg_search/tasks.rb +9 -2
- data/lib/pg_search/version.rb +1 -1
- data/pg_search.gemspec +7 -6
- data/spec/{associations_spec.rb → integration/associations_spec.rb} +36 -0
- data/spec/{pg_search_spec.rb → integration/pg_search_spec.rb} +55 -11
- data/spec/{pg_search → lib/pg_search}/document_spec.rb +0 -0
- data/spec/lib/pg_search/features/trigram_spec.rb +26 -0
- data/spec/lib/pg_search/features/tsearch_spec.rb +51 -0
- data/spec/{pg_search → lib/pg_search}/multisearch/rebuilder_spec.rb +0 -0
- data/spec/{pg_search → lib/pg_search}/multisearch_spec.rb +0 -0
- data/spec/{pg_search → lib/pg_search}/multisearchable_spec.rb +0 -0
- data/spec/lib/pg_search/normalizer_spec.rb +82 -0
- data/spec/spec_helper.rb +15 -45
- data/sql/dmetaphone.sql +1 -1
- metadata +40 -45
- data/.rvmrc +0 -52
- data/spec/pg_search/normalizer_spec.rb +0 -58
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 953137586cb6148bd40249e053348adc9d1e4c4e
|
4
|
+
data.tar.gz: bd82cbede7a515ea77280bb2667617abcbb3ba6a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4054d7eb7e376aee61ed698ccda4f8573752823e4b8de9e7bc192eefc84845aa2f3b0162f8de12704f5696367187bc1db2202f03c28aca1816128145e6aeebf9
|
7
|
+
data.tar.gz: 3a2031283e5b9a8e80e19607dc1b6bf044c4bd9340febdc0fd6606dffeff9729be7a36e214dddd877a915e6ae02e61b9099aab4b6d972d8a43afd314fc218dd0
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -2,14 +2,35 @@ language: ruby
|
|
2
2
|
|
3
3
|
rvm:
|
4
4
|
- 1.8.7
|
5
|
-
- 1.9.2
|
6
5
|
- 1.9.3
|
6
|
+
- 2.0.0
|
7
7
|
- jruby-18mode
|
8
8
|
- jruby-19mode
|
9
9
|
- rbx-18mode
|
10
10
|
- rbx-19mode
|
11
11
|
- ree
|
12
12
|
|
13
|
+
env:
|
14
|
+
- ACTIVE_RECORD_VERSION="~> 4.0.0.beta1"
|
15
|
+
- ACTIVE_RECORD_VERSION="~> 3.2.0"
|
16
|
+
- ACTIVE_RECORD_VERSION="~> 3.1.0"
|
17
|
+
|
18
|
+
matrix:
|
19
|
+
allow_failures:
|
20
|
+
- rvm: rbx-18mode
|
21
|
+
- rvm: rbx-19mode
|
22
|
+
- env: ACTIVE_RECORD_VERSION="~> 4.0.0.beta1"
|
23
|
+
exclude:
|
24
|
+
- rvm: 1.8.7
|
25
|
+
env: ACTIVE_RECORD_VERSION="~> 4.0.0.beta1"
|
26
|
+
- rvm: jruby-18mode
|
27
|
+
env: ACTIVE_RECORD_VERSION="~> 4.0.0.beta1"
|
28
|
+
- rvm: rbx-18mode
|
29
|
+
env: ACTIVE_RECORD_VERSION="~> 4.0.0.beta1"
|
30
|
+
- rvm: ree
|
31
|
+
env: ACTIVE_RECORD_VERSION="~> 4.0.0.beta1"
|
32
|
+
|
33
|
+
|
13
34
|
before_script:
|
14
35
|
- "psql -c 'create database pg_search_test;' -U postgres >/dev/null"
|
15
36
|
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
= PgSearch
|
2
2
|
|
3
|
+
== 0.6.0
|
4
|
+
|
5
|
+
* Drop support for Active Record 3.0.
|
6
|
+
|
7
|
+
* Address warnings in Ruby 2.0.
|
8
|
+
|
9
|
+
* Remove all usages of sanitize_sql_array for future Rails 4 compatibility.
|
10
|
+
|
11
|
+
* Start using Arel internally to build SQL strings (not yet complete).
|
12
|
+
|
13
|
+
* Disable eager loading, fixes issue #14.
|
14
|
+
|
15
|
+
* Support named schemas in pg_search:multisearch:rebuild. (Victor Olteanu)
|
16
|
+
|
3
17
|
== 0.5.7
|
4
18
|
|
5
19
|
* Fix issue with eager loading now that the Scope class has been removed. (Piotr Murach)
|
data/Gemfile
CHANGED
@@ -6,15 +6,19 @@ gem "rake"
|
|
6
6
|
gem "rdoc"
|
7
7
|
gem "pry"
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
platforms :jruby do
|
14
|
-
gem "activerecord-jdbcpostgresql-adapter"
|
15
|
-
end
|
9
|
+
gem 'pg', :platform => :ruby
|
10
|
+
gem "activerecord-jdbcpostgresql-adapter", :platform => :jruby
|
16
11
|
|
17
12
|
gem "rspec"
|
18
13
|
gem "with_model"
|
19
14
|
|
20
|
-
gem "activerecord",
|
15
|
+
gem "activerecord", ENV["ACTIVE_RECORD_VERSION"] if ENV["ACTIVE_RECORD_VERSION"]
|
16
|
+
|
17
|
+
gem 'coveralls', :require => false, :platform => :mri_20
|
18
|
+
|
19
|
+
group :development do
|
20
|
+
gem 'guard-rspec', :require => false
|
21
|
+
gem 'rb-inotify', :require => false
|
22
|
+
gem 'rb-fsevent', :require => false
|
23
|
+
gem 'rb-fchange', :require => false
|
24
|
+
end
|
data/Guardfile
ADDED
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -2,31 +2,51 @@
|
|
2
2
|
|
3
3
|
* http://github.com/casecommons/pg_search/
|
4
4
|
|
5
|
-
{<img src="https://secure.travis-ci.org/Casecommons/pg_search.png?branch=master" alt="Build Status" />}[http://travis-ci.org/Casecommons/pg_search]
|
5
|
+
{<img src="https://secure.travis-ci.org/Casecommons/pg_search.png?branch=master" alt="Build Status" />}[http://travis-ci.org/Casecommons/pg_search]
|
6
|
+
{<img src="https://gemnasium.com/Casecommons/pg_search.png" alt="Dependency Status" />}[https://gemnasium.com/Casecommons/pg_search]
|
7
|
+
{<img src="https://codeclimate.com/github/Casecommons/pg_search.png" />}[https://codeclimate.com/github/Casecommons/pg_search]
|
8
|
+
{<img src="https://coveralls.io/repos/Casecommons/pg_search/badge.png?branch=master" alt="Coverage Status" />}[https://coveralls.io/r/Casecommons/pg_search]
|
9
|
+
{<img src="https://badge.fury.io/rb/pg_search.png" alt="Gem Version" />}[http://badge.fury.io/rb/pg_search]
|
6
10
|
|
7
11
|
== DESCRIPTION
|
8
12
|
|
9
13
|
PgSearch builds named scopes that take advantage of PostgreSQL's full text search
|
10
14
|
|
11
|
-
Read the blog post introducing PgSearch at http://
|
15
|
+
Read the blog post introducing PgSearch at http://pivotallabs.com/pg-search/
|
16
|
+
|
17
|
+
== REQUIREMENTS
|
18
|
+
|
19
|
+
* Active Record 3.1 or later
|
20
|
+
* PostgreSQL
|
21
|
+
* {PostgreSQL contrib packages for certain features}[https://github.com/Casecommons/pg_search/wiki/Installing-Postgres-Contrib-Modules]
|
12
22
|
|
13
23
|
== INSTALL
|
14
24
|
|
15
25
|
gem install pg_search
|
16
26
|
|
17
|
-
=== Rails 3
|
27
|
+
=== Rails 3.1 or later
|
18
28
|
|
19
29
|
In Gemfile
|
20
30
|
|
21
31
|
gem 'pg_search'
|
22
32
|
|
33
|
+
=== Rails 3.0
|
34
|
+
|
35
|
+
The newest versions of PgSearch no longer support Rails 3.0. However, the 0.5 series still works. It's not actively maintained, but submissions are welcome for backports and bugfixes.
|
36
|
+
|
37
|
+
gem 'pg_search', "~> 0.5.7"
|
38
|
+
|
39
|
+
The 0.5 branch lives at https://github.com/Casecommons/pg_search/tree/0.5-stable
|
40
|
+
|
23
41
|
=== Rails 2
|
24
42
|
|
25
43
|
The newest versions of PgSearch no longer support Rails 2. However, the 0.2 series still works. It's not actively maintained, but submissions are welcome for backports and bugfixes.
|
26
44
|
|
45
|
+
gem 'pg_search', "~> 0.2.0"
|
46
|
+
|
27
47
|
The 0.2 branch lives at https://github.com/Casecommons/pg_search/tree/0.2-stable
|
28
48
|
|
29
|
-
=== Other
|
49
|
+
=== Other Active Record projects
|
30
50
|
|
31
51
|
In addition to installing and requiring the gem, you may want to include the PgSearch rake tasks in your Rakefile. This isn't necessary for Rails projects, which gain the Rake tasks via a Railtie.
|
32
52
|
|
@@ -34,7 +54,7 @@ In addition to installing and requiring the gem, you may want to include the PgS
|
|
34
54
|
|
35
55
|
== USAGE
|
36
56
|
|
37
|
-
To add PgSearch to an
|
57
|
+
To add PgSearch to an Active Record model, simply include the PgSearch module.
|
38
58
|
|
39
59
|
class Shape < ActiveRecord::Base
|
40
60
|
include PgSearch
|
@@ -71,6 +91,8 @@ To add a model to the global search index for your application, call multisearch
|
|
71
91
|
multisearchable :against => :color
|
72
92
|
end
|
73
93
|
|
94
|
+
If this model already has existing records, you will need to reindex this model to get existing records into the pg_search_documents table. See the rebuild task below.
|
95
|
+
|
74
96
|
Whenever a record is created, updated, or destroyed, an Active Record callback will fire, leading to the creation of a corresponding PgSearch::Document record in the pg_search_documents table. The :against option can be one or several methods which will be called on the record to generate its search text.
|
75
97
|
|
76
98
|
You can also pass a Proc or method name to call to determine whether or not a particular record should be included.
|
@@ -164,16 +186,23 @@ To remove all of the documents for a given class, you can simply delete all of t
|
|
164
186
|
|
165
187
|
PgSearch::Document.delete_all(:searchable_type => "Animal")
|
166
188
|
|
167
|
-
|
189
|
+
To regenerate the documents for a given class, run:
|
190
|
+
|
191
|
+
PgSearch::Multisearch.rebuild(Product)
|
192
|
+
|
193
|
+
This is also available as a Rake task, for convenience.
|
168
194
|
|
169
195
|
$ rake pg_search:multisearch:rebuild[BlogPost]
|
170
196
|
|
171
|
-
|
197
|
+
A second optional argument can be passed to specify the PostgreSQL schema search path to use, for multi-tenant databases that have multiple pg_search_documents tables. The following will set the schema search path to "my_schema" before reindexing.
|
198
|
+
|
199
|
+
$ rake pg_search:multisearch:rebuild[BlogPost,my_schema]
|
200
|
+
|
201
|
+
For models that are multisearchable :against methods that directly map to Active Record attributes, an efficient single SQL statement is run to update the pg_search_documents table all at once. However, if you call any dynamic methods in :against, the following strategy will be used:
|
172
202
|
|
173
203
|
PgSearch::Document.delete_all(:searchable_type => "Ingredient")
|
174
204
|
Ingredient.find_each { |record| record.update_pg_search_document }
|
175
205
|
|
176
|
-
|
177
206
|
You can also provide a custom implementation for rebuilding the documents by adding a class method called `rebuild_pg_search_documents` to your model.
|
178
207
|
|
179
208
|
class Movie < ActiveRecord::Base
|
@@ -569,12 +598,6 @@ To use this functionality you'll need to do a few things:
|
|
569
598
|
|
570
599
|
Please note that the :against column is only used when the tsvector_column is not present for the search type.
|
571
600
|
|
572
|
-
== REQUIREMENTS
|
573
|
-
|
574
|
-
* ActiveRecord 3
|
575
|
-
* PostgreSQL
|
576
|
-
* {PostgreSQL contrib packages for certain features}[https://github.com/Casecommons/pg_search/wiki/Installing-Postgres-Contrib-Modules]
|
577
|
-
|
578
601
|
== ATTRIBUTIONS
|
579
602
|
|
580
603
|
PgSearch would not have been possible without inspiration from
|
@@ -59,6 +59,14 @@ module PgSearch
|
|
59
59
|
Array(options[:using])
|
60
60
|
end
|
61
61
|
|
62
|
+
def feature_options
|
63
|
+
@feature_options ||= Hash.new.tap do |hash|
|
64
|
+
features.map do |feature_name, feature_options|
|
65
|
+
hash[feature_name] = feature_options
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
62
70
|
def order_within_rank
|
63
71
|
options[:order_within_rank]
|
64
72
|
end
|
@@ -85,11 +93,7 @@ module PgSearch
|
|
85
93
|
|
86
94
|
def assert_valid_options(options)
|
87
95
|
unless options[:against] || options[:associated_against]
|
88
|
-
raise ArgumentError, "the search scope #{@name} must have :against
|
89
|
-
end
|
90
|
-
|
91
|
-
if options[:associated_against] && !defined?(ActiveRecord::Relation)
|
92
|
-
raise ArgumentError, ":associated_against requires Active Record 3 or later"
|
96
|
+
raise ArgumentError, "the search scope #{@name} must have :against or :associated_against in its options"
|
93
97
|
end
|
94
98
|
|
95
99
|
options.assert_valid_keys(VALID_KEYS)
|
@@ -2,17 +2,27 @@ module PgSearch
|
|
2
2
|
module Features
|
3
3
|
class Trigram < Feature
|
4
4
|
def conditions
|
5
|
-
|
6
|
-
"
|
7
|
-
|
8
|
-
]
|
5
|
+
Arel::Nodes::Grouping.new(
|
6
|
+
Arel::Nodes::InfixOperation.new("%", normalized_document, normalize(query))
|
7
|
+
)
|
9
8
|
end
|
10
9
|
|
11
10
|
def rank
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
Arel::Nodes::Grouping.new(
|
12
|
+
Arel::Nodes::NamedFunction.new(
|
13
|
+
"similarity",
|
14
|
+
[
|
15
|
+
normalized_document,
|
16
|
+
normalize(query)
|
17
|
+
]
|
18
|
+
)
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def normalized_document
|
25
|
+
Arel::Nodes::Grouping.new(normalize(Arel.sql(document)))
|
16
26
|
end
|
17
27
|
end
|
18
28
|
end
|
@@ -3,8 +3,6 @@ require "active_support/core_ext/module/delegation"
|
|
3
3
|
module PgSearch
|
4
4
|
module Features
|
5
5
|
class TSearch < Feature
|
6
|
-
delegate :connection, :quoted_table_name, :to => :'@model'
|
7
|
-
|
8
6
|
def initialize(*args)
|
9
7
|
super
|
10
8
|
|
@@ -16,19 +14,17 @@ module PgSearch
|
|
16
14
|
end
|
17
15
|
|
18
16
|
def conditions
|
19
|
-
|
17
|
+
Arel::Nodes::Grouping.new(
|
18
|
+
Arel::Nodes::InfixOperation.new("@@", arel_wrap(tsdocument), arel_wrap(tsquery))
|
19
|
+
)
|
20
20
|
end
|
21
21
|
|
22
22
|
def rank
|
23
|
-
tsearch_rank
|
23
|
+
arel_wrap(tsearch_rank)
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
def interpolations
|
29
|
-
{:query => query.to_s, :dictionary => dictionary.to_s}
|
30
|
-
end
|
31
|
-
|
32
28
|
DISALLOWED_TSQUERY_CHARACTERS = /['?\\:]/
|
33
29
|
|
34
30
|
def tsquery_for_term(term)
|
@@ -45,7 +41,10 @@ module PgSearch
|
|
45
41
|
(connection.quote(':*') if options[:prefix])
|
46
42
|
].compact.join(" || ")
|
47
43
|
|
48
|
-
|
44
|
+
Arel::Nodes::NamedFunction.new(
|
45
|
+
"to_tsquery",
|
46
|
+
[dictionary, Arel.sql(tsquery_sql)]
|
47
|
+
).to_sql
|
49
48
|
end
|
50
49
|
|
51
50
|
def tsquery
|
@@ -61,7 +60,11 @@ module PgSearch
|
|
61
60
|
"#{quoted_table_name}.#{column_name}"
|
62
61
|
else
|
63
62
|
columns.map do |search_column|
|
64
|
-
tsvector =
|
63
|
+
tsvector = Arel::Nodes::NamedFunction.new(
|
64
|
+
"to_tsvector",
|
65
|
+
[dictionary, Arel.sql(normalize(search_column.to_sql))]
|
66
|
+
).to_sql
|
67
|
+
|
65
68
|
if search_column.weight.nil?
|
66
69
|
tsvector
|
67
70
|
else
|
@@ -85,12 +88,16 @@ module PgSearch
|
|
85
88
|
end
|
86
89
|
|
87
90
|
def tsearch_rank
|
88
|
-
|
91
|
+
"ts_rank((#{tsdocument}), (#{tsquery}), #{normalization})"
|
89
92
|
end
|
90
93
|
|
91
94
|
def dictionary
|
92
95
|
options[:dictionary] || :simple
|
93
96
|
end
|
97
|
+
|
98
|
+
def arel_wrap(sql_string)
|
99
|
+
Arel::Nodes::Grouping.new(Arel.sql(sql_string))
|
100
|
+
end
|
94
101
|
end
|
95
102
|
end
|
96
103
|
end
|
data/lib/pg_search/migration/templates/add_pg_search_associated_against_support_functions.rb.erb
CHANGED
@@ -2,7 +2,7 @@ class AddPgSearchAssociatedAgainstSupportFunctions < ActiveRecord::Migration
|
|
2
2
|
def self.up
|
3
3
|
say_with_time("Adding support functions for pg_search :associated_against") do
|
4
4
|
if ActiveRecord::Base.connection.send(:postgresql_version) < 80400
|
5
|
-
execute <<-SQL
|
5
|
+
execute <<-'SQL'
|
6
6
|
<%= read_sql_file "array_agg" %>
|
7
7
|
SQL
|
8
8
|
end
|
@@ -12,7 +12,7 @@ class AddPgSearchAssociatedAgainstSupportFunctions < ActiveRecord::Migration
|
|
12
12
|
def self.down
|
13
13
|
say_with_time("Dropping support functions for pg_search :associated_against") do
|
14
14
|
if ActiveRecord::Base.connection.send(:postgresql_version) < 80400
|
15
|
-
execute <<-SQL
|
15
|
+
execute <<-'SQL'
|
16
16
|
<%= read_sql_file "uninstall_array_agg" %>
|
17
17
|
SQL
|
18
18
|
end
|
@@ -2,12 +2,12 @@ class AddPgSearchDmetaphoneSupportFunctions < ActiveRecord::Migration
|
|
2
2
|
def self.up
|
3
3
|
say_with_time("Adding support functions for pg_search :dmetaphone") do
|
4
4
|
if ActiveRecord::Base.connection.send(:postgresql_version) < 80400
|
5
|
-
execute <<-SQL
|
5
|
+
execute <<-'SQL'
|
6
6
|
<%= read_sql_file "unnest" %>
|
7
7
|
SQL
|
8
8
|
end
|
9
9
|
|
10
|
-
execute <<-SQL
|
10
|
+
execute <<-'SQL'
|
11
11
|
<%= read_sql_file "dmetaphone" %>
|
12
12
|
SQL
|
13
13
|
end
|
@@ -15,12 +15,12 @@ class AddPgSearchDmetaphoneSupportFunctions < ActiveRecord::Migration
|
|
15
15
|
|
16
16
|
def self.down
|
17
17
|
say_with_time("Dropping support functions for pg_search :dmetaphone") do
|
18
|
-
execute <<-SQL
|
18
|
+
execute <<-'SQL'
|
19
19
|
<%= read_sql_file "uninstall_dmetaphone" %>
|
20
20
|
SQL
|
21
21
|
|
22
22
|
if ActiveRecord::Base.connection.send(:postgresql_version) < 80400
|
23
|
-
execute <<-SQL
|
23
|
+
execute <<-'SQL'
|
24
24
|
<%= read_sql_file "uninstall_unnest" %>
|
25
25
|
SQL
|
26
26
|
end
|
data/lib/pg_search/normalizer.rb
CHANGED
@@ -5,18 +5,26 @@ module PgSearch
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def add_normalization(sql_expression)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
"#{PgSearch.unaccent_function}(#{sql_expression})"
|
16
|
-
end
|
17
|
-
else
|
18
|
-
sql_expression
|
8
|
+
return sql_expression unless config.ignore.include?(:accents)
|
9
|
+
|
10
|
+
if config.postgresql_version < 90000
|
11
|
+
raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.gsub /^\s*/, '')
|
12
|
+
Sorry, {:ignoring => :accents} only works in PostgreSQL 9.0 and above.
|
13
|
+
#{config.inspect}
|
14
|
+
MESSAGE
|
19
15
|
end
|
16
|
+
|
17
|
+
sql_node = case sql_expression
|
18
|
+
when Arel::Nodes::Node
|
19
|
+
sql_expression
|
20
|
+
else
|
21
|
+
Arel.sql(sql_expression)
|
22
|
+
end
|
23
|
+
|
24
|
+
Arel::Nodes::NamedFunction.new(
|
25
|
+
PgSearch.unaccent_function,
|
26
|
+
[sql_node]
|
27
|
+
).to_sql
|
20
28
|
end
|
21
29
|
|
22
30
|
private
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require "active_support/core_ext/module/delegation"
|
2
4
|
|
3
5
|
module PgSearch
|
@@ -7,21 +9,35 @@ module PgSearch
|
|
7
9
|
def initialize(config)
|
8
10
|
@config = config
|
9
11
|
@model = config.model
|
10
|
-
@feature_options =
|
12
|
+
@feature_options = config.feature_options
|
11
13
|
end
|
12
14
|
|
13
15
|
def apply(scope)
|
14
|
-
scope.
|
16
|
+
scope.
|
17
|
+
select("#{quoted_table_name}.*, (#{rank}) AS pg_search_rank").
|
18
|
+
where(conditions).
|
19
|
+
order("pg_search_rank DESC, #{order_within_rank}").
|
20
|
+
joins(joins).
|
21
|
+
extend(DisableEagerLoading)
|
22
|
+
end
|
23
|
+
|
24
|
+
# workaround for https://github.com/Casecommons/pg_search/issues/14
|
25
|
+
module DisableEagerLoading
|
26
|
+
def eager_loading?
|
27
|
+
return false
|
28
|
+
end
|
15
29
|
end
|
16
30
|
|
17
31
|
private
|
18
32
|
|
19
|
-
delegate :connection, :quoted_table_name, :
|
33
|
+
delegate :connection, :quoted_table_name, :to => :@model
|
20
34
|
|
21
35
|
def conditions
|
22
36
|
config.features.map do |feature_name, feature_options|
|
23
|
-
|
24
|
-
end.
|
37
|
+
feature_for(feature_name).conditions
|
38
|
+
end.inject do |accumulator, expression|
|
39
|
+
Arel::Nodes::Or.new(accumulator, expression)
|
40
|
+
end
|
25
41
|
end
|
26
42
|
|
27
43
|
def order_within_rank
|
@@ -63,7 +79,7 @@ module PgSearch
|
|
63
79
|
|
64
80
|
def rank
|
65
81
|
(config.ranking_sql || ":tsearch").gsub(/:(\w*)/) do
|
66
|
-
|
82
|
+
feature_for($1).rank.to_sql
|
67
83
|
end
|
68
84
|
end
|
69
85
|
end
|
data/lib/pg_search/tasks.rb
CHANGED
@@ -4,13 +4,20 @@ require 'pg_search'
|
|
4
4
|
namespace :pg_search do
|
5
5
|
namespace :multisearch do
|
6
6
|
desc "Rebuild PgSearch multisearch records for a given model"
|
7
|
-
task :rebuild, [:model] => :environment do |task, args|
|
7
|
+
task :rebuild, [:model,:schema] => :environment do |task, args|
|
8
8
|
raise ArgumentError, <<-MESSAGE unless args.model
|
9
9
|
You must pass a model as an argument.
|
10
10
|
Example: rake pg_search:multisearch:rebuild[BlogPost]
|
11
11
|
MESSAGE
|
12
12
|
model_class = args.model.classify.constantize
|
13
|
-
PgSearch::
|
13
|
+
connection = PgSearch::Document.connection
|
14
|
+
original_schema_search_path = connection.schema_search_path
|
15
|
+
begin
|
16
|
+
connection.schema_search_path = args.schema if args.schema
|
17
|
+
PgSearch::Multisearch.rebuild(model_class)
|
18
|
+
ensure
|
19
|
+
connection.schema_search_path = original_schema_search_path
|
20
|
+
end
|
14
21
|
end
|
15
22
|
end
|
16
23
|
end
|
data/lib/pg_search/version.rb
CHANGED
data/pg_search.gemspec
CHANGED
@@ -6,17 +6,18 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = "pg_search"
|
7
7
|
s.version = PgSearch::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Case Commons, LLC"]
|
10
|
-
s.email = ["casecommons-dev@googlegroups.com"]
|
9
|
+
s.authors = ["Grant Hutchins", "Case Commons, LLC"]
|
10
|
+
s.email = ["gems@nertzy.com", "casecommons-dev@googlegroups.com"]
|
11
11
|
s.homepage = "https://github.com/Casecommons/pg_search"
|
12
|
-
s.summary = %q{PgSearch builds
|
13
|
-
s.description = %q{PgSearch builds
|
12
|
+
s.summary = %q{PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search}
|
13
|
+
s.description = %q{PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search}
|
14
|
+
s.licenses = ["MIT"]
|
14
15
|
|
15
16
|
s.files = `git ls-files`.split("\n")
|
16
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
19
|
s.require_paths = ["lib"]
|
19
20
|
|
20
|
-
s.add_dependency 'activerecord', '>=3'
|
21
|
-
s.add_dependency 'activesupport', '>=3'
|
21
|
+
s.add_dependency 'activerecord', '>=3.1'
|
22
|
+
s.add_dependency 'activesupport', '>=3.1'
|
22
23
|
end
|
@@ -343,6 +343,42 @@ describe PgSearch do
|
|
343
343
|
results.should_not include(excluded)
|
344
344
|
end
|
345
345
|
end
|
346
|
+
|
347
|
+
context "when including the associated model" do
|
348
|
+
with_model :Parent do
|
349
|
+
table do |t|
|
350
|
+
t.text :name
|
351
|
+
end
|
352
|
+
|
353
|
+
model do
|
354
|
+
has_many :children
|
355
|
+
include PgSearch
|
356
|
+
pg_search_scope :search_name, :against => :name
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
with_model :Child do
|
361
|
+
table do |t|
|
362
|
+
t.belongs_to :parent
|
363
|
+
end
|
364
|
+
|
365
|
+
model do
|
366
|
+
belongs_to :parent
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# https://github.com/Casecommons/pg_search/issues/14
|
371
|
+
it "supports queries with periods" do
|
372
|
+
included = Parent.create!(:name => 'bar.foo')
|
373
|
+
excluded = Parent.create!(:name => 'foo.bar')
|
374
|
+
|
375
|
+
results = Parent.search_name('bar.foo').includes(:children)
|
376
|
+
results.to_a
|
377
|
+
|
378
|
+
results.should include(included)
|
379
|
+
results.should_not include(excluded)
|
380
|
+
end
|
381
|
+
end
|
346
382
|
end
|
347
383
|
|
348
384
|
context "merging a pg_search_scope into another model's scope" do
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe "an
|
4
|
-
|
3
|
+
describe "an Active Record model which includes PgSearch" do
|
5
4
|
with_model :ModelWithPgSearch do
|
6
5
|
table do |t|
|
7
6
|
t.string 'title'
|
@@ -163,9 +162,6 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
163
162
|
end
|
164
163
|
|
165
164
|
it "returns rows that match the query but not its case" do
|
166
|
-
# \303\241 is a with acute accent
|
167
|
-
# \303\251 is e with acute accent
|
168
|
-
|
169
165
|
included = [ModelWithPgSearch.create!(:content => "foo"),
|
170
166
|
ModelWithPgSearch.create!(:content => "FOO")]
|
171
167
|
|
@@ -600,7 +596,11 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
600
596
|
end
|
601
597
|
|
602
598
|
it "should pass the custom configuration down to the specified feature" do
|
603
|
-
stub_feature = stub(
|
599
|
+
stub_feature = stub(
|
600
|
+
:conditions => Arel::Nodes::Grouping.new(Arel.sql("1 = 1")),
|
601
|
+
:rank => Arel::Nodes::Grouping.new(Arel.sql("1.0"))
|
602
|
+
)
|
603
|
+
|
604
604
|
PgSearch::Features::TSearch.should_receive(:new).with(anything, @tsearch_config, anything, anything, anything).at_least(:once).and_return(stub_feature)
|
605
605
|
PgSearch::Features::Trigram.should_receive(:new).with(anything, @trigram_config, anything, anything, anything).at_least(:once).and_return(stub_feature)
|
606
606
|
|
@@ -734,22 +734,66 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
734
734
|
|
735
735
|
%w[tsearch trigram dmetaphone].each do |feature|
|
736
736
|
context "using the #{feature} ranking algorithm" do
|
737
|
-
|
738
|
-
|
737
|
+
it "should return results with a rank" do
|
738
|
+
scope_name = :"search_content_ranked_by_#{feature}"
|
739
739
|
|
740
740
|
ModelWithPgSearch.pg_search_scope scope_name,
|
741
741
|
:against => :content,
|
742
742
|
:ranked_by => ":#{feature}"
|
743
|
-
end
|
744
743
|
|
745
|
-
it "should return results with a rank" do
|
746
744
|
ModelWithPgSearch.create!(:content => 'foo')
|
747
745
|
|
748
|
-
results = ModelWithPgSearch.send(
|
746
|
+
results = ModelWithPgSearch.send(scope_name, 'foo')
|
749
747
|
results.first.pg_search_rank.should be_a Float
|
750
748
|
end
|
751
749
|
end
|
752
750
|
end
|
751
|
+
|
752
|
+
context "using the tsearch ranking algorithm" do
|
753
|
+
it "sorts results by the tsearch rank" do
|
754
|
+
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_tsearch,
|
755
|
+
:using => :tsearch,
|
756
|
+
:against => :content,
|
757
|
+
:ranked_by => ":tsearch"
|
758
|
+
|
759
|
+
|
760
|
+
once = ModelWithPgSearch.create!(:content => 'foo bar')
|
761
|
+
twice = ModelWithPgSearch.create!(:content => 'foo foo')
|
762
|
+
|
763
|
+
results = ModelWithPgSearch.search_content_ranked_by_tsearch('foo')
|
764
|
+
results.index(twice).should be < results.index(once)
|
765
|
+
end
|
766
|
+
end
|
767
|
+
|
768
|
+
context "using the trigram ranking algorithm" do
|
769
|
+
it "sorts results by the trigram rank" do
|
770
|
+
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_trigram,
|
771
|
+
:using => :trigram,
|
772
|
+
:against => :content,
|
773
|
+
:ranked_by => ":trigram"
|
774
|
+
|
775
|
+
close = ModelWithPgSearch.create!(:content => 'abcdef')
|
776
|
+
exact = ModelWithPgSearch.create!(:content => 'abc')
|
777
|
+
|
778
|
+
results = ModelWithPgSearch.search_content_ranked_by_trigram('abc')
|
779
|
+
results.index(exact).should be < results.index(close)
|
780
|
+
end
|
781
|
+
end
|
782
|
+
|
783
|
+
context "using the dmetaphone ranking algorithm" do
|
784
|
+
it "sorts results by the dmetaphone rank" do
|
785
|
+
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
786
|
+
:using => :dmetaphone,
|
787
|
+
:against => :content,
|
788
|
+
:ranked_by => ":dmetaphone"
|
789
|
+
|
790
|
+
once = ModelWithPgSearch.create!(:content => 'Phoo Bar')
|
791
|
+
twice = ModelWithPgSearch.create!(:content => 'Phoo Fu')
|
792
|
+
|
793
|
+
results = ModelWithPgSearch.search_content_ranked_by_dmetaphone('foo')
|
794
|
+
results.index(twice).should be < results.index(once)
|
795
|
+
end
|
796
|
+
end
|
753
797
|
end
|
754
798
|
|
755
799
|
context "on an STI subclass" do
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe PgSearch::Features::Trigram do
|
4
|
+
describe "#rank" do
|
5
|
+
with_model :Model do
|
6
|
+
table do |t|
|
7
|
+
t.string :name
|
8
|
+
t.text :content
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns an expression using the similarity() function" do
|
13
|
+
query = "query"
|
14
|
+
columns = [
|
15
|
+
PgSearch::Configuration::Column.new(:name, nil, Model),
|
16
|
+
PgSearch::Configuration::Column.new(:content, nil, Model),
|
17
|
+
]
|
18
|
+
options = stub(:options)
|
19
|
+
config = stub(:config, :ignore => [])
|
20
|
+
normalizer = PgSearch::Normalizer.new(config)
|
21
|
+
|
22
|
+
feature = described_class.new(query, options, columns, Model, normalizer)
|
23
|
+
feature.rank.to_sql.should == %Q{(similarity((coalesce(#{Model.quoted_table_name}."name"::text, '') || ' ' || coalesce(#{Model.quoted_table_name}."content"::text, '')), 'query'))}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe PgSearch::Features::TSearch do
|
4
|
+
describe "#rank" do
|
5
|
+
with_model :Model do
|
6
|
+
table do |t|
|
7
|
+
t.string :name
|
8
|
+
t.text :content
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns an expression using the ts_rank() function" do
|
13
|
+
query = "query"
|
14
|
+
columns = [
|
15
|
+
PgSearch::Configuration::Column.new(:name, nil, Model),
|
16
|
+
PgSearch::Configuration::Column.new(:content, nil, Model),
|
17
|
+
]
|
18
|
+
options = {}
|
19
|
+
config = stub(:config, :ignore => [])
|
20
|
+
normalizer = PgSearch::Normalizer.new(config)
|
21
|
+
|
22
|
+
feature = described_class.new(query, options, columns, Model, normalizer)
|
23
|
+
feature.rank.to_sql.should ==
|
24
|
+
%Q{(ts_rank((to_tsvector('simple', coalesce(#{Model.quoted_table_name}."name"::text, '')) || to_tsvector('simple', coalesce(#{Model.quoted_table_name}."content"::text, ''))), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 0))}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#conditions" do
|
29
|
+
with_model :Model do
|
30
|
+
table do |t|
|
31
|
+
t.string :name
|
32
|
+
t.text :content
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns an expression using the @@ infix operator" do
|
37
|
+
query = "query"
|
38
|
+
columns = [
|
39
|
+
PgSearch::Configuration::Column.new(:name, nil, Model),
|
40
|
+
PgSearch::Configuration::Column.new(:content, nil, Model),
|
41
|
+
]
|
42
|
+
options = {}
|
43
|
+
config = stub(:config, :ignore => [])
|
44
|
+
normalizer = PgSearch::Normalizer.new(config)
|
45
|
+
|
46
|
+
feature = described_class.new(query, options, columns, Model, normalizer)
|
47
|
+
feature.conditions.to_sql.should ==
|
48
|
+
%Q{((to_tsvector('simple', coalesce(#{Model.quoted_table_name}."name"::text, '')) || to_tsvector('simple', coalesce(#{Model.quoted_table_name}."content"::text, ''))) @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe PgSearch::Normalizer do
|
4
|
+
describe "#add_normalization" do
|
5
|
+
context "for PostgreSQL 9.0 and above" do
|
6
|
+
context "when config[:ignore] includes :accents" do
|
7
|
+
context "when passed an Arel node" do
|
8
|
+
it "wraps the expression in unaccent()" do
|
9
|
+
config = stub("config", :ignore => [:accents], :postgresql_version => 90000)
|
10
|
+
node = Arel::Nodes::NamedFunction.new("foo", ["bar"])
|
11
|
+
|
12
|
+
normalizer = PgSearch::Normalizer.new(config)
|
13
|
+
normalizer.add_normalization(node).should == "unaccent(foo('bar'))"
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when a custom unaccent function is specified" do
|
17
|
+
it "wraps the expression in that function" do
|
18
|
+
PgSearch.stub(:unaccent_function).and_return("my_unaccent")
|
19
|
+
node = Arel::Nodes::NamedFunction.new("foo", ["bar"])
|
20
|
+
|
21
|
+
config = stub("config", :ignore => [:accents], :postgresql_version => 90000)
|
22
|
+
|
23
|
+
normalizer = PgSearch::Normalizer.new(config)
|
24
|
+
normalizer.add_normalization(node).should == "my_unaccent(foo('bar'))"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when passed a String" do
|
30
|
+
it "wraps the expression in unaccent()" do
|
31
|
+
config = stub("config", :ignore => [:accents], :postgresql_version => 90000)
|
32
|
+
|
33
|
+
normalizer = PgSearch::Normalizer.new(config)
|
34
|
+
normalizer.add_normalization("foo").should == "unaccent(foo)"
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when a custom unaccent function is specified" do
|
38
|
+
it "wraps the expression in that function" do
|
39
|
+
PgSearch.stub(:unaccent_function).and_return("my_unaccent")
|
40
|
+
|
41
|
+
config = stub("config", :ignore => [:accents], :postgresql_version => 90000)
|
42
|
+
|
43
|
+
normalizer = PgSearch::Normalizer.new(config)
|
44
|
+
normalizer.add_normalization("foo").should == "my_unaccent(foo)"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when config[:ignore] does not include :accents" do
|
51
|
+
it "passes the expression through" do
|
52
|
+
config = stub("config", :ignore => [], :postgresql_version => 90000)
|
53
|
+
|
54
|
+
normalizer = PgSearch::Normalizer.new(config)
|
55
|
+
normalizer.add_normalization("foo").should == "foo"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "for PostgreSQL versions before 9.0" do
|
61
|
+
context "when config[:ignore] includes :accents" do
|
62
|
+
it "raises a NotSupportedForPostgresqlVersion exception" do
|
63
|
+
config = stub("config", :ignore => [:accents], :postgresql_version => 89999)
|
64
|
+
|
65
|
+
normalizer = PgSearch::Normalizer.new(config)
|
66
|
+
expect {
|
67
|
+
normalizer.add_normalization("foo")
|
68
|
+
}.to raise_exception(PgSearch::NotSupportedForPostgresqlVersion)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when config[:ignore] does not include :accents" do
|
73
|
+
it "passes the expression through" do
|
74
|
+
config = stub("config", :ignore => [], :postgresql_version => 90000)
|
75
|
+
|
76
|
+
normalizer = PgSearch::Normalizer.new(config)
|
77
|
+
normalizer.add_normalization("foo").should == "foo"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require "bundler/setup"
|
2
2
|
require "pg_search"
|
3
3
|
|
4
|
+
begin
|
5
|
+
require 'coveralls'
|
6
|
+
Coveralls.wear!
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
4
10
|
begin
|
5
11
|
require "pg"
|
6
12
|
error_class = PGError
|
@@ -73,13 +79,19 @@ unless postgresql_version < 90000
|
|
73
79
|
end
|
74
80
|
install_extension_if_missing("fuzzystrmatch", "SELECT dmetaphone('foo')", "f")
|
75
81
|
|
82
|
+
def load_sql(filename)
|
83
|
+
connection = ActiveRecord::Base.connection
|
84
|
+
file_contents = File.read(File.join(File.dirname(__FILE__), '..', 'sql', filename))
|
85
|
+
connection.execute(file_contents)
|
86
|
+
end
|
87
|
+
|
76
88
|
if postgresql_version < 80400
|
77
89
|
unless connection.select_value("SELECT 1 FROM pg_catalog.pg_aggregate WHERE aggfnoid = 'array_agg'::REGPROC") == "1"
|
78
|
-
|
90
|
+
load_sql("array_agg.sql")
|
79
91
|
end
|
80
|
-
|
92
|
+
load_sql("unnest.sql")
|
81
93
|
end
|
82
|
-
|
94
|
+
load_sql("dmetaphone.sql")
|
83
95
|
|
84
96
|
require "with_model"
|
85
97
|
|
@@ -94,45 +106,3 @@ DOCUMENTS_SCHEMA = lambda do |t|
|
|
94
106
|
t.text :content
|
95
107
|
t.timestamps
|
96
108
|
end
|
97
|
-
|
98
|
-
require 'irb'
|
99
|
-
|
100
|
-
class IRB::Irb
|
101
|
-
alias initialize_orig initialize
|
102
|
-
def initialize(workspace = nil, *args)
|
103
|
-
default = IRB.conf[:DEFAULT_OBJECT]
|
104
|
-
workspace ||= IRB::WorkSpace.new default if default
|
105
|
-
initialize_orig(workspace, *args)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Drop into an IRB session for whatever object you pass in:
|
110
|
-
#
|
111
|
-
# class Dude
|
112
|
-
# def abides
|
113
|
-
# true
|
114
|
-
# end
|
115
|
-
# end
|
116
|
-
#
|
117
|
-
# console_for(Dude.new)
|
118
|
-
#
|
119
|
-
# Then type "quit" or "exit" to get out. In a step definition, it should look like:
|
120
|
-
#
|
121
|
-
# When /^I console/ do
|
122
|
-
# console_for(self)
|
123
|
-
# end
|
124
|
-
#
|
125
|
-
# Also, I definitely stole this hack from some mailing list post somewhere. I wish I
|
126
|
-
# could remember who did it, but I can't. Sorry!
|
127
|
-
def console_for(target)
|
128
|
-
puts "== ENTERING CONSOLE MODE. ==\nType 'exit' to move on.\nContext: #{target.inspect}"
|
129
|
-
|
130
|
-
begin
|
131
|
-
oldargs = ARGV.dup
|
132
|
-
ARGV.clear
|
133
|
-
IRB.conf[:DEFAULT_OBJECT] = target
|
134
|
-
IRB.start
|
135
|
-
ensure
|
136
|
-
ARGV.replace(oldargs)
|
137
|
-
end
|
138
|
-
end
|
data/sql/dmetaphone.sql
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
CREATE OR REPLACE FUNCTION pg_search_dmetaphone(text) RETURNS text LANGUAGE SQL IMMUTABLE STRICT AS $function$
|
2
|
-
SELECT array_to_string(ARRAY(SELECT dmetaphone(unnest(regexp_split_to_array($1, E'
|
2
|
+
SELECT array_to_string(ARRAY(SELECT dmetaphone(unnest(regexp_split_to_array($1, E'\\s+')))), ' ')
|
3
3
|
$function$;
|
metadata
CHANGED
@@ -1,51 +1,48 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.6.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
7
|
+
- Grant Hutchins
|
8
8
|
- Case Commons, LLC
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-04-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
17
|
requirements:
|
19
|
-
- -
|
18
|
+
- - '>='
|
20
19
|
- !ruby/object:Gem::Version
|
21
|
-
version: '3'
|
20
|
+
version: '3.1'
|
22
21
|
type: :runtime
|
23
22
|
prerelease: false
|
24
23
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
24
|
requirements:
|
27
|
-
- -
|
25
|
+
- - '>='
|
28
26
|
- !ruby/object:Gem::Version
|
29
|
-
version: '3'
|
27
|
+
version: '3.1'
|
30
28
|
- !ruby/object:Gem::Dependency
|
31
29
|
name: activesupport
|
32
30
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
31
|
requirements:
|
35
|
-
- -
|
32
|
+
- - '>='
|
36
33
|
- !ruby/object:Gem::Version
|
37
|
-
version: '3'
|
34
|
+
version: '3.1'
|
38
35
|
type: :runtime
|
39
36
|
prerelease: false
|
40
37
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
38
|
requirements:
|
43
|
-
- -
|
39
|
+
- - '>='
|
44
40
|
- !ruby/object:Gem::Version
|
45
|
-
version: '3'
|
46
|
-
description: PgSearch builds
|
41
|
+
version: '3.1'
|
42
|
+
description: PgSearch builds Active Record named scopes that take advantage of PostgreSQL's
|
47
43
|
full text search
|
48
44
|
email:
|
45
|
+
- gems@nertzy.com
|
49
46
|
- casecommons-dev@googlegroups.com
|
50
47
|
executables: []
|
51
48
|
extensions: []
|
@@ -54,10 +51,10 @@ files:
|
|
54
51
|
- .autotest
|
55
52
|
- .gitignore
|
56
53
|
- .rspec
|
57
|
-
- .rvmrc
|
58
54
|
- .travis.yml
|
59
55
|
- CHANGELOG.rdoc
|
60
56
|
- Gemfile
|
57
|
+
- Guardfile
|
61
58
|
- LICENSE
|
62
59
|
- README.rdoc
|
63
60
|
- Rakefile
|
@@ -87,13 +84,15 @@ files:
|
|
87
84
|
- lib/pg_search/tasks.rb
|
88
85
|
- lib/pg_search/version.rb
|
89
86
|
- pg_search.gemspec
|
90
|
-
- spec/associations_spec.rb
|
91
|
-
- spec/
|
92
|
-
- spec/pg_search/
|
93
|
-
- spec/pg_search/
|
94
|
-
- spec/pg_search/
|
95
|
-
- spec/pg_search/
|
96
|
-
- spec/
|
87
|
+
- spec/integration/associations_spec.rb
|
88
|
+
- spec/integration/pg_search_spec.rb
|
89
|
+
- spec/lib/pg_search/document_spec.rb
|
90
|
+
- spec/lib/pg_search/features/trigram_spec.rb
|
91
|
+
- spec/lib/pg_search/features/tsearch_spec.rb
|
92
|
+
- spec/lib/pg_search/multisearch/rebuilder_spec.rb
|
93
|
+
- spec/lib/pg_search/multisearch_spec.rb
|
94
|
+
- spec/lib/pg_search/multisearchable_spec.rb
|
95
|
+
- spec/lib/pg_search/normalizer_spec.rb
|
97
96
|
- spec/spec_helper.rb
|
98
97
|
- sql/array_agg.sql
|
99
98
|
- sql/dmetaphone.sql
|
@@ -102,42 +101,38 @@ files:
|
|
102
101
|
- sql/uninstall_unnest.sql
|
103
102
|
- sql/unnest.sql
|
104
103
|
homepage: https://github.com/Casecommons/pg_search
|
105
|
-
licenses:
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
106
107
|
post_install_message:
|
107
108
|
rdoc_options: []
|
108
109
|
require_paths:
|
109
110
|
- lib
|
110
111
|
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
-
none: false
|
112
112
|
requirements:
|
113
|
-
- -
|
113
|
+
- - '>='
|
114
114
|
- !ruby/object:Gem::Version
|
115
115
|
version: '0'
|
116
|
-
segments:
|
117
|
-
- 0
|
118
|
-
hash: -1475822108196160881
|
119
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
-
none: false
|
121
117
|
requirements:
|
122
|
-
- -
|
118
|
+
- - '>='
|
123
119
|
- !ruby/object:Gem::Version
|
124
120
|
version: '0'
|
125
|
-
segments:
|
126
|
-
- 0
|
127
|
-
hash: -1475822108196160881
|
128
121
|
requirements: []
|
129
122
|
rubyforge_project:
|
130
|
-
rubygems_version:
|
123
|
+
rubygems_version: 2.0.3
|
131
124
|
signing_key:
|
132
|
-
specification_version:
|
133
|
-
summary: PgSearch builds
|
125
|
+
specification_version: 4
|
126
|
+
summary: PgSearch builds Active Record named scopes that take advantage of PostgreSQL's
|
134
127
|
full text search
|
135
128
|
test_files:
|
136
|
-
- spec/associations_spec.rb
|
137
|
-
- spec/
|
138
|
-
- spec/pg_search/
|
139
|
-
- spec/pg_search/
|
140
|
-
- spec/pg_search/
|
141
|
-
- spec/pg_search/
|
142
|
-
- spec/
|
129
|
+
- spec/integration/associations_spec.rb
|
130
|
+
- spec/integration/pg_search_spec.rb
|
131
|
+
- spec/lib/pg_search/document_spec.rb
|
132
|
+
- spec/lib/pg_search/features/trigram_spec.rb
|
133
|
+
- spec/lib/pg_search/features/tsearch_spec.rb
|
134
|
+
- spec/lib/pg_search/multisearch/rebuilder_spec.rb
|
135
|
+
- spec/lib/pg_search/multisearch_spec.rb
|
136
|
+
- spec/lib/pg_search/multisearchable_spec.rb
|
137
|
+
- spec/lib/pg_search/normalizer_spec.rb
|
143
138
|
- spec/spec_helper.rb
|
data/.rvmrc
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
#!/usr/bin/env bash
|
2
|
-
|
3
|
-
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
-
# development environment upon cd'ing into the directory
|
5
|
-
|
6
|
-
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
|
7
|
-
# Only full ruby name is supported here, for short names use:
|
8
|
-
# echo "rvm use 1.9.3" > .rvmrc
|
9
|
-
environment_id="ruby-1.9.3-p194@pg_search"
|
10
|
-
|
11
|
-
# Uncomment the following lines if you want to verify rvm version per project
|
12
|
-
# rvmrc_rvm_version="1.12.4 ()" # 1.10.1 seams as a safe start
|
13
|
-
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
|
14
|
-
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
|
15
|
-
# return 1
|
16
|
-
# }
|
17
|
-
|
18
|
-
# First we attempt to load the desired environment directly from the environment
|
19
|
-
# file. This is very fast and efficient compared to running through the entire
|
20
|
-
# CLI and selector. If you want feedback on which environment was used then
|
21
|
-
# insert the word 'use' after --create as this triggers verbose mode.
|
22
|
-
if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
|
23
|
-
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
24
|
-
then
|
25
|
-
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
26
|
-
[[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
|
27
|
-
\. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
|
28
|
-
if [[ $- == *i* ]] # check for interactive shells
|
29
|
-
then echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
|
30
|
-
else echo "Using: $GEM_HOME" # don't use colors in non-interactive shells
|
31
|
-
fi
|
32
|
-
else
|
33
|
-
# If the environment file has not yet been created, use the RVM CLI to select.
|
34
|
-
rvm --create use "$environment_id" || {
|
35
|
-
echo "Failed to create RVM environment '${environment_id}'."
|
36
|
-
return 1
|
37
|
-
}
|
38
|
-
fi
|
39
|
-
|
40
|
-
# If you use bundler, this might be useful to you:
|
41
|
-
if [[ -s Gemfile ]] && {
|
42
|
-
! builtin command -v bundle >/dev/null ||
|
43
|
-
builtin command -v bundle | grep $rvm_path/bin/bundle >/dev/null
|
44
|
-
}
|
45
|
-
then
|
46
|
-
printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
|
47
|
-
gem install bundler
|
48
|
-
fi
|
49
|
-
if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
|
50
|
-
then
|
51
|
-
bundle install | grep -vE '^Using|Your bundle is complete'
|
52
|
-
fi
|
@@ -1,58 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe PgSearch::Normalizer do
|
4
|
-
describe "#add_normalization" do
|
5
|
-
context "for PostgreSQL 9.0 and above" do
|
6
|
-
context "when config[:ignore] includes :accents" do
|
7
|
-
it "wraps the expression in unaccent()" do
|
8
|
-
config = stub("config", :ignore => [:accents], :postgresql_version => 90000)
|
9
|
-
|
10
|
-
normalizer = PgSearch::Normalizer.new(config)
|
11
|
-
normalizer.add_normalization("foo").should == "unaccent(foo)"
|
12
|
-
end
|
13
|
-
|
14
|
-
context "when a custom unaccent function is specified" do
|
15
|
-
it "wraps the expression in that function" do
|
16
|
-
PgSearch.stub(:unaccent_function).and_return("my_unaccent")
|
17
|
-
|
18
|
-
config = stub("config", :ignore => [:accents], :postgresql_version => 90000)
|
19
|
-
|
20
|
-
normalizer = PgSearch::Normalizer.new(config)
|
21
|
-
normalizer.add_normalization("foo").should == "my_unaccent(foo)"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context "when config[:ignore] does not include :accents" do
|
27
|
-
it "passes the expression through" do
|
28
|
-
config = stub("config", :ignore => [], :postgresql_version => 90000)
|
29
|
-
|
30
|
-
normalizer = PgSearch::Normalizer.new(config)
|
31
|
-
normalizer.add_normalization("foo").should == "foo"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context "for PostgreSQL versions before 9.0" do
|
37
|
-
context "when config[:ignore] includes :accents" do
|
38
|
-
it "raises a NotSupportedForPostgresqlVersion exception" do
|
39
|
-
config = stub("config", :ignore => [:accents], :postgresql_version => 89999)
|
40
|
-
|
41
|
-
normalizer = PgSearch::Normalizer.new(config)
|
42
|
-
expect {
|
43
|
-
normalizer.add_normalization("foo")
|
44
|
-
}.to raise_exception(PgSearch::NotSupportedForPostgresqlVersion)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context "when config[:ignore] does not include :accents" do
|
49
|
-
it "passes the expression through" do
|
50
|
-
config = stub("config", :ignore => [], :postgresql_version => 90000)
|
51
|
-
|
52
|
-
normalizer = PgSearch::Normalizer.new(config)
|
53
|
-
normalizer.add_normalization("foo").should == "foo"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|