diff options
author | rhenium <re4k@re4k.info> | 2013-06-01 00:22:57 +0900 |
---|---|---|
committer | rhenium <re4k@re4k.info> | 2013-06-01 00:22:57 +0900 |
commit | e1b34a2234a7ff30c30f643d59b73c610372a8c0 (patch) | |
tree | 244c31c964f4579049a9c2a692a42cec17d6d109 | |
parent | cf51cb4bb07ccd6cfc17d0ee9d22377cc1ea9fc9 (diff) | |
download | aclog-e1b34a2234a7ff30c30f643d59b73c610372a8c0.tar.gz |
move parse_query to Tweet model
-rw-r--r-- | app/controllers/search_controller.rb | 59 | ||||
-rw-r--r-- | app/models/tweet.rb | 57 |
2 files changed, 58 insertions, 58 deletions
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 6cb5014..0ed404a 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -3,63 +3,6 @@ class SearchController < ApplicationController def search @caption = "search" - @tweets = Tweet.where(parse_query(params[:query] || "")).reacted.recent(7).order_by_id.list(params, force_page: true) - end - - private - def parse_query(input) - str = input.dup - strings = [] - str.gsub!(/"((?:\\"|[^"])*?)"/) {|m| strings << $1; "##{strings.size - 1}" } - groups = [] - while str.sub!(/\(([^()]*?)\)/) {|m| groups << $1; " $#{groups.size - 1} " }; end - - conv = -> s do - s.scan(/\S+(?: +OR +\S+)*/).map {|co| - co.split(/ +OR +/).map {|token| - if /^\$(\d+)$/ =~ token - conv.call(groups[$1.to_i]) - else - parse_condition(token, strings) - end - }.inject(&:or) - }.inject(&:and) - end - conv.call(str) - end - - def parse_condition(token, strings) - tweets = Tweet.arel_table - escape_text = -> str do - str.gsub(/#(\d+)/) { strings[$1.to_i] } - .gsub("%", "\\%") - .gsub("*", "%") - .gsub("_", "\\_") - .gsub("?", "_") - end - - positive = token[0] != "-" - case token - when /^-?(?:user|from):([A-Za-z0-9_]{1,20})$/ - u = User.find_by(screen_name: $1) - uid = u && u.id || 0 - tweets[:user_id].__send__(positive ? :eq :not_eq, uid) - when /^-?since:(\d{4}(-?)\d{2}\2\d{2})$/ - tweets[:id].__send__(positive ? :gteq : :lt, snowflake(Date.parse($1))) - when /^-?until:(\d{4}(-?)\d{2}\2\d{2})$/ - tweets[:id].__send__(positive ? :lt : :gteq, snowflake(Date.parse($1) + 1)) - when /^-?favs?:(\d+)$/ - tweets[:favorites_count].__send__(positive ? :gteq : :lt, $1.to_i) - when /^-?rts?:(\d+)$/ - tweets[:retweets_count].__send__(positive ? :gteq : :lt, $1.to_i) - when /^-?(?:sum|reactions?):(\d+)$/ - (tweets[:favorites_count] + tweets[:retweets_count]).__send__(positive ? :gteq : :lt, $1.to_i) - when /^(?:source|via):(.+)$/ - source_text = "<url:%:#{escape_text.call($1).gsub(":", "%3A")}>" - tweets[:source].__send__(positive ? :matches : :does_not_match, source_text) - else - search_text = escape_text.call(positive ? token : token[1..-1]) - tweets[:text].__send__(positive ? :matches : :does_not_match, "%#{search_text}%") - end + @tweets = Tweet.recent(7).parse_query(params[:query] || "").reacted.order_by_id.list(params, force_page: true) end end diff --git a/app/models/tweet.rb b/app/models/tweet.rb index dd7d0bc..602fdaa 100644 --- a/app/models/tweet.rb +++ b/app/models/tweet.rb @@ -92,7 +92,64 @@ class Tweet < ActiveRecord::Base end end + def self.parse_query(query) + str = query.dup + strings = [] + str.gsub!(/"((?:\\"|[^"])*?)"/) {|m| strings << $1; "##{strings.size - 1}" } + groups = [] + while str.sub!(/\(([^()]*?)\)/) {|m| groups << $1; " $#{groups.size - 1} " }; end + + conv = -> s do + s.scan(/\S+(?: +OR +\S+)*/).map {|co| + co.split(/ +OR +/).map {|token| + if /^\$(\d+)$/ =~ token + conv.call(groups[$1.to_i]) + else + parse_condition(token, strings) + end + }.inject(&:or) + }.inject(&:and) + end + + where(conv.call(str)) + end + private + def self.parse_condition(token, strings) + tweets = Tweet.arel_table + escape_text = -> str do + str.gsub(/#(\d+)/) { strings[$1.to_i] } + .gsub("%", "\\%") + .gsub("*", "%") + .gsub("_", "\\_") + .gsub("?", "_") + end + + positive = token[0] != "-" + case token + when /^-?(?:user|from):([A-Za-z0-9_]{1,20})$/ + u = User.find_by(screen_name: $1) + uid = u && u.id || 0 + tweets[:user_id].__send__(positive ? :eq :not_eq, uid) + when /^-?since:(\d{4}(-?)\d{2}\2\d{2})$/ + tweets[:id].__send__(positive ? :gteq : :lt, snowflake(Date.parse($1))) + when /^-?until:(\d{4}(-?)\d{2}\2\d{2})$/ + tweets[:id].__send__(positive ? :lt : :gteq, snowflake(Date.parse($1) + 1)) + when /^-?favs?:(\d+)$/ + tweets[:favorites_count].__send__(positive ? :gteq : :lt, $1.to_i) + when /^-?rts?:(\d+)$/ + tweets[:retweets_count].__send__(positive ? :gteq : :lt, $1.to_i) + when /^-?(?:sum|reactions?):(\d+)$/ + (tweets[:favorites_count] + tweets[:retweets_count]).__send__(positive ? :gteq : :lt, $1.to_i) + when /^(?:source|via):(.+)$/ + source_text = "<url:%:#{escape_text.call($1).gsub(":", "%3A")}>" + tweets[:source].__send__(positive ? :matches : :does_not_match, source_text) + else + search_text = escape_text.call(positive ? token : token[1..-1]) + tweets[:text].__send__(positive ? :matches : :does_not_match, "%#{search_text}%") + end + end + def self.cache_list(expires_in) key = "tweets/#{scoped.to_sql}" ids = Rails.cache.read(key) |