| 37640 |
amit |
1 |
-- ============================================================================
|
|
|
2 |
-- Hot Deal brand - SCHEMA 2026-09-15
|
|
|
3 |
--
|
|
|
4 |
-- Spec : docs/superpowers/specs/2026-09-10-hot-deal-brand-design.md
|
|
|
5 |
-- Plan : docs/superpowers/plans/2026-09-11-hot-deal-brand.md
|
|
|
6 |
--
|
|
|
7 |
-- "Hot Deal" becomes a real brand in catalog.brand. Brand membership replaces
|
|
|
8 |
-- the model_hot_deal date window as the hot-deal flag, and model_hot_deal is
|
|
|
9 |
-- reduced to per-SKU attributes (the five partner-facing pills) plus
|
|
|
10 |
-- oem_brand, which feeds the new Solr field oem_brand_s.
|
|
|
11 |
--
|
|
|
12 |
-- RUN ORDER - this file is applied in THREE separate passes:
|
|
|
13 |
--
|
|
|
14 |
-- PASS 1 (steps 1-3) before hot_deal_brand_migration.sql
|
|
|
15 |
-- PASS 2 (step 4) after hot_deal_brand_migration.sql
|
|
|
16 |
-- PASS 3 (steps 5-6) after the new wars are DEPLOYED
|
|
|
17 |
--
|
|
|
18 |
-- Do not run the whole file in one go. Each pass is marked below.
|
|
|
19 |
--
|
|
|
20 |
-- Steps 1 and 2 are idempotent. The ALTER statements are not - re-running
|
|
|
21 |
-- them errors with "Duplicate column name" / "Duplicate key name", which is
|
|
|
22 |
-- harmless and expected. MySQL 5.7 has no ADD COLUMN IF NOT EXISTS.
|
|
|
23 |
-- ============================================================================
|
|
|
24 |
|
|
|
25 |
|
|
|
26 |
-- =========================== PASS 1 =======================================
|
|
|
27 |
-- Run BEFORE hot_deal_brand_migration.sql
|
|
|
28 |
-- ============================================================================
|
|
|
29 |
|
|
|
30 |
-- ---------------------------------------------------------------------------
|
|
|
31 |
-- 1. The brand itself.
|
|
|
32 |
-- logo_url is NOT NULL with no default, so it must be supplied.
|
|
|
33 |
-- catalog.brand is latin1; 'Hot Deal' is pure ASCII, so there is no
|
|
|
34 |
-- charset risk here (see the latin1 rupee/emoji class of bug).
|
|
|
35 |
-- ---------------------------------------------------------------------------
|
|
|
36 |
INSERT INTO catalog.brand (name, logo_url, logo_url_transparent)
|
|
|
37 |
SELECT 'Hot Deal', '', NULL
|
|
|
38 |
WHERE NOT EXISTS (SELECT 1 FROM catalog.brand WHERE name = 'Hot Deal');
|
|
|
39 |
|
|
|
40 |
-- ---------------------------------------------------------------------------
|
|
|
41 |
-- 2. Visibility in the brand pickers.
|
|
|
42 |
--
|
|
|
43 |
-- catalog.brand_category is a SEPARATE taxonomy from catalog.category:
|
|
|
44 |
-- group 3 = handsets -> covers category 10006 Mobile Phone
|
|
|
45 |
-- and 10007 Refurbished Mobile
|
|
|
46 |
-- group 6 = accessories &
|
|
|
47 |
-- other devices -> covers category 10024 Ear Buds
|
|
|
48 |
-- and 14202 LED TV
|
|
|
49 |
--
|
|
|
50 |
-- The in-scope SKUs span all four categories, so BOTH rows are required.
|
|
|
51 |
-- Omitting either makes the brand invisible in that family's pickers.
|
|
|
52 |
-- ---------------------------------------------------------------------------
|
|
|
53 |
INSERT INTO catalog.brand_category (brand_id, category_id, active, `rank`)
|
|
|
54 |
SELECT b.id, 3, 1, 99
|
|
|
55 |
FROM catalog.brand b
|
|
|
56 |
WHERE b.name = 'Hot Deal'
|
|
|
57 |
AND NOT EXISTS (SELECT 1 FROM catalog.brand_category bc
|
|
|
58 |
WHERE bc.brand_id = b.id AND bc.category_id = 3);
|
|
|
59 |
|
|
|
60 |
INSERT INTO catalog.brand_category (brand_id, category_id, active, `rank`)
|
|
|
61 |
SELECT b.id, 6, 1, 99
|
|
|
62 |
FROM catalog.brand b
|
|
|
63 |
WHERE b.name = 'Hot Deal'
|
|
|
64 |
AND NOT EXISTS (SELECT 1 FROM catalog.brand_category bc
|
|
|
65 |
WHERE bc.brand_id = b.id AND bc.category_id = 6);
|
|
|
66 |
|
|
|
67 |
-- ---------------------------------------------------------------------------
|
|
|
68 |
-- 3. model_hot_deal gains oem_brand.
|
|
|
69 |
--
|
|
|
70 |
-- Once catalog.brand reads 'Hot Deal' the original brand is gone from every
|
|
|
71 |
-- queryable field. oem_brand preserves it and is the ONLY source of the
|
|
|
72 |
-- Solr field oem_brand_s, which drives the brand chips inside the hot-deal
|
|
|
73 |
-- listing.
|
|
|
74 |
--
|
|
|
75 |
-- It deliberately does NOT go into Solr's brand_ss. brand_ss is
|
|
|
76 |
-- multi-valued and feeds SolrService.brandExclusionFq, so an OEM value
|
|
|
77 |
-- there would hide the SKU from a partner blocked on that OEM - the exact
|
|
|
78 |
-- opposite of the intended behaviour, which is that channel and non-channel
|
|
|
79 |
-- stock are different brands.
|
|
|
80 |
-- ---------------------------------------------------------------------------
|
|
|
81 |
ALTER TABLE catalog.model_hot_deal
|
|
|
82 |
ADD COLUMN oem_brand VARCHAR(64) NULL
|
|
|
83 |
COMMENT 'brand before the Hot Deal move; sole source of Solr oem_brand_s';
|
|
|
84 |
|
|
|
85 |
-- ---------------------------------------------------------------------------
|
|
|
86 |
-- 3b. Optional link to the CHANNEL-side catalog entry for the same model.
|
|
|
87 |
--
|
|
|
88 |
-- A hot-deal SKU is bought outside the OEM channel, but the same model
|
|
|
89 |
-- usually also exists as normal channel stock under its real brand. This
|
|
|
90 |
-- records that counterpart where ops can identify one.
|
|
|
91 |
--
|
|
|
92 |
-- Nullable on purpose - plenty of hot-deal models have no channel twin, and
|
|
|
93 |
-- a wrong mapping is worse than none, so it is never inferred. It is set
|
|
|
94 |
-- only by an explicit choice in the admin.
|
|
|
95 |
-- ---------------------------------------------------------------------------
|
|
|
96 |
ALTER TABLE catalog.model_hot_deal
|
|
|
97 |
ADD COLUMN oem_catalog_id INT NULL
|
|
|
98 |
COMMENT 'catalog.catalog.id of the same model under its OEM brand, if one exists';
|
|
|
99 |
|
|
|
100 |
|
|
|
101 |
-- =========================== PASS 2 =======================================
|
|
|
102 |
-- Run AFTER hot_deal_brand_migration.sql
|
|
|
103 |
-- ============================================================================
|
|
|
104 |
|
|
|
105 |
-- ---------------------------------------------------------------------------
|
|
|
106 |
-- 4. One attributes row per catalog.
|
|
|
107 |
--
|
|
|
108 |
-- model_hot_deal is now an attributes table, so catalog_item_id is its
|
|
|
109 |
-- natural key. This is placed after the migration on purpose: if the
|
|
|
110 |
-- migration left duplicates this ALTER fails loudly, which is the desired
|
|
|
111 |
-- outcome - a silent duplicate would mean two conflicting pill rows for one
|
|
|
112 |
-- SKU, and buildTags would pick an arbitrary one.
|
|
|
113 |
-- ---------------------------------------------------------------------------
|
|
|
114 |
ALTER TABLE catalog.model_hot_deal
|
|
|
115 |
ADD UNIQUE KEY uk_model_hot_deal_catalog (catalog_item_id);
|
|
|
116 |
|
|
|
117 |
|
|
|
118 |
-- =========================== PASS 3 =======================================
|
|
|
119 |
-- Run only AFTER the new wars are deployed. Both statements drop columns the
|
|
|
120 |
-- running code must already have stopped using.
|
|
|
121 |
-- ============================================================================
|
|
|
122 |
|
|
|
123 |
-- ---------------------------------------------------------------------------
|
|
|
124 |
-- 5. The window and brand columns are meaningless once brand drives
|
|
|
125 |
-- membership: there is no date window, no per-brand cap, and one brand.
|
|
|
126 |
-- `activated` is separately dead - a leftover of the activated -> fresh
|
|
|
127 |
-- rename (see model_hot_deal_activated_to_fresh.sql).
|
|
|
128 |
-- ---------------------------------------------------------------------------
|
|
|
129 |
ALTER TABLE catalog.model_hot_deal
|
|
|
130 |
DROP COLUMN start_date,
|
|
|
131 |
DROP COLUMN end_date,
|
|
|
132 |
DROP COLUMN brand_id,
|
|
|
133 |
DROP COLUMN activated;
|
|
|
134 |
|
|
|
135 |
-- ---------------------------------------------------------------------------
|
|
|
136 |
-- 6. catalog.tag_listing.hot_deals had no readers before this work, and after
|
|
|
137 |
-- it no writers either: the last one was
|
|
|
138 |
-- V2FofoIndentController.hotdealUpdate (POST /v2/fofo/indent/confirm-
|
|
|
139 |
-- hotdeals-pause), removed in the same change.
|
|
|
140 |
-- ---------------------------------------------------------------------------
|
|
|
141 |
ALTER TABLE catalog.tag_listing
|
|
|
142 |
DROP COLUMN hot_deals;
|
|
|
143 |
|
|
|
144 |
|
|
|
145 |
-- ============================ ROLLBACK ====================================
|
|
|
146 |
-- PASS 3:
|
|
|
147 |
-- ALTER TABLE catalog.tag_listing ADD COLUMN hot_deals TINYINT(1) NOT NULL DEFAULT 0;
|
|
|
148 |
-- ALTER TABLE catalog.model_hot_deal
|
|
|
149 |
-- ADD COLUMN start_date DATE NOT NULL DEFAULT '2000-01-01',
|
|
|
150 |
-- ADD COLUMN end_date DATE NOT NULL DEFAULT '2099-12-31',
|
|
|
151 |
-- ADD COLUMN brand_id INT NOT NULL DEFAULT 0,
|
|
|
152 |
-- ADD COLUMN activated TINYINT(1) NULL;
|
|
|
153 |
-- (the old hot_deals values are NOT recoverable - they were the 31 legacy
|
|
|
154 |
-- rows, all of which are represented in the migration freeze table)
|
|
|
155 |
--
|
|
|
156 |
-- PASS 2:
|
|
|
157 |
-- ALTER TABLE catalog.model_hot_deal DROP INDEX uk_model_hot_deal_catalog;
|
|
|
158 |
--
|
|
|
159 |
-- PASS 1:
|
|
|
160 |
-- ALTER TABLE catalog.model_hot_deal DROP COLUMN oem_brand;
|
|
|
161 |
-- DELETE FROM catalog.brand_category
|
|
|
162 |
-- WHERE brand_id = (SELECT id FROM catalog.brand WHERE name = 'Hot Deal');
|
|
|
163 |
-- DELETE FROM catalog.brand WHERE name = 'Hot Deal';
|
|
|
164 |
-- (only safe while no catalog/item row still points at the brand - run the
|
|
|
165 |
-- data migration rollback first)
|
|
|
166 |
-- ============================================================================
|