- npm run db:export: kampane a sablony cenoviek do supabase/data/ (+ obrazky z uloziska) - npm run db:import [-- --dry-run]: nahra data s povodnymi ID, prepise odkazy na nove ulozisko, da sa spustit opakovane - aktualny export: 7 kampani, 1 sablona cenovky Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
3.5 KiB
JavaScript
80 lines
3.5 KiB
JavaScript
// Import kampaní a šablón cenoviek zo supabase/data/ (vytvorené cez npm run db:export) do nového Supabase.
|
|
// - nahrá obrázky zo supabase/data/files/ do úložiska newsletter-assets
|
|
// - odkazy na pôvodné úložisko v dátach prepíše na úložisko nového projektu
|
|
// - záznamy vloží s pôvodnými ID; existujúce záznamy s rovnakým ID prepíše (dá sa spustiť opakovane)
|
|
// Predpoklad: spustený supabase/schema.sql. Spustenie: npm run db:import
|
|
// Skúška bez zápisu: npm run db:import -- --dry-run
|
|
import { createClient } from '@supabase/supabase-js';
|
|
import { readFile, readdir } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
|
|
const BUCKET = 'newsletter-assets';
|
|
const TABLES = ['templates', 'badges'];
|
|
const DATA_DIR = path.join(process.cwd(), 'supabase', 'data');
|
|
const FILES_DIR = path.join(DATA_DIR, 'files');
|
|
const CONTENT_TYPES = { '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.webp': 'image/webp' };
|
|
|
|
const url = (process.env.NEXT_PUBLIC_SUPABASE_URL || '').replace(/\/$/, '');
|
|
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
if (!url || !serviceKey) {
|
|
console.error('Chýba NEXT_PUBLIC_SUPABASE_URL alebo SUPABASE_SERVICE_ROLE_KEY v .env.local');
|
|
process.exit(1);
|
|
}
|
|
|
|
const dryRun = process.argv.includes('--dry-run');
|
|
const supabase = createClient(url, serviceKey);
|
|
if (dryRun) console.log('Skúšobný režim (--dry-run): nič sa nezapíše.');
|
|
const meta = JSON.parse(await readFile(path.join(DATA_DIR, 'meta.json'), 'utf8'));
|
|
const newStorageBase = `${url}/storage/v1/object/public/${BUCKET}/`;
|
|
|
|
// 1. Obrázky
|
|
async function listFiles(dir, prefix = '') {
|
|
const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
const out = [];
|
|
for (const e of entries) {
|
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
if (e.isDirectory()) out.push(...(await listFiles(path.join(dir, e.name), rel)));
|
|
else out.push(rel);
|
|
}
|
|
return out;
|
|
}
|
|
const files = await listFiles(FILES_DIR);
|
|
let failed = 0;
|
|
for (const rel of files) {
|
|
if (dryRun) continue;
|
|
const { error } = await supabase.storage.from(BUCKET).upload(rel, await readFile(path.join(FILES_DIR, rel)), {
|
|
contentType: CONTENT_TYPES[path.extname(rel).toLowerCase()] || 'application/octet-stream',
|
|
upsert: true
|
|
});
|
|
if (error) {
|
|
failed++;
|
|
console.error(`✗ súbor ${rel}: ${error.message}`);
|
|
}
|
|
}
|
|
console.log(`${dryRun ? '•' : '✓'} obrázky: ${files.length - failed}/${files.length} ${dryRun ? 'na nahratie' : 'nahratých'}`);
|
|
|
|
// 2. Dáta (s prepisom odkazov na nové úložisko)
|
|
for (const table of TABLES) {
|
|
const raw = await readFile(path.join(DATA_DIR, `${table}.json`), 'utf8');
|
|
const rewritten = raw.split(meta.sourceStorageBase).length - 1;
|
|
const rows = JSON.parse(raw.split(meta.sourceStorageBase).join(newStorageBase));
|
|
if (dryRun) {
|
|
console.log(`• ${table}: ${rows.length} záznamov, ${meta.sourceStorageBase === newStorageBase ? 0 : rewritten} prepísaných odkazov na úložisko`);
|
|
continue;
|
|
}
|
|
for (let i = 0; i < rows.length; i += 50) {
|
|
const { error } = await supabase.from(table).upsert(rows.slice(i, i + 50), { onConflict: 'id' });
|
|
if (error) {
|
|
console.error(`✗ ${table}: ${error.message}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
console.log(`✓ ${table}: ${rows.length} záznamov`);
|
|
}
|
|
|
|
if (meta.sourceStorageBase !== newStorageBase) {
|
|
console.log(`\nOdkazy ${meta.sourceStorageBase} → ${newStorageBase}`);
|
|
}
|
|
console.log('Hotovo.');
|
|
if (failed) process.exit(1);
|