summaryrefslogtreecommitdiff
path: root/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/collection.rb
diff options
context:
space:
mode:
authorhukl <contact@smyck.org>2009-04-28 00:15:53 +0200
committerhukl <contact@smyck.org>2009-05-01 17:14:02 +0200
commit4bd16f053847f2efe347ebda9136ef2233ee0d2c (patch)
treef4c11f89455de991c8d87726d5757b752e7129e2 /vendor/plugins/thinking-sphinx/lib/thinking_sphinx/collection.rb
parentd3a9b46ba5c863a0ff377dcffae9a494fe476e02 (diff)
added thinking_sphinx plugin for fulltext search on nodes and heads
Diffstat (limited to 'vendor/plugins/thinking-sphinx/lib/thinking_sphinx/collection.rb')
-rw-r--r--vendor/plugins/thinking-sphinx/lib/thinking_sphinx/collection.rb147
1 files changed, 147 insertions, 0 deletions
diff --git a/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/collection.rb b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/collection.rb
new file mode 100644
index 0000000..406c2ae
--- /dev/null
+++ b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/collection.rb
@@ -0,0 +1,147 @@
1module ThinkingSphinx
2 class Collection < ::Array
3 attr_reader :total_entries, :total_pages, :current_page, :per_page
4 attr_accessor :results
5
6 # Compatibility with older versions of will_paginate
7 alias_method :page_count, :total_pages
8
9 def initialize(page, per_page, entries, total_entries)
10 @current_page, @per_page, @total_entries = page, per_page, total_entries
11
12 @total_pages = (entries / @per_page.to_f).ceil
13 end
14
15 def self.ids_from_results(results, page, limit, options)
16 collection = self.new(page, limit,
17 results[:total] || 0, results[:total_found] || 0
18 )
19 collection.results = results
20 collection.replace results[:matches].collect { |match|
21 match[:attributes]["sphinx_internal_id"]
22 }
23 return collection
24 end
25
26 def self.create_from_results(results, page, limit, options)
27 collection = self.new(page, limit,
28 results[:total] || 0, results[:total_found] || 0
29 )
30 collection.results = results
31 collection.replace instances_from_matches(results[:matches], options)
32 return collection
33 end
34
35 def self.instances_from_matches(matches, options = {})
36 if klass = options[:class]
37 instances_from_class klass, matches, options
38 else
39 instances_from_classes matches, options
40 end
41 end
42
43 def self.instances_from_class(klass, matches, options = {})
44 index_options = klass.sphinx_index_options
45
46 ids = matches.collect { |match| match[:attributes]["sphinx_internal_id"] }
47 instances = ids.length > 0 ? klass.find(
48 :all,
49 :conditions => {klass.primary_key.to_sym => ids},
50 :include => (options[:include] || index_options[:include]),
51 :select => (options[:select] || index_options[:select]),
52 :order => (options[:sql_order] || index_options[:sql_order])
53 ) : []
54
55 # Raise an exception if we find records in Sphinx but not in the DB, so
56 # the search method can retry without them. See
57 # ThinkingSphinx::Search.retry_search_on_stale_index.
58 if options[:raise_on_stale] && instances.length < ids.length
59 stale_ids = ids - instances.map {|i| i.id }
60 raise StaleIdsException, stale_ids
61 end
62
63 # if the user has specified an SQL order, return the collection
64 # without rearranging it into the Sphinx order
65 return instances if options[:sql_order]
66
67 ids.collect { |obj_id|
68 instances.detect { |obj| obj.id == obj_id }
69 }
70 end
71
72 # Group results by class and call #find(:all) once for each group to reduce
73 # the number of #find's in multi-model searches.
74 #
75 def self.instances_from_classes(matches, options = {})
76 groups = matches.group_by { |match| match[:attributes]["class_crc"] }
77 groups.each do |crc, group|
78 group.replace(
79 instances_from_class(class_from_crc(crc), group, options)
80 )
81 end
82
83 matches.collect do |match|
84 groups.detect { |crc, group|
85 crc == match[:attributes]["class_crc"]
86 }[1].detect { |obj|
87 obj.id == match[:attributes]["sphinx_internal_id"]
88 }
89 end
90 end
91
92 def self.class_from_crc(crc)
93 @@models_by_crc ||= ThinkingSphinx.indexed_models.inject({}) do |hash, model|
94 hash[model.constantize.to_crc32] = model
95 model.constantize.subclasses.each { |subclass|
96 hash[subclass.to_crc32] = subclass.name
97 }
98 hash
99 end
100 @@models_by_crc[crc].constantize
101 end
102
103 def previous_page
104 current_page > 1 ? (current_page - 1) : nil
105 end
106
107 def next_page
108 current_page < total_pages ? (current_page + 1): nil
109 end
110
111 def offset
112 (current_page - 1) * @per_page
113 end
114
115 def method_missing(method, *args, &block)
116 super unless method.to_s[/^each_with_.*/]
117
118 each_with_attribute method.to_s.gsub(/^each_with_/, ''), &block
119 end
120
121 def each_with_groupby_and_count(&block)
122 results[:matches].each_with_index do |match, index|
123 yield self[index], match[:attributes]["@groupby"], match[:attributes]["@count"]
124 end
125 end
126
127 def each_with_attribute(attribute, &block)
128 results[:matches].each_with_index do |match, index|
129 yield self[index], (match[:attributes][attribute] || match[:attributes]["@#{attribute}"])
130 end
131 end
132
133 def each_with_weighting(&block)
134 results[:matches].each_with_index do |match, index|
135 yield self[index], match[:weight]
136 end
137 end
138
139 def inject_with_groupby_and_count(initial = nil, &block)
140 index = -1
141 results[:matches].inject(initial) do |memo, match|
142 index += 1
143 yield memo, self[index], match[:attributes]["@groupby"], match[:attributes]["@count"]
144 end
145 end
146 end
147end