124 lines
4 KiB
JavaScript
124 lines
4 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
|
||
|
|
import dotenv from 'dotenv';
|
||
|
|
import { neon } from '@neondatabase/serverless';
|
||
|
|
import { generateUniqueSlug } from '../lib/slug-utils.js';
|
||
|
|
|
||
|
|
dotenv.config({ path: '.env.local' });
|
||
|
|
|
||
|
|
async function addCollectionSlugs() {
|
||
|
|
const sql = neon(process.env.POSTGRES_URL);
|
||
|
|
|
||
|
|
try {
|
||
|
|
console.log('🔗 Adding slug support to collections...');
|
||
|
|
|
||
|
|
// Step 1: Add slug column to collections table
|
||
|
|
console.log('📝 Adding slug column...');
|
||
|
|
await sql`
|
||
|
|
ALTER TABLE collections
|
||
|
|
ADD COLUMN IF NOT EXISTS slug VARCHAR(100) UNIQUE
|
||
|
|
`;
|
||
|
|
console.log('✅ Added slug column');
|
||
|
|
|
||
|
|
// Step 2: Get all existing collections
|
||
|
|
console.log('🔍 Fetching existing collections...');
|
||
|
|
const collections = await sql`
|
||
|
|
SELECT id, name, slug FROM collections
|
||
|
|
ORDER BY created_at ASC
|
||
|
|
`;
|
||
|
|
console.log(`📊 Found ${collections.length} collections`);
|
||
|
|
|
||
|
|
if (collections.length === 0) {
|
||
|
|
console.log('✅ No collections to migrate');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Step 3: Generate unique slugs for all collections
|
||
|
|
console.log('🏷️ Generating unique slugs...');
|
||
|
|
const existingSlugs = [];
|
||
|
|
const updates = [];
|
||
|
|
|
||
|
|
for (const collection of collections) {
|
||
|
|
// Skip if collection already has a slug
|
||
|
|
if (collection.slug) {
|
||
|
|
existingSlugs.push(collection.slug);
|
||
|
|
console.log(`⏭️ Skipping "${collection.name}" - already has slug: ${collection.slug}`);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Generate unique slug
|
||
|
|
const uniqueSlug = await generateUniqueSlug(collection.name, existingSlugs);
|
||
|
|
existingSlugs.push(uniqueSlug);
|
||
|
|
|
||
|
|
updates.push({
|
||
|
|
id: collection.id,
|
||
|
|
name: collection.name,
|
||
|
|
slug: uniqueSlug
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log(`🎯 "${collection.name}" → "${uniqueSlug}"`);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Step 4: Update collections with their new slugs
|
||
|
|
if (updates.length > 0) {
|
||
|
|
console.log(`📝 Updating ${updates.length} collections with slugs...`);
|
||
|
|
|
||
|
|
for (const update of updates) {
|
||
|
|
await sql`
|
||
|
|
UPDATE collections
|
||
|
|
SET slug = ${update.slug}
|
||
|
|
WHERE id = ${update.id}
|
||
|
|
`;
|
||
|
|
console.log(`✅ Updated: ${update.name} → ${update.slug}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Step 5: Add index for performance
|
||
|
|
console.log('🚀 Adding slug index for performance...');
|
||
|
|
try {
|
||
|
|
await sql`CREATE UNIQUE INDEX IF NOT EXISTS idx_collections_slug ON collections(slug)`;
|
||
|
|
console.log('✅ Added slug index');
|
||
|
|
} catch (error) {
|
||
|
|
if (!error.message.includes('already exists')) {
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
console.log('✅ Slug index already exists');
|
||
|
|
}
|
||
|
|
|
||
|
|
// Step 6: Add constraint to ensure slugs are not null for new collections
|
||
|
|
console.log('🔒 Adding slug constraints...');
|
||
|
|
try {
|
||
|
|
await sql`ALTER TABLE collections ADD CONSTRAINT check_slug_format CHECK (slug ~ '^[a-z0-9]([a-z0-9-]*[a-z0-9])?$' AND length(slug) <= 50)`;
|
||
|
|
console.log('✅ Added slug format constraint');
|
||
|
|
} catch (error) {
|
||
|
|
if (!error.message.includes('already exists')) {
|
||
|
|
console.warn('⚠️ Could not add slug constraint:', error.message);
|
||
|
|
} else {
|
||
|
|
console.log('✅ Slug constraint already exists');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n🎉 Collection slug migration completed successfully!');
|
||
|
|
console.log('\n📋 Summary:');
|
||
|
|
console.log(` 📊 Total collections: ${collections.length}`);
|
||
|
|
console.log(` 🆕 New slugs created: ${updates.length}`);
|
||
|
|
console.log(` ⏭️ Already had slugs: ${collections.length - updates.length}`);
|
||
|
|
|
||
|
|
if (updates.length > 0) {
|
||
|
|
console.log('\n🔗 New URL structure:');
|
||
|
|
console.log(' Old: /collection/123');
|
||
|
|
console.log(' New: /collection/modern-masters-2021');
|
||
|
|
}
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('❌ Failed to add collection slugs:', error.message);
|
||
|
|
console.error('Full error:', error);
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
||
|
|
addCollectionSlugs();
|
||
|
|
}
|
||
|
|
|
||
|
|
export { addCollectionSlugs };
|