From 62f1d883af715a044c3095e790d4131108cb1333 Mon Sep 17 00:00:00 2001 From: Matchu Date: Fri, 28 Jul 2023 14:10:13 -0700 Subject: [PATCH] Improve not_occupied solution Not being a subquery is better! I realized later that a LEFT JOIN would probably do it even betterer? with like `HAVING count(x) = 0`? but the `left_outer_joins` method doesn't seem to be in Rails 4, and I don't want to do stringy joins, so this is fine for now! --- app/models/item.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/models/item.rb b/app/models/item.rb index 095340b3..2bbd918d 100644 --- a/app/models/item.rb +++ b/app/models/item.rb @@ -87,11 +87,15 @@ class Item < ActiveRecord::Base zone_ids = Zone.matching_label(zone_label, locale).map(&:id) i = Item.arel_table sa = SwfAsset.arel_table - psa = ParentSwfAssetRelationship.arel_table - subquery = SwfAsset.select('COUNT(*)').joins(:parent_swf_asset_relationships). - where(psa[:parent_type].eq('Item')).where(psa[:parent_id].eq(i[:id])). - where(sa[:zone_id].in(zone_ids)) - where("(#{subquery.to_sql}) = 0") + # Querying for "has NO swf_assets matching these zone IDs" is trickier than + # the positive case! To do it, we GROUP_CONCAT the zone_ids together for + # each item, then use FIND_IN_SET to search the result for each zone ID, + # and assert that it must not find a match. (This is uhh, not exactly fast, + # so it helps to have other tighter conditions applied first!) + # TODO: I feel like this could also be solved with a LEFT JOIN, idk if that + # performs any better? In Rails 5+ `left_outer_joins` is built in so! + condition = zone_ids.map { 'FIND_IN_SET(?, GROUP_CONCAT(zone_id)) = 0' }.join(' AND ') + joins(:swf_assets).group(i[:id]).having(condition, *zone_ids).distinct } scope :restricts, ->(zone_label, locale = I18n.locale) { zone_ids = Zone.matching_label(zone_label, locale).map(&:id)