aboutsummaryrefslogtreecommitdiffstats
path: root/app/models/tweet.rb
diff options
context:
space:
mode:
authorRhenium <rhenium@rhe.jp>2014-01-19 13:13:39 +0900
committerRhenium <rhenium@rhe.jp>2014-01-19 13:13:39 +0900
commit1be52291bfb5ab37e4dddfc71e9cd97d477b8517 (patch)
treee46ef410ee9902d4da87935eb73ede4b1c911e62 /app/models/tweet.rb
parent6897d802857ec6fafe28779cb171be6b71b684a6 (diff)
downloadaclog-1be52291bfb5ab37e4dddfc71e9cd97d477b8517.tar.gz
rename search to filter
Diffstat (limited to 'app/models/tweet.rb')
-rw-r--r--app/models/tweet.rb87
1 files changed, 35 insertions, 52 deletions
diff --git a/app/models/tweet.rb b/app/models/tweet.rb
index d5ad222..ff826b9 100644
--- a/app/models/tweet.rb
+++ b/app/models/tweet.rb
@@ -90,26 +90,44 @@ class Tweet < ActiveRecord::Base
return nil
end
- def self.parse_query(query)
- str = query.dup
+ def self.filter_by_query(query)
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)
+ query.gsub!(/"((?:\\"|[^"])*?)"/) {|m| strings << $1; "##{strings.size - 1}" }
+
+ escape_text = -> str do
+ str.gsub(/#(\d+)/) { strings[$1.to_i] }
+ .gsub("%", "\\%")
+ .gsub("*", "%")
+ .gsub("_", "\\_")
+ .gsub("?", "_")
+ end
+
+ parse_condition = ->(scoped, token) do
+ p positive = !token.slice!(/^[-!]/)
+
+ where_args = case token
+ when /^(?:user|from):([A-Za-z0-9_]{1,20})$/
+ u = User.find_by(screen_name: $1)
+ uid = u && u.id || -1
+ { user_id: uid }
+ when /^fav(?:orite)?s?:(\d+)$/
+ ["favorites_count >= ?", $1.to_i]
+ when /^(?:retweet|rt)s?:(\d+)$/
+ ["retweets_count >= ?", $1.to_i]
+ when /^(?:sum|(?:re)?act(?:ion)?s?):(\d+)$/
+ ["reactions_count >= ?", $1.to_i]
+ when /^(?:source|via):(.+)$/
+ ["source LIKE ?", escape_text.call($1)]
+ when /^text:(.+)$/
+ ["text LIKE ?", "%" + escape_text.call($1) + "%"]
+ else
+ nil
+ end
+
+ positive ? scoped.where(where_args) : scoped.where.not(where_args)
end
- where(conv.call(str))
+ query.scan(/\S+/).inject(self.scoped) {|s, token| parse_condition.call(s, token) }
end
private
@@ -138,41 +156,6 @@ class Tweet < ActiveRecord::Base
result
end
- 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_min(Date.parse($1)))
- when /^-?until:(\d{4}(-?)\d{2}\2\d{2})$/
- tweets[:id].__send__(positive ? :lt : :gteq, snowflake_min(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[:reactions_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.snowflake_min(time)
(time.to_datetime.to_i * 1000 - 1288834974657) << 22
end