dusen 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +3 -0
  3. data/README.md +176 -47
  4. data/documents/fulltext_vs_like_benchmark/all_records_and_scope/fulltext.csv +22 -0
  5. data/documents/fulltext_vs_like_benchmark/all_records_and_scope/fulltext_vs_like.xls +0 -0
  6. data/documents/fulltext_vs_like_benchmark/all_records_and_scope/like.csv +22 -0
  7. data/documents/fulltext_vs_like_benchmark/benchmark.rb +70 -0
  8. data/documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext.csv +22 -0
  9. data/documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext_vs_like.png +0 -0
  10. data/documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext_vs_like.xls +0 -0
  11. data/documents/fulltext_vs_like_benchmark/exact_number_of_records/like.csv +21 -0
  12. data/dusen.gemspec +1 -1
  13. data/lib/dusen/active_record/base_ext.rb +104 -0
  14. data/lib/dusen/active_record/search_text.rb +50 -0
  15. data/lib/dusen/description.rb +5 -4
  16. data/lib/dusen/query.rb +24 -4
  17. data/lib/dusen/railtie.rb +9 -0
  18. data/lib/dusen/syntax.rb +5 -0
  19. data/lib/dusen/tasks.rb +31 -0
  20. data/lib/dusen/token.rb +4 -0
  21. data/lib/dusen/util.rb +86 -1
  22. data/lib/dusen/version.rb +1 -1
  23. data/lib/dusen.rb +7 -1
  24. data/spec/rails-2.3/Gemfile +3 -1
  25. data/spec/rails-2.3/Rakefile +1 -1
  26. data/spec/rails-2.3/app_root/config/database.yml +4 -19
  27. data/spec/rails-2.3/app_root/config/environments/{in_memory.rb → test.rb} +0 -0
  28. data/spec/rails-2.3/spec/spec_helper.rb +7 -9
  29. data/spec/rails-3.0/Gemfile +3 -1
  30. data/spec/rails-3.0/Rakefile +1 -1
  31. data/spec/rails-3.0/app_root/config/database.yml +5 -3
  32. data/spec/rails-3.0/spec/spec_helper.rb +6 -7
  33. data/spec/rails-3.2/Gemfile +2 -1
  34. data/spec/rails-3.2/Rakefile +1 -1
  35. data/spec/rails-3.2/app_root/config/database.yml +5 -3
  36. data/spec/rails-3.2/spec/spec_helper.rb +3 -7
  37. data/spec/shared/app_root/app/models/recipe/category.rb +13 -0
  38. data/spec/shared/app_root/app/models/recipe/ingredient.rb +13 -0
  39. data/spec/shared/app_root/app/models/recipe.rb +14 -0
  40. data/spec/shared/app_root/app/models/user/with_fulltext.rb +35 -0
  41. data/spec/shared/app_root/app/models/user/without_fulltext.rb +34 -0
  42. data/spec/shared/app_root/config/database.sample.yml +6 -0
  43. data/spec/shared/app_root/db/migrate/001_create_search_text.rb +19 -0
  44. data/spec/shared/app_root/db/migrate/002_create_user_variants.rb +25 -0
  45. data/spec/shared/app_root/db/migrate/003_create_recipe_models.rb +23 -0
  46. data/spec/shared/spec/dusen/active_record/base_ext_spec.rb +138 -0
  47. data/spec/shared/spec/dusen/active_record/search_text_spec.rb +23 -0
  48. data/spec/shared/spec/dusen/parser_spec.rb +14 -0
  49. data/spec/shared/spec/dusen/query_spec.rb +20 -0
  50. data/spec/shared/spec/dusen/util_spec.rb +21 -0
  51. metadata +80 -46
  52. data/lib/dusen/active_record_ext.rb +0 -35
  53. data/spec/rails-2.3/app_root/config/environments/mysql.rb +0 -0
  54. data/spec/rails-2.3/app_root/config/environments/postgresql.rb +0 -0
  55. data/spec/rails-2.3/app_root/config/environments/sqlite.rb +0 -0
  56. data/spec/rails-2.3/app_root/config/environments/sqlite3.rb +0 -0
  57. data/spec/shared/app_root/app/models/user.rb +0 -22
  58. data/spec/shared/app_root/db/migrate/001_create_users.rb +0 -17
  59. data/spec/shared/dusen/active_record_spec.rb +0 -55
@@ -0,0 +1,138 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ shared_examples_for 'model with search syntax' do
6
+
7
+ describe '.search' do
8
+
9
+ it 'should find records by given words' do
10
+ match = subject.create!(:name => 'Abraham')
11
+ no_match = subject.create!(:name => 'Elizabath')
12
+ subject.search('Abraham').to_a.should == [match]
13
+ end
14
+
15
+ it 'should AND multiple words' do
16
+ match = subject.create!(:name => 'Abraham Lincoln')
17
+ no_match = subject.create!(:name => 'Abraham')
18
+ subject.search('Abraham Lincoln').to_a.should == [match]
19
+ end
20
+
21
+ it 'should find records by phrases' do
22
+ match = subject.create!(:name => 'Abraham Lincoln')
23
+ no_match = subject.create!(:name => 'Abraham John Lincoln')
24
+ subject.search('"Abraham Lincoln"').to_a.should == [match]
25
+ end
26
+
27
+ it 'should find records by qualified fields' do
28
+ match = subject.create!(:name => 'foo@bar.com', :email => 'foo@bar.com')
29
+ no_match = subject.create!(:name => 'foo@bar.com', :email => 'bam@baz.com')
30
+ subject.search('email:foo@bar.com').to_a.should == [match]
31
+ end
32
+
33
+ it 'should allow phrases as values for qualified field queries' do
34
+ match = subject.create!(:name => 'Foo Bar', :city => 'Foo Bar')
35
+ no_match = subject.create!(:name => 'Foo Bar', :city => 'Bar Foo')
36
+ subject.search('city:"Foo Bar"').to_a.should == [match]
37
+ end
38
+
39
+ it 'should allow to mix multiple types of tokens in a single query' do
40
+ match = subject.create!(:name => 'Abraham', :city => 'Foohausen')
41
+ no_match = subject.create!(:name => 'Abraham', :city => 'Barhausen')
42
+ subject.search('Foo city:Foohausen').to_a.should == [match]
43
+ end
44
+
45
+ it 'should not find records from another model' do
46
+ match = subject.create!(:name => 'Abraham')
47
+ Recipe.create!(:name => 'Abraham')
48
+ subject.search('Abraham').to_a.should == [match]
49
+ end
50
+
51
+ end
52
+
53
+ describe '.search_syntax' do
54
+
55
+ it "should return the model's syntax definition when called without a block" do
56
+ subject.search_syntax.should be_a(Dusen::Syntax)
57
+ end
58
+
59
+ it 'should be callable multiple times, appending additional syntax' do
60
+ subject.search_syntax.fields.keys.should =~ ['text', 'email', 'city', 'role']
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+
68
+ describe ActiveRecord::Base do
69
+
70
+ describe 'for a model without an associated FULLTEXT table' do
71
+
72
+ subject { User::WithoutFulltext }
73
+
74
+ it_should_behave_like 'model with search syntax'
75
+
76
+ end
77
+
78
+ describe 'for a model with an associated FULLTEXT table' do
79
+
80
+ subject { User::WithFulltext }
81
+
82
+ it_should_behave_like 'model with search syntax'
83
+
84
+ it 'should be shadowed by a Dusen::ActiveRecord::SearchText, which is created, updated and destroyed with the record' do
85
+ user = User::WithFulltext.create!(:name => 'name', :email => 'email', :city => 'city')
86
+ User::WithFulltext.index_search_texts
87
+ Dusen::ActiveRecord::SearchText.all.collect(&:words).should == ['name email city']
88
+ user.reload
89
+ user.update_attributes!(:email => 'changed_email')
90
+ User::WithFulltext.index_search_texts
91
+ Dusen::ActiveRecord::SearchText.all.collect(&:words).should == ['name changed_email city']
92
+ user.destroy
93
+ User::WithFulltext.index_search_texts
94
+ Dusen::ActiveRecord::SearchText.count.should be_zero
95
+ end
96
+
97
+ describe 'indexing fields from associated records'
98
+
99
+ it 'should allow to index fields from an associated record' do
100
+ category = Recipe::Category.create!(:name => 'Rice')
101
+ recipe = Recipe.create!(:name => 'Martini Chicken', :category => category)
102
+ recipe.ingredients.create!(:name => 'Paprica')
103
+ recipe.ingredients.create!(:name => 'Tomatoes')
104
+ Recipe.search('Rice').to_a.should == [recipe]
105
+ Recipe.search('Martini').to_a.should == [recipe]
106
+ Recipe.search('Paprica').to_a.should == [recipe]
107
+ Recipe.search('Tomatoes').to_a.should == [recipe]
108
+ end
109
+
110
+ context 'if the associated model has a .part_of_search_text_for directive' do
111
+
112
+ it 'should automatically reindex itself when an associated record changes' do
113
+ category = Recipe::Category.create!(:name => 'Rice')
114
+ recipe = category.recipes.create!(:name => 'Martini Chicken')
115
+ ingredient = recipe.ingredients.create!(:name => 'Paprica')
116
+ category.update_attributes!(:name => 'Noodles')
117
+ ingredient.update_attributes!(:name => 'Onions')
118
+ Recipe.search('Noodles').to_a.should == [recipe]
119
+ Recipe.search('Onion').to_a.should == [recipe]
120
+ category.reload
121
+ category.destroy
122
+ Recipe.search('Noodles').to_a.should be_empty
123
+ end
124
+
125
+ #it 'should automatically reindex both containers if the container changes' do
126
+ # recipe1 = Recipe.create!(:name => 'Martini Chicken')
127
+ # recipe2 = Recipe.create!(:name => 'Whiskey Chicken')
128
+ # ingredient = recipe1.ingredients.create!(:name => 'Paprica')
129
+ # Recipe.search('Paprica').to_a.should == [recipe1]
130
+ # ingredient.update_attributes!(:recipe => recipe2)
131
+ # Recipe.search('Paprica').to_a.should == [recipe2]
132
+ #end
133
+
134
+ end
135
+
136
+ end
137
+
138
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dusen::ActiveRecord::SearchText do
4
+
5
+ describe '.match' do
6
+
7
+ it 'should find records for the given list of words' do
8
+ match = User::WithFulltext.create!(:name => 'Abraham', :city => 'Fooville')
9
+ no_match = User::WithFulltext.create!(:name => 'Elizabeth', :city => 'Fooville')
10
+ matches = Dusen::ActiveRecord::SearchText.match(User::WithFulltext, ['Abraham', 'Fooville'])
11
+ matches.all.should == [match]
12
+ end
13
+
14
+ it 'should find records by only giving the prefix of a word' do
15
+ match = User::WithFulltext.create!(:name => 'Abraham')
16
+ no_match = User::WithFulltext.create!(:name => 'Elizabeth')
17
+ matches = Dusen::ActiveRecord::SearchText.match(User::WithFulltext, ['Abra'])
18
+ matches.all.should == [match]
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dusen::Parser do
4
+
5
+ describe '.parse' do
6
+
7
+ it 'should parse field tokens first, because they usually give maximum filtering at little cost' do
8
+ query = Dusen::Parser.parse('word1 field1:field1-value word2 field2:field2-value')
9
+ query.collect(&:value).should == ['field1-value', 'field2-value', 'word1', 'word2']
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dusen::Query do
4
+
5
+ describe '#condensed' do
6
+
7
+ it 'should return a version of the query where all text tokens have been collapsed into a single token with an Array value' do
8
+ query = Dusen::Parser.parse('field:value foo bar baz')
9
+ query.tokens.size.should == 4
10
+ condensed_query = query.condensed
11
+ condensed_query.tokens.size.should == 2
12
+ condensed_query[0].field.should == 'field'
13
+ condensed_query[0].value.should == 'value'
14
+ condensed_query[1].field.should == 'text'
15
+ condensed_query[1].value.should == ['foo', 'bar', 'baz']
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dusen::Util do
4
+
5
+ describe '.boolean_fulltext_query' do
6
+
7
+ it 'should generate a query for boolean MySQL fulltext search, which includes all words and allows additional characters on the right side' do
8
+ Dusen::Util.boolean_fulltext_query(['aaa', 'bbb']).should == '+aaa* +bbb*'
9
+ end
10
+
11
+ it 'should keep phrases intact' do
12
+ Dusen::Util.boolean_fulltext_query(['aaa', 'bbb ccc', 'ddd']).should == '+aaa* +"bbb ccc" +ddd*'
13
+ end
14
+
15
+ it 'should escape characters that have special meaning in boolean MySQL fulltext searches' do
16
+ Dusen::Util.boolean_fulltext_query(['+-~\\']).should == '+\\+\\-\\~\\\\*'
17
+ end
18
+
19
+ end
20
+
21
+ end
metadata CHANGED
@@ -1,50 +1,68 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: dusen
3
- version: !ruby/object:Gem::Version
4
- version: 0.2.2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Henning Koch
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-11-23 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2012-12-10 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
15
22
  name: rails
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
23
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
25
  none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- description: Maps Google-like queries (words, "phrases", qualified:fields) to ActiveRecord
31
- scope chains
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: Comprehensive full text search for ActiveRecord and MySQL
32
36
  email: henning.koch@makandra.de
33
37
  executables: []
38
+
34
39
  extensions: []
40
+
35
41
  extra_rdoc_files: []
36
- files:
42
+
43
+ files:
37
44
  - .gitignore
38
45
  - .travis.yml
39
46
  - README.md
40
47
  - Rakefile
48
+ - documents/fulltext_vs_like_benchmark/all_records_and_scope/fulltext.csv
49
+ - documents/fulltext_vs_like_benchmark/all_records_and_scope/fulltext_vs_like.xls
50
+ - documents/fulltext_vs_like_benchmark/all_records_and_scope/like.csv
51
+ - documents/fulltext_vs_like_benchmark/benchmark.rb
52
+ - documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext.csv
53
+ - documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext_vs_like.png
54
+ - documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext_vs_like.xls
55
+ - documents/fulltext_vs_like_benchmark/exact_number_of_records/like.csv
41
56
  - dusen.gemspec
42
57
  - lib/dusen.rb
43
- - lib/dusen/active_record_ext.rb
58
+ - lib/dusen/active_record/base_ext.rb
59
+ - lib/dusen/active_record/search_text.rb
44
60
  - lib/dusen/description.rb
45
61
  - lib/dusen/parser.rb
46
62
  - lib/dusen/query.rb
63
+ - lib/dusen/railtie.rb
47
64
  - lib/dusen/syntax.rb
65
+ - lib/dusen/tasks.rb
48
66
  - lib/dusen/token.rb
49
67
  - lib/dusen/util.rb
50
68
  - lib/dusen/version.rb
@@ -53,11 +71,7 @@ files:
53
71
  - spec/rails-2.3/app_root/config/boot.rb
54
72
  - spec/rails-2.3/app_root/config/database.yml
55
73
  - spec/rails-2.3/app_root/config/environment.rb
56
- - spec/rails-2.3/app_root/config/environments/in_memory.rb
57
- - spec/rails-2.3/app_root/config/environments/mysql.rb
58
- - spec/rails-2.3/app_root/config/environments/postgresql.rb
59
- - spec/rails-2.3/app_root/config/environments/sqlite.rb
60
- - spec/rails-2.3/app_root/config/environments/sqlite3.rb
74
+ - spec/rails-2.3/app_root/config/environments/test.rb
61
75
  - spec/rails-2.3/app_root/config/initializers/fix_missing_source_file.rb
62
76
  - spec/rails-2.3/app_root/config/preinitializer.rb
63
77
  - spec/rails-2.3/app_root/config/routes.rb
@@ -104,33 +118,53 @@ files:
104
118
  - spec/rails-3.2/rcov.opts
105
119
  - spec/rails-3.2/spec/spec_helper.rb
106
120
  - spec/shared/app_root/app/controllers/application_controller.rb
107
- - spec/shared/app_root/app/models/user.rb
108
- - spec/shared/app_root/db/migrate/001_create_users.rb
109
- - spec/shared/dusen/active_record_spec.rb
121
+ - spec/shared/app_root/app/models/recipe.rb
122
+ - spec/shared/app_root/app/models/recipe/category.rb
123
+ - spec/shared/app_root/app/models/recipe/ingredient.rb
124
+ - spec/shared/app_root/app/models/user/with_fulltext.rb
125
+ - spec/shared/app_root/app/models/user/without_fulltext.rb
126
+ - spec/shared/app_root/config/database.sample.yml
127
+ - spec/shared/app_root/db/migrate/001_create_search_text.rb
128
+ - spec/shared/app_root/db/migrate/002_create_user_variants.rb
129
+ - spec/shared/app_root/db/migrate/003_create_recipe_models.rb
130
+ - spec/shared/spec/dusen/active_record/base_ext_spec.rb
131
+ - spec/shared/spec/dusen/active_record/search_text_spec.rb
132
+ - spec/shared/spec/dusen/parser_spec.rb
133
+ - spec/shared/spec/dusen/query_spec.rb
134
+ - spec/shared/spec/dusen/util_spec.rb
135
+ has_rdoc: true
110
136
  homepage: https://github.com/makandra/dusen
111
137
  licenses: []
138
+
112
139
  post_install_message:
113
140
  rdoc_options: []
114
- require_paths:
141
+
142
+ require_paths:
115
143
  - lib
116
- required_ruby_version: !ruby/object:Gem::Requirement
144
+ required_ruby_version: !ruby/object:Gem::Requirement
117
145
  none: false
118
- requirements:
119
- - - ! '>='
120
- - !ruby/object:Gem::Version
121
- version: '0'
122
- required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ hash: 3
150
+ segments:
151
+ - 0
152
+ version: "0"
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
154
  none: false
124
- requirements:
125
- - - ! '>='
126
- - !ruby/object:Gem::Version
127
- version: '0'
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ hash: 3
159
+ segments:
160
+ - 0
161
+ version: "0"
128
162
  requirements: []
163
+
129
164
  rubyforge_project:
130
- rubygems_version: 1.8.24
165
+ rubygems_version: 1.3.9.4
131
166
  signing_key:
132
167
  specification_version: 3
133
- summary: Maps Google-like queries (words, "phrases", qualified:fields) to ActiveRecord
134
- scope chains
168
+ summary: Comprehensive full text search for ActiveRecord and MySQL
135
169
  test_files: []
136
- has_rdoc:
170
+
@@ -1,35 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Dusen
4
- module ActiveRecord
5
-
6
- def search_syntax(&dsl)
7
- if dsl
8
- @search_syntax = Dusen::Description.read_syntax(&dsl)
9
- singleton_class.send(:define_method, :search) do |query_string|
10
- @search_syntax.search(self, query_string)
11
- end
12
- else
13
- @search_syntax
14
- end
15
- end
16
-
17
- def where_like(conditions)
18
- scope = self
19
- conditions.each do |field_or_fields, query|
20
- fields = Array(field_or_fields).collect do |field|
21
- Util.qualify_column_name(scope, field)
22
- end
23
- query_with_placeholders = fields.collect { |field| "#{field} LIKE ?" }.join(' OR ')
24
- like_expression = Dusen::Util.like_expression(query)
25
- bindings = [like_expression] * fields.size
26
- conditions = [ query_with_placeholders, *bindings ]
27
- scope = Util.append_scope_conditions(scope, conditions)
28
- end
29
- scope
30
- end
31
-
32
- end
33
- end
34
-
35
- ActiveRecord::Base.send(:extend, Dusen::ActiveRecord)
File without changes
@@ -1,22 +0,0 @@
1
- # encoding: utf-8
2
-
3
- class User < ActiveRecord::Base
4
-
5
- search_syntax do
6
-
7
- search_by :text do |scope, text|
8
- scope.where_like([:name, :email, :city] => text)
9
- end
10
-
11
- search_by :city do |scope, city|
12
- scope.scoped(:conditions => { :city => city })
13
- end
14
-
15
- search_by :email do |scope, email|
16
- scope.scoped(:conditions => { :email => email })
17
- end
18
-
19
- end
20
-
21
- end
22
-
@@ -1,17 +0,0 @@
1
- # encoding: utf-8
2
-
3
- class CreateUsers < ActiveRecord::Migration
4
-
5
- def self.up
6
- create_table :users do |t|
7
- t.string :name
8
- t.string :email
9
- t.string :city
10
- end
11
- end
12
-
13
- def self.down
14
- drop_table :users
15
- end
16
-
17
- end
@@ -1,55 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Dusen::ActiveRecord do
6
-
7
- describe '.search' do
8
-
9
- it 'should find records by given words' do
10
- match = User.create!(:name => 'foo')
11
- no_match = User.create!(:name => 'bar')
12
- User.search('foo').to_a.should == [match]
13
- end
14
-
15
- it 'should AND multiple words' do
16
- match = User.create!(:name => 'foo bar')
17
- no_match = User.create!(:name => 'foo')
18
- User.search('foo bar').to_a.should == [match]
19
- end
20
-
21
- it 'should find records by phrases' do
22
- match = User.create!(:name => 'foo bar baz')
23
- no_match = User.create!(:name => 'foo baz bar')
24
- User.search('"foo bar"').to_a.should == [match]
25
- end
26
-
27
- it 'should find records by qualified fields' do
28
- match = User.create!(:name => 'foo@bar.com', :email => 'foo@bar.com')
29
- no_match = User.create!(:name => 'foo@bar.com', :email => 'bam@baz.com')
30
- User.search('email:foo@bar.com').to_a.should == [match]
31
- end
32
-
33
- it 'should allow phrases as values for qualified field queries' do
34
- match = User.create!(:name => 'Foo Bar', :city => 'Foo Bar')
35
- no_match = User.create!(:name => 'Foo Bar', :city => 'Bar Foo')
36
- User.search('city:"Foo Bar"').to_a.should == [match]
37
- end
38
-
39
- it 'should allow to mix multiple types of tokens in a single query' do
40
- match = User.create!(:name => 'Foo', :city => 'Foohausen')
41
- no_match = User.create!(:name => 'Foo', :city => 'Barhausen')
42
- User.search('Foo city:Foohausen').to_a.should == [match]
43
- end
44
-
45
- end
46
-
47
- describe '.search_syntax' do
48
-
49
- it "should return the model's syntax definition when called without a block" do
50
- User.search_syntax.should be_a(Dusen::Syntax)
51
- end
52
-
53
- end
54
-
55
- end