-- 120_restore_partial_active_indexes.sql
-- Fixes #1398: restore WHERE is_active = true predicate on 3 composite listings indexes
-- that were de-partialized by 097_index_hygiene.sql on the false premise that
-- is_active is 100% true.  104_index_hygiene_geom_dedup.sql explicitly acknowledges the
-- premise is stale (prod 2026-06-13: 19312 active / 39115 total, ~49% active), but
-- only dropped the redundant geom duplicate -- the composite indexes were left full.
--
-- Indexes restored with WHERE is_active = true predicate:
--   1. listings_active_filter_idx  (rooms, price_rub, area_m2, scraped_at DESC)
--   2. listings_house_price_idx    (house_id_fk, price_rub)
--   3. listings_rooms_area_idx     (rooms, area_m2)
--
-- These indexes directly back the estimator hot-path (estimator.py _COMMON_WHERE:
--   AND rooms = :rooms  AND area_m2 BETWEEN ...  AND is_active = true  AND price_rub > 0)
-- and asking_to_sold_ratio.py, which always filters is_active = true.
-- Restoring the predicate excludes ~51% inactive rows from the index, making it
-- roughly half the size and allowing index-only scans on active-only queries.
--
-- Excluded from restore:
--   listings_geom_active_idx  -- dropped by 104 as exact dup of listings_geom_idx
--                                (keep listings_geom_idx as the single full GIST)
--   listings_scraped_desc_idx -- simple recency sort not in hot-path composite filters;
--                                issue #1398 suggested fix does not include it
--
-- Note on CONCURRENTLY:
--   NOT used here. The deploy migration runner wraps each file in an explicit
--   transaction (BEGIN/COMMIT). CREATE INDEX CONCURRENTLY cannot run inside a
--   transaction block. At ~40k rows the ACCESS EXCLUSIVE lock is sub-second.
--   See migration 117_listings_last_seen_deactivate_index.sql for the same rationale.
--
-- Idempotency:
--   DROP INDEX IF EXISTS + CREATE INDEX IF NOT EXISTS -- safe to re-run.
--
-- Dependencies: 002_core_tables.sql, 050_search_optimization.sql,
--               097_index_hygiene.sql (de-partialized these indexes),
--               104_index_hygiene_geom_dedup.sql (acknowledges stale premise)
-- Deploy order: standalone, apply any time after 097 + 104.

BEGIN;

-- 1. listings_active_filter_idx
--    Original (050_search_optimization.sql:52):
--      ON listings (rooms, price_rub, area_m2, scraped_at DESC) WHERE is_active = true
--    097 stripped the predicate. Restoring it.
DROP INDEX IF EXISTS listings_active_filter_idx;
CREATE INDEX IF NOT EXISTS listings_active_filter_idx
    ON listings (rooms, price_rub, area_m2, scraped_at DESC)
    WHERE is_active = true;

-- 2. listings_house_price_idx
--    Original (050_search_optimization.sql:57):
--      ON listings (house_id_fk, price_rub) WHERE is_active = true
--    097 stripped the predicate. Restoring it.
DROP INDEX IF EXISTS listings_house_price_idx;
CREATE INDEX IF NOT EXISTS listings_house_price_idx
    ON listings (house_id_fk, price_rub)
    WHERE is_active = true;

-- 3. listings_rooms_area_idx
--    Original (002_core_tables.sql:58):
--      ON listings (rooms, area_m2) WHERE is_active = true
--    097 stripped the predicate. Restoring it.
DROP INDEX IF EXISTS listings_rooms_area_idx;
CREATE INDEX IF NOT EXISTS listings_rooms_area_idx
    ON listings (rooms, area_m2)
    WHERE is_active = true;

COMMIT;
