import pymysql import re import ulid def canonicalize_media_key(raw_key): if not raw_key: return None s = str(raw_key).strip().lower() s = re.sub(r'[\s_/\\]+', '-', s) s = re.sub(r'-+', '-', s) s = s.strip('-') return s if s else None conn = pymysql.connect(unix_socket='/var/run/mysqld/mysqld.sock', user='root', password='', database='ifixkartecommerce', autocommit=False) cur = conn.cursor() print("=== Fetching indexed media_groups and media_assets ===") cur.execute("SELECT id, media_key FROM media_groups") mg_rows = cur.fetchall() media_group_map = {} for mg_id, media_key in mg_rows: cur.execute("SELECT cdn_url FROM media_library WHERE media_group_id = %s ORDER BY created_at ASC", (mg_id,)) asset_urls = [r[0] for r in cur.fetchall()] if asset_urls: media_group_map[media_key] = asset_urls print(f"Indexed media groups with valid assets: {len(media_group_map)}") print("=== Fetching all products with Brand and Category ===") cur.execute(""" SELECT p.product_id, p.name, p.slug, b.slug as brand_slug, c.slug as category_slug FROM products p LEFT JOIN brands b ON p.brand_id = b.brand_id LEFT JOIN categories c ON p.category_id = c.category_id """) products = cur.fetchall() prod_linked_count = 0 var_linked_count = 0 for product_id, name, slug, brand_slug, category_slug in products: # Fetch variants for this product cur.execute("SELECT variant_id FROM product_variants WHERE product_id = %s", (product_id,)) variants = [r[0] for r in cur.fetchall()] prod_matched_urls = [] for v_id in variants: # Fetch Color attribute for variant cur.execute(""" SELECT va.attribute_value FROM variant_attributes va JOIN attribute_types at ON va.attribute_id = at.attribute_id WHERE va.variant_id = %s AND (at.code = 'color' OR at.name = 'Color') LIMIT 1 """, (v_id,)) color_row = cur.fetchone() color_val = color_row[0] if color_row else "" # Candidates candidates = [] if brand_slug and category_slug and color_val: color_slug = canonicalize_media_key(color_val) candidates.append(f"{brand_slug}-{category_slug}-{color_slug}") candidates.append(f"{brand_slug}-{category_slug}") if brand_slug and category_slug: candidates.append(f"{brand_slug}-{category_slug}") candidates.append(canonicalize_media_key(slug)) candidates.append(canonicalize_media_key(name)) matched_urls = None for k in candidates: if k and k in media_group_map: matched_urls = media_group_map[k] break if not matched_urls and brand_slug and category_slug: prefix = f"{brand_slug}-{category_slug}" for k, urls in media_group_map.items(): if k.startswith(prefix): matched_urls = urls break if matched_urls: cur.execute("DELETE FROM variant_images WHERE variant_id = %s", (v_id,)) for idx, url in enumerate(matched_urls): vi_id = str(ulid.ULID()) cur.execute( "INSERT INTO variant_images (image_id, variant_id, image_url, sort_order, is_primary) VALUES (%s, %s, %s, %s, %s)", (vi_id, v_id, url, idx, idx == 0) ) var_linked_count += 1 if not prod_matched_urls: prod_matched_urls = matched_urls if prod_matched_urls: cur.execute("DELETE FROM product_images WHERE product_id = %s", (product_id,)) for idx, url in enumerate(prod_matched_urls): pi_id = str(ulid.ULID()) cur.execute( "INSERT INTO product_images (image_id, product_id, image_url, alt_text, sort_order, is_banner) VALUES (%s, %s, %s, %s, %s, %s)", (pi_id, product_id, url, f"{name} Image {idx+1}", idx, idx == 0) ) prod_linked_count += 1 conn.commit() print(f"=== Backfill Complete! ===") print(f"Linked images to {prod_linked_count} products and {var_linked_count} variants.") conn.close()