Finalizando migração de dados do MongoDB Atlas para Supabase: corrigindo esquemas de campos decimais e garantindo integridade de relacionamento de projetos
This commit is contained in:
@@ -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()
|
||||
|
||||
101
migrate.js
Normal file
101
migrate.js
Normal file
@@ -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();
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user