buscando_el_viento 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +45 -0
- data/Rakefile +14 -0
- data/buscando_el_viento.gemspec +21 -0
- data/lib/buscando_el_viento.rb +12 -0
- data/lib/buscando_el_viento/indexes.rb +26 -0
- data/lib/buscando_el_viento/search.rb +12 -0
- data/lib/buscando_el_viento/triggers.rb +32 -0
- data/lib/buscando_el_viento/vectors.rb +17 -0
- data/lib/buscando_el_viento/version.rb +4 -0
- data/readme.md +77 -0
- data/spec/buscando_el_viento_spec.rb +11 -0
- data/spec/fuzzy_spec.rb +54 -0
- data/spec/indexes_spec.rb +68 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/triggers_spec.rb +89 -0
- data/spec/vectors_spec.rb +27 -0
- data/spec/wrapper_spec.rb +31 -0
- metadata +91 -0
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm ruby-1.8.7-p334@buscando_el_viento
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
buscando_el_viento (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activemodel (3.1.0.rc1)
|
10
|
+
activesupport (= 3.1.0.rc1)
|
11
|
+
bcrypt-ruby (~> 2.1.4)
|
12
|
+
builder (~> 3.0.0)
|
13
|
+
i18n (~> 0.6.0beta1)
|
14
|
+
activerecord (3.1.0.rc1)
|
15
|
+
activemodel (= 3.1.0.rc1)
|
16
|
+
activesupport (= 3.1.0.rc1)
|
17
|
+
arel (~> 2.1.1)
|
18
|
+
tzinfo (~> 0.3.27)
|
19
|
+
activesupport (3.1.0.rc1)
|
20
|
+
multi_json (~> 1.0)
|
21
|
+
arel (2.1.3)
|
22
|
+
bcrypt-ruby (2.1.4)
|
23
|
+
builder (3.0.0)
|
24
|
+
diff-lcs (1.1.2)
|
25
|
+
i18n (0.6.0)
|
26
|
+
multi_json (1.0.3)
|
27
|
+
rake (0.8.7)
|
28
|
+
rspec (2.6.0)
|
29
|
+
rspec-core (~> 2.6.0)
|
30
|
+
rspec-expectations (~> 2.6.0)
|
31
|
+
rspec-mocks (~> 2.6.0)
|
32
|
+
rspec-core (2.6.4)
|
33
|
+
rspec-expectations (2.6.0)
|
34
|
+
diff-lcs (~> 1.1.2)
|
35
|
+
rspec-mocks (2.6.0)
|
36
|
+
tzinfo (0.3.29)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
activerecord (= 3.1.0.rc1)
|
43
|
+
buscando_el_viento!
|
44
|
+
rake (= 0.8.7)
|
45
|
+
rspec
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
# copied from RSpec :-p
|
5
|
+
require 'rspec'
|
6
|
+
require 'rspec/core'
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
desc "Run all examples"
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
10
|
+
t.rspec_path = 'rspec'
|
11
|
+
t.rspec_opts = %w[--color]
|
12
|
+
t.verbose = false
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "buscando_el_viento/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "buscando_el_viento"
|
7
|
+
s.version = BuscandoElViento::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["giles bowkett", "xavier shay"]
|
10
|
+
s.email = ["gilesb@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/gilesbowkett/buscando_el_viento"
|
12
|
+
s.summary = s.description = %q{Rails migration class methods for PostgreSQL search}
|
13
|
+
|
14
|
+
s.rubyforge_project = "buscando_el_viento"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/base' # https://github.com/rails/rails/pull/1999
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + '/buscando_el_viento/vectors'
|
5
|
+
require File.dirname(__FILE__) + '/buscando_el_viento/triggers'
|
6
|
+
require File.dirname(__FILE__) + '/buscando_el_viento/indexes'
|
7
|
+
require File.dirname(__FILE__) + '/buscando_el_viento/search'
|
8
|
+
|
9
|
+
class BuscandoMigration < ActiveRecord::Migration
|
10
|
+
include BuscandoElViento
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BuscandoElViento
|
2
|
+
def index_name(table, column) # FIXME: better variable names
|
3
|
+
case column
|
4
|
+
when String, Symbol
|
5
|
+
"index_#{table}_on_#{column}_search_vector"
|
6
|
+
when Array
|
7
|
+
"index_#{table}_on_#{column.join("_and_")}_search_vector"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# yes, we're overwriting ActiveRecord::Migration's add_index, which, in this
|
12
|
+
# context, is less useful than it should be
|
13
|
+
def add_index(table, column)
|
14
|
+
execute <<-ADD_INDEX
|
15
|
+
CREATE INDEX #{index_name(table, column)}
|
16
|
+
ON #{table}
|
17
|
+
USING gin(search_vector);
|
18
|
+
ADD_INDEX
|
19
|
+
end
|
20
|
+
|
21
|
+
# remove_index gets the job done 9 times out of 10 for this stuff, but it
|
22
|
+
# needs a little assistance on composite indices
|
23
|
+
def remove_composite_index(table, columns)
|
24
|
+
remove_index table, vector_name(columns).to_s
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module BuscandoElViento
|
2
|
+
def add_search(table, columns, options = {:fuzzy => false})
|
3
|
+
add_search_vector(table, columns)
|
4
|
+
add_trigger(table, columns, options)
|
5
|
+
add_index(table, columns)
|
6
|
+
end
|
7
|
+
def remove_search(table, columns)
|
8
|
+
remove_search_vector(table, columns)
|
9
|
+
remove_trigger(table, columns)
|
10
|
+
remove_index(table, columns)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module BuscandoElViento
|
2
|
+
def trigger_name(table, column)
|
3
|
+
"#{table}_#{vector_name(column)}_update"
|
4
|
+
end
|
5
|
+
def add_trigger(table, names, options = {:fuzzy => false})
|
6
|
+
dictionary = if options[:fuzzy]
|
7
|
+
"english"
|
8
|
+
else
|
9
|
+
"simple"
|
10
|
+
end
|
11
|
+
|
12
|
+
column = case names
|
13
|
+
when String, Symbol
|
14
|
+
names.to_s
|
15
|
+
when Array
|
16
|
+
names.join(", ")
|
17
|
+
end
|
18
|
+
execute <<TRIGGER
|
19
|
+
CREATE TRIGGER #{trigger_name(table, names)}
|
20
|
+
BEFORE INSERT OR UPDATE
|
21
|
+
ON #{table}
|
22
|
+
FOR EACH ROW EXECUTE PROCEDURE
|
23
|
+
tsvector_update_trigger(#{vector_name(names).to_s},
|
24
|
+
'pg_catalog.#{dictionary}',
|
25
|
+
#{column});
|
26
|
+
TRIGGER
|
27
|
+
end
|
28
|
+
def remove_trigger(table, column)
|
29
|
+
execute "DROP TRIGGER IF EXISTS #{trigger_name(table, column)} on #{table};"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module BuscandoElViento
|
2
|
+
def vector_name(name)
|
3
|
+
case name
|
4
|
+
when String, Symbol
|
5
|
+
"#{name}_search_vector".to_sym
|
6
|
+
when Array
|
7
|
+
"#{name.join("_and_")}_search_vector".to_sym
|
8
|
+
end
|
9
|
+
end
|
10
|
+
def add_search_vector(table, column)
|
11
|
+
add_column(table, vector_name(column), "tsvector")
|
12
|
+
end
|
13
|
+
def remove_search_vector(table, column)
|
14
|
+
remove_column(table, vector_name(column))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/readme.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
buscando el viento
|
2
|
+
==================
|
3
|
+
|
4
|
+
buscando el viento is a search migrations gem for PostgreSQL and Rails 3. It enables full-text searching by automating the process of creating appropriate migrations, and is largely based on Xavier Shay's PeepCode video on Postgres.
|
5
|
+
|
6
|
+
http://peepcode.com/products/postgresql
|
7
|
+
|
8
|
+
usage
|
9
|
+
-----
|
10
|
+
|
11
|
+
Inherit from `BuscandoMigration` instead of `ActiveRecord::Migration`. The `BuscandoElViento` version includes additional class methods. For example,
|
12
|
+
|
13
|
+
add_search_vector :users, :username
|
14
|
+
|
15
|
+
will add a search vector attribute to your `users` table, tracking the `username` attribute.
|
16
|
+
|
17
|
+
However if you do this
|
18
|
+
|
19
|
+
add_search :users, :username, :fuzzy => true
|
20
|
+
|
21
|
+
you get the search vector, a database trigger to keep that vector up to date, and an index to make retrieval fast.
|
22
|
+
|
23
|
+
Obviously the `:fuzzy` flag represents fuzzy versus exact search; this simply turns stemming on or off, although PostgreSQL supports a lot of additional features and options in its full-text search capacities. Use `remove_search` in the `down` method, to avoid `IrreversibleMigrations`. (Buscando doesn't support the `def change` approach yet, although there's no real reason why not.)
|
24
|
+
|
25
|
+
tests and specs
|
26
|
+
---------------
|
27
|
+
|
28
|
+
In order to run your Rails tests, if you use PostgreSQL this way, you'll need to modify how Rails handles schema dumps. See the Postgres PeepCode for more info.
|
29
|
+
|
30
|
+
http://peepcode.com/products/postgresql
|
31
|
+
|
32
|
+
In terms of the gem's own specs, these could be better. They really just test the implementation, which is to say they verify that calling particular methods on the custom migration invokes particular other methods on the ActiveRecord migration.
|
33
|
+
|
34
|
+
This makes the specs fast, and I prefer tests and specs which circumvent the database in most circumstances, but if you're noodling around wondering what kind of patches a project this awesome could possibly need, I'd have a look at verifying that the specs actually result in code which can perform searches properly.
|
35
|
+
|
36
|
+
wtf? is that name spanish?
|
37
|
+
--------------------------
|
38
|
+
|
39
|
+
yes. "buscando el viento" means "seeking the wind" and gets its name from a line in a poem by Pablo Neruda.
|
40
|
+
|
41
|
+
mi voz buscaba el viento para tocar su oido
|
42
|
+
|
43
|
+
which means
|
44
|
+
|
45
|
+
my voice sought the wind to touch her hearing
|
46
|
+
|
47
|
+
(there's a nuance here: where in English, you say a person "plays" a musical instrument, in order to bring forth sound, in Spanish, you say a person "touches" a musical instrument.)
|
48
|
+
|
49
|
+
I chose the name because it annoys me how many APIs use `find` where what they really mean is `seek` or `look for`, and this made me think of how useful it is that Spanish has a commonly-used word which means `to look for something`. In English, we have `look for`, which is not really a word but an idiom, and incorporating prepositions into your code is difficult outside of Smalltalk; meanwhile, `seek` is great, but nobody in the United States seems to use it at all, unless they're hippies seeking for truth or sword-bearing elves seeking the Great Chalice Of Whatever The Fuck.
|
50
|
+
|
51
|
+
authors
|
52
|
+
-------
|
53
|
+
|
54
|
+
+ Giles Bowkett
|
55
|
+
+ Xavier Shay
|
56
|
+
|
57
|
+
license
|
58
|
+
-------
|
59
|
+
|
60
|
+
MIT License (which document included by reference)
|
61
|
+
|
62
|
+
hook a brother up
|
63
|
+
-----------------
|
64
|
+
|
65
|
+
Patches requested:
|
66
|
+
|
67
|
+
+ `setweight()` support (**crucial**)
|
68
|
+
+ Rails 3.1 generators, both to generate migrations and relevant model finders
|
69
|
+
+ support for `def change` vs `def up` and `def down`
|
70
|
+
+ better specs
|
71
|
+
+ quite frankly, a better understanding of PostgreSQL would be useful
|
72
|
+
|
73
|
+
here be dragons
|
74
|
+
---------------
|
75
|
+
|
76
|
+
This gem is still very early days status. May explode unexpectedly. Do not taunt Happy Fun Ball.
|
77
|
+
|
data/spec/fuzzy_spec.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe BuscandoElViento do
|
4
|
+
before(:each) do
|
5
|
+
@search_migration = SearchMigration.new
|
6
|
+
end
|
7
|
+
|
8
|
+
# fuzzy search methods, in practice, only affect the definition of the DB trigger;
|
9
|
+
# however, I think requiring the downstream programmer to remember that kind of
|
10
|
+
# implementation detail somewhat defeats the purpose of a convenient API in the
|
11
|
+
# first place. BUT, since nobody's perfect, the search wrapper spec also contains a
|
12
|
+
# *tiny* bit of fuzzy-related whatnot.
|
13
|
+
|
14
|
+
it "enables fuzzy search" do
|
15
|
+
fuzzy_trigger = <<TRIGGER
|
16
|
+
CREATE TRIGGER posts_title_search_vector_update
|
17
|
+
BEFORE INSERT OR UPDATE
|
18
|
+
ON posts
|
19
|
+
FOR EACH ROW EXECUTE PROCEDURE
|
20
|
+
tsvector_update_trigger(title_search_vector,
|
21
|
+
'pg_catalog.english',
|
22
|
+
title);
|
23
|
+
TRIGGER
|
24
|
+
@search_migration.should_receive(:execute).with(fuzzy_trigger)
|
25
|
+
@search_migration.add_trigger(:posts, :title, :fuzzy => true)
|
26
|
+
end
|
27
|
+
it "disables fuzzy search" do
|
28
|
+
exact_trigger = <<TRIGGER
|
29
|
+
CREATE TRIGGER posts_title_search_vector_update
|
30
|
+
BEFORE INSERT OR UPDATE
|
31
|
+
ON posts
|
32
|
+
FOR EACH ROW EXECUTE PROCEDURE
|
33
|
+
tsvector_update_trigger(title_search_vector,
|
34
|
+
'pg_catalog.simple',
|
35
|
+
title);
|
36
|
+
TRIGGER
|
37
|
+
@search_migration.should_receive(:execute).with(exact_trigger)
|
38
|
+
@search_migration.add_trigger(:posts, :title, :fuzzy => false)
|
39
|
+
end
|
40
|
+
it "defaults to exact search" do
|
41
|
+
exact_trigger = <<TRIGGER
|
42
|
+
CREATE TRIGGER posts_title_search_vector_update
|
43
|
+
BEFORE INSERT OR UPDATE
|
44
|
+
ON posts
|
45
|
+
FOR EACH ROW EXECUTE PROCEDURE
|
46
|
+
tsvector_update_trigger(title_search_vector,
|
47
|
+
'pg_catalog.simple',
|
48
|
+
title);
|
49
|
+
TRIGGER
|
50
|
+
@search_migration.should_receive(:execute).with(exact_trigger)
|
51
|
+
@search_migration.add_trigger(:posts, :title)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe BuscandoElViento do
|
4
|
+
before(:each) do
|
5
|
+
@search_migration = SearchMigration.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "names indexes" do
|
9
|
+
index_name = "index_users_on_username_search_vector"
|
10
|
+
@search_migration.index_name(:users, :username).should eq(index_name)
|
11
|
+
end
|
12
|
+
it "creates indexes" do
|
13
|
+
create_index = <<-CREATE_INDEX
|
14
|
+
CREATE INDEX index_users_on_username_search_vector
|
15
|
+
ON users
|
16
|
+
USING gin(search_vector);
|
17
|
+
CREATE_INDEX
|
18
|
+
@search_migration.should_receive(:execute).with(create_index)
|
19
|
+
@search_migration.add_index(:users, :username)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "names composite indexes for searching multiple attributes" do
|
23
|
+
index_name = "index_posts_on_title_and_body_search_vector"
|
24
|
+
@search_migration.index_name(:posts, [:title, :body]).should eq(index_name)
|
25
|
+
|
26
|
+
index_name = "index_posts_on_title_and_body_and_topic_search_vector"
|
27
|
+
@search_migration.index_name(:posts, [:title, :body, :topic]).should eq(index_name)
|
28
|
+
end
|
29
|
+
it "creates composite indexes for searching multiple attributes" do
|
30
|
+
create_index = <<-CREATE_INDEX
|
31
|
+
CREATE INDEX index_posts_on_title_and_body_search_vector
|
32
|
+
ON posts
|
33
|
+
USING gin(search_vector);
|
34
|
+
CREATE_INDEX
|
35
|
+
@search_migration.should_receive(:execute).with(create_index)
|
36
|
+
@search_migration.add_index(:posts, [:title, :body])
|
37
|
+
end
|
38
|
+
it "removes composite indexes for searching multiple attributes" do
|
39
|
+
vector_name = "title_and_body_search_vector"
|
40
|
+
@search_migration.should_receive(:remove_index).with(:posts, vector_name)
|
41
|
+
@search_migration.remove_composite_index(:posts, [:title, :body])
|
42
|
+
end
|
43
|
+
|
44
|
+
# FIXME: spec cleanup...
|
45
|
+
# this last spec, and a few others like it, are maybe a little dumb. now that
|
46
|
+
# I think of it, I should probably just delete these. to create multiple
|
47
|
+
# distinct indices for searching distinct attributes, or to delete same, you
|
48
|
+
# just call add_index() or remove_index() as appropriate.
|
49
|
+
|
50
|
+
it "creates multiple indexes for searching distinct attributes" do
|
51
|
+
create_username_index = <<-CREATE_INDEX
|
52
|
+
CREATE INDEX index_users_on_username_search_vector
|
53
|
+
ON users
|
54
|
+
USING gin(search_vector);
|
55
|
+
CREATE_INDEX
|
56
|
+
@search_migration.should_receive(:execute).with(create_username_index)
|
57
|
+
@search_migration.add_index(:users, :username)
|
58
|
+
|
59
|
+
create_email_index = <<-CREATE_INDEX
|
60
|
+
CREATE INDEX index_users_on_email_search_vector
|
61
|
+
ON users
|
62
|
+
USING gin(search_vector);
|
63
|
+
CREATE_INDEX
|
64
|
+
@search_migration.should_receive(:execute).with(create_email_index)
|
65
|
+
@search_migration.add_index(:users, :email)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe BuscandoElViento do
|
4
|
+
before(:each) do
|
5
|
+
@search_migration = SearchMigration.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "names triggers" do
|
9
|
+
@search_migration.trigger_name(:users, :username).should eq("users_username_search_vector_update")
|
10
|
+
end
|
11
|
+
it "creates triggers" do
|
12
|
+
@add_trigger = <<TRIGGER
|
13
|
+
CREATE TRIGGER users_username_search_vector_update
|
14
|
+
BEFORE INSERT OR UPDATE
|
15
|
+
ON users
|
16
|
+
FOR EACH ROW EXECUTE PROCEDURE
|
17
|
+
tsvector_update_trigger(username_search_vector,
|
18
|
+
'pg_catalog.simple',
|
19
|
+
username);
|
20
|
+
TRIGGER
|
21
|
+
@search_migration.should_receive(:execute).with(@add_trigger)
|
22
|
+
@search_migration.add_trigger(:users, :username)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "removes triggers" do
|
26
|
+
@drop_trigger = "DROP TRIGGER IF EXISTS users_username_search_vector_update on users;"
|
27
|
+
@search_migration.should_receive(:execute).with(@drop_trigger)
|
28
|
+
@search_migration.remove_trigger(:users, :username)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "creates triggers for multiple distinct attributes, separately" do
|
32
|
+
@add_trigger = <<TRIGGER
|
33
|
+
CREATE TRIGGER users_username_search_vector_update
|
34
|
+
BEFORE INSERT OR UPDATE
|
35
|
+
ON users
|
36
|
+
FOR EACH ROW EXECUTE PROCEDURE
|
37
|
+
tsvector_update_trigger(username_search_vector,
|
38
|
+
'pg_catalog.simple',
|
39
|
+
username);
|
40
|
+
TRIGGER
|
41
|
+
@search_migration.should_receive(:execute).with(@add_trigger)
|
42
|
+
@search_migration.add_trigger(:users, :username)
|
43
|
+
@add_trigger = <<TRIGGER
|
44
|
+
CREATE TRIGGER users_email_search_vector_update
|
45
|
+
BEFORE INSERT OR UPDATE
|
46
|
+
ON users
|
47
|
+
FOR EACH ROW EXECUTE PROCEDURE
|
48
|
+
tsvector_update_trigger(email_search_vector,
|
49
|
+
'pg_catalog.simple',
|
50
|
+
email);
|
51
|
+
TRIGGER
|
52
|
+
@search_migration.should_receive(:execute).with(@add_trigger)
|
53
|
+
@search_migration.add_trigger(:users, :email)
|
54
|
+
end
|
55
|
+
it "removes triggers for multiple distinct attributes, separately" do
|
56
|
+
@username_drop_trigger = "DROP TRIGGER IF EXISTS users_username_search_vector_update on users;"
|
57
|
+
@email_drop_trigger = "DROP TRIGGER IF EXISTS users_email_search_vector_update on users;"
|
58
|
+
|
59
|
+
@search_migration.should_receive(:execute).with(@username_drop_trigger)
|
60
|
+
@search_migration.remove_trigger(:users, :username)
|
61
|
+
|
62
|
+
@search_migration.should_receive(:execute).with(@email_drop_trigger)
|
63
|
+
@search_migration.remove_trigger(:users, :email)
|
64
|
+
end
|
65
|
+
|
66
|
+
# multiple combined attributes, as one
|
67
|
+
it "names triggers with multiple combined attributes" do
|
68
|
+
attributes = [:title, :body]
|
69
|
+
trigger_name = "posts_title_and_body_search_vector_update"
|
70
|
+
@search_migration.trigger_name(:posts, attributes).should eq(trigger_name)
|
71
|
+
end
|
72
|
+
it "creates triggers for multiple combined attributes, as one" do
|
73
|
+
# FIXME: join these multi-line heredocs to eliminate indentation
|
74
|
+
# before executing, simply because getting the indentation
|
75
|
+
# right in the specs is an irritating waste of time
|
76
|
+
@add_trigger = <<TRIGGER
|
77
|
+
CREATE TRIGGER posts_title_and_body_search_vector_update
|
78
|
+
BEFORE INSERT OR UPDATE
|
79
|
+
ON posts
|
80
|
+
FOR EACH ROW EXECUTE PROCEDURE
|
81
|
+
tsvector_update_trigger(title_and_body_search_vector,
|
82
|
+
'pg_catalog.simple',
|
83
|
+
title, body);
|
84
|
+
TRIGGER
|
85
|
+
@search_migration.should_receive(:execute).with(@add_trigger)
|
86
|
+
@search_migration.add_trigger(:posts, [:title, :body])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe BuscandoElViento do
|
4
|
+
before(:each) do
|
5
|
+
@search_migration = SearchMigration.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "names vectors" do
|
9
|
+
@search_migration.vector_name(:username).should eq(:username_search_vector)
|
10
|
+
end
|
11
|
+
it "creates vector names for multiple combined attributes, as one" do
|
12
|
+
attributes = [:title, :description]
|
13
|
+
@search_migration.vector_name(attributes).should eq(:title_and_description_search_vector)
|
14
|
+
end
|
15
|
+
it "auto-adds search vectors" do
|
16
|
+
@search_migration.should_receive(:add_column).with(:users,
|
17
|
+
:username_search_vector,
|
18
|
+
"tsvector")
|
19
|
+
@search_migration.add_search_vector :users, :username
|
20
|
+
end
|
21
|
+
it "removes search vectors" do
|
22
|
+
@search_migration.should_receive(:remove_column).with(:users,
|
23
|
+
:username_search_vector)
|
24
|
+
@search_migration.remove_search_vector :users, :username
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe BuscandoElViento do
|
4
|
+
before(:each) do
|
5
|
+
@search_migration = SearchMigration.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "adds search, defaulting to exact search" do
|
9
|
+
@search_migration.should_receive(:add_search_vector).with(:users, :username)
|
10
|
+
@search_migration.should_receive(:add_trigger).with(:users, :username, :fuzzy => false)
|
11
|
+
@search_migration.should_receive(:add_index).with(:users, :username)
|
12
|
+
|
13
|
+
@search_migration.add_search :users, :username
|
14
|
+
end
|
15
|
+
it "supports fuzzy search (stemming)" do
|
16
|
+
@search_migration.should_receive(:add_search_vector).with(:users, :username)
|
17
|
+
@search_migration.should_receive(:add_trigger).with(:users, :username, :fuzzy => true)
|
18
|
+
@search_migration.should_receive(:add_index).with(:users, :username)
|
19
|
+
|
20
|
+
@search_migration.add_search :users, :username, :fuzzy => true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "removes search" do
|
24
|
+
@search_migration.should_receive(:remove_search_vector).with(:users, :username)
|
25
|
+
@search_migration.should_receive(:remove_trigger).with(:users, :username)
|
26
|
+
@search_migration.should_receive(:remove_index).with(:users, :username)
|
27
|
+
|
28
|
+
@search_migration.remove_search :users, :username
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: buscando_el_viento
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- giles bowkett
|
14
|
+
- xavier shay
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-07-14 00:00:00 Z
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Rails migration class methods for PostgreSQL search
|
23
|
+
email:
|
24
|
+
- gilesb@gmail.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- .rvmrc
|
33
|
+
- Gemfile
|
34
|
+
- Gemfile.lock
|
35
|
+
- Rakefile
|
36
|
+
- buscando_el_viento.gemspec
|
37
|
+
- lib/buscando_el_viento.rb
|
38
|
+
- lib/buscando_el_viento/indexes.rb
|
39
|
+
- lib/buscando_el_viento/search.rb
|
40
|
+
- lib/buscando_el_viento/triggers.rb
|
41
|
+
- lib/buscando_el_viento/vectors.rb
|
42
|
+
- lib/buscando_el_viento/version.rb
|
43
|
+
- readme.md
|
44
|
+
- spec/buscando_el_viento_spec.rb
|
45
|
+
- spec/fuzzy_spec.rb
|
46
|
+
- spec/indexes_spec.rb
|
47
|
+
- spec/spec_helper.rb
|
48
|
+
- spec/triggers_spec.rb
|
49
|
+
- spec/vectors_spec.rb
|
50
|
+
- spec/wrapper_spec.rb
|
51
|
+
homepage: https://github.com/gilesbowkett/buscando_el_viento
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 3
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project: buscando_el_viento
|
80
|
+
rubygems_version: 1.8.3
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Rails migration class methods for PostgreSQL search
|
84
|
+
test_files:
|
85
|
+
- spec/buscando_el_viento_spec.rb
|
86
|
+
- spec/fuzzy_spec.rb
|
87
|
+
- spec/indexes_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/triggers_spec.rb
|
90
|
+
- spec/vectors_spec.rb
|
91
|
+
- spec/wrapper_spec.rb
|