scoped_search 2.2.0 → 2.2.1
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.
- data/README.rdoc +25 -22
- data/lib/scoped_search.rb +1 -1
- data/lib/scoped_search/query_language/parser.rb +1 -0
- data/scoped_search.gemspec +12 -7
- data/spec/integration/api_spec.rb +6 -6
- data/spec/integration/ordinal_querying_spec.rb +6 -6
- data/spec/integration/profile_querying_spec.rb +6 -6
- data/spec/integration/relation_querying_spec.rb +193 -190
- data/spec/integration/string_querying_spec.rb +6 -6
- data/spec/lib/database.rb +10 -6
- data/spec/lib/matchers.rb +17 -34
- data/spec/lib/mocks.rb +1 -1
- data/spec/spec_helper.rb +4 -5
- data/spec/unit/ast_spec.rb +1 -1
- data/spec/unit/definition_spec.rb +1 -1
- data/spec/unit/parser_spec.rb +1 -1
- data/spec/unit/query_builder_spec.rb +1 -1
- data/spec/unit/tokenizer_spec.rb +1 -1
- data/tasks/github-gem.rake +41 -51
- metadata +48 -40
data/README.rdoc
CHANGED
@@ -10,24 +10,6 @@ and build a query based on the search string they enter. If you want to build a
|
|
10
10
|
more complex search form with multiple fields, searchlogic (see
|
11
11
|
http://github.com/binarylogic/searchlogic) may be a good choice for you.
|
12
12
|
|
13
|
-
=== Usage
|
14
|
-
|
15
|
-
If you include a :profile parameter in scoped_search, the fields specified will only
|
16
|
-
be search when you pass :profile into the search_for command:
|
17
|
-
|
18
|
-
class User < ActiveRecord::Base
|
19
|
-
scoped_search :on => :public_information
|
20
|
-
scoped_search :on => :private_information, :profile => :members
|
21
|
-
end
|
22
|
-
|
23
|
-
This will only search the :public_information column:
|
24
|
-
|
25
|
-
User.search_for('blah blah blah')
|
26
|
-
|
27
|
-
And this will only search the :private_information column:
|
28
|
-
|
29
|
-
User.search_for('blah blah blah', :profile => :members)
|
30
|
-
|
31
13
|
== Installing
|
32
14
|
|
33
15
|
The recommended method to enable scoped search in your project is adding the
|
@@ -54,7 +36,7 @@ Scoped search requires you to define the fields you want to search in:
|
|
54
36
|
|
55
37
|
For more information about options and using fields from relations, see the
|
56
38
|
project wiki on search definitions:
|
57
|
-
http://
|
39
|
+
http://github.com/wvanbergen/scoped_search/wiki/search-definition
|
58
40
|
|
59
41
|
Now, the <b>search_for</b> scope is available for queries. You should pass a
|
60
42
|
query string to the scope. This can be empty or nil, in which case all no search
|
@@ -73,8 +55,28 @@ actually chain the call with other scopes, or with will_paginate. An example:
|
|
73
55
|
# using chained named_scopes and will_paginate in your controller
|
74
56
|
Project.public.search_for(params[:q]).paginate(:page => params[:page], :include => :tasks)
|
75
57
|
|
58
|
+
=== Search profiles
|
59
|
+
|
60
|
+
If you include a :profile option to the scoped_searchcall, the fields specified will only
|
61
|
+
be searched when you include this :profile into the search_for command as well:
|
62
|
+
|
63
|
+
class User < ActiveRecord::Base
|
64
|
+
scoped_search :on => :public_information
|
65
|
+
scoped_search :on => :private_information, :profile => :members
|
66
|
+
end
|
67
|
+
|
68
|
+
This will only search the :public_information column:
|
69
|
+
|
70
|
+
User.search_for('blah blah blah')
|
71
|
+
|
72
|
+
And this will only search the :private_information column:
|
73
|
+
|
74
|
+
User.search_for('blah blah blah', :profile => :members)
|
75
|
+
|
76
|
+
=== More information
|
77
|
+
|
76
78
|
More information about usage can be found in the project wiki:
|
77
|
-
http://
|
79
|
+
http://github.com/wvanbergen/scoped_search/wiki/usage
|
78
80
|
|
79
81
|
== Query language
|
80
82
|
|
@@ -108,12 +110,13 @@ nickname:
|
|
108
110
|
|
109
111
|
("Ruby" OR "Rails") -cobol, age >= 18, updated_at > 2009-01-01 && nickname !~ l33t
|
110
112
|
|
111
|
-
For more info, see the the project wiki: http://
|
113
|
+
For more info, see the the project wiki: http://github.com/wvanbergen/scoped_search/wiki/query-language
|
112
114
|
|
113
115
|
== Additional resources
|
114
116
|
|
115
117
|
* Source code: http://github.com/wvanbergen/scoped_search/tree
|
116
|
-
* Project wiki: http://
|
118
|
+
* Project wiki: http://github.com/wvanbergen/scoped_search/wiki
|
119
|
+
* Issue tracker: http://github.com/wvanbergen/scoped_search/issues
|
117
120
|
* RDoc documentation: http://rdoc.info/projects/wvanbergen/scoped_search
|
118
121
|
* wvanbergen's blog posts: http://techblog.floorplanner.com/tag/scoped_search
|
119
122
|
|
data/lib/scoped_search.rb
CHANGED
@@ -12,7 +12,7 @@ module ScopedSearch
|
|
12
12
|
|
13
13
|
# The current scoped_search version. Do not change thisvalue by hand,
|
14
14
|
# because it will be updated automatically by the gem release script.
|
15
|
-
VERSION = "2.2.
|
15
|
+
VERSION = "2.2.1"
|
16
16
|
|
17
17
|
# The ClassMethods module will be included into the ActiveRecord::Base class
|
18
18
|
# to add the <tt>ActiveRecord::Base.scoped_search</tt> method and the
|
@@ -18,6 +18,7 @@ module ScopedSearch::QueryLanguage::Parser
|
|
18
18
|
# Start the parsing process by parsing an expression sequence
|
19
19
|
def parse
|
20
20
|
@tokens = tokenize
|
21
|
+
@tokens.delete_at(@tokens.size - 1) if @tokens.last.is_a?(Symbol)
|
21
22
|
parse_expression_sequence(true).simplify
|
22
23
|
end
|
23
24
|
|
data/scoped_search.gemspec
CHANGED
@@ -3,30 +3,35 @@ Gem::Specification.new do |s|
|
|
3
3
|
|
4
4
|
# Do not change the version and date fields by hand. This will be done
|
5
5
|
# automatically by the gem release script.
|
6
|
-
s.version = "2.2.
|
7
|
-
s.date = "2010-
|
6
|
+
s.version = "2.2.1"
|
7
|
+
s.date = "2010-11-09"
|
8
8
|
|
9
9
|
s.summary = "Easily search you ActiveRecord models with a simple query language using a named scope."
|
10
10
|
s.description = <<-EOS
|
11
11
|
Scoped search makes it easy to search your ActiveRecord-based models.
|
12
|
+
|
12
13
|
It will create a named scope :search_for that can be called with a query string. It will build an SQL query using
|
13
14
|
the provided query string and a definition that specifies on what fields to search. Because the functionality is
|
14
15
|
built on named_scope, the result of the search_for call can be used like any other named_scope, so it can be
|
15
|
-
chained with another scope or combined with will_paginate.
|
16
|
+
chained with another scope or combined with will_paginate.
|
17
|
+
|
18
|
+
Because it uses standard SQL, it does not require any setup, indexers or daemons. This makes scoped_search
|
19
|
+
suitable to quickly add basic search functionality to your application with little hassle. On the other hand,
|
20
|
+
it may not be the best choice if it is going to be used on very large datasets or by a large user base.
|
16
21
|
EOS
|
17
22
|
|
18
23
|
s.authors = ['Willem van Bergen', 'Wes Hays']
|
19
24
|
s.email = ['willem@railsdoctors.com', 'weshays@gbdev.com']
|
20
|
-
s.homepage = 'http://
|
25
|
+
s.homepage = 'http://github.com/wvanbergen/scoped_search/wiki'
|
21
26
|
|
22
27
|
s.add_runtime_dependency('activerecord', '>= 2.1.0')
|
23
|
-
s.add_development_dependency('rspec', '
|
28
|
+
s.add_development_dependency('rspec', '~> 2.0')
|
24
29
|
|
25
30
|
s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
|
26
31
|
s.extra_rdoc_files = ['README.rdoc']
|
27
32
|
|
28
33
|
# Do not change the files and test_files fields by hand. This will be done
|
29
34
|
# automatically by the gem release script.
|
30
|
-
s.files = %w(
|
31
|
-
s.test_files = %w(spec/integration/
|
35
|
+
s.files = %w(.gitignore LICENSE README.rdoc Rakefile init.rb lib/scoped_search.rb lib/scoped_search/definition.rb lib/scoped_search/query_builder.rb lib/scoped_search/query_language.rb lib/scoped_search/query_language/ast.rb lib/scoped_search/query_language/parser.rb lib/scoped_search/query_language/tokenizer.rb scoped_search.gemspec spec/database.yml spec/integration/api_spec.rb spec/integration/ordinal_querying_spec.rb spec/integration/profile_querying_spec.rb spec/integration/relation_querying_spec.rb spec/integration/string_querying_spec.rb spec/lib/database.rb spec/lib/matchers.rb spec/lib/mocks.rb spec/spec_helper.rb spec/unit/ast_spec.rb spec/unit/definition_spec.rb spec/unit/parser_spec.rb spec/unit/query_builder_spec.rb spec/unit/tokenizer_spec.rb tasks/github-gem.rake)
|
36
|
+
s.test_files = %w(spec/integration/api_spec.rb spec/integration/ordinal_querying_spec.rb spec/integration/profile_querying_spec.rb spec/integration/relation_querying_spec.rb spec/integration/string_querying_spec.rb spec/unit/ast_spec.rb spec/unit/definition_spec.rb spec/unit/parser_spec.rb spec/unit/query_builder_spec.rb spec/unit/tokenizer_spec.rb)
|
32
37
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ScopedSearch, "API" do
|
4
4
|
|
@@ -14,11 +14,11 @@ describe ScopedSearch, "API" do
|
|
14
14
|
# be changed for new major releases.
|
15
15
|
|
16
16
|
before(:all) do
|
17
|
-
ScopedSearch::
|
17
|
+
ScopedSearch::RSpec::Database.establish_connection
|
18
18
|
end
|
19
19
|
|
20
20
|
after(:all) do
|
21
|
-
ScopedSearch::
|
21
|
+
ScopedSearch::RSpec::Database.close_connection
|
22
22
|
end
|
23
23
|
|
24
24
|
context 'for unprepared ActiveRecord model' do
|
@@ -31,13 +31,13 @@ describe ScopedSearch, "API" do
|
|
31
31
|
context 'for a prepared ActiveRecord model' do
|
32
32
|
|
33
33
|
before(:all) do
|
34
|
-
@class = ScopedSearch::
|
34
|
+
@class = ScopedSearch::RSpec::Database.create_model(:field => :string) do |klass|
|
35
35
|
klass.scoped_search :on => :field
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
after(:all) do
|
40
|
-
ScopedSearch::
|
40
|
+
ScopedSearch::RSpec::Database.drop_model(@class)
|
41
41
|
end
|
42
42
|
|
43
43
|
it "should respond to :search_for to perform searches" do
|
@@ -62,7 +62,7 @@ describe ScopedSearch, "API" do
|
|
62
62
|
context 'having backwards compatibility' do
|
63
63
|
|
64
64
|
before(:each) do
|
65
|
-
class Foo < ActiveRecord::Base
|
65
|
+
class ::Foo < ActiveRecord::Base
|
66
66
|
belongs_to :bar
|
67
67
|
end
|
68
68
|
end
|
@@ -1,23 +1,23 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
# These specs will run on all databases that are defined in the spec/database.yml file.
|
4
4
|
# Comment out any databases that you do not have available for testing purposes if needed.
|
5
|
-
ScopedSearch::
|
5
|
+
ScopedSearch::RSpec::Database.test_databases.each do |db|
|
6
6
|
|
7
7
|
describe ScopedSearch, "using a #{db} database" do
|
8
8
|
|
9
9
|
before(:all) do
|
10
|
-
ScopedSearch::
|
10
|
+
ScopedSearch::RSpec::Database.establish_named_connection(db)
|
11
11
|
|
12
|
-
@class = ScopedSearch::
|
12
|
+
@class = ScopedSearch::RSpec::Database.create_model(:int => :integer, :timestamp => :datetime, :date => :date, :unindexed => :integer) do |klass|
|
13
13
|
klass.scoped_search :on => [:int, :timestamp]
|
14
14
|
klass.scoped_search :on => :date, :only_explicit => true
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
after(:all) do
|
19
|
-
ScopedSearch::
|
20
|
-
ScopedSearch::
|
19
|
+
ScopedSearch::RSpec::Database.drop_model(@class)
|
20
|
+
ScopedSearch::RSpec::Database.close_connection
|
21
21
|
end
|
22
22
|
|
23
23
|
context 'quering numerical fields' do
|
@@ -1,15 +1,15 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
# These specs will run on all databases that are defined in the spec/database.yml file.
|
4
4
|
# Comment out any databases that you do not have available for testing purposes if needed.
|
5
|
-
ScopedSearch::
|
5
|
+
ScopedSearch::RSpec::Database.test_databases.each do |db|
|
6
6
|
|
7
7
|
describe ScopedSearch, "using a #{db} database" do
|
8
8
|
|
9
9
|
before(:all) do
|
10
|
-
ScopedSearch::
|
10
|
+
ScopedSearch::RSpec::Database.establish_named_connection(db)
|
11
11
|
|
12
|
-
@class = ScopedSearch::
|
12
|
+
@class = ScopedSearch::RSpec::Database.create_model(:public => :string, :private => :string, :useless => :string) do |klass|
|
13
13
|
klass.scoped_search :on => :public
|
14
14
|
klass.scoped_search :on => :private, :profile => :private_profile
|
15
15
|
klass.scoped_search :on => :useless, :profile => :another_profile
|
@@ -21,8 +21,8 @@ ScopedSearch::Spec::Database.test_databases.each do |db|
|
|
21
21
|
end
|
22
22
|
|
23
23
|
after(:all) do
|
24
|
-
ScopedSearch::
|
25
|
-
ScopedSearch::
|
24
|
+
ScopedSearch::RSpec::Database.drop_model(@class)
|
25
|
+
ScopedSearch::RSpec::Database.close_connection
|
26
26
|
end
|
27
27
|
|
28
28
|
context "searching without profile specified" do
|
@@ -1,262 +1,265 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
#
|
5
|
-
|
3
|
+
if ActiveRecord::VERSION::MAJOR == 2
|
4
|
+
# These specs will run on all databases that are defined in the spec/database.yml file.
|
5
|
+
# Comment out any databases that you do not have available for testing purposes if needed.
|
6
|
+
ScopedSearch::RSpec::Database.test_databases.each do |db|
|
6
7
|
|
7
|
-
|
8
|
+
describe ScopedSearch, "using a #{db} database" do
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
before(:all) do
|
11
|
+
ScopedSearch::RSpec::Database.establish_named_connection(db)
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
after(:all) do
|
15
|
+
ScopedSearch::RSpec::Database.close_connection
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
+
context 'querying a :belongs_to relation' do
|
18
19
|
|
19
|
-
|
20
|
+
before(:all) do
|
21
|
+
|
22
|
+
# The related class
|
23
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related }
|
24
|
+
class ::Bar < ActiveRecord::Base; has_many :foos; end
|
25
|
+
|
26
|
+
# The class on which to call search_for
|
27
|
+
::Foo = ScopedSearch::Spec::Database.create_model(:foo => :string, :bar_id => :integer) do |klass|
|
28
|
+
klass.belongs_to :bar
|
29
|
+
klass.scoped_search :in => :bar, :on => :related
|
30
|
+
end
|
20
31
|
|
21
|
-
|
22
|
-
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related }
|
23
|
-
class Bar < ActiveRecord::Base; has_many :foos; end
|
32
|
+
@bar_record = Bar.create!(:related => 'bar')
|
24
33
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
34
|
+
Foo.create!(:foo => 'foo', :bar => @bar_record)
|
35
|
+
Foo.create!(:foo => 'foo too', :bar => @bar_record)
|
36
|
+
Foo.create!(:foo => 'foo three', :bar => Bar.create!(:related => 'another bar'))
|
37
|
+
Foo.create!(:foo => 'foo four')
|
29
38
|
end
|
30
39
|
|
31
|
-
|
40
|
+
after(:all) do
|
41
|
+
ScopedSearch::RSpec::Database.drop_model(Bar)
|
42
|
+
ScopedSearch::RSpec::Database.drop_model(Foo)
|
43
|
+
Object.send :remove_const, :Foo
|
44
|
+
Object.send :remove_const, :Bar
|
45
|
+
end
|
32
46
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
Foo.create!(:foo => 'foo four')
|
37
|
-
end
|
47
|
+
it "should find all records with a related bar record containing bar" do
|
48
|
+
Foo.search_for('bar').should have(3).items
|
49
|
+
end
|
38
50
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
Object.send :remove_const, :Foo
|
43
|
-
Object.send :remove_const, :Bar
|
44
|
-
end
|
51
|
+
it "should find all records with a related bar record having an exact value of bar with an explicit field" do
|
52
|
+
Foo.search_for('related = bar').should have(2).items
|
53
|
+
end
|
45
54
|
|
46
|
-
|
47
|
-
|
55
|
+
it "should find records for which the bar relation is not set using null?" do
|
56
|
+
Foo.search_for('null? related').should have(1).items
|
57
|
+
end
|
48
58
|
end
|
49
59
|
|
50
|
-
|
51
|
-
Foo.search_for('= bar').should have(2).items
|
52
|
-
end
|
60
|
+
context 'querying a :has_many relation' do
|
53
61
|
|
54
|
-
|
55
|
-
Foo.search_for('related = bar').should have(2).items
|
56
|
-
end
|
62
|
+
before(:all) do
|
57
63
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
64
|
+
# The related class
|
65
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related; t.integer :foo_id }
|
66
|
+
class ::Bar < ActiveRecord::Base; belongs_to :foo; end
|
62
67
|
|
63
|
-
|
68
|
+
# The class on which to call search_for
|
69
|
+
::Foo = ScopedSearch::Spec::Database.create_model(:foo => :string, :bar_id => :integer) do |klass|
|
70
|
+
klass.has_many :bars
|
71
|
+
klass.scoped_search :in => :bars, :on => :related
|
72
|
+
end
|
64
73
|
|
65
|
-
|
74
|
+
@foo_1 = Foo.create!(:foo => 'foo')
|
75
|
+
@foo_2 = Foo.create!(:foo => 'foo too')
|
76
|
+
@foo_3 = Foo.create!(:foo => 'foo three')
|
66
77
|
|
67
|
-
|
68
|
-
|
69
|
-
|
78
|
+
Bar.create!(:related => 'bar', :foo => @foo_1)
|
79
|
+
Bar.create!(:related => 'another bar', :foo => @foo_1)
|
80
|
+
Bar.create!(:related => 'other bar', :foo => @foo_2)
|
81
|
+
end
|
70
82
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
83
|
+
after(:all) do
|
84
|
+
ScopedSearch::Spec::Database.drop_model(Bar)
|
85
|
+
ScopedSearch::Spec::Database.drop_model(Foo)
|
86
|
+
Object.send :remove_const, :Foo
|
87
|
+
Object.send :remove_const, :Bar
|
75
88
|
end
|
76
89
|
|
77
|
-
|
78
|
-
|
79
|
-
|
90
|
+
it "should find all records with at least one bar record containing 'bar'" do
|
91
|
+
Foo.search_for('bar').should have(2).items
|
92
|
+
end
|
80
93
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
94
|
+
it "should find the only record with at least one bar record having the exact value 'bar'" do
|
95
|
+
Foo.search_for('= bar').should have(1).item
|
96
|
+
end
|
85
97
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
Object.send :remove_const, :Foo
|
90
|
-
Object.send :remove_const, :Bar
|
91
|
-
end
|
98
|
+
it "should find all records for which at least one related bar record exists" do
|
99
|
+
Foo.search_for('set? related').should have(2).items
|
100
|
+
end
|
92
101
|
|
93
|
-
|
94
|
-
|
95
|
-
|
102
|
+
it "should find all records for which none related bar records exist" do
|
103
|
+
Foo.search_for('null? related').should have(1).items
|
104
|
+
end
|
96
105
|
|
97
|
-
it "should find the only record with at least one bar record having the exact value 'bar'" do
|
98
|
-
Foo.search_for('= bar').should have(1).item
|
99
106
|
end
|
100
107
|
|
101
|
-
|
102
|
-
Foo.search_for('set? related').should have(2).items
|
103
|
-
end
|
108
|
+
context 'querying a :has_one relation' do
|
104
109
|
|
105
|
-
|
106
|
-
Foo.search_for('null? related').should have(1).items
|
107
|
-
end
|
110
|
+
before(:all) do
|
108
111
|
|
109
|
-
|
112
|
+
# The related class
|
113
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related; t.integer :foo_id }
|
114
|
+
class ::Bar < ActiveRecord::Base; belongs_to :foo; end
|
110
115
|
|
111
|
-
|
116
|
+
# The class on which to call search_for
|
117
|
+
::Foo = ScopedSearch::Spec::Database.create_model(:foo => :string) do |klass|
|
118
|
+
klass.has_one :bar
|
119
|
+
klass.scoped_search :in => :bar, :on => :related
|
120
|
+
end
|
112
121
|
|
113
|
-
|
122
|
+
@foo_1 = ::Foo.create!(:foo => 'foo')
|
123
|
+
@foo_2 = ::Foo.create!(:foo => 'foo too')
|
124
|
+
@foo_3 = ::Foo.create!(:foo => 'foo three')
|
114
125
|
|
115
|
-
|
116
|
-
|
117
|
-
|
126
|
+
::Bar.create!(:related => 'bar', :foo => @foo_1)
|
127
|
+
::Bar.create!(:related => 'other bar', :foo => @foo_2)
|
128
|
+
end
|
118
129
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
130
|
+
after(:all) do
|
131
|
+
ScopedSearch::Spec::Database.drop_model(::Bar)
|
132
|
+
ScopedSearch::Spec::Database.drop_model(::Foo)
|
133
|
+
Object.send :remove_const, :Foo
|
134
|
+
Object.send :remove_const, :Bar
|
123
135
|
end
|
124
136
|
|
125
|
-
|
126
|
-
|
127
|
-
|
137
|
+
it "should find all records with a bar record containing 'bar" do
|
138
|
+
::Foo.search_for('bar').should have(2).items
|
139
|
+
end
|
128
140
|
|
129
|
-
|
130
|
-
|
131
|
-
|
141
|
+
it "should find the only record with the bar record has the exact value 'bar" do
|
142
|
+
::Foo.search_for('= bar').should have(1).item
|
143
|
+
end
|
132
144
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
Object.send :remove_const, :Foo
|
137
|
-
Object.send :remove_const, :Bar
|
138
|
-
end
|
145
|
+
it "should find all records for which the related bar record exists" do
|
146
|
+
::Foo.search_for('set? related').should have(2).items
|
147
|
+
end
|
139
148
|
|
140
|
-
|
141
|
-
|
149
|
+
it "should find all records for which the related bar record does not exist" do
|
150
|
+
::Foo.search_for('null? related').should have(1).items
|
151
|
+
end
|
142
152
|
end
|
143
153
|
|
144
|
-
|
145
|
-
Foo.search_for('= bar').should have(1).item
|
146
|
-
end
|
154
|
+
context 'querying a :has_and_belongs_to_many relation' do
|
147
155
|
|
148
|
-
|
149
|
-
Foo.search_for('set? related').should have(2).items
|
150
|
-
end
|
156
|
+
before(:all) do
|
151
157
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
158
|
+
# Create some tables
|
159
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related }
|
160
|
+
ActiveRecord::Migration.create_table(:bars_foos, :id => false) { |t| t.integer :foo_id; t.integer :bar_id }
|
161
|
+
ActiveRecord::Migration.create_table(:foos) { |t| t.string :foo }
|
156
162
|
|
157
|
-
|
163
|
+
# The related class
|
164
|
+
class ::Bar < ActiveRecord::Base; end
|
158
165
|
|
159
|
-
|
166
|
+
# The class on which to call search_for
|
167
|
+
class ::Foo < ActiveRecord::Base
|
168
|
+
has_and_belongs_to_many :bars
|
169
|
+
scoped_search :in => :bars, :on => :related
|
170
|
+
end
|
160
171
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
ActiveRecord::Migration.create_table(:foos) { |t| t.string :foo }
|
172
|
+
@foo_1 = ::Foo.create!(:foo => 'foo')
|
173
|
+
@foo_2 = ::Foo.create!(:foo => 'foo too')
|
174
|
+
@foo_3 = ::Foo.create!(:foo => 'foo three')
|
165
175
|
|
166
|
-
|
167
|
-
|
176
|
+
@bar_1 = ::Bar.create!(:related => 'bar')
|
177
|
+
@bar_2 = ::Bar.create!(:related => 'other bar')
|
178
|
+
@bar_3 = ::Bar.create!(:related => 'last bar')
|
168
179
|
|
169
|
-
|
170
|
-
|
171
|
-
has_and_belongs_to_many :bars
|
172
|
-
scoped_search :in => :bars, :on => :related
|
180
|
+
@foo_1.bars << @bar_1 << @bar_2
|
181
|
+
@foo_2.bars << @bar_2 << @bar_3
|
173
182
|
end
|
174
183
|
|
175
|
-
|
176
|
-
|
177
|
-
|
184
|
+
after(:all) do
|
185
|
+
ActiveRecord::Migration.drop_table(:bars_foos)
|
186
|
+
ActiveRecord::Migration.drop_table(:bars)
|
187
|
+
ActiveRecord::Migration.drop_table(:foos)
|
188
|
+
Object.send :remove_const, :Foo
|
189
|
+
Object.send :remove_const, :Bar
|
190
|
+
end
|
178
191
|
|
179
|
-
|
180
|
-
|
181
|
-
|
192
|
+
it "should find all records with at least one associated bar record containing 'bar'" do
|
193
|
+
::Foo.search_for('bar').should have(2).items
|
194
|
+
end
|
182
195
|
|
183
|
-
|
184
|
-
|
185
|
-
|
196
|
+
it "should find record which is related to @bar_1" do
|
197
|
+
::Foo.search_for('= bar').should have(1).items
|
198
|
+
end
|
186
199
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
ActiveRecord::Migration.drop_table(:foos)
|
191
|
-
Object.send :remove_const, :Foo
|
192
|
-
Object.send :remove_const, :Bar
|
193
|
-
end
|
200
|
+
it "should find the only record related to @bar_3" do
|
201
|
+
::Foo.search_for('last').should have(1).items
|
202
|
+
end
|
194
203
|
|
195
|
-
|
196
|
-
|
204
|
+
it "should find all records that are related to @bar_2" do
|
205
|
+
::Foo.search_for('other').should have(2).items
|
206
|
+
end
|
197
207
|
end
|
198
208
|
|
199
|
-
|
200
|
-
Foo.search_for('= bar').should have(1).items
|
201
|
-
end
|
209
|
+
context 'querying a :has_many => :through relation' do
|
202
210
|
|
203
|
-
|
204
|
-
Foo.search_for('last').should have(1).items
|
205
|
-
end
|
211
|
+
before(:all) do
|
206
212
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
213
|
+
# Create some tables
|
214
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.integer :foo_id; t.integer :baz_id }
|
215
|
+
ActiveRecord::Migration.create_table(:bazs) { |t| t.string :related }
|
216
|
+
ActiveRecord::Migration.create_table(:foos) { |t| t.string :foo }
|
211
217
|
|
212
|
-
|
218
|
+
# The related classes
|
219
|
+
class ::Bar < ActiveRecord::Base; belongs_to :baz; belongs_to :foo; end
|
220
|
+
class ::Baz < ActiveRecord::Base; has_many :bars; end
|
213
221
|
|
214
|
-
|
222
|
+
# The class on which to call search_for
|
223
|
+
class ::Foo < ActiveRecord::Base
|
224
|
+
has_many :bars
|
225
|
+
has_many :bazs, :through => :bars
|
215
226
|
|
216
|
-
|
217
|
-
|
218
|
-
ActiveRecord::Migration.create_table(:bazs) { |t| t.string :related }
|
219
|
-
ActiveRecord::Migration.create_table(:foos) { |t| t.string :foo }
|
227
|
+
scoped_search :in => :bazs, :on => :related
|
228
|
+
end
|
220
229
|
|
221
|
-
|
222
|
-
|
223
|
-
|
230
|
+
@foo_1 = ::Foo.create!(:foo => 'foo')
|
231
|
+
@foo_2 = ::Foo.create!(:foo => 'foo too')
|
232
|
+
@foo_3 = ::Foo.create!(:foo => 'foo three')
|
224
233
|
|
225
|
-
|
226
|
-
|
227
|
-
has_many :bars
|
228
|
-
has_many :bazs, :through => :bars
|
234
|
+
@baz_1 = ::Baz.create(:related => 'baz')
|
235
|
+
@baz_2 = ::Baz.create(:related => 'baz too!')
|
229
236
|
|
230
|
-
|
237
|
+
@bar_1 = ::Bar.create!(:foo => @foo_1, :baz => @baz_1)
|
238
|
+
@bar_2 = ::Bar.create!(:foo => @foo_1)
|
239
|
+
@bar_3 = ::Bar.create!(:foo => @foo_2, :baz => @baz_1)
|
240
|
+
@bar_3 = ::Bar.create!(:foo => @foo_2, :baz => @baz_2)
|
241
|
+
@bar_3 = ::Bar.create!(:foo => @foo_2, :baz => @baz_2)
|
242
|
+
@bar_4 = ::Bar.create!(:foo => @foo_3)
|
231
243
|
end
|
232
244
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
@bar_2 = Bar.create!(:foo => @foo_1)
|
242
|
-
@bar_3 = Bar.create!(:foo => @foo_2, :baz => @baz_1)
|
243
|
-
@bar_3 = Bar.create!(:foo => @foo_2, :baz => @baz_2)
|
244
|
-
@bar_3 = Bar.create!(:foo => @foo_2, :baz => @baz_2)
|
245
|
-
@bar_4 = Bar.create!(:foo => @foo_3)
|
246
|
-
end
|
247
|
-
|
248
|
-
after(:all) do
|
249
|
-
ActiveRecord::Migration.drop_table(:bazs)
|
250
|
-
ActiveRecord::Migration.drop_table(:bars)
|
251
|
-
ActiveRecord::Migration.drop_table(:foos)
|
252
|
-
Object.send :remove_const, :Foo
|
253
|
-
Object.send :remove_const, :Bar
|
254
|
-
Object.send :remove_const, :Baz
|
255
|
-
end
|
245
|
+
after(:all) do
|
246
|
+
ActiveRecord::Migration.drop_table(:bazs)
|
247
|
+
ActiveRecord::Migration.drop_table(:bars)
|
248
|
+
ActiveRecord::Migration.drop_table(:foos)
|
249
|
+
Object.send :remove_const, :Foo
|
250
|
+
Object.send :remove_const, :Bar
|
251
|
+
Object.send :remove_const, :Baz
|
252
|
+
end
|
256
253
|
|
257
|
-
|
258
|
-
|
254
|
+
it "should find the two records that are related to a baz record" do
|
255
|
+
::Foo.search_for('baz').should have(2).items
|
256
|
+
end
|
259
257
|
end
|
260
258
|
end
|
261
259
|
end
|
260
|
+
else
|
261
|
+
puts
|
262
|
+
puts "WARNING:"
|
263
|
+
puts "Currently, relationships querying is only 100% supported on Rails 2.x. Use at your own risk when using Rails 3."
|
264
|
+
puts
|
262
265
|
end
|