forked from OpenNeo/impress
remove old item search interface
This commit is contained in:
parent
332a7e67d8
commit
94ecc6f02d
1 changed files with 0 additions and 242 deletions
|
@ -194,38 +194,6 @@ class Item < ActiveRecord::Base
|
||||||
Species.find(species_ids)
|
Species.find(species_ids)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.search(query, user, locale)
|
|
||||||
raise SearchError, "Please provide a search query" unless query
|
|
||||||
query = query.strip
|
|
||||||
raise SearchError, "Search queries should be at least 3 characters" if query.length < 3
|
|
||||||
query_conditions = [Condition.new]
|
|
||||||
in_phrase = false
|
|
||||||
query.each_char do |c|
|
|
||||||
if c == ' ' && !in_phrase
|
|
||||||
query_conditions << Condition.new
|
|
||||||
elsif c == '"'
|
|
||||||
in_phrase = !in_phrase
|
|
||||||
elsif c == ':' && !in_phrase
|
|
||||||
query_conditions.last.to_filter!
|
|
||||||
elsif c == '-' && !in_phrase && query_conditions.last.empty?
|
|
||||||
query_conditions.last.negate!
|
|
||||||
else
|
|
||||||
query_conditions.last << c
|
|
||||||
end
|
|
||||||
end
|
|
||||||
limited_filters_used = []
|
|
||||||
query_conditions.inject(self.with_translations(locale)) do |scope, condition|
|
|
||||||
if condition.filter? && LimitedSearchFilters.include?(condition.filter)
|
|
||||||
if limited_filters_used.include?(condition.filter)
|
|
||||||
raise SearchError, "The #{condition.filter} filter is complex; please only use one per search. Thanks!"
|
|
||||||
else
|
|
||||||
limited_filters_used << condition.filter
|
|
||||||
end
|
|
||||||
end
|
|
||||||
condition.narrow(scope, user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def as_json(options = {})
|
def as_json(options = {})
|
||||||
{
|
{
|
||||||
:description => description,
|
:description => description,
|
||||||
|
@ -709,214 +677,4 @@ class Item < ActiveRecord::Base
|
||||||
class SpiderHTTPError < SpiderError;end
|
class SpiderHTTPError < SpiderError;end
|
||||||
class SpiderJSONError < SpiderError;end
|
class SpiderJSONError < SpiderError;end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
SearchFilterScopes = []
|
|
||||||
LimitedSearchFilters = []
|
|
||||||
|
|
||||||
def self.search_filter(name, options={}, &block)
|
|
||||||
assume_complement = options.delete(:assume_complement) || true
|
|
||||||
name = name.to_s
|
|
||||||
SearchFilterScopes << name
|
|
||||||
LimitedSearchFilters << name if options[:limit]
|
|
||||||
|
|
||||||
(class << self; self; end).instance_eval do
|
|
||||||
if options[:full]
|
|
||||||
define_method "search_filter_#{name}", &options[:full]
|
|
||||||
else
|
|
||||||
if assume_complement
|
|
||||||
define_method "search_filter_not_#{name}", &Item.search_filter_block(options, false, &block)
|
|
||||||
end
|
|
||||||
define_method "search_filter_#{name}", &Item.search_filter_block(options, true, &block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.single_search_filter(name, options={}, &block)
|
|
||||||
options[:assume_complement] = false
|
|
||||||
search_filter name, options, &block
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.search_filter_block(options, positive, &block)
|
|
||||||
Proc.new { |str, user, scope|
|
|
||||||
condition = block.arity == 1 ? block.call(str) : block.call(str, user)
|
|
||||||
unless positive
|
|
||||||
condition = condition.to_sql if condition.respond_to?(:to_sql)
|
|
||||||
condition = "!(#{condition})"
|
|
||||||
end
|
|
||||||
scope = scope.send(options[:scope]) if options[:scope]
|
|
||||||
scope.where(condition)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
search_filter :name do |name|
|
|
||||||
Item::Translation.arel_table[:name].matches("%#{name}%")
|
|
||||||
end
|
|
||||||
|
|
||||||
search_filter :description do |description|
|
|
||||||
Item::Translation.arel_table[:description].matches("%#{description}%")
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.adjective_filters
|
|
||||||
@adjective_filters ||= {
|
|
||||||
'nc' => arel_table[:rarity_index].in(NCRarities),
|
|
||||||
'pb' => arel_table[:description].eq(PAINTBRUSH_SET_DESCRIPTION)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
search_filter :is do |adjective|
|
|
||||||
filter = adjective_filters[adjective]
|
|
||||||
unless filter
|
|
||||||
raise SearchError,
|
|
||||||
"We don't know how an item can be \"#{adjective}\". " +
|
|
||||||
"Did you mean is:nc or is:pb?"
|
|
||||||
end
|
|
||||||
filter
|
|
||||||
end
|
|
||||||
|
|
||||||
USER_ADJECTIVES = {
|
|
||||||
'own' => true,
|
|
||||||
'owns' => true,
|
|
||||||
'owned' => true,
|
|
||||||
'want' => false,
|
|
||||||
'wants' => false,
|
|
||||||
'wanted' => false,
|
|
||||||
'all' => nil,
|
|
||||||
'items' => nil
|
|
||||||
}
|
|
||||||
def self.parse_user_adjective(adjective, user)
|
|
||||||
unless USER_ADJECTIVES.has_key?(adjective)
|
|
||||||
raise SearchError, "We don't understand user:#{adjective}. " +
|
|
||||||
"Find items you own with user:owns, items you want with user:wants, or " +
|
|
||||||
"both with user:all"
|
|
||||||
end
|
|
||||||
|
|
||||||
unless user
|
|
||||||
raise SearchError, "It looks like you're not logged in, so you don't own any items."
|
|
||||||
end
|
|
||||||
|
|
||||||
USER_ADJECTIVES[adjective]
|
|
||||||
end
|
|
||||||
|
|
||||||
search_filter :user do |adjective, user|
|
|
||||||
# Though joins may seem more efficient here for the positive case, we need
|
|
||||||
# to be able to handle cases like "user:owns user:wants", which breaks on
|
|
||||||
# the JOIN approach. Just have to look up the IDs in advance.
|
|
||||||
|
|
||||||
owned_value = parse_user_adjective(adjective, user)
|
|
||||||
hangers = ClosetHanger.arel_table
|
|
||||||
items = user.closeted_items
|
|
||||||
items = items.where(ClosetHanger.arel_table[:owned].eq(owned_value)) unless owned_value.nil?
|
|
||||||
item_ids = items.map(&:id)
|
|
||||||
# Though it's best to do arel_table[:id].in(item_ids), it breaks in this
|
|
||||||
# version of Arel, and other conditions will overwrite this one. Since IDs
|
|
||||||
# are guaranteed to be integers, let's just build our own string condition
|
|
||||||
# and be done with it.
|
|
||||||
|
|
||||||
if item_ids.empty?
|
|
||||||
raise SearchError, "You don't #{ClosetHanger.verb :you, owned_value} " +
|
|
||||||
"any items yet. Head to Your Items to add some!"
|
|
||||||
end
|
|
||||||
|
|
||||||
arel_table[:id].in(item_ids)
|
|
||||||
end
|
|
||||||
|
|
||||||
search_filter :only do |species_name|
|
|
||||||
begin
|
|
||||||
id = Species.require_by_name(species_name).id
|
|
||||||
rescue Species::NotFound => e
|
|
||||||
raise SearchError, e.message
|
|
||||||
end
|
|
||||||
arel_table[:species_support_ids].eq(id.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
search_filter :species do |species_name|
|
|
||||||
begin
|
|
||||||
id = Species.require_by_name(species_name).id
|
|
||||||
rescue Species::NotFound => e
|
|
||||||
raise SearchError, e.message
|
|
||||||
end
|
|
||||||
ids = arel_table[:species_support_ids]
|
|
||||||
ids.eq('').or(ids.matches_any([
|
|
||||||
id,
|
|
||||||
"#{id},%",
|
|
||||||
"%,#{id},%",
|
|
||||||
"%,#{id}"
|
|
||||||
]))
|
|
||||||
end
|
|
||||||
|
|
||||||
single_search_filter :type, {:limit => true, :scope => :join_swf_assets} do |zone_set_name|
|
|
||||||
zone_set = Zone.find_set(zone_set_name)
|
|
||||||
raise SearchError, "Type \"#{zone_set_name}\" does not exist" unless zone_set
|
|
||||||
SwfAsset.arel_table[:zone_id].in(zone_set.map(&:id))
|
|
||||||
end
|
|
||||||
|
|
||||||
single_search_filter :not_type, :full => lambda { |zone_set_name, user, scope|
|
|
||||||
zone_set = Zone::ItemZoneSets[zone_set_name]
|
|
||||||
raise SearchError, "Type \"#{zone_set_name}\" does not exist" unless zone_set
|
|
||||||
psa = ParentSwfAssetRelationship.arel_table.alias
|
|
||||||
sa = SwfAsset.arel_table.alias
|
|
||||||
# Join to SWF assets, including the zone condition in the join so that
|
|
||||||
# SWFs that don't match end up being NULL rows. Then we take the max SWF
|
|
||||||
# asset ID, which is NULL if and only if there are no rows that matched
|
|
||||||
# the zone requirement. If that max was NULL, return the object.
|
|
||||||
item_ids = select(arel_table[:id]).joins(
|
|
||||||
"LEFT JOIN #{ParentSwfAssetRelationship.table_name} #{psa.name} ON " +
|
|
||||||
psa[:parent_type].eq(self.name).
|
|
||||||
and(psa[:parent_id].eq(arel_table[:id])).
|
|
||||||
to_sql
|
|
||||||
).
|
|
||||||
joins(
|
|
||||||
"LEFT JOIN #{SwfAsset.table_name} #{sa.name} ON " +
|
|
||||||
sa[:type].eq(SwfAssetType).
|
|
||||||
and(sa[:id].eq(psa[:swf_asset_id])).
|
|
||||||
and(sa[:zone_id].in(zone_set.map(&:id))).
|
|
||||||
to_sql
|
|
||||||
).
|
|
||||||
group("#{table_name}.id").
|
|
||||||
having("MAX(#{sa.name}.id) IS NULL"). # SwfAsset.arel_table[:id].maximum has no #eq
|
|
||||||
map(&:id)
|
|
||||||
scope.where(arel_table[:id].in(item_ids))
|
|
||||||
}
|
|
||||||
|
|
||||||
class Condition < String
|
|
||||||
attr_accessor :filter
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@positive = true
|
|
||||||
end
|
|
||||||
|
|
||||||
def filter?
|
|
||||||
!@filter.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_filter!
|
|
||||||
@filter = self.clone
|
|
||||||
self.replace ''
|
|
||||||
end
|
|
||||||
|
|
||||||
def negate!
|
|
||||||
@positive = !@positive
|
|
||||||
end
|
|
||||||
|
|
||||||
def narrow(scope, user)
|
|
||||||
if SearchFilterScopes.include?(filter)
|
|
||||||
polarized_filter = @positive ? filter : "not_#{filter}"
|
|
||||||
Item.send("search_filter_#{polarized_filter}", self, user, scope)
|
|
||||||
else
|
|
||||||
raise SearchError, "Filter #{filter} does not exist"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def filter
|
|
||||||
@filter || 'name'
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
@filter ? "#{@filter}:#{super}" : super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class SearchError < ArgumentError;end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue