lib/sup/index.rb in sup-0.2 vs lib/sup/index.rb in sup-0.3

- old
+ new

@@ -1,10 +1,16 @@ ## the index structure for redwood. interacts with ferret. -require 'thread' require 'fileutils' require 'ferret' +begin + require 'chronic' + $have_chronic = true +rescue LoadError => e + Redwood::log "optional 'chronic' library not found (run 'gem install chronic' to install)" + $have_chronic = false +end module Redwood class Index class LockError < StandardError @@ -16,10 +22,11 @@ end include Singleton attr_reader :index + alias ferret index def initialize dir=BASE_DIR @dir = dir @sources = {} @sources_dirty = false @@ -44,11 +51,11 @@ raise LockError, @lock.lockinfo_on_disk end end def start_lock_update_thread - @lock_update_thread = Redwood::reporting_thread do + @lock_update_thread = Redwood::reporting_thread("lock update") do while true sleep 30 @lock.touch_yourself end end @@ -110,12 +117,12 @@ end def add_source source raise "duplicate source!" if @sources.include? source @sources_dirty = true - source.id ||= @sources.size - ##TODO: why was this necessary? + max = @sources.max_of { |id, s| s.is_a?(DraftLoader) || s.is_a?(SentLoader) ? 0 : id } + source.id ||= (max || 0) + 1 ##source.id += 1 while @sources.member? source.id @sources[source.id] = source end def source_for uri; @sources.values.find { |s| s.is_source_for? uri }; end @@ -169,11 +176,11 @@ :source_id => source_id, :source_info => m.source_info, :date => m.date.to_indexable_s, :body => m.content, :snippet => m.snippet, - :label => m.labels.join(" "), + :label => m.labels.uniq.join(" "), :from => m.from ? m.from.email : "", :to => (m.to + m.cc + m.bcc).map { |x| x.email }.join(" "), :subject => wrap_subj(Message.normalize_subj(m.subj)), :refs => (m.refs + m.replytos).uniq.join(" "), } @@ -254,17 +261,19 @@ else pending = [m.id] end until pending.empty? || (opts[:limit] && messages.size >= opts[:limit]) - id = pending.pop - next if searched.member? id - searched[id] = true q = Ferret::Search::BooleanQuery.new true - q.add_query Ferret::Search::TermQuery.new(:message_id, id), :should - q.add_query Ferret::Search::TermQuery.new(:refs, id), :should + pending.each do |id| + searched[id] = true + q.add_query Ferret::Search::TermQuery.new(:message_id, id), :should + q.add_query Ferret::Search::TermQuery.new(:refs, id), :should + end + pending = [] + q = build_query :qobj => q num_queries += 1 killed = false @index.search_each(q, :limit => :all) do |docid, score| @@ -276,14 +285,15 @@ mid = @index[docid][:message_id] unless messages.member?(mid) #Redwood::log "got #{mid} as a child of #{id}" messages[mid] ||= lambda { build_message docid } refs = @index[docid][:refs].split(" ") - pending += refs + pending += refs.select { |id| !searched[id] } end end end + if killed Redwood::log "thread for #{m.id} is killed, ignoring" false else Redwood::log "ran #{num_queries} queries to build thread of #{messages.size + 1} messages for #{m.id}: #{m.subj}" if num_queries > 0 @@ -368,21 +378,49 @@ index.search(q, :limit => 1).total_hits > 0 end protected + ## do any specialized parsing + ## returns nil and flashes error message if parsing failed def parse_user_query_string str - str2 = str.gsub(/(to|from):(\S+)/) do + result = str.gsub(/\b(to|from):(\S+)\b/) do field, name = $1, $2 if(p = ContactManager.contact_for(name)) [field, p.email] else [field, name] end.join(":") end - Redwood::log "translated #{str} to #{str2}" unless str2 == str - @qparser.parse str2 + if $have_chronic + chronic_failure = false + result = result.gsub(/\b(before|on|in|after):(\((.+?)\)\B|(\S+)\b)/) do + break if chronic_failure + field, datestr = $1, ($3 || $4) + realdate = Chronic.parse(datestr, :guess => false, :context => :none) + if realdate + case field + when "after" + Redwood::log "chronic: translated #{field}:#{datestr} to #{realdate.end}" + "date:(>= #{sprintf "%012d", realdate.end.to_i})" + when "before" + Redwood::log "chronic: translated #{field}:#{datestr} to #{realdate.begin}" + "date:(<= #{sprintf "%012d", realdate.begin.to_i})" + else + Redwood::log "chronic: translated #{field}:#{datestr} to #{realdate}" + "date:(<= #{sprintf "%012d", realdate.end.to_i}) date:(>= #{sprintf "%012d", realdate.begin.to_i})" + end + else + BufferManager.flash "Don't understand date #{datestr.inspect}!" + chronic_failure = true + end + end + result = nil if chronic_failure + end + + Redwood::log "translated #{str.inspect} to #{result}" unless result == str + @qparser.parse result if result end def build_query opts query = Ferret::Search::BooleanQuery.new query.add_query opts[:qobj], :must if opts[:qobj]