diff --git a/full_schema.sql b/full_schema.sql index 7933a63..3001234 100644 --- a/full_schema.sql +++ b/full_schema.sql @@ -66,15 +66,15 @@ CREATE TABLE IF NOT EXISTS gpi.painting_schemes ( name TEXT NOT NULL, type TEXT, coat TEXT, - solids_volume DECIMAL(5,2), - yield_theoretical DECIMAL(10,2), - eps_min DECIMAL(5,2), - eps_max DECIMAL(5,2), - dilution DECIMAL(5,2), + solids_volume DECIMAL(12,3), + yield_theoretical DECIMAL(12,3), + eps_min DECIMAL(12,3), + eps_max DECIMAL(12,3), + dilution DECIMAL(12,3), manufacturer TEXT, color TEXT, - paint_consumption DECIMAL(10,3), - thinner_consumption DECIMAL(10,3), + paint_consumption DECIMAL(12,3), + thinner_consumption DECIMAL(12,3), paint_id TEXT, thinner_id TEXT, color_hex TEXT, @@ -148,23 +148,23 @@ CREATE TABLE IF NOT EXISTS gpi.technical_data_sheets ( type TEXT, file_url TEXT, upload_date DATE, - solids_volume DECIMAL(5,2), - density DECIMAL(6,3), + solids_volume DECIMAL(12,3), + density DECIMAL(12,3), mixing_ratio TEXT, - yield_theoretical DECIMAL(10,2), - wft_min DECIMAL(6,2), - wft_max DECIMAL(6,2), - dft_min DECIMAL(6,2), - dft_max DECIMAL(6,2), + yield_theoretical DECIMAL(12,3), + wft_min DECIMAL(12,3), + wft_max DECIMAL(12,3), + dft_min DECIMAL(12,3), + dft_max DECIMAL(12,3), reducer TEXT, mixing_ratio_weight TEXT, mixing_ratio_volume TEXT, - dft_reference DECIMAL(6,2), - yield_factor DECIMAL(5,3), - dilution DECIMAL(5,2), + dft_reference DECIMAL(12,3), + yield_factor DECIMAL(12,3), + dilution DECIMAL(12,3), notes TEXT, manufacturer_code TEXT, - min_stock DECIMAL(10,3), + min_stock DECIMAL(12,3), typical_application TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() diff --git a/migrate.js b/migrate.js new file mode 100644 index 0000000..cee5d2f --- /dev/null +++ b/migrate.js @@ -0,0 +1,101 @@ +import { MongoClient } from 'mongodb'; +import { execSync } from 'child_process'; +import crypto from 'crypto'; + +const MONGO_URI = "mongodb+srv://admtracksteel:mongodb26@cluster0.a4xiilu.mongodb.net/ts_gpi"; +const DB_NAME = "ts_gpi"; +const DEFAULT_ORG_ID = "e47e6210-4879-4e5b-bf21-9285d2713123"; + +const client = new MongoClient(MONGO_URI); + +// Map Mongo _id -> Supabase UUID +const idMap = new Map(); + +function getUUID(mongoId) { + if (!mongoId) return null; + const mid = mongoId.toString(); + if (idMap.has(mid)) return idMap.get(mid); + const newUuid = crypto.randomUUID(); + idMap.set(mid, newUuid); + return newUuid; +} + +function sqlSafe(val) { + if (val === null || val === undefined) return 'NULL'; + if (val instanceof Date) return `'${val.toISOString()}'`; + if (Array.isArray(val)) return `'{"${val.join('","')}"}'`; + if (typeof val === 'object' && val.toString) { + const s = val.toString(); + return `'${s.replace(/'/g, "''")}'`; + } + if (typeof val === 'string') return `'${val.replace(/'/g, "''")}'`; + return val; +} + +async function run() { + try { + await client.connect(); + console.log("🚀 Conectado ao MongoDB Atlas..."); + const db = client.db(DB_NAME); + + // 1. Mapear Projetos primeiro + const mongoProjects = await db.collection('projects').find().toArray(); + console.log(`📦 Encontrados ${mongoProjects.length} projetos.`); + + let projectInserts = []; + for (const p of mongoProjects) { + const uuid = getUUID(p._id); + projectInserts.push(`INSERT INTO gpi.projects (id, organization_id, name, client, start_date, end_date, environment, technician, weight_kg, status, created_at, updated_at) VALUES (${sqlSafe(uuid)}, ${sqlSafe(DEFAULT_ORG_ID)}, ${sqlSafe(p.name)}, ${sqlSafe(p.client)}, ${sqlSafe(p.startDate)}, ${sqlSafe(p.endDate)}, ${sqlSafe(p.environment)}, ${sqlSafe(p.technician)}, ${sqlSafe(p.weightKg)}, 'active', ${sqlSafe(p.createdAt)}, ${sqlSafe(p.updatedAt)});`); + } + + // 2. Mapear Biblioteca de Tintas (Technical Data Sheets) + const mongoTDS = await db.collection('technicaldatasheets').find().toArray(); + console.log(`📚 Encontradas ${mongoTDS.length} fichas técnicas.`); + let tdsInserts = []; + for (const t of mongoTDS) { + const uuid = getUUID(t._id); + tdsInserts.push(`INSERT INTO gpi.technical_data_sheets (id, organization_id, name, manufacturer, manufacturer_code, type, min_stock, typical_application, solids_volume, mixing_ratio, yield_theoretical, wft_min, wft_max, dft_min, dft_max, reducer, mixing_ratio_weight, mixing_ratio_volume, dft_reference, yield_factor, dilution, notes, created_at, updated_at) VALUES (${sqlSafe(uuid)}, ${sqlSafe(DEFAULT_ORG_ID)}, ${sqlSafe(t.name)}, ${sqlSafe(t.manufacturer)}, ${sqlSafe(t.manufacturerCode)}, ${sqlSafe(t.type)}, ${sqlSafe(t.minStock)}, ${sqlSafe(t.typicalApplication)}, ${sqlSafe(t.solidsVolume)}, ${sqlSafe(t.mixingRatio)}, ${sqlSafe(t.yieldTheoretical)}, ${sqlSafe(t.wftMin)}, ${sqlSafe(t.wftMax)}, ${sqlSafe(t.dftMin)}, ${sqlSafe(t.dftMax)}, ${sqlSafe(t.reducer)}, ${sqlSafe(t.mixingRatioWeight)}, ${sqlSafe(t.mixingRatioVolume)}, ${sqlSafe(t.dftReference)}, ${sqlSafe(t.yieldFactor)}, ${sqlSafe(t.dilution)}, ${sqlSafe(t.notes)}, ${sqlSafe(t.createdAt)}, ${sqlSafe(t.updatedAt)});`); + } + + // 3. Mapear Esquemas de Pintura + const mongoSchemes = await db.collection('paintingschemes').find().toArray(); + console.log(`🎨 Encontrados ${mongoSchemes.length} esquemas de pintura.`); + let schemeInserts = []; + for (const s of mongoSchemes) { + const uuid = crypto.randomUUID(); + const projectId = getUUID(s.projectId); + schemeInserts.push(`INSERT INTO gpi.painting_schemes (id, organization_id, project_id, name, type, coat, solids_volume, yield_theoretical, eps_min, eps_max, dilution, manufacturer, color, paint_consumption, thinner_consumption, paint_id, thinner_id, color_hex, thinner_symbol, notes, created_at, updated_at) VALUES (${sqlSafe(uuid)}, ${sqlSafe(DEFAULT_ORG_ID)}, ${sqlSafe(projectId)}, ${sqlSafe(s.name)}, ${sqlSafe(s.type)}, ${sqlSafe(s.coat)}, ${sqlSafe(s.solidsVolume)}, ${sqlSafe(s.yieldTheoretical)}, ${sqlSafe(s.epsMin)}, ${sqlSafe(s.epsMax)}, ${sqlSafe(s.dilution)}, ${sqlSafe(s.manufacturer)}, ${sqlSafe(s.color)}, ${sqlSafe(s.paintConsumption)}, ${sqlSafe(s.thinnerConsumption)}, ${sqlSafe(s.paintId)}, ${sqlSafe(s.thinnerId)}, ${sqlSafe(s.colorHex)}, ${sqlSafe(s.thinnerSymbol)}, ${sqlSafe(s.notes)}, NOW(), NOW());`); + } + + // 4. Mapear Peças (Parts) + const mongoParts = await db.collection('parts').find().toArray(); + console.log(`🧩 Encontradas ${mongoParts.length} peças.`); + let partsInserts = []; + for (const pt of mongoParts) { + const uuid = getUUID(pt._id); + const projectId = getUUID(pt.projectId); + partsInserts.push(`INSERT INTO gpi.parts (id, organization_id, project_id, description, dimensions, weight, type, area, quantity, notes, created_at, updated_at) VALUES (${sqlSafe(uuid)}, ${sqlSafe(DEFAULT_ORG_ID)}, ${sqlSafe(projectId)}, ${sqlSafe(pt.description)}, ${sqlSafe(pt.dimensions)}, ${sqlSafe(pt.weight)}, ${sqlSafe(pt.type)}, ${sqlSafe(pt.area)}, ${sqlSafe(pt.quantity)}, ${sqlSafe(pt.notes)}, NOW(), NOW());`); + } + + // Executar SQL + const allSQL = [...projectInserts, ...tdsInserts, ...schemeInserts, ...partsInserts].join('\n'); + + console.log("💾 Executando SQL no Supabase..."); + + // Escrever para arquivo temporário + const fs = await import('fs'); + fs.writeFileSync('/tmp/bulk_migration.sql', allSQL); + + // Executar via docker + execSync(`docker exec -i supabase-db-h0oggskgs0ws0sco8kc4s8ws psql -U supabase_admin -d postgres < /tmp/bulk_migration.sql`); + + console.log("✅ Migração Concluída com Sucesso!"); + + } catch (e) { + console.error("❌ ERRO DURANTE MIGRAÇÃO:", e.message); + } finally { + await client.close(); + } +} + +run(); diff --git a/supabase_gpi_schema.sql b/supabase_gpi_schema.sql index ec168a1..adbe3c4 100644 --- a/supabase_gpi_schema.sql +++ b/supabase_gpi_schema.sql @@ -65,15 +65,15 @@ CREATE TABLE IF NOT EXISTS gpi.painting_schemes ( name TEXT NOT NULL, type TEXT, coat TEXT, - solids_volume DECIMAL(5,2), - yield_theoretical DECIMAL(10,2), - eps_min DECIMAL(5,2), - eps_max DECIMAL(5,2), - dilution DECIMAL(5,2), + solids_volume DECIMAL(12,3), + yield_theoretical DECIMAL(12,3), + eps_min DECIMAL(12,3), + eps_max DECIMAL(12,3), + dilution DECIMAL(12,3), manufacturer TEXT, color TEXT, - paint_consumption DECIMAL(10,3), - thinner_consumption DECIMAL(10,3), + paint_consumption DECIMAL(12,3), + thinner_consumption DECIMAL(12,3), paint_id TEXT, thinner_id TEXT, color_hex TEXT, @@ -147,23 +147,23 @@ CREATE TABLE IF NOT EXISTS gpi.technical_data_sheets ( type TEXT, file_url TEXT, upload_date DATE, - solids_volume DECIMAL(5,2), - density DECIMAL(6,3), + solids_volume DECIMAL(12,3), + density DECIMAL(12,3), mixing_ratio TEXT, - yield_theoretical DECIMAL(10,2), - wft_min DECIMAL(6,2), - wft_max DECIMAL(6,2), - dft_min DECIMAL(6,2), - dft_max DECIMAL(6,2), + yield_theoretical DECIMAL(12,3), + wft_min DECIMAL(12,3), + wft_max DECIMAL(12,3), + dft_min DECIMAL(12,3), + dft_max DECIMAL(12,3), reducer TEXT, mixing_ratio_weight TEXT, mixing_ratio_volume TEXT, - dft_reference DECIMAL(6,2), - yield_factor DECIMAL(5,3), - dilution DECIMAL(5,2), + dft_reference DECIMAL(12,3), + yield_factor DECIMAL(12,3), + dilution DECIMAL(12,3), notes TEXT, manufacturer_code TEXT, - min_stock DECIMAL(10,3), + min_stock DECIMAL(12,3), typical_application TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW()