acts_as_solr_reloaded 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. data/LICENSE +22 -0
  2. data/README.markdown +64 -0
  3. data/README.rdoc +93 -0
  4. data/Rakefile +71 -0
  5. data/TESTING_THE_PLUGIN +25 -0
  6. data/VERSION +1 -0
  7. data/config/solr.yml +14 -0
  8. data/config/solr_environment.rb +35 -0
  9. data/generators/dynamic_attributes_migration/dynamic_attributes_migration_generator.rb +7 -0
  10. data/generators/dynamic_attributes_migration/templates/migration.rb +15 -0
  11. data/generators/local_migration/local_migration_generator.rb +7 -0
  12. data/generators/local_migration/templates/migration.rb +16 -0
  13. data/lib/acts_as_solr.rb +65 -0
  14. data/lib/acts_as_solr/acts_methods.rb +363 -0
  15. data/lib/acts_as_solr/class_methods.rb +240 -0
  16. data/lib/acts_as_solr/common_methods.rb +89 -0
  17. data/lib/acts_as_solr/deprecation.rb +61 -0
  18. data/lib/acts_as_solr/dynamic_attribute.rb +3 -0
  19. data/lib/acts_as_solr/instance_methods.rb +194 -0
  20. data/lib/acts_as_solr/lazy_document.rb +18 -0
  21. data/lib/acts_as_solr/local.rb +4 -0
  22. data/lib/acts_as_solr/parser_methods.rb +248 -0
  23. data/lib/acts_as_solr/search_results.rb +74 -0
  24. data/lib/acts_as_solr/solr_fixtures.rb +13 -0
  25. data/lib/acts_as_solr/tasks.rb +10 -0
  26. data/lib/acts_as_solr/tasks/database.rake +16 -0
  27. data/lib/acts_as_solr/tasks/solr.rake +142 -0
  28. data/lib/acts_as_solr/tasks/test.rake +5 -0
  29. data/lib/solr.rb +26 -0
  30. data/lib/solr/connection.rb +177 -0
  31. data/lib/solr/document.rb +75 -0
  32. data/lib/solr/exception.rb +13 -0
  33. data/lib/solr/field.rb +36 -0
  34. data/lib/solr/importer.rb +19 -0
  35. data/lib/solr/importer/array_mapper.rb +26 -0
  36. data/lib/solr/importer/delimited_file_source.rb +38 -0
  37. data/lib/solr/importer/hpricot_mapper.rb +27 -0
  38. data/lib/solr/importer/mapper.rb +51 -0
  39. data/lib/solr/importer/solr_source.rb +41 -0
  40. data/lib/solr/importer/xpath_mapper.rb +35 -0
  41. data/lib/solr/indexer.rb +52 -0
  42. data/lib/solr/request.rb +26 -0
  43. data/lib/solr/request/add_document.rb +58 -0
  44. data/lib/solr/request/base.rb +36 -0
  45. data/lib/solr/request/commit.rb +29 -0
  46. data/lib/solr/request/delete.rb +48 -0
  47. data/lib/solr/request/dismax.rb +46 -0
  48. data/lib/solr/request/index_info.rb +22 -0
  49. data/lib/solr/request/modify_document.rb +46 -0
  50. data/lib/solr/request/optimize.rb +19 -0
  51. data/lib/solr/request/ping.rb +36 -0
  52. data/lib/solr/request/select.rb +54 -0
  53. data/lib/solr/request/spellcheck.rb +30 -0
  54. data/lib/solr/request/standard.rb +406 -0
  55. data/lib/solr/request/update.rb +23 -0
  56. data/lib/solr/response.rb +27 -0
  57. data/lib/solr/response/add_document.rb +17 -0
  58. data/lib/solr/response/base.rb +42 -0
  59. data/lib/solr/response/commit.rb +15 -0
  60. data/lib/solr/response/delete.rb +13 -0
  61. data/lib/solr/response/dismax.rb +8 -0
  62. data/lib/solr/response/index_info.rb +26 -0
  63. data/lib/solr/response/modify_document.rb +17 -0
  64. data/lib/solr/response/optimize.rb +14 -0
  65. data/lib/solr/response/ping.rb +26 -0
  66. data/lib/solr/response/ruby.rb +42 -0
  67. data/lib/solr/response/select.rb +17 -0
  68. data/lib/solr/response/spellcheck.rb +20 -0
  69. data/lib/solr/response/standard.rb +65 -0
  70. data/lib/solr/response/xml.rb +39 -0
  71. data/lib/solr/solrtasks.rb +27 -0
  72. data/lib/solr/util.rb +32 -0
  73. data/lib/solr/xml.rb +44 -0
  74. data/solr/README.txt +36 -0
  75. data/solr/etc/jetty.xml +212 -0
  76. data/solr/etc/webdefault.xml +379 -0
  77. data/solr/exampledocs/books.csv +11 -0
  78. data/solr/exampledocs/hd.xml +46 -0
  79. data/solr/exampledocs/ipod_other.xml +50 -0
  80. data/solr/exampledocs/ipod_video.xml +35 -0
  81. data/solr/exampledocs/locales.xml +16 -0
  82. data/solr/exampledocs/mem.xml +58 -0
  83. data/solr/exampledocs/monitor.xml +31 -0
  84. data/solr/exampledocs/monitor2.xml +30 -0
  85. data/solr/exampledocs/mp500.xml +39 -0
  86. data/solr/exampledocs/post.jar +0 -0
  87. data/solr/exampledocs/post.sh +28 -0
  88. data/solr/exampledocs/sd500.xml +33 -0
  89. data/solr/exampledocs/solr.xml +38 -0
  90. data/solr/exampledocs/spellchecker.xml +58 -0
  91. data/solr/exampledocs/test_utf8.sh +83 -0
  92. data/solr/exampledocs/utf8-example.xml +42 -0
  93. data/solr/exampledocs/vidcard.xml +52 -0
  94. data/solr/lib/jetty-6.1.3.jar +0 -0
  95. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  96. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  97. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  98. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  99. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  100. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  101. data/solr/multicore/README.txt +3 -0
  102. data/solr/multicore/core0/conf/schema.xml +41 -0
  103. data/solr/multicore/core0/conf/solrconfig.xml +40 -0
  104. data/solr/multicore/core1/conf/schema.xml +41 -0
  105. data/solr/multicore/core1/conf/solrconfig.xml +40 -0
  106. data/solr/multicore/exampledocs/ipod_other.xml +34 -0
  107. data/solr/multicore/exampledocs/ipod_video.xml +22 -0
  108. data/solr/multicore/solr.xml +35 -0
  109. data/solr/solr/README.txt +52 -0
  110. data/solr/solr/bin/abc +190 -0
  111. data/solr/solr/bin/abo +190 -0
  112. data/solr/solr/bin/backup +117 -0
  113. data/solr/solr/bin/backupcleaner +142 -0
  114. data/solr/solr/bin/commit +133 -0
  115. data/solr/solr/bin/optimize +134 -0
  116. data/solr/solr/bin/readercycle +129 -0
  117. data/solr/solr/bin/rsyncd-disable +77 -0
  118. data/solr/solr/bin/rsyncd-enable +76 -0
  119. data/solr/solr/bin/rsyncd-start +145 -0
  120. data/solr/solr/bin/rsyncd-stop +105 -0
  121. data/solr/solr/bin/scripts-util +99 -0
  122. data/solr/solr/bin/snapcleaner +154 -0
  123. data/solr/solr/bin/snapinstaller +198 -0
  124. data/solr/solr/bin/snappuller +269 -0
  125. data/solr/solr/bin/snappuller-disable +77 -0
  126. data/solr/solr/bin/snappuller-enable +77 -0
  127. data/solr/solr/bin/snapshooter +136 -0
  128. data/solr/solr/conf/admin-extra.html +31 -0
  129. data/solr/solr/conf/elevate.xml +36 -0
  130. data/solr/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  131. data/solr/solr/conf/protwords.txt +21 -0
  132. data/solr/solr/conf/schema.xml +132 -0
  133. data/solr/solr/conf/scripts.conf +24 -0
  134. data/solr/solr/conf/solrconfig.xml +906 -0
  135. data/solr/solr/conf/spellings.txt +2 -0
  136. data/solr/solr/conf/stopwords.txt +58 -0
  137. data/solr/solr/conf/synonyms.txt +31 -0
  138. data/solr/solr/conf/xslt/example.xsl +132 -0
  139. data/solr/solr/conf/xslt/example_atom.xsl +67 -0
  140. data/solr/solr/conf/xslt/example_rss.xsl +66 -0
  141. data/solr/solr/conf/xslt/luke.xsl +337 -0
  142. data/solr/solr/lib/localsolr.jar +0 -0
  143. data/solr/solr/lib/lucene-spatial-2.9-dev.jar +0 -0
  144. data/solr/start.jar +0 -0
  145. data/solr/webapps/solr.war +0 -0
  146. data/test/config/solr.yml +2 -0
  147. data/test/db/connections/mysql/connection.rb +11 -0
  148. data/test/db/connections/sqlite/connection.rb +8 -0
  149. data/test/db/migrate/001_create_books.rb +15 -0
  150. data/test/db/migrate/002_create_movies.rb +12 -0
  151. data/test/db/migrate/003_create_categories.rb +11 -0
  152. data/test/db/migrate/004_create_electronics.rb +16 -0
  153. data/test/db/migrate/005_create_authors.rb +12 -0
  154. data/test/db/migrate/006_create_postings.rb +9 -0
  155. data/test/db/migrate/007_create_posts.rb +13 -0
  156. data/test/db/migrate/008_create_gadgets.rb +11 -0
  157. data/test/db/migrate/009_create_dynamic_attributes.rb +15 -0
  158. data/test/db/migrate/010_create_advertises.rb +13 -0
  159. data/test/db/migrate/011_create_locals.rb +15 -0
  160. data/test/db/test.db +0 -0
  161. data/test/fixtures/advertises.yml +12 -0
  162. data/test/fixtures/authors.yml +9 -0
  163. data/test/fixtures/books.yml +13 -0
  164. data/test/fixtures/categories.yml +7 -0
  165. data/test/fixtures/db_definitions/mysql.sql +41 -0
  166. data/test/fixtures/dynamic_attributes.yml +11 -0
  167. data/test/fixtures/electronics.yml +49 -0
  168. data/test/fixtures/locals.yml +9 -0
  169. data/test/fixtures/movies.yml +9 -0
  170. data/test/fixtures/postings.yml +10 -0
  171. data/test/functional/acts_as_solr_test.rb +463 -0
  172. data/test/functional/association_indexing_test.rb +37 -0
  173. data/test/functional/faceted_search_test.rb +163 -0
  174. data/test/functional/multi_solr_search_test.rb +57 -0
  175. data/test/models/advertise.rb +6 -0
  176. data/test/models/author.rb +10 -0
  177. data/test/models/book.rb +10 -0
  178. data/test/models/category.rb +8 -0
  179. data/test/models/dynamic_attribute.rb +7 -0
  180. data/test/models/electronic.rb +25 -0
  181. data/test/models/gadget.rb +9 -0
  182. data/test/models/local.rb +7 -0
  183. data/test/models/movie.rb +17 -0
  184. data/test/models/novel.rb +2 -0
  185. data/test/models/post.rb +3 -0
  186. data/test/models/posting.rb +11 -0
  187. data/test/test_helper.rb +56 -0
  188. data/test/unit/acts_methods_shoulda.rb +95 -0
  189. data/test/unit/class_methods_shoulda.rb +85 -0
  190. data/test/unit/common_methods_shoulda.rb +111 -0
  191. data/test/unit/instance_methods_shoulda.rb +372 -0
  192. data/test/unit/lazy_document_shoulda.rb +34 -0
  193. data/test/unit/parser_instance.rb +19 -0
  194. data/test/unit/parser_methods_shoulda.rb +338 -0
  195. data/test/unit/solr_instance.rb +74 -0
  196. data/test/unit/test_helper.rb +24 -0
  197. metadata +290 -0
Binary file
data/solr/start.jar ADDED
Binary file
Binary file
@@ -0,0 +1,2 @@
1
+ test:
2
+ url: http://localhost:8981/solr
@@ -0,0 +1,11 @@
1
+ require 'logger'
2
+ ActiveRecord::Base.logger = Logger.new("debug.log")
3
+
4
+ ActiveRecord::Base.establish_connection(
5
+ :adapter => "mysql",
6
+ :username => "root",
7
+ :password => "rotz2od",
8
+ :encoding => "utf8",
9
+ :database => "actsassolr_test"
10
+ )
11
+
@@ -0,0 +1,8 @@
1
+ require 'logger'
2
+ ActiveRecord::Base.logger = Logger.new("debug.log")
3
+
4
+ ActiveRecord::Base.establish_connection(
5
+ :adapter => "sqlite3",
6
+ :encoding => "utf8",
7
+ :database => File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'test.db')
8
+ )
@@ -0,0 +1,15 @@
1
+ class CreateBooks < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :books, :force => true do |t|
4
+ t.column :category_id, :integer
5
+ t.column :name, :string
6
+ t.column :author, :string
7
+ t.column :type, :string
8
+ t.column :published_on, :date
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :books
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ class CreateMovies < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :movies, :force => true do |t|
4
+ t.column :name, :string
5
+ t.column :description, :string
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :movies
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class CreateCategories < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :categories, :force => true do |t|
4
+ t.column :name, :string
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :categories
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ class CreateElectronics < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :electronics, :force => true do |t|
4
+ t.column :name, :string
5
+ t.column :manufacturer, :string
6
+ t.column :features, :string
7
+ t.column :category, :string
8
+ t.column :price, :string
9
+ t.timestamps
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ drop_table :electronics
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ class CreateAuthors < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :authors, :force => true do |t|
4
+ t.column :name, :string
5
+ t.column :biography, :text
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :authors
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ class CreatePostings < ActiveRecord::Migration
2
+ def self.up
3
+ execute "CREATE TABLE postings(`guid` varchar(20) NOT NULL PRIMARY KEY, `name` varchar(200), `description` text)"
4
+ end
5
+
6
+ def self.down
7
+ drop_table :postings
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ class CreatePosts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :posts, :force => true do |t|
4
+ t.column :name, :string
5
+ t.column :reply_counter, :integer
6
+ t.column :posted_at, :datetime
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :posts
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ class CreateGadgets < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :gadgets, :force => true do |t|
4
+ t.column :name, :string
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :gadgets
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ class CreateDynamicAttributes < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :dynamic_attributes do |t|
4
+ t.integer :dynamicable_id
5
+ t.string :dynamicable_type
6
+ t.string :name
7
+ t.text :value
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :dynamic_attributes
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class CreateAdvertises < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :advertises do |t|
4
+ t.column :description, :string
5
+ t.timestamps
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :advertises
11
+ end
12
+ end
13
+
@@ -0,0 +1,15 @@
1
+ class CreateLocals < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :locals do |t|
4
+ t.integer :localizable_id
5
+ t.string :localizable_type
6
+ t.string :latitude
7
+ t.string :longitude
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :locals
14
+ end
15
+ end
data/test/db/test.db ADDED
Binary file
@@ -0,0 +1,12 @@
1
+ car:
2
+ id: 1
3
+ description: Car
4
+
5
+ house:
6
+ id: 2
7
+ description: House
8
+
9
+ bike:
10
+ id: 3
11
+ description: Bike
12
+
@@ -0,0 +1,9 @@
1
+ tom_clancy:
2
+ id: 1
3
+ name: Tom Clancy
4
+ biography: Tom Clancy (born 1947) writes novels of adventure and espionage in the international military-industrial complex that have earned him enormous popularity in the 1980s as a creator of the "techno-thriller" genre.
5
+
6
+ stephen_king:
7
+ id: 2
8
+ name: Stephen King
9
+ biography: Stephen King (born 1947) is a prolific and immensely popular author of horror fiction. In his works, King blends elements of the traditional gothic tale with those of the modern psychological thriller, detective, and science fiction genres.
@@ -0,0 +1,13 @@
1
+ splinter_cell:
2
+ id: 1
3
+ category_id: 1
4
+ name: Splinter Cell
5
+ author: Tom Clancy
6
+ published_on: <%= Date.today - 1.year %>
7
+
8
+ ruby:
9
+ id: 2
10
+ category_id: 2
11
+ name: Ruby for Dummies
12
+ author: Peter McPeterson
13
+ published_on: <%= Date.today - 2.years %>
@@ -0,0 +1,7 @@
1
+ thriller:
2
+ id: 1
3
+ name: Thriller/Novels
4
+
5
+ technical:
6
+ id: 2
7
+ name: Technical Books
@@ -0,0 +1,41 @@
1
+ DROP DATABASE IF EXISTS `actsassolr_tests`;
2
+ CREATE DATABASE IF NOT EXISTS `actsassolr_tests`;
3
+ USE `actsassolr_tests`
4
+
5
+ CREATE TABLE `books` (
6
+ `id` int(11) NOT NULL auto_increment,
7
+ `category_id` int(11),
8
+ `name` varchar(200) default NULL,
9
+ `author` varchar(200) default NULL,
10
+ PRIMARY KEY (`id`)
11
+ );
12
+
13
+ CREATE TABLE `movies` (
14
+ `id` int(11) NOT NULL auto_increment,
15
+ `name` varchar(200) default NULL,
16
+ `description` varchar(255) default NULL,
17
+ PRIMARY KEY (`id`)
18
+ );
19
+
20
+ CREATE TABLE `categories` (
21
+ `id` int(11) NOT NULL auto_increment,
22
+ `name` varchar(200) default NULL,
23
+ PRIMARY KEY (`id`)
24
+ );
25
+
26
+ CREATE TABLE `electronics` (
27
+ `id` int(11) NOT NULL auto_increment,
28
+ `name` varchar(200) default NULL,
29
+ `manufacturer` varchar(255) default NULL,
30
+ `features` varchar(255) default NULL,
31
+ `category` varchar(255) default NULL,
32
+ `price` varchar(20) default NULL,
33
+ PRIMARY KEY (`id`)
34
+ );
35
+
36
+ CREATE TABLE `authors` (
37
+ `id` int(11) NOT NULL auto_increment,
38
+ `name` varchar(200) default NULL,
39
+ `biography` text default NULL,
40
+ PRIMARY KEY (`id`)
41
+ );
@@ -0,0 +1,11 @@
1
+ DynamicAttribute:
2
+ id: 1
3
+ #name: Description
4
+ #value: Very cool bike
5
+ #advertise_id: 1
6
+
7
+ DynamicAttribute:
8
+ id: 2
9
+ #name: Price
10
+ #value: 500
11
+ #advertise_id: 1
@@ -0,0 +1,49 @@
1
+ ipod_video:
2
+ id: 1
3
+ name: Apple 60 GB Memory iPod with Video Playback Black
4
+ manufacturer: Apple Computer Inc.
5
+ features: iTunes, Podcasts, Audiobooks
6
+ category: Electronics
7
+ price: 599.00
8
+ created_at: <%= (Time.now - 1.year).utc %>
9
+ updated_at: <%= (Time.now - 1.month).utc %>
10
+
11
+ dell_monitor:
12
+ id: 2
13
+ name: Dell Widescreen UltraSharp 3007WFP
14
+ manufacturer: Dell, Inc
15
+ features: 30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast
16
+ category: Electronics
17
+ price: 750.00
18
+ created_at: <%= (Time.now - 1.year).utc %>
19
+ updated_at: <%= (Time.now - 1.month).utc %>
20
+
21
+ samsung_hd:
22
+ id: 3
23
+ name: Samsung SpinPoint P120 SP2514N - hard drive - 250 GB of Memory Storage - ATA-133
24
+ manufacturer: Samsung Electronics Co. Ltd.
25
+ features: 7200RPM, 8MB cache, IDE Ultra ATA-133
26
+ category: Hard Drive
27
+ price: 319.00
28
+ created_at: <%= (Time.now - 2.years).utc %>
29
+ updated_at: <%= (Time.now - 2.months).utc %>
30
+
31
+ corsair_ram:
32
+ id: 4
33
+ name: CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail
34
+ manufacturer: Corsair Microsystems Inc.
35
+ features: CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader
36
+ category: Memory
37
+ price: 155.00
38
+ created_at: <%= (Time.now - 6.years).utc %>
39
+ updated_at: <%= (Time.now - 3.months).utc %>
40
+
41
+ a_data_ram:
42
+ id: 5
43
+ name: A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM
44
+ manufacturer: A-DATA Technology Inc.
45
+ features: CAS latency 3, 2.7v
46
+ category: Memory
47
+ price: 65.79
48
+ created_at: <%= (Time.now - 9.years).utc %>
49
+ updated_at: <%= (Time.now - 4.months).utc %>
@@ -0,0 +1,9 @@
1
+ home:
2
+ id: 1
3
+ longitude: -77.4027
4
+ latitude: 39.36
5
+
6
+ work:
7
+ id: 2
8
+ longitude: -77.4027
9
+ latitude: 38.36
@@ -0,0 +1,9 @@
1
+ napoleon_dynamite:
2
+ id: 1
3
+ name: Napoleon Dynamite
4
+ description: Cool movie about a goofy guy
5
+
6
+ office_space:
7
+ id: 2
8
+ name: Office Space
9
+ description: Hypnotized dude loves fishing but not working
@@ -0,0 +1,10 @@
1
+ first:
2
+ guid: ABC-123
3
+ name: Posting ABC
4
+ description: First posting testing primary key as string
5
+
6
+ second:
7
+ guid: DEF-456
8
+ name: Posting DEF
9
+ description: Second posting testing primary key as string
10
+
@@ -0,0 +1,463 @@
1
+ # encoding: utf-8
2
+ require "#{File.dirname(File.expand_path(__FILE__))}/../test_helper"
3
+
4
+ class ActsAsSolrTest < Test::Unit::TestCase
5
+
6
+ fixtures :books, :movies, :electronics, :postings, :authors, :advertises
7
+
8
+ DynamicAttribute.delete_all
9
+ Advertise.first.dynamic_attributes.create! :name => 'Description', :value => 'A very cool bike'
10
+ Advertise.first.dynamic_attributes.create! :name => 'Price', :value => '1000'
11
+
12
+ Local.delete_all
13
+ Local.create! :localizable => Advertise.find(1), :longitude => '-77.4027', :latitude => '39.36'
14
+ Local.create! :localizable => Advertise.find(2), :longitude => '77.4027', :latitude => '-38.36'
15
+
16
+ # Inserting new data into Solr and making sure it's getting indexed
17
+ def test_insert_new_data
18
+ assert_equal 2, Book.count_by_solr('ruby OR splinter OR bob')
19
+ b = Book.create(:name => "Fuze in action", :author => "Bob Bobber", :category_id => 1)
20
+ assert b.valid?
21
+ assert_equal 3, Book.count_by_solr('ruby OR splinter OR bob')
22
+ end
23
+
24
+ # Check the type column stored in the index isn't stemmed by SOLR. If it is stemmed,
25
+ # then both Post and Posting will be stored as type:Post, so a query for Posts will
26
+ # return Postings and vice versa
27
+
28
+ def test_insert_new_data_doesnt_stem_type
29
+ assert_equal 0, Post.count_by_solr('aardvark')
30
+ p = Posting.new :name => 'aardvark', :description => "An interesting animal"
31
+ p.guid = '12AB'
32
+ p.save!
33
+ assert_equal 0, Post.count_by_solr('aardvark')
34
+ end
35
+
36
+ def test_type_determined_from_database_if_not_explicitly_set
37
+ assert Post.configuration[:solr_fields][:posted_at][:type] == :date
38
+ end
39
+
40
+ def test_search_includes_subclasses
41
+ Novel.create! :name => 'Wuthering Heights', :author => 'Emily Bronte'
42
+ Book.create! :name => 'Jane Eyre', :author => 'Charlotte Bronte'
43
+ assert_equal 1, Novel.find_by_solr('Bronte').total_hits
44
+ assert_equal 2, Book.find_by_solr('Bronte').total_hits
45
+ end
46
+
47
+ # Testing basic solr search:
48
+ # Model.find_by_solr 'term'
49
+ # Note that you're able to mix free-search with fields and boolean operators
50
+ def test_find_by_solr_ruby
51
+ ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
52
+ 'author:peter AND ruby', 'peter dummy'].each do |term|
53
+ records = Book.find_by_solr term
54
+ assert_equal 1, records.total
55
+ assert_equal "Peter McPeterson", records.docs.first.author
56
+ assert_equal "Ruby for Dummies", records.docs.first.name
57
+ assert_equal ({"id" => 2,
58
+ "category_id" => 2,
59
+ "name" => "Ruby for Dummies",
60
+ "author" => "Peter McPeterson", "published_on" => (Date.today - 2.years), "type" => nil}), records.docs.first.attributes
61
+ end
62
+ end
63
+
64
+ # Testing basic solr search:
65
+ # Model.find_by_solr 'term'
66
+ # Note that you're able to mix free-search with fields and boolean operators
67
+ def test_find_by_solr_splinter
68
+ ['splinter', 'name:splinter', 'name:splinter AND author:clancy',
69
+ 'author:clancy AND splinter', 'cell tom'].each do |term|
70
+ records = Book.find_by_solr term
71
+ assert_equal 1, records.total
72
+ assert_equal "Splinter Cell", records.docs.first.name
73
+ assert_equal "Tom Clancy", records.docs.first.author
74
+ assert_equal ({"id" => 1, "category_id" => 1, "name" => "Splinter Cell",
75
+ "author" => "Tom Clancy", "published_on" => (Date.today - 1.year), "type" => nil}), records.docs.first.attributes
76
+ end
77
+ end
78
+
79
+ # Testing basic solr search:
80
+ # Model.find_by_solr 'term'
81
+ # Note that you're able to mix free-search with fields and boolean operators
82
+ def test_find_by_solr_ruby_or_splinter
83
+ ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', 'dummy OR cell'].each do |term|
84
+ records = Book.find_by_solr term
85
+ assert_equal 2, records.total
86
+ end
87
+ end
88
+
89
+ # Testing search in indexed field methods:
90
+ #
91
+ # class Movie < ActiveRecord::Base
92
+ # acts_as_solr :fields => [:name, :description, :current_time]
93
+ #
94
+ # def current_time
95
+ # Time.now.to_s
96
+ # end
97
+ #
98
+ # end
99
+ #
100
+ # The method current_time above gets indexed as being part of the
101
+ # Movie model and it's available for search as well
102
+ def test_find_with_dynamic_fields
103
+ date = Time.now.strftime('%b %d %Y')
104
+ ["dynamite AND #{date}", "description:goofy AND #{date}", "goofy napoleon #{date}",
105
+ "goofiness #{date}"].each do |term|
106
+ records = Movie.find_by_solr term
107
+ assert_equal 1, records.total
108
+ assert_equal ({"id" => 1, "name" => "Napoleon Dynamite",
109
+ "description" => "Cool movie about a goofy guy"}), records.docs.first.attributes
110
+ end
111
+ end
112
+
113
+ # Testing basic solr search that returns just the ids instead of the objects:
114
+ # Model.find_id_by_solr 'term'
115
+ # Note that you're able to mix free-search with fields and boolean operators
116
+ def test_find_id_by_solr_ruby
117
+ ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
118
+ 'author:peter AND ruby'].each do |term|
119
+ records = Book.find_id_by_solr term
120
+ assert_equal 1, records.docs.size
121
+ assert_equal [2], records.docs
122
+ end
123
+ end
124
+
125
+ # Testing basic solr search that returns just the ids instead of the objects:
126
+ # Model.find_id_by_solr 'term'
127
+ # Note that you're able to mix free-search with fields and boolean operators
128
+ def test_find_id_by_solr_splinter
129
+ ['splinter', 'name:splinter', 'name:splinter AND author:clancy',
130
+ 'author:clancy AND splinter'].each do |term|
131
+ records = Book.find_id_by_solr term
132
+ assert_equal 1, records.docs.size
133
+ assert_equal [1], records.docs
134
+ end
135
+ end
136
+
137
+ # Testing basic solr search that returns just the ids instead of the objects:
138
+ # Model.find_id_by_solr 'term'
139
+ # Note that you're able to mix free-search with fields and boolean operators
140
+ def test_find_id_by_solr_ruby_or_splinter
141
+ ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter',
142
+ 'dummy OR cell'].each do |term|
143
+ records = Book.find_id_by_solr term
144
+ assert_equal 2, records.docs.size
145
+ assert_equal [1,2], records.docs
146
+ end
147
+ end
148
+
149
+ # Testing basic solr search that returns the total number of records found:
150
+ # Model.find_count_by_solr 'term'
151
+ # Note that you're able to mix free-search with fields and boolean operators
152
+ def test_count_by_solr
153
+ ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
154
+ 'author:peter AND ruby'].each do |term|
155
+ assert_equal 1, Book.count_by_solr(term), "there should only be 1 result for search: #{term}"
156
+ end
157
+ end
158
+
159
+ # Testing basic solr search that returns the total number of records found:
160
+ # Model.find_count_by_solr 'term'
161
+ # Note that you're able to mix free-search with fields and boolean operators
162
+ def test_count_by_solr_splinter
163
+ ['splinter', 'name:splinter', 'name:splinter AND author:clancy',
164
+ 'author:clancy AND splinter', 'author:clancy cell'].each do |term|
165
+ assert_equal 1, Book.count_by_solr(term)
166
+ end
167
+ end
168
+
169
+ # Testing basic solr search that returns the total number of records found:
170
+ # Model.find_count_by_solr 'term'
171
+ # Note that you're able to mix free-search with fields and boolean operators
172
+ def test_count_by_solr_ruby_or_splinter
173
+ ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', 'dummy OR cell'].each do |term|
174
+ assert_equal 2, Book.count_by_solr(term)
175
+ end
176
+ end
177
+
178
+ # Testing basic solr search with additional options:
179
+ # Model.find_count_by_solr 'term', :limit => 10, :offset => 0
180
+ def test_find_with_options
181
+ [1,2].each do |count|
182
+ records = Book.find_by_solr 'ruby OR splinter', :limit => count
183
+ assert_equal count, records.docs.size
184
+ end
185
+ end
186
+
187
+ # Testing self.rebuild_solr_index
188
+ # - It makes sure the index is rebuilt after a data has been lost
189
+ def test_rebuild_solr_index
190
+ assert_equal 1, Book.count_by_solr('splinter')
191
+
192
+ Book.find(:first).solr_destroy
193
+ assert_equal 0, Book.count_by_solr('splinter')
194
+
195
+ Book.rebuild_solr_index
196
+ assert_equal 1, Book.count_by_solr('splinter')
197
+ end
198
+
199
+ # Testing instance methods:
200
+ # - solr_save
201
+ # - solr_destroy
202
+ def test_solr_save_and_solr_destroy
203
+ assert_equal 1, Book.count_by_solr('splinter')
204
+
205
+ Book.find(:first).solr_destroy
206
+ assert_equal 0, Book.count_by_solr('splinter')
207
+
208
+ Book.find(:first).solr_save
209
+ assert_equal 1, Book.count_by_solr('splinter')
210
+ end
211
+
212
+ # Testing the order of results
213
+ def test_find_returns_records_in_order
214
+ records = Book.find_by_solr 'ruby^5 OR splinter'
215
+ # we boosted ruby so ruby should come first
216
+
217
+ assert_equal 2, records.total
218
+ assert_equal 'Ruby for Dummies', records.docs.first.name
219
+ assert_equal 'Splinter Cell', records.docs.last.name
220
+ end
221
+
222
+ # Testing solr search with optional :order argument
223
+ def _test_with_order_option
224
+ records = Movie.find_by_solr 'office^5 OR goofiness'
225
+ assert_equal 'Hypnotized dude loves fishing but not working', records.docs.first.description
226
+ assert_equal 'Cool movie about a goofy guy', records.docs.last.description
227
+
228
+ records = Movie.find_by_solr 'office^5 OR goofiness', :order => 'description asc'
229
+ assert_equal 'Cool movie about a goofy guy', records.docs.first.description
230
+ assert_equal 'Hypnotized dude loves fishing but not working', records.docs.last.description
231
+ end
232
+
233
+ # Testing search with omitted :field_types should
234
+ # return the same result set as if when we use it
235
+ def test_omit_field_types_in_search
236
+ records = Electronic.find_by_solr "price:[200 TO 599.99]"
237
+ assert_match(/599/, records.docs.first.price)
238
+ assert_match(/319/, records.docs.last.price)
239
+
240
+ records = Electronic.find_by_solr "price:[200 TO 599.99]", :order => 'price asc'
241
+ assert_match(/319/, records.docs.first.price)
242
+ assert_match(/599/, records.docs.last.price)
243
+
244
+ end
245
+
246
+ # Test to make sure the result returned when no matches
247
+ # are found has the same structure when there are results
248
+ def test_returns_no_matches
249
+ records = Book.find_by_solr 'rubyist'
250
+ assert_equal [], records.docs
251
+ assert_equal 0, records.total
252
+
253
+ records = Book.find_id_by_solr 'rubyist'
254
+ assert_equal [], records.docs
255
+ assert_equal 0, records.total
256
+
257
+ records = Book.find_by_solr 'rubyist', :facets => {}
258
+ assert_equal [], records.docs
259
+ assert_equal 0, records.total
260
+ assert_equal({"facet_fields"=>[]}, records.facets)
261
+ end
262
+
263
+
264
+ # Testing the :exclude_fields option when set in the
265
+ # model to make sure it doesn't get indexed
266
+ def test_exclude_fields_option
267
+ records = Electronic.find_by_solr 'audiobooks OR latency'
268
+ assert records.docs.empty?
269
+ assert_equal 0, records.total
270
+
271
+ assert_nothing_raised{
272
+ records = Electronic.find_by_solr 'features:audiobooks'
273
+ assert records.docs.empty?
274
+ assert_equal 0, records.total
275
+ }
276
+ end
277
+
278
+ # Testing the :auto_commit option set to false in the model
279
+ # should not send the commit command to Solr
280
+ def test_auto_commit_turned_off
281
+ assert_equal 0, Author.count_by_solr('raymond chandler')
282
+
283
+ original_count = Author.count
284
+ Author.create(:name => 'Raymond Chandler', :biography => 'Writes noirish detective stories')
285
+
286
+ assert_equal original_count + 1, Author.count
287
+ assert_equal 0, Author.count_by_solr('raymond chandler')
288
+ end
289
+
290
+ # Testing models that use a different key as the primary key
291
+ def test_search_on_model_with_string_id_field
292
+ records = Posting.find_by_solr 'first^5 OR second'
293
+ assert_equal 2, records.total
294
+ assert_equal 'ABC-123', records.docs.first.guid
295
+ assert_equal 'DEF-456', records.docs.last.guid
296
+ end
297
+
298
+ # Making sure the result set is ordered correctly even on
299
+ # models that use a different key as the primary key
300
+ def test_records_in_order_on_model_with_string_id_field
301
+ records = Posting.find_by_solr 'first OR second^5'
302
+ assert_equal 2, records.total
303
+ assert_equal 'DEF-456', records.docs.first.guid
304
+ assert_equal 'ABC-123', records.docs.last.guid
305
+ end
306
+
307
+ # Making sure the records are added when passing a batch size
308
+ # to rebuild_solr_index
309
+ def test_using_rebuild_solr_index_with_batch
310
+ assert_equal 2, Movie.count_by_solr('office OR napoleon')
311
+ Movie.find(:all).each(&:solr_destroy)
312
+ assert_equal 0, Movie.count_by_solr('office OR napoleon')
313
+
314
+ Movie.rebuild_solr_index 100
315
+ assert_equal 2, Movie.count_by_solr('office OR napoleon')
316
+ end
317
+
318
+ # Making sure find_by_solr with scores actually return the scores
319
+ # for each individual record
320
+ def test_find_by_solr_with_score
321
+ books = Book.find_by_solr 'ruby^10 OR splinter', :scores => true
322
+
323
+ assert_equal 2, books.total
324
+ assert (books.max_score >= 0.3 && books.max_score <= 0.6)
325
+
326
+ books.records.each { |book| assert_not_nil book.solr_score }
327
+ assert (books.docs.first.solr_score >= 0.3 && books.docs.first.solr_score <= 0.6)
328
+ assert (books.docs.last.solr_score < books.docs.first.solr_score)
329
+ end
330
+
331
+ # Making sure nothing breaks when html entities are inside
332
+ # the content to be indexed; and on the search as well.
333
+ def test_index_and_search_with_html_entities
334
+ description = "
335
+ inverted exclamation mark &iexcl; &#161;
336
+ ¤ currency &curren; &#164;
337
+ ¢ cent &cent; &#162;
338
+ £ pound &pound; &#163;
339
+ ¥ yen &yen; &#165;
340
+ ¦ broken vertical bar &brvbar; &#166;
341
+ § section &sect; &#167;
342
+ ¨ spacing diaeresis &uml; &#168;
343
+ © copyright &copy; &#169;
344
+ ª feminine ordinal indicator &ordf; &#170;
345
+ « angle quotation mark (left) &laquo; &#171;
346
+ ¬ negation &not; &#172;
347
+ ­ soft hyphen &shy; &#173;
348
+ ® registered trademark &reg; &#174;
349
+ ™ trademark &trade; &#8482;
350
+ ¯ spacing macron &macr; &#175;
351
+ ° degree &deg; &#176;
352
+ ± plus-or-minus &plusmn; &#177;
353
+ ² superscript 2 &sup2; &#178;
354
+ ³ superscript 3 &sup3; &#179;
355
+ ´ spacing acute &acute; &#180;
356
+ µ micro &micro; &#181;
357
+ ¶ paragraph &para; &#182;
358
+ · middle dot &middot; &#183;
359
+ ¸ spacing cedilla &cedil; &#184;
360
+ ¹ superscript 1 &sup1; &#185;
361
+ º masculine ordinal indicator &ordm; &#186;
362
+ » angle quotation mark (right) &raquo; &#187;
363
+ ¼ fraction 1/4 &frac14; &#188;
364
+ ½ fraction 1/2 &frac12; &#189;
365
+ ¾ fraction 3/4 &frac34; &#190;
366
+ ¿ inverted question mark &iquest; &#191;
367
+ × multiplication &times; &#215;
368
+ ÷ division &divide; &#247
369
+ &hearts; &diams; &clubs; &spades;"
370
+
371
+ author = Author.create(:name => "Test in Action&trade; - Copyright &copy; Bob", :biography => description)
372
+ assert author.valid?
373
+ author.solr_commit
374
+
375
+ author = Author.find_by_solr 'trademark &copy &#190 &iexcl &#163'
376
+ assert_equal 1, author.total
377
+ end
378
+
379
+ def test_operator_search_option
380
+ assert_nothing_raised {
381
+ books = Movie.find_by_solr "office napoleon", :operator => :or
382
+ assert_equal 2, books.total
383
+
384
+ books = Movie.find_by_solr "office napoleon", :operator => :and
385
+ assert_equal 0, books.total
386
+ }
387
+
388
+ assert_raise RuntimeError do
389
+ Movie.find_by_solr "office napoleon", :operator => :bad
390
+ end
391
+ end
392
+
393
+ # Making sure find_by_solr with scores actually return the scores
394
+ # for each individual record and orders them accordingly
395
+ def test_find_by_solr_order_by_score
396
+ books = Book.find_by_solr 'ruby^10 OR splinter', {:scores => true, :order => 'score asc' }
397
+ assert (books.docs.collect(&:solr_score).compact.size == books.docs.size), "Each book should have a score"
398
+ assert (books.docs.last.solr_score >= 0.3 && books.docs.last.solr_score <= 0.6)
399
+
400
+ books = Book.find_by_solr 'ruby^10 OR splinter', {:scores => true, :order => 'score desc' }
401
+ assert (books.docs.first.solr_score >= 0.3 && books.docs.first.solr_score <= 0.6)
402
+ assert (books.docs.last.solr_score < books.docs.first.solr_score)
403
+ end
404
+
405
+ # Search based on fields with the :date format
406
+ def test_indexed_date_field_format
407
+ movies = Movie.find_by_solr 'time_on_xml:[NOW-1DAY TO NOW]'
408
+ assert_equal 2, movies.total
409
+ end
410
+
411
+ def test_query_time_is_returned
412
+ results = Book.find_by_solr('ruby')
413
+ assert_not_nil(results.query_time)
414
+ assert_equal(results.query_time.class,Fixnum)
415
+ end
416
+
417
+ def test_should_not_index_the_record_when_offline_proc_returns_true
418
+ Gadget.search_disabled = true
419
+ gadget = Gadget.create(:name => "flipvideo mino")
420
+ assert_equal 0, Gadget.find_id_by_solr('flipvideo').total
421
+ end
422
+
423
+ def test_should_find_filtering_a_dynamic_attribute
424
+ records = Advertise.find_by_solr "description:bike"
425
+ assert_equal 1, records.total
426
+ end
427
+
428
+ def test_dynamic_attributes_are_faceted
429
+ records = Advertise.find_by_solr "Description:bike", :facets => { :fields => [:Description] }
430
+ expected = { "A very cool bike" => 1 }
431
+ assert_equal expected, records.facets['facet_fields']['Description_facet']
432
+ end
433
+
434
+ def test_search_is_an_alias_for_find_by_solr
435
+ assert_equal Advertise.find_by_solr("bike").docs, Advertise.search("bike").docs
436
+ end
437
+
438
+ def test_search_given_a_radius
439
+ records = Advertise.search "bike", :around => {:latitude => '-39.36',
440
+ :longitude => '77.4027',
441
+ :radius => 1}
442
+ assert_equal 0, records.total
443
+ end
444
+
445
+ def test_records_are_found_in_a_radius
446
+ records = Advertise.search "bike", :around => {:latitude => '39.36',
447
+ :longitude => '-77.4027',
448
+ :radius => 1}
449
+ assert_equal 1, records.total
450
+ end
451
+
452
+ def test_records_are_found_with_highlight
453
+ records = Book.find_by_solr "ruby", :highlight => { :fields => "name" }
454
+ assert_equal 1, records.total
455
+ end
456
+
457
+ def test_records_wiht_highlights_are_returned_properly
458
+ records = Book.find_by_solr "ruby", :highlight => { :fields => "name" }
459
+ expected = {"name"=>["<em>Ruby</em> for Dummies"]}
460
+ assert_equal expected, records.highlights.values.first
461
+ end
462
+
463
+ end