scoped_search 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,210 @@
1
+ module ScopedSearch
2
+ module RailsHelper
3
+ # Creates a link that alternates between ascending and descending.
4
+ #
5
+ # Examples:
6
+ #
7
+ # sort @search, :by => :username
8
+ # sort @search, :by => :created_at, :as => "Created"
9
+ #
10
+ # This helper accepts the following options:
11
+ #
12
+ # * <tt>:by</tt> - the name of the named scope. This helper will prepend this value with "ascend_by_" and "descend_by_"
13
+ # * <tt>:as</tt> - the text used in the link, defaults to whatever is passed to :by
14
+ def sort(field, options = {}, html_options = {})
15
+
16
+ unless options[:as]
17
+ id = field.to_s.downcase == "id"
18
+ options[:as] = id ? field.to_s.upcase : field.to_s.humanize
19
+ end
20
+
21
+ ascend = "#{field} ASC"
22
+ descend = "#{field} DESC"
23
+
24
+ ascending = params[:order] == ascend
25
+ new_sort = ascending ? descend : ascend
26
+ selected = [ascend, descend].include?(params[:order])
27
+
28
+ if selected
29
+ css_classes = html_options[:class] ? html_options[:class].split(" ") : []
30
+ if ascending
31
+ options[:as] = "&#9650;&nbsp;#{options[:as]}"
32
+ css_classes << "ascending"
33
+ else
34
+ options[:as] = "&#9660;&nbsp;#{options[:as]}"
35
+ css_classes << "descending"
36
+ end
37
+ html_options[:class] = css_classes.join(" ")
38
+ end
39
+
40
+ url_options = params.merge(:order => new_sort)
41
+
42
+ options[:as] = raw(options[:as]) if defined?(RailsXss)
43
+
44
+ a_link(options[:as], html_escape(url_for(url_options)),html_options)
45
+ end
46
+
47
+ # Adds AJAX auto complete functionality to the text input field with the
48
+ # DOM ID specified by +field_id+.
49
+ #
50
+ # Required +options+ is:
51
+ # <tt>:url</tt>:: URL to call for auto completion results
52
+ # in url_for format.
53
+ #
54
+ # Additional +options+ are:
55
+ # <tt>:update</tt>:: Specifies the DOM ID of the element whose
56
+ # innerHTML should be updated with the auto complete
57
+ # entries returned by the AJAX request.
58
+ # Defaults to <tt>field_id</tt> + '_auto_complete'
59
+ # <tt>:with</tt>:: A JavaScript expression specifying the
60
+ # parameters for the XMLHttpRequest. This defaults
61
+ # to 'fieldname=value'.
62
+ # <tt>:frequency</tt>:: Determines the time to wait after the last keystroke
63
+ # for the AJAX request to be initiated.
64
+ # <tt>:indicator</tt>:: Specifies the DOM ID of an element which will be
65
+ # displayed while auto complete is running.
66
+ # <tt>:tokens</tt>:: A string or an array of strings containing
67
+ # separator tokens for tokenized incremental
68
+ # auto completion. Example: <tt>:tokens => ','</tt> would
69
+ # allow multiple auto completion entries, separated
70
+ # by commas.
71
+ # <tt>:min_chars</tt>:: The minimum number of characters that should be
72
+ # in the input field before an Ajax call is made
73
+ # to the server.
74
+ # <tt>:on_hide</tt>:: A Javascript expression that is called when the
75
+ # auto completion div is hidden. The expression
76
+ # should take two variables: element and update.
77
+ # Element is a DOM element for the field, update
78
+ # is a DOM element for the div from which the
79
+ # innerHTML is replaced.
80
+ # <tt>:on_show</tt>:: Like on_hide, only now the expression is called
81
+ # then the div is shown.
82
+ # <tt>:after_update_element</tt>:: A Javascript expression that is called when the
83
+ # user has selected one of the proposed values.
84
+ # The expression should take two variables: element and value.
85
+ # Element is a DOM element for the field, value
86
+ # is the value selected by the user.
87
+ # <tt>:select</tt>:: Pick the class of the element from which the value for
88
+ # insertion should be extracted. If this is not specified,
89
+ # the entire element is used.
90
+ # <tt>:method</tt>:: Specifies the HTTP verb to use when the auto completion
91
+ # request is made. Defaults to POST.
92
+ def auto_complete_field(field_id, options = {})
93
+ function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
94
+ function << "'#{field_id}', "
95
+ function << "'" + (options[:update] || "#{field_id}_auto_complete") + "', "
96
+ function << "'#{url_for(options[:url])}'"
97
+
98
+ js_options = {}
99
+ js_options[:tokens] = array_or_string_for_javascript(options[:tokens]) if options[:tokens]
100
+ js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
101
+ js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
102
+ js_options[:select] = "'#{options[:select]}'" if options[:select]
103
+ js_options[:paramName] = "'#{options[:param_name]}'" if options[:param_name]
104
+ js_options[:frequency] = "#{options[:frequency]}" if options[:frequency]
105
+ js_options[:method] = "'#{options[:method].to_s}'" if options[:method]
106
+
107
+ { :after_update_element => :afterUpdateElement,
108
+ :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
109
+ js_options[v] = options[k] if options[k]
110
+ end
111
+
112
+ function << (', ' + options_for_javascript(js_options) + ')')
113
+
114
+ javascript_tag(function)
115
+ end
116
+
117
+ def auto_complete_field_jquery(method, url, options = {})
118
+ function = <<-EOF
119
+ $.widget( "custom.catcomplete", $.ui.autocomplete, {
120
+ _renderMenu: function( ul, items ) {
121
+ var self = this,
122
+ currentCategory = "";
123
+ $.each( items, function( index, item ) {
124
+ if ( item.category != undefined && item.category != currentCategory ) {
125
+ ul.append( "<li class='ui-autocomplete-category'>" + item.category + "</li>" );
126
+ currentCategory = item.category;
127
+ }
128
+ if ( item.error != undefined ) {
129
+ ul.append( "<li class='ui-autocomplete-error'>" + item.error + "</li>" );
130
+ }
131
+ if( item.completed != undefined ) {
132
+ $( "<li></li>" ).data( "item.autocomplete", item )
133
+ .append( "<a>" + "<strong class='ui-autocomplete-completed'>" + item.completed + "</strong>" + item.part + "</a>" )
134
+ .appendTo( ul );
135
+ } else {
136
+ self._renderItem( ul, item );
137
+ }
138
+ });
139
+ }
140
+ });
141
+
142
+ $("##{method}")
143
+ .catcomplete({
144
+ source: function( request, response ) { $.getJSON( "#{url}", { #{method}: request.term }, response ); },
145
+ minLength: #{options[:min_length] || 0},
146
+ delay: #{options[:delay] || 200},
147
+ select: function(event, ui) { $( this ).catcomplete( "search" , ui.item.value); },
148
+ search: function(event, ui) { $(".auto_complete_clear").hide(); },
149
+ open: function(event, ui) { $(".auto_complete_clear").show(); }
150
+ });
151
+
152
+ $("##{method}").bind( "focus", function( event ) {
153
+ if( $( this )[0].value == "" ) {
154
+ $( this ).catcomplete( "search" );
155
+ }
156
+ });
157
+
158
+ EOF
159
+
160
+
161
+ javascript_tag(function)
162
+ end
163
+
164
+ def auto_complete_clear_value_button(field_id)
165
+ html_options = {:tabindex => '-1',:class=>"auto_complete_clear",:title =>'Clear Search', :onclick=>"document.getElementById('#{field_id}').value = '';"}
166
+ a_link("", "#", html_options)
167
+ end
168
+
169
+ def a_link(name, href, html_options)
170
+ tag_options = tag_options(html_options)
171
+ link = "<a href=\"#{href}\"#{tag_options}>#{name}</a>"
172
+ return link.respond_to?(:html_safe) ? link.html_safe : link
173
+ end
174
+
175
+ # Use this method in your view to generate a return for the AJAX auto complete requests.
176
+ #
177
+ # The auto_complete_result can of course also be called from a view belonging to the
178
+ # auto_complete action if you need to decorate it further.
179
+ def auto_complete_result(entries, phrase = nil)
180
+ return unless entries
181
+ items = entries.map { |entry| content_tag("li", phrase ? highlight(entry, phrase) : h(entry)) }
182
+ content_tag("ul", items)
183
+ end
184
+
185
+ # Wrapper for text_field with added AJAX auto completion functionality.
186
+ #
187
+ # In your controller, you'll need to define an action called
188
+ # auto_complete_method to respond the AJAX calls,
189
+ def auto_complete_field_tag(method, val,tag_options = {}, completion_options = {})
190
+ auto_completer_options = { :url => { :action => "auto_complete_#{method}" } }.update(completion_options)
191
+
192
+ text_field_tag(method, val,tag_options.merge(:class => "auto_complete_input")) +
193
+ auto_complete_clear_value_button(method) +
194
+ content_tag("div", "", :id => "#{method}_auto_complete", :class => "auto_complete") +
195
+ auto_complete_field(method, auto_completer_options)
196
+ end
197
+
198
+ # Wrapper for text_field with added JQuery auto completion functionality.
199
+ #
200
+ # In your controller, you'll need to define an action called
201
+ # auto_complete_method to respond the JQuery calls,
202
+ def auto_complete_field_tag_jquery(method, val,tag_options = {}, completion_options = {})
203
+ url = url_for(:action => "auto_complete_#{method}")
204
+ options = tag_options.merge(:class => "auto_complete_input")
205
+ text_field_tag(method, val, options) + auto_complete_clear_value_button(method) +
206
+ auto_complete_field_jquery(method, url, completion_options)
207
+ end
208
+
209
+ end
210
+ end
data/lib/scoped_search.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'active_record'
2
+
1
3
  # ScopedSearch is the base module for the scoped_search plugin. This file
2
4
  # defines some modules and exception classes, loads the necessary files, and
3
5
  # installs itself in ActiveRecord.
@@ -12,7 +14,7 @@ module ScopedSearch
12
14
 
13
15
  # The current scoped_search version. Do not change thisvalue by hand,
14
16
  # because it will be updated automatically by the gem release script.
15
- VERSION = "2.2.1"
17
+ VERSION = "2.3.0"
16
18
 
17
19
  # The ClassMethods module will be included into the ActiveRecord::Base class
18
20
  # to add the <tt>ActiveRecord::Base.scoped_search</tt> method and the
@@ -85,7 +87,13 @@ end
85
87
  require 'scoped_search/definition'
86
88
  require 'scoped_search/query_language'
87
89
  require 'scoped_search/query_builder'
90
+ require 'scoped_search/auto_complete_builder'
88
91
 
89
92
  # Import the search_on method in the ActiveReocrd::Base class
90
93
  ActiveRecord::Base.send(:extend, ScopedSearch::ClassMethods)
91
94
  ActiveRecord::Base.send(:extend, ScopedSearch::BackwardsCompatibility)
95
+
96
+ if defined?(ActionController)
97
+ require "scoped_search/rails_helper"
98
+ ActionController::Base.helper(ScopedSearch::RailsHelper)
99
+ end
@@ -3,8 +3,8 @@ 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.1"
7
- s.date = "2010-11-09"
6
+ s.version = "2.3.0"
7
+ s.date = "2011-05-16"
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
@@ -26,12 +26,14 @@ Gem::Specification.new do |s|
26
26
 
27
27
  s.add_runtime_dependency('activerecord', '>= 2.1.0')
28
28
  s.add_development_dependency('rspec', '~> 2.0')
29
+
30
+ s.add_development_dependency('sqlite3-ruby')
29
31
 
30
32
  s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
31
33
  s.extra_rdoc_files = ['README.rdoc']
32
34
 
33
35
  # Do not change the files and test_files fields by hand. This will be done
34
36
  # automatically by the gem release script.
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)
37
- end
37
+ s.files = %w(.gitignore .infinity_test Gemfile LICENSE README.rdoc Rakefile init.rb lib/scoped_search.rb lib/scoped_search/auto_complete_builder.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 lib/scoped_search/rails_helper.rb scoped_search.gemspec spec/database.yml spec/integration/api_spec.rb spec/integration/auto_complete_spec.rb spec/integration/key_value_querying_spec.rb spec/integration/ordinal_querying_spec.rb spec/integration/profile_querying_spec.rb spec/integration/relation_querying_spec.rb spec/integration/set_query_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/auto_complete_builder_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)
38
+ s.test_files = %w(spec/integration/api_spec.rb spec/integration/auto_complete_spec.rb spec/integration/key_value_querying_spec.rb spec/integration/ordinal_querying_spec.rb spec/integration/profile_querying_spec.rb spec/integration/relation_querying_spec.rb spec/integration/set_query_spec.rb spec/integration/string_querying_spec.rb spec/unit/ast_spec.rb spec/unit/auto_complete_builder_spec.rb spec/unit/definition_spec.rb spec/unit/parser_spec.rb spec/unit/query_builder_spec.rb spec/unit/tokenizer_spec.rb)
39
+ end
data/spec/database.yml CHANGED
@@ -7,13 +7,20 @@
7
7
  # to you.
8
8
 
9
9
 
10
- <% if Gem.available?('sqlite3-ruby') %>
11
- sqlite3:
12
- adapter: "sqlite3"
13
- database: ":memory:"
14
- <% end %>
10
+ # <% if Gem.available?('sqlite3-ruby') %>
11
+ # sqlite3:
12
+ # adapter: "sqlite3"
13
+ # database: ":memory:"
14
+ # <% end %>
15
15
 
16
- <% if Gem.available?('mysql') %>
16
+ <% if Gem.available?('mysql2') %>
17
+ mysql2:
18
+ adapter: "mysql2"
19
+ host: "localhost"
20
+ username: "root"
21
+ password:
22
+ database: "scoped_search_test"
23
+ <% elsif Gem.available?('mysql') %>
17
24
  mysql:
18
25
  adapter: "mysql"
19
26
  host: "localhost"
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
2
 
3
3
  describe ScopedSearch, "API" do
4
4
 
@@ -0,0 +1,140 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ # These specs will run on all databases that are defined in the spec/database.yml file.
4
+ # Comment out any databases that you do not have available for testing purposes if needed.
5
+ ScopedSearch::RSpec::Database.test_databases.each do |db|
6
+
7
+ describe ScopedSearch, "using a #{db} database" do
8
+
9
+ before(:all) do
10
+ ScopedSearch::RSpec::Database.establish_named_connection(db)
11
+
12
+ ## The related class
13
+ ActiveRecord::Migration.drop_table(:bars) rescue nil
14
+ ActiveRecord::Migration.create_table(:bars) { |t| t.string :related; t.integer :foo_id }
15
+ class ::Bar < ActiveRecord::Base; belongs_to :foo; end
16
+
17
+ ::Foo = ScopedSearch::RSpec::Database.create_model(:string => :string, :another => :string, :explicit => :string, :int => :integer, :date => :date, :unindexed => :integer) do |klass|
18
+ klass.has_many :bars
19
+
20
+ klass.scoped_search :on => [:string, :int, :date]
21
+ klass.scoped_search :on => :another, :default_operator => :eq, :alias => :alias
22
+ klass.scoped_search :on => :explicit, :only_explicit => true, :complete_value => true
23
+ klass.scoped_search :on => :related, :in => :bars, :rename => 'bars.related'.to_sym
24
+
25
+ end
26
+
27
+ @foo_1 = Foo.create!(:string => 'foo', :another => 'temp 1', :explicit => 'baz', :int => 9 , :date => 'February 8, 20011' , :unindexed => 10)
28
+ Foo.create!(:string => 'bar', :another => 'temp 2', :explicit => 'baz', :int => 9 , :date => 'February 10, 20011', :unindexed => 10)
29
+ Foo.create!(:string => 'baz', :another => nil, :explicit => nil , :int => nil, :date => nil , :unindexed => nil)
30
+
31
+ Bar.create!(:related => 'lala', :foo => @foo_1)
32
+ Bar.create!(:related => 'another lala', :foo => @foo_1)
33
+ end
34
+
35
+ after(:all) do
36
+ ScopedSearch::RSpec::Database.drop_model(Foo)
37
+ ScopedSearch::RSpec::Database.drop_model(Bar)
38
+ ScopedSearch::RSpec::Database.close_connection
39
+ end
40
+
41
+ context 'basic auto completer' do
42
+ it "should complete the field name" do
43
+ Foo.complete_for('str').should =~ ([' string '])
44
+ end
45
+
46
+ it "should not complete the logical operators at the beginning" do
47
+ Foo.complete_for('a').should_not contain(['and'])
48
+ end
49
+
50
+ it "should complete the string comparators" do
51
+ Foo.complete_for('string ').should =~ (["string != ", "string !~ ", "string = ", "string ~ "])
52
+ end
53
+
54
+ it "should complete the numerical comparators" do
55
+ Foo.complete_for('int ').should =~ (["int != ", "int < ", "int <= ", "int = ", "int > ", "int >= "])
56
+ end
57
+
58
+ it "should complete the temporal (date) comparators" do
59
+ Foo.complete_for('date ').should =~ (["date = ", "date < ", "date > "])
60
+ end
61
+
62
+ it "should raise error for unindexed field" do
63
+ lambda { Foo.complete_for('unindexed = 10 ')}.should raise_error(ScopedSearch::QueryNotSupported)
64
+ end
65
+
66
+ it "should raise error for unknown field" do
67
+ lambda {Foo.complete_for('unknown = 10 ')}.should raise_error(ScopedSearch::QueryNotSupported)
68
+ end
69
+
70
+ it "should complete logical comparators" do
71
+ Foo.complete_for('string ~ fo ').should contain("string ~ fo and", "string ~ fo or")
72
+ end
73
+
74
+ it "should complete prefix operators" do
75
+ Foo.complete_for(' ').should contain(" has", " not")
76
+ end
77
+
78
+ it "should not complete logical infix operators" do
79
+ Foo.complete_for(' ').should_not contain(" and", " or")
80
+ end
81
+
82
+ it "should not repeat logical operators" do
83
+ Foo.complete_for('string = foo and ').should_not contain("string = foo and and", "string = foo and or")
84
+ end
85
+ end
86
+
87
+ context 'using an aliased field' do
88
+ it "should complete an explicit match using its alias" do
89
+ Foo.complete_for('al').should contain(' alias ')
90
+ end
91
+ end
92
+
93
+ context 'value auto complete' do
94
+ it "should complete values list of values " do
95
+ Foo.complete_for('explicit = ').should have(1).item
96
+ end
97
+
98
+ it "should complete values should contain baz" do
99
+ Foo.complete_for('explicit = ').should contain('explicit = baz')
100
+ end
101
+ end
102
+
103
+ context 'auto complete relations' do
104
+ it "should complete related object name" do
105
+ Foo.complete_for('ba').should contain(' bars.related ')
106
+ end
107
+
108
+ it "should complete related object name with field name" do
109
+ Foo.complete_for('bars.').should contain(' bars.related ')
110
+ end
111
+ end
112
+
113
+ context 'using null prefix operators queries' do
114
+
115
+ it "should complete has operator" do
116
+ Foo.complete_for('has strin').should eql(['has string '])
117
+ end
118
+
119
+ it "should complete null? operator" do
120
+ Foo.complete_for('null? st').should eql(['null? string '])
121
+ end
122
+
123
+ it "should complete set? operator" do
124
+ Foo.complete_for('set? exp').should eql(['set? explicit '])
125
+ end
126
+
127
+ it "should complete null? operator for explicit field" do
128
+ Foo.complete_for('null? explici').should eql(['null? explicit '])
129
+ end
130
+
131
+ it "should not complete comparators after prefix statement" do
132
+ Foo.complete_for('has string ').should_not contain(['has string = '])
133
+ end
134
+
135
+ it "should not complete infix operator" do
136
+ Foo.complete_for('has string ').should_not contain('has string = ')
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,87 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ # These specs will run on all databases that are defined in the spec/database.yml file.
4
+ # Comment out any databases that you do not have available for testing purposes if needed.
5
+ ScopedSearch::RSpec::Database.test_databases.each do |db|
6
+
7
+ describe ScopedSearch, "using a #{db} database" do
8
+
9
+ before(:all) do
10
+ ScopedSearch::RSpec::Database.establish_named_connection(db)
11
+ end
12
+
13
+ after(:all) do
14
+ ScopedSearch::RSpec::Database.close_connection
15
+ end
16
+
17
+ context 'querying a key-value schema' do
18
+
19
+ before(:all) do
20
+ ActiveRecord::Migration.create_table(:keys) { |t| t.string :name }
21
+ class ::Key < ActiveRecord::Base; has_many :facts; end
22
+
23
+ ActiveRecord::Migration.create_table(:facts) { |t| t.string :value; t.integer :key_id; t.integer :bar_id }
24
+ class ::Fact < ActiveRecord::Base; belongs_to :key; belongs_to :bar; end
25
+
26
+ # The class that will run the queries
27
+ ::Bar = ScopedSearch::RSpec::Database.create_model(:name => :string) do |klass|
28
+ klass.has_many :facts
29
+ klass.has_many :keys, :through => :facts
30
+ klass.scoped_search :in => :facts, :on => :value, :rename => :facts, :in_key => :keys, :on_key => :name, :complete_value => true
31
+ end
32
+
33
+ @key1 = Key.create!(:name => 'color')
34
+ @key2 = Key.create!(:name => 'size')
35
+
36
+
37
+ @bar1 = Bar.create!(:name => 'bar')
38
+ @bar2 = Bar.create!(:name => 'barbary')
39
+
40
+ Fact.create!(:value => 'green', :key => @key1, :bar => @bar1)
41
+ Fact.create!(:value => 'gold' , :key => @key1, :bar => @bar2)
42
+ Fact.create!(:value => '5' , :key => @key2, :bar => @bar1)
43
+
44
+ end
45
+
46
+ after(:all) do
47
+ ScopedSearch::RSpec::Database.drop_model(Bar)
48
+ ScopedSearch::RSpec::Database.drop_model(Fact)
49
+ ScopedSearch::RSpec::Database.drop_model(Key)
50
+ Object.send :remove_const, :Fact
51
+ Object.send :remove_const, :Key
52
+ Object.send :remove_const, :Bar
53
+ end
54
+
55
+ it "should find all bars with a fact name color and fact value green" do
56
+ Bar.search_for('facts.color = green').should have(1).items
57
+ end
58
+
59
+ it "should find all bars with a fact name size and fact value 5" do
60
+ Bar.search_for('facts.size = 5').should have(1).items
61
+ end
62
+
63
+ it "should find all bars with a fact color green and fact size 5" do
64
+ Bar.search_for('facts.color = green and facts.size = 5').should have(1).items
65
+ end
66
+
67
+ it "should find all bars that has size value" do
68
+ Bar.search_for('has facts.size').should have(1).items
69
+ end
70
+
71
+ it "should find all bars that has color value" do
72
+ Bar.search_for('has facts.color').should have(2).items
73
+ end
74
+
75
+ it "should complete facts names" do
76
+ Bar.complete_for('facts.').should have(2).items
77
+ end
78
+
79
+ it "should complete values for fact name = color" do
80
+ Bar.complete_for('facts.color = ').should have(2).items
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+ end
87
+