diff --git a/app/models/item.rb b/app/models/item.rb index e7dc8f8c..369fb136 100644 --- a/app/models/item.rb +++ b/app/models/item.rb @@ -30,8 +30,6 @@ class Item < ActiveRecord::Base order(it[:name]) } - scope :join_swf_assets, -> { joins(:swf_assets).group(arel_table[:id]) } - scope :newest, -> { order(arel_table[:created_at].desc) if arel_table[:created_at] } @@ -77,6 +75,22 @@ class Item < ActiveRecord::Base where('description NOT LIKE ?', '%' + Item.sanitize_sql_like(PAINTBRUSH_SET_DESCRIPTION) + '%') } + scope :occupies, ->(zone_label, locale = I18n.locale) { + zone_ids = Zone.matching_label(zone_label, locale).map(&:id) + i = Item.arel_table + sa = SwfAsset.arel_table + Item.joins(:swf_assets).where(sa[:zone_id].in(zone_ids)).distinct + } + scope :not_occupies, ->(zone_label, locale = I18n.locale) { + # TODO: The perf on this is miserable on its own, the query plan chooses + # a bad index for the join on parents_swf_assets here (but not in the + # `occupies` scope?) and I don't know why! But it makes a better plan when + # combined with `name_includes` so this is probably fine in practice? + zone_ids = Zone.matching_label(zone_label, locale).map(&:id) + i = Item.arel_table + sa = SwfAsset.arel_table + Item.joins(:swf_assets).where(sa[:zone_id].not_in(zone_ids)).distinct + } def closeted? @owned || @wanted diff --git a/app/models/item/search/query.rb b/app/models/item/search/query.rb index 6bb41f64..c0b3f167 100644 --- a/app/models/item/search/query.rb +++ b/app/models/item/search/query.rb @@ -38,6 +38,10 @@ class Item filters << (is_positive ? Filter.name_includes(value, locale) : Filter.name_excludes(value, locale)) + when 'occupies' + filters << (is_positive ? + Filter.occupies(value, locale) : + Filter.not_occupies(value, locale)) when 'is' case value when 'nc' @@ -101,6 +105,14 @@ class Item self.new Item.name_excludes(value, locale), text end + def self.occupies(value, locale) + self.new Item.occupies(value, locale), "occupies:#{value}" + end + + def self.not_occupies(value, locale) + self.new Item.not_occupies(value, locale), "-occupies:#{value}" + end + def self.is_nc self.new Item.is_nc, 'is:nc' end diff --git a/app/models/zone.rb b/app/models/zone.rb index b29312ab..af668f74 100644 --- a/app/models/zone.rb +++ b/app/models/zone.rb @@ -9,11 +9,11 @@ class Zone < ActiveRecord::Base with_translations(I18n.locale).order(Zone::Translation.arel_table[:label]) } scope :includes_translations, -> { includes(:translations) } - scope :with_plain_label, ->(label) { + scope :matching_label, ->(label, locale = I18n.locale) { t = Zone::Translation.arel_table - includes(:translations) + joins(:translations) + .where(t[:locale].eq(locale)) .where(t[:plain_label].eq(Zone.plainify_label(label))) - .where(t[:locale].eq(I18n.locale)) } scope :for_items, -> { where(arel_table[:type_id].gt(1)) }