From 3b10dc5869cb016ad4ac8820317db1caebe206bf Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Tue, 17 Mar 2026 20:33:50 -0300 Subject: [PATCH 1/5] =?UTF-8?q?v1=20migration=20de=20restrutura=C3=A7?= =?UTF-8?q?=C3=A3o=20da=20tabela=20de=20variedades?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...311154039_corrige-duplicatas-variedades.ts | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/database/migration/20260311154039_corrige-duplicatas-variedades.ts diff --git a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts new file mode 100644 index 0000000..de4d6ea --- /dev/null +++ b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts @@ -0,0 +1,172 @@ +import { Knex } from 'knex' + +function normalize(value: unknown): string { + return String(value ?? '') + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .trim() + .replace(/\s+/g, ' ') + .toLowerCase() +} + +type SnapshotItem = { + tomboId: number + key: string +} + +type NovaVariedade = { + key: string + nome: string + familia_id: number + genero_id: number + especie_id: number +} + +export async function up(knex: Knex): Promise { + const trx = await knex.transaction() + + try { + const tombos = await trx('tombos as t') + .select( + 't.hcf as tombo_id', + 't.familia_id', + 't.genero_id', + 't.especie_id', + 't.variedade_nome as variedade_nome', + 't.familia_nome as familia_nome', + 't.genero_nome as genero_nome', + 't.especie_nome as especie_nome' + ) + .whereNotNull('t.variedade_nome') + .whereNotNull('t.familia_nome') + .whereNotNull('t.genero_nome') + .whereNotNull('t.especie_nome') + .whereNotNull('t.familia_id') + .whereNotNull('t.genero_id') + .whereNotNull('t.especie_id') + + const snapshot: SnapshotItem[] = [] + const variedadesMap = new Map() + + for (const row of tombos) { + const key = [ + normalize(row.variedade_nome), + normalize(row.familia_nome), + normalize(row.genero_nome), + normalize(row.especie_nome), + ].join('|') + + snapshot.push({ + tomboId: Number(row.tombo_id), + key, + }) + + if (!variedadesMap.has(key)) { + variedadesMap.set(key, { + key, + nome: String(row.variedade_nome).trim(), + familia_id: Number(row.familia_id), + genero_id: Number(row.genero_id), + especie_id: Number(row.especie_id), + }) + } + } + + const novasVariedades = Array.from(variedadesMap.values()) + + const tomboIds = snapshot.map((item) => item.tomboId) + + if (tomboIds.length > 0) { + await trx('tombos') + .whereIn('hcf', tomboIds) + .update({ variedade_id: null }) + } + + await trx('variedades').del() + + const inserted = await trx('variedades') + .insert( + novasVariedades.map((item) => ({ + nome: item.nome, + familia_id: item.familia_id, + genero_id: item.genero_id, + especie_id: item.especie_id, + })) + ) + .returning(['id', 'nome', 'familia_id', 'genero_id', 'especie_id']) + + const newIdMap = new Map() + + for (const row of inserted as Array<{ + id: number + nome: string + familia_id: number + genero_id: number + especie_id: number + }>) { + const key = [ + normalize(row.nome), + normalize( + tombos.find( + (t) => + Number(t.familia_id) === Number(row.familia_id) && + Number(t.genero_id) === Number(row.genero_id) && + Number(t.especie_id) === Number(row.especie_id) && + normalize(t.variedade_nome) === normalize(row.nome) + )?.familia_nome + ), + normalize( + tombos.find( + (t) => + Number(t.familia_id) === Number(row.familia_id) && + Number(t.genero_id) === Number(row.genero_id) && + Number(t.especie_id) === Number(row.especie_id) && + normalize(t.variedade_nome) === normalize(row.nome) + )?.genero_nome + ), + normalize( + tombos.find( + (t) => + Number(t.familia_id) === Number(row.familia_id) && + Number(t.genero_id) === Number(row.genero_id) && + Number(t.especie_id) === Number(row.especie_id) && + normalize(t.variedade_nome) === normalize(row.nome) + )?.especie_nome + ), + ].join('|') + + newIdMap.set(key, Number(row.id)) + } + + let tombosAtualizados = 0 + + for (const item of snapshot) { + const novaVariedadeId = newIdMap.get(item.key) + + if (!novaVariedadeId) { + throw new Error(`Nao foi possivel encontrar nova variedade para o tombo ${item.tomboId}`) + } + + const updated = await trx('tombos') + .where('hcf', item.tomboId) + .update({ variedade_id: novaVariedadeId }) + + tombosAtualizados += Number(updated || 0) + } + + await trx.commit() + + console.log('Migracao concluida com sucesso') + console.log(`Tombos processados: ${snapshot.length}`) + console.log(`Variedades recriadas: ${novasVariedades.length}`) + console.log(`Tombos atualizados: ${tombosAtualizados}`) + } catch (error) { + await trx.rollback() + console.error('Erro na migracao. Rollback executado.', error) + throw error + } +} + +export async function down(): Promise { + console.log('Migracao irreversivel: down nao implementado.') +} From a378109fbb9670e6fa86e739daf1b7667e6cd0a6 Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Wed, 18 Mar 2026 19:08:51 -0300 Subject: [PATCH 2/5] =?UTF-8?q?Atualizando=20migra=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...311154039_corrige-duplicatas-variedades.ts | 250 ++++++++---------- 1 file changed, 113 insertions(+), 137 deletions(-) diff --git a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts index de4d6ea..42787f8 100644 --- a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts +++ b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts @@ -22,151 +22,127 @@ type NovaVariedade = { especie_id: number } -export async function up(knex: Knex): Promise { - const trx = await knex.transaction() - - try { - const tombos = await trx('tombos as t') - .select( - 't.hcf as tombo_id', - 't.familia_id', - 't.genero_id', - 't.especie_id', - 't.variedade_nome as variedade_nome', - 't.familia_nome as familia_nome', - 't.genero_nome as genero_nome', - 't.especie_nome as especie_nome' - ) - .whereNotNull('t.variedade_nome') - .whereNotNull('t.familia_nome') - .whereNotNull('t.genero_nome') - .whereNotNull('t.especie_nome') - .whereNotNull('t.familia_id') - .whereNotNull('t.genero_id') - .whereNotNull('t.especie_id') - - const snapshot: SnapshotItem[] = [] - const variedadesMap = new Map() - - for (const row of tombos) { - const key = [ - normalize(row.variedade_nome), - normalize(row.familia_nome), - normalize(row.genero_nome), - normalize(row.especie_nome), - ].join('|') - - snapshot.push({ - tomboId: Number(row.tombo_id), - key, - }) - - if (!variedadesMap.has(key)) { - variedadesMap.set(key, { +export async function run(knex: Knex): Promise { + await knex.transaction(async (trx) => { + try { + // 1. Buscamos os Tombos trazendo os nomes REAIS das tabelas de taxonomia via JOIN + const tombos = await trx('tombos as t') + .join('familias as f', 't.familia_id', 'f.id') + .join('generos as g', 't.genero_id', 'g.id') + .join('especies as e', 't.especie_id', 'e.id') + .leftJoin('variedades as v', 't.variedade_id', 'v.id') + .select( + 't.hcf as tombo_id', + 't.familia_id', + 't.genero_id', + 't.especie_id', + 'v.nome as variedade_nome', // Nome atual na tabela de variedades + 'f.nome as familia_nome', + 'g.nome as genero_nome', + 'e.nome as especie_nome' + ) + // Filtramos apenas onde a árvore taxonômica está completa + .whereNotNull('t.familia_id') + .whereNotNull('t.genero_id') + .whereNotNull('t.especie_id') + .whereNotNull('v.nome') + + const snapshot: SnapshotItem[] = [] + const variedadesMap = new Map() + + // 2. Mapeamos as variedades únicas baseadas na composição visual + for (const row of tombos) { + const key = [ + normalize(row.variedade_nome), + normalize(row.familia_nome), + normalize(row.genero_nome), + normalize(row.especie_nome), + ].join('|') + + snapshot.push({ + tomboId: Number(row.tombo_id), key, - nome: String(row.variedade_nome).trim(), - familia_id: Number(row.familia_id), - genero_id: Number(row.genero_id), - especie_id: Number(row.especie_id), }) - } - } - - const novasVariedades = Array.from(variedadesMap.values()) - - const tomboIds = snapshot.map((item) => item.tomboId) - if (tomboIds.length > 0) { - await trx('tombos') - .whereIn('hcf', tomboIds) - .update({ variedade_id: null }) - } - - await trx('variedades').del() - - const inserted = await trx('variedades') - .insert( - novasVariedades.map((item) => ({ - nome: item.nome, - familia_id: item.familia_id, - genero_id: item.genero_id, - especie_id: item.especie_id, - })) - ) - .returning(['id', 'nome', 'familia_id', 'genero_id', 'especie_id']) - - const newIdMap = new Map() - - for (const row of inserted as Array<{ - id: number - nome: string - familia_id: number - genero_id: number - especie_id: number - }>) { - const key = [ - normalize(row.nome), - normalize( - tombos.find( - (t) => - Number(t.familia_id) === Number(row.familia_id) && - Number(t.genero_id) === Number(row.genero_id) && - Number(t.especie_id) === Number(row.especie_id) && - normalize(t.variedade_nome) === normalize(row.nome) - )?.familia_nome - ), - normalize( - tombos.find( - (t) => - Number(t.familia_id) === Number(row.familia_id) && - Number(t.genero_id) === Number(row.genero_id) && - Number(t.especie_id) === Number(row.especie_id) && - normalize(t.variedade_nome) === normalize(row.nome) - )?.genero_nome - ), - normalize( - tombos.find( - (t) => - Number(t.familia_id) === Number(row.familia_id) && - Number(t.genero_id) === Number(row.genero_id) && - Number(t.especie_id) === Number(row.especie_id) && - normalize(t.variedade_nome) === normalize(row.nome) - )?.especie_nome - ), - ].join('|') - - newIdMap.set(key, Number(row.id)) - } + if (!variedadesMap.has(key)) { + variedadesMap.set(key, { + key, + nome: String(row.variedade_nome).trim(), + familia_id: Number(row.familia_id), + genero_id: Number(row.genero_id), + especie_id: Number(row.especie_id), + }) + } + } - let tombosAtualizados = 0 + const novasVariedades = Array.from(variedadesMap.values()) + const tomboIds = snapshot.map((item) => item.tomboId) - for (const item of snapshot) { - const novaVariedadeId = newIdMap.get(item.key) + // 3. Limpeza: removemos vínculos antigos para evitar erros de FK + if (tomboIds.length > 0) { + await trx('tombos') + .whereIn('hcf', tomboIds) + .update({ variedade_id: null }) + } - if (!novaVariedadeId) { - throw new Error(`Nao foi possivel encontrar nova variedade para o tombo ${item.tomboId}`) + // 4. Reset da tabela de variedades + await trx('variedades').del() + + // 5. Inserção das novas variedades normalizadas + const inserted = await trx('variedades') + .insert( + novasVariedades.map((item) => ({ + nome: item.nome, + familia_id: item.familia_id, + genero_id: item.genero_id, + especie_id: item.especie_id, + })) + ) + .returning(['id', 'nome', 'familia_id', 'genero_id', 'especie_id']) + + // 6. Criamos o mapa de Novos IDs para atualizar os Tombos + const newIdMap = new Map() + + for (const row of inserted) { + const matchingTombo = tombos.find( + (t) => + Number(t.familia_id) === Number(row.familia_id) && + Number(t.genero_id) === Number(row.genero_id) && + Number(t.especie_id) === Number(row.especie_id) && + normalize(t.variedade_nome) === normalize(row.nome) + ) + + const key = [ + normalize(row.nome), + normalize(matchingTombo?.familia_nome), + normalize(matchingTombo?.genero_nome), + normalize(matchingTombo?.especie_nome), + ].join('|') + + newIdMap.set(key, Number(row.id)) } - const updated = await trx('tombos') - .where('hcf', item.tomboId) - .update({ variedade_id: novaVariedadeId }) + // 7. Atualização final dos Tombos com os IDs corretos + let tombosAtualizados = 0 + for (const item of snapshot) { + const novaVariedadeId = newIdMap.get(item.key) + + if (novaVariedadeId) { + const updated = await trx('tombos') + .where('hcf', item.tomboId) + .update({ variedade_id: novaVariedadeId }) + + tombosAtualizados += Number(updated || 0) + } + } - tombosAtualizados += Number(updated || 0) + console.log('Migração finalizada com sucesso!') + console.log(`Variedades recriadas: ${novasVariedades.length}`) + console.log(`Registros de Tombos corrigidos: ${tombosAtualizados}`) + + } catch (error) { + console.error('Falha na migração. O banco realizou rollback.', error) + throw error } - - await trx.commit() - - console.log('Migracao concluida com sucesso') - console.log(`Tombos processados: ${snapshot.length}`) - console.log(`Variedades recriadas: ${novasVariedades.length}`) - console.log(`Tombos atualizados: ${tombosAtualizados}`) - } catch (error) { - await trx.rollback() - console.error('Erro na migracao. Rollback executado.', error) - throw error - } -} - -export async function down(): Promise { - console.log('Migracao irreversivel: down nao implementado.') + }) } From 486c899992656cd7d1c5b84ef302170d7eb3954c Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Wed, 18 Mar 2026 19:31:12 -0300 Subject: [PATCH 3/5] fix lint --- ...311154039_corrige-duplicatas-variedades.ts | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts index 42787f8..c3b7a27 100644 --- a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts +++ b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts @@ -23,7 +23,7 @@ type NovaVariedade = { } export async function run(knex: Knex): Promise { - await knex.transaction(async (trx) => { + await knex.transaction(async trx => { try { // 1. Buscamos os Tombos trazendo os nomes REAIS das tabelas de taxonomia via JOIN const tombos = await trx('tombos as t') @@ -45,7 +45,7 @@ export async function run(knex: Knex): Promise { .whereNotNull('t.familia_id') .whereNotNull('t.genero_id') .whereNotNull('t.especie_id') - .whereNotNull('v.nome') + .whereNotNull('v.nome') const snapshot: SnapshotItem[] = [] const variedadesMap = new Map() @@ -56,12 +56,12 @@ export async function run(knex: Knex): Promise { normalize(row.variedade_nome), normalize(row.familia_nome), normalize(row.genero_nome), - normalize(row.especie_nome), + normalize(row.especie_nome) ].join('|') snapshot.push({ tomboId: Number(row.tombo_id), - key, + key }) if (!variedadesMap.has(key)) { @@ -70,13 +70,13 @@ export async function run(knex: Knex): Promise { nome: String(row.variedade_nome).trim(), familia_id: Number(row.familia_id), genero_id: Number(row.genero_id), - especie_id: Number(row.especie_id), + especie_id: Number(row.especie_id) }) } } const novasVariedades = Array.from(variedadesMap.values()) - const tomboIds = snapshot.map((item) => item.tomboId) + const tomboIds = snapshot.map(item => item.tomboId) // 3. Limpeza: removemos vínculos antigos para evitar erros de FK if (tomboIds.length > 0) { @@ -91,32 +91,38 @@ export async function run(knex: Knex): Promise { // 5. Inserção das novas variedades normalizadas const inserted = await trx('variedades') .insert( - novasVariedades.map((item) => ({ + novasVariedades.map(item => ({ nome: item.nome, familia_id: item.familia_id, genero_id: item.genero_id, - especie_id: item.especie_id, + especie_id: item.especie_id })) ) - .returning(['id', 'nome', 'familia_id', 'genero_id', 'especie_id']) + .returning([ + 'id', + 'nome', + 'familia_id', + 'genero_id', + 'especie_id' + ]) // 6. Criamos o mapa de Novos IDs para atualizar os Tombos const newIdMap = new Map() for (const row of inserted) { const matchingTombo = tombos.find( - (t) => - Number(t.familia_id) === Number(row.familia_id) && - Number(t.genero_id) === Number(row.genero_id) && - Number(t.especie_id) === Number(row.especie_id) && - normalize(t.variedade_nome) === normalize(row.nome) + t => + Number(t.familia_id) === Number(row.familia_id) + && Number(t.genero_id) === Number(row.genero_id) + && Number(t.especie_id) === Number(row.especie_id) + && normalize(t.variedade_nome) === normalize(row.nome) ) const key = [ normalize(row.nome), normalize(matchingTombo?.familia_nome), normalize(matchingTombo?.genero_nome), - normalize(matchingTombo?.especie_nome), + normalize(matchingTombo?.especie_nome) ].join('|') newIdMap.set(key, Number(row.id)) @@ -131,7 +137,7 @@ export async function run(knex: Knex): Promise { const updated = await trx('tombos') .where('hcf', item.tomboId) .update({ variedade_id: novaVariedadeId }) - + tombosAtualizados += Number(updated || 0) } } @@ -139,7 +145,6 @@ export async function run(knex: Knex): Promise { console.log('Migração finalizada com sucesso!') console.log(`Variedades recriadas: ${novasVariedades.length}`) console.log(`Registros de Tombos corrigidos: ${tombosAtualizados}`) - } catch (error) { console.error('Falha na migração. O banco realizou rollback.', error) throw error From ab687be2b12b9ebd20ff580ab444a48f2834606d Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Wed, 18 Mar 2026 19:54:38 -0300 Subject: [PATCH 4/5] fix lint --- ...311154039_corrige-duplicatas-variedades.ts | 216 ++++++++---------- 1 file changed, 99 insertions(+), 117 deletions(-) diff --git a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts index c3b7a27..81fcba1 100644 --- a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts +++ b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts @@ -1,7 +1,9 @@ import { Knex } from 'knex' function normalize(value: unknown): string { - return String(value ?? '') + const safeValue = typeof value === 'string' || typeof value === 'number' ? String(value) : '' + + return safeValue .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .trim() @@ -24,130 +26,110 @@ type NovaVariedade = { export async function run(knex: Knex): Promise { await knex.transaction(async trx => { - try { - // 1. Buscamos os Tombos trazendo os nomes REAIS das tabelas de taxonomia via JOIN - const tombos = await trx('tombos as t') - .join('familias as f', 't.familia_id', 'f.id') - .join('generos as g', 't.genero_id', 'g.id') - .join('especies as e', 't.especie_id', 'e.id') - .leftJoin('variedades as v', 't.variedade_id', 'v.id') - .select( - 't.hcf as tombo_id', - 't.familia_id', - 't.genero_id', - 't.especie_id', - 'v.nome as variedade_nome', // Nome atual na tabela de variedades - 'f.nome as familia_nome', - 'g.nome as genero_nome', - 'e.nome as especie_nome' - ) - // Filtramos apenas onde a árvore taxonômica está completa - .whereNotNull('t.familia_id') - .whereNotNull('t.genero_id') - .whereNotNull('t.especie_id') - .whereNotNull('v.nome') - - const snapshot: SnapshotItem[] = [] - const variedadesMap = new Map() - - // 2. Mapeamos as variedades únicas baseadas na composição visual - for (const row of tombos) { - const key = [ - normalize(row.variedade_nome), - normalize(row.familia_nome), - normalize(row.genero_nome), - normalize(row.especie_nome) - ].join('|') - - snapshot.push({ - tomboId: Number(row.tombo_id), - key + const tombos = await trx('tombos as t') + .join('familias as f', 't.familia_id', 'f.id') + .join('generos as g', 't.genero_id', 'g.id') + .join('especies as e', 't.especie_id', 'e.id') + .leftJoin('variedades as v', 't.variedade_id', 'v.id') + .select( + 't.hcf as tombo_id', + 't.familia_id', + 't.genero_id', + 't.especie_id', + 'v.nome as variedade_nome', + 'f.nome as familia_nome', + 'g.nome as genero_nome', + 'e.nome as especie_nome' + ) + .whereNotNull('t.familia_id') + .whereNotNull('t.genero_id') + .whereNotNull('t.especie_id') + .whereNotNull('v.nome') + + const snapshot: SnapshotItem[] = [] + const variedadesMap = new Map() + + for (const row of tombos) { + const key = [ + normalize(row.variedade_nome), + normalize(row.familia_nome), + normalize(row.genero_nome), + normalize(row.especie_nome) + ].join('|') + + snapshot.push({ + tomboId: Number(row.tombo_id), + key + }) + + if (!variedadesMap.has(key)) { + variedadesMap.set(key, { + key, + nome: String(row.variedade_nome).trim(), + familia_id: Number(row.familia_id), + genero_id: Number(row.genero_id), + especie_id: Number(row.especie_id) }) - - if (!variedadesMap.has(key)) { - variedadesMap.set(key, { - key, - nome: String(row.variedade_nome).trim(), - familia_id: Number(row.familia_id), - genero_id: Number(row.genero_id), - especie_id: Number(row.especie_id) - }) - } } + } - const novasVariedades = Array.from(variedadesMap.values()) - const tomboIds = snapshot.map(item => item.tomboId) - - // 3. Limpeza: removemos vínculos antigos para evitar erros de FK - if (tomboIds.length > 0) { - await trx('tombos') - .whereIn('hcf', tomboIds) - .update({ variedade_id: null }) - } + const novasVariedades = Array.from(variedadesMap.values()) + const tomboIds = snapshot.map(item => item.tomboId) - // 4. Reset da tabela de variedades - await trx('variedades').del() - - // 5. Inserção das novas variedades normalizadas - const inserted = await trx('variedades') - .insert( - novasVariedades.map(item => ({ - nome: item.nome, - familia_id: item.familia_id, - genero_id: item.genero_id, - especie_id: item.especie_id - })) - ) - .returning([ - 'id', - 'nome', - 'familia_id', - 'genero_id', - 'especie_id' - ]) - - // 6. Criamos o mapa de Novos IDs para atualizar os Tombos - const newIdMap = new Map() - - for (const row of inserted) { - const matchingTombo = tombos.find( - t => - Number(t.familia_id) === Number(row.familia_id) - && Number(t.genero_id) === Number(row.genero_id) - && Number(t.especie_id) === Number(row.especie_id) - && normalize(t.variedade_nome) === normalize(row.nome) - ) - - const key = [ - normalize(row.nome), - normalize(matchingTombo?.familia_nome), - normalize(matchingTombo?.genero_nome), - normalize(matchingTombo?.especie_nome) - ].join('|') - - newIdMap.set(key, Number(row.id)) - } + if (tomboIds.length > 0) { + await trx('tombos') + .whereIn('hcf', tomboIds) + .update({ variedade_id: null }) + } - // 7. Atualização final dos Tombos com os IDs corretos - let tombosAtualizados = 0 - for (const item of snapshot) { - const novaVariedadeId = newIdMap.get(item.key) + await trx('variedades').del() + + const inserted = await trx('variedades') + .insert( + novasVariedades.map(item => ({ + nome: item.nome, + familia_id: item.familia_id, + genero_id: item.genero_id, + especie_id: item.especie_id + })) + ) + .returning([ + 'id', + 'nome', + 'familia_id', + 'genero_id', + 'especie_id' + ]) + + const newIdMap = new Map() + + for (const row of inserted) { + const matchingTombo = tombos.find( + t => + Number(t.familia_id) === Number(row.familia_id) + && Number(t.genero_id) === Number(row.genero_id) + && Number(t.especie_id) === Number(row.especie_id) + && normalize(t.variedade_nome) === normalize(row.nome) + ) + + const key = [ + normalize(row.nome), + normalize(matchingTombo?.familia_nome), + normalize(matchingTombo?.genero_nome), + normalize(matchingTombo?.especie_nome) + ].join('|') + + newIdMap.set(key, Number(row.id)) + } - if (novaVariedadeId) { - const updated = await trx('tombos') - .where('hcf', item.tomboId) - .update({ variedade_id: novaVariedadeId }) + for (const item of snapshot) { + const novaVariedadeId = newIdMap.get(item.key) - tombosAtualizados += Number(updated || 0) - } + if (novaVariedadeId) { + await trx('tombos') + .where('hcf', item.tomboId) + .update({ variedade_id: novaVariedadeId }) } - - console.log('Migração finalizada com sucesso!') - console.log(`Variedades recriadas: ${novasVariedades.length}`) - console.log(`Registros de Tombos corrigidos: ${tombosAtualizados}`) - } catch (error) { - console.error('Falha na migração. O banco realizou rollback.', error) - throw error } }) } From 6c83b2b741c21e92e2a9294cb9913fd6287ea2c6 Mon Sep 17 00:00:00 2001 From: Lucas Vaz Date: Wed, 18 Mar 2026 20:22:03 -0300 Subject: [PATCH 5/5] fix: adiciona o id do autor da variedade --- ...0311154039_corrige-duplicatas-variedades.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts index 81fcba1..35f27c5 100644 --- a/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts +++ b/src/database/migration/20260311154039_corrige-duplicatas-variedades.ts @@ -22,6 +22,7 @@ type NovaVariedade = { familia_id: number genero_id: number especie_id: number + autor_id: number | null } export async function run(knex: Knex): Promise { @@ -37,6 +38,7 @@ export async function run(knex: Knex): Promise { 't.genero_id', 't.especie_id', 'v.nome as variedade_nome', + 'v.autor_id as variedade_autor_id', 'f.nome as familia_nome', 'g.nome as genero_nome', 'e.nome as especie_nome' @@ -54,7 +56,8 @@ export async function run(knex: Knex): Promise { normalize(row.variedade_nome), normalize(row.familia_nome), normalize(row.genero_nome), - normalize(row.especie_nome) + normalize(row.especie_nome), + row.variedade_autor_id ].join('|') snapshot.push({ @@ -68,7 +71,8 @@ export async function run(knex: Knex): Promise { nome: String(row.variedade_nome).trim(), familia_id: Number(row.familia_id), genero_id: Number(row.genero_id), - especie_id: Number(row.especie_id) + especie_id: Number(row.especie_id), + autor_id: row.variedade_autor_id ? Number(row.variedade_autor_id) : null }) } } @@ -90,7 +94,8 @@ export async function run(knex: Knex): Promise { nome: item.nome, familia_id: item.familia_id, genero_id: item.genero_id, - especie_id: item.especie_id + especie_id: item.especie_id, + autor_id: item.autor_id })) ) .returning([ @@ -98,7 +103,8 @@ export async function run(knex: Knex): Promise { 'nome', 'familia_id', 'genero_id', - 'especie_id' + 'especie_id', + 'autor_id' ]) const newIdMap = new Map() @@ -110,13 +116,15 @@ export async function run(knex: Knex): Promise { && Number(t.genero_id) === Number(row.genero_id) && Number(t.especie_id) === Number(row.especie_id) && normalize(t.variedade_nome) === normalize(row.nome) + && (t.variedade_autor_id ? Number(t.variedade_autor_id) : null) === (row.autor_id ? Number(row.autor_id) : null) ) const key = [ normalize(row.nome), normalize(matchingTombo?.familia_nome), normalize(matchingTombo?.genero_nome), - normalize(matchingTombo?.especie_nome) + normalize(matchingTombo?.especie_nome), + row.autor_id ? Number(row.autor_id) : null ].join('|') newIdMap.set(key, Number(row.id))