From fd87b41c172110396e43e4132e7b7f3981a3dc63 Mon Sep 17 00:00:00 2001 From: Matchu Date: Sat, 29 Jul 2023 12:48:45 -0700 Subject: [PATCH] Oops, add unowned & unwanted support to search! Uhhh idk how I messed this up, but right, wanting is not the opposite of owning, LOL! --- app/models/item/search/query.rb | 19 +++++++++++---- app/models/user.rb | 41 ++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/app/models/item/search/query.rb b/app/models/item/search/query.rb index a3751851..67dcf2a8 100644 --- a/app/models/item/search/query.rb +++ b/app/models/item/search/query.rb @@ -66,9 +66,12 @@ class Item case value when 'owns' filters << (is_positive ? - Filter.user_owns(user) : - Filter.user_wants(user)) + Filter.owned_by(user) : + Filter.not_owned_by(user)) when 'wants' + filters << (is_positive ? + Filter.wanted_by(user) : + Filter.not_wanted_by(user)) else message = I18n.translate('items.search.errors.not_found.ownership', keyword: value) @@ -167,14 +170,22 @@ class Item self.new Item.not_fits(body_id), "-fits:#{value}" end - def self.user_owns(user) + def self.owned_by(user) self.new user.owned_items, 'user:owns' end - def self.user_wants(user) + def self.not_owned_by(user) + self.new user.unowned_items, 'user:owns' + end + + def self.wanted_by(user) self.new user.wanted_items, 'user:wants' end + def self.not_wanted_by(user) + self.new user.unwanted_items, 'user:wants' + end + def self.is_nc self.new Item.is_nc, 'is:nc' end diff --git a/app/models/user.rb b/app/models/user.rb index 5d3df686..dea2df2c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,13 +7,17 @@ class User < ActiveRecord::Base has_many :closet_hangers has_many :closet_lists has_many :closeted_items, through: :closet_hangers, source: :item + has_many :contributions + has_many :neopets_connections + has_many :outfits + + # TODO: When `owned_items` and `wanted_items` are merged, they override one + # another instead of correctly returning an empty set. Is this a Rails bug + # that gets fixed down the line once we finish upgrading, or...? has_many :owned_items, -> { where(ClosetHanger.arel_table[:owned].eq(true)) }, through: :closet_hangers, source: :item has_many :wanted_items, -> { where(ClosetHanger.arel_table[:owned].eq(false)) }, through: :closet_hangers, source: :item - has_many :contributions - has_many :neopets_connections - has_many :outfits belongs_to :contact_neopets_connection, class_name: 'NeopetsConnection' @@ -25,6 +29,37 @@ class User < ActiveRecord::Base name == 'matchu' # you know that's right. end + def unowned_items + # Join all items against our owned closet hangers, group by item ID, then + # only return those with zero matching hangers. + # + # TODO: It'd be nice to replace this with a `left_outer_joins` call in + # Rails 5+, but these conditions really do need to be part of the join: + # if we do them as a `where`, they prevent unmatching items from being + # returned in the first place. + # + # TODO: This crashes the query when combined with `unwanted_items`. + ch = ClosetHanger.arel_table.alias("owned_hangers") + Item. + joins( + "LEFT JOIN closet_hangers owned_hangers ON owned_hangers.item_id = items.id " + + "AND #{ch[:user_id].eq(self.id).to_sql} AND owned_hangers.owned = true" + ). + group("items.id").having("COUNT(owned_hangers.id) = 0") + end + + def unwanted_items + # See `unowned_items` above! We just change the `true` to `false`. + # TODO: This crashes the query when combined with `unowned_items`. + ch = ClosetHanger.arel_table.alias("wanted_hangers") + Item. + joins( + "LEFT JOIN closet_hangers wanted_hangers ON wanted_hangers.item_id = items.id " + + "AND #{ch[:user_id].eq(self.id).to_sql} AND wanted_hangers.owned = false" + ). + group("items.id").having("COUNT(wanted_hangers.id) = 0") + end + def contribute!(pet) new_contributions = [] pet.contributables.each do |contributable|