From 2a81abac694ff6d2e31ef250e5479333cff0da8c Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev <572431+veikab@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:15:57 +0700 Subject: [PATCH] fix(products): backfill missing spec fields --- scripts/backfill-product-specs.js | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 scripts/backfill-product-specs.js diff --git a/scripts/backfill-product-specs.js b/scripts/backfill-product-specs.js new file mode 100644 index 0000000..aa37681 --- /dev/null +++ b/scripts/backfill-product-specs.js @@ -0,0 +1,75 @@ +import 'dotenv/config'; + +import { prisma } from '../src/prisma-client.js'; + +function normalizeText(value) { + return String(value ?? '').replaceAll(/\s+/g, ' ').trim(); +} + +function sentenceCase(value) { + if (!value) { + return value; + } + + return value[0].toUpperCase() + value.slice(1); +} + +function parseProductName(name) { + const normalizedName = normalizeText(name); + const [productTypeRaw] = normalizedName.split(','); + const sizeMatch = normalizedName.match(/(\d+)\s*[xх*]\s*(\d+)\s*м/i); + const thicknessMatch = normalizedName.match(/(\d+)\s*мкм/i); + const sleeveMatch = normalizedName.match(/втулка\s+([^,]+)/i); + const quantityMatch = normalizedName.match(/короб\s+([^,]+)/i); + + if (!productTypeRaw || !sizeMatch || !thicknessMatch || !sleeveMatch || !quantityMatch) { + throw new Error(`Unable to parse product name: ${name}`); + } + + return { + productType: normalizeText(productTypeRaw).toLowerCase(), + widthMm: Number.parseInt(sizeMatch[1] ?? '', 10), + lengthM: Number.parseInt(sizeMatch[2] ?? '', 10), + thicknessMicron: Number.parseInt(thicknessMatch[1] ?? '', 10), + sleeveBrand: normalizeText(sleeveMatch[1]).toLowerCase(), + quantityPerBox: normalizeText(quantityMatch[1]), + }; +} + +const products = await prisma.product.findMany({ + where: { + isActive: true, + OR: [ + { productType: null }, + { widthMm: null }, + { lengthM: null }, + { thicknessMicron: null }, + { sleeveBrand: null }, + { quantityPerBox: null }, + ], + }, + select: { + id: true, + sku: true, + name: true, + }, +}); + +for (const product of products) { + const parsed = parseProductName(product.name); + + await prisma.product.update({ + where: { id: product.id }, + data: { + productType: sentenceCase(parsed.productType), + widthMm: parsed.widthMm, + lengthM: parsed.lengthM, + thicknessMicron: parsed.thicknessMicron, + sleeveBrand: parsed.sleeveBrand, + quantityPerBox: parsed.quantityPerBox, + }, + }); +} + +console.log(`Backfilled ${products.length} products.`); +await prisma.$disconnect();