#!/usr/bin/env tsx
import { readFileSync } from 'fs';
import { join } from 'path';
import { supabase } from './client.js';
import type { Style, Palette, CompatibilityMatrix } from '../types.js';
async function loadJSONFile<T>(filePath: string): Promise<T> {
try {
const fullPath = join(process.cwd(), '..', filePath);
const content = readFileSync(fullPath, 'utf-8');
return JSON.parse(content) as T;
} catch (error) {
console.error(`β Error loading ${filePath}:`, error);
throw error;
}
}
async function createTables(): Promise<void> {
console.log('π§ Creating database tables...');
const serviceClient = supabase.getServiceClient();
const sqlFiles = [
'./sql/001_design_styles.sql',
'./sql/002_design_palettes.sql',
'./sql/003_compatibility.sql'
];
for (const sqlFile of sqlFiles) {
try {
const sql = readFileSync(join(process.cwd(), sqlFile), 'utf-8');
const { error } = await serviceClient.rpc('exec_sql', { sql });
if (error) {
console.error(`β Error executing ${sqlFile}:`, error);
throw error;
}
console.log(`β
Executed ${sqlFile}`);
} catch (error) {
// Try alternative approach for table creation
console.log(`βΉοΈ Trying alternative approach for ${sqlFile}...`);
if (sqlFile.includes('001_design_styles')) {
await createStylesTable();
} else if (sqlFile.includes('002_design_palettes')) {
await createPalettesTable();
} else if (sqlFile.includes('003_compatibility')) {
await createCompatibilityTable();
}
}
}
}
async function createStylesTable(): Promise<void> {
const serviceClient = supabase.getServiceClient();
// Since we can't execute DDL directly, let's check if table exists
const { data, error } = await serviceClient
.from('design_styles')
.select('count', { count: 'exact', head: true });
if (error && error.code === 'PGRST116') {
console.log('β οΈ design_styles table does not exist. Please run the SQL manually.');
console.log('SQL to run:', readFileSync('./sql/001_design_styles.sql', 'utf-8'));
} else {
console.log('β
design_styles table exists');
}
}
async function createPalettesTable(): Promise<void> {
const serviceClient = supabase.getServiceClient();
const { data, error } = await serviceClient
.from('design_palettes')
.select('count', { count: 'exact', head: true });
if (error && error.code === 'PGRST116') {
console.log('β οΈ design_palettes table does not exist. Please run the SQL manually.');
console.log('SQL to run:', readFileSync('./sql/002_design_palettes.sql', 'utf-8'));
} else {
console.log('β
design_palettes table exists');
}
}
async function createCompatibilityTable(): Promise<void> {
const serviceClient = supabase.getServiceClient();
const { data, error } = await serviceClient
.from('style_palette_compatibility')
.select('count', { count: 'exact', head: true });
if (error && error.code === 'PGRST116') {
console.log('β οΈ style_palette_compatibility table does not exist. Please run the SQL manually.');
console.log('SQL to run:', readFileSync('./sql/003_compatibility.sql', 'utf-8'));
} else {
console.log('β
style_palette_compatibility table exists');
}
}
async function seedStyles(): Promise<void> {
console.log('π₯ Seeding styles data...');
const stylesData = await loadJSONFile<Record<string, Style>>('../style-library/styles-complete.json');
const serviceClient = supabase.getServiceClient();
const styles = Object.values(stylesData).map(style => ({
id: style.id,
name: style.name,
industry: style.industry,
style_dna: style.styleDNA,
dos: style.dos,
donts: style.donts,
tokens: style.tokens,
raw_length: style.rawLength,
businesses: style.businesses,
category: style.category,
category_label: style.categoryLabel
}));
// Insert in batches of 10
const batchSize = 10;
for (let i = 0; i < styles.length; i += batchSize) {
const batch = styles.slice(i, i + batchSize);
const { error } = await serviceClient
.from('design_styles')
.upsert(batch);
if (error) {
console.error(`β Error inserting styles batch ${i}-${i + batch.length}:`, error);
throw error;
}
console.log(`β
Inserted styles ${i + 1}-${i + batch.length} of ${styles.length}`);
}
}
async function seedPalettes(): Promise<void> {
console.log('π₯ Seeding palettes data...');
const palettesData = await loadJSONFile<Palette[]>('../style-library/palettes/palettes-index.json');
const serviceClient = supabase.getServiceClient();
const palettes = palettesData.map(palette => ({
id: palette.id,
name: palette.name,
mood: palette.mood,
industries: palette.industries,
category: palette.category,
primary_light: palette.primaryLight,
primary_dark: palette.primaryDark,
accent_light: palette.accentLight,
heading_font: palette.heading,
body_font: palette.body,
border_radius: palette.radius
}));
// Insert in batches of 10
const batchSize = 10;
for (let i = 0; i < palettes.length; i += batchSize) {
const batch = palettes.slice(i, i + batchSize);
const { error } = await serviceClient
.from('design_palettes')
.upsert(batch);
if (error) {
console.error(`β Error inserting palettes batch ${i}-${i + batch.length}:`, error);
throw error;
}
console.log(`β
Inserted palettes ${i + 1}-${i + batch.length} of ${palettes.length}`);
}
}
async function seedCompatibility(): Promise<void> {
console.log('π₯ Seeding compatibility data...');
const compatibilityData = await loadJSONFile<CompatibilityMatrix[]>('../style-library/compatibility-matrix.json');
const serviceClient = supabase.getServiceClient();
// Flatten the compatibility data
const compatibilityRecords: Array<{
style_id: string;
palette_id: string;
score: number;
}> = [];
for (const styleMatrix of compatibilityData) {
for (const score of styleMatrix.allScores) {
compatibilityRecords.push({
style_id: styleMatrix.styleId,
palette_id: score.id,
score: score.score
});
}
}
console.log(`Found ${compatibilityRecords.length} compatibility records`);
// Insert in batches of 50
const batchSize = 50;
for (let i = 0; i < compatibilityRecords.length; i += batchSize) {
const batch = compatibilityRecords.slice(i, i + batchSize);
const { error } = await serviceClient
.from('style_palette_compatibility')
.upsert(batch);
if (error) {
console.error(`β Error inserting compatibility batch ${i}-${i + batch.length}:`, error);
throw error;
}
console.log(`β
Inserted compatibility ${i + 1}-${i + batch.length} of ${compatibilityRecords.length}`);
}
}
async function verifyData(): Promise<void> {
console.log('π Verifying seeded data...');
const anonClient = supabase.getAnonClient();
// Check styles count
const { count: stylesCount, error: stylesError } = await anonClient
.from('design_styles')
.select('*', { count: 'exact', head: true });
if (stylesError) {
console.error('β Error counting styles:', stylesError);
} else {
console.log(`β
Styles in database: ${stylesCount}`);
}
// Check palettes count
const { count: palettesCount, error: palettesError } = await anonClient
.from('design_palettes')
.select('*', { count: 'exact', head: true });
if (palettesError) {
console.error('β Error counting palettes:', palettesError);
} else {
console.log(`β
Palettes in database: ${palettesCount}`);
}
// Check compatibility count
const { count: compatibilityCount, error: compatibilityError } = await anonClient
.from('style_palette_compatibility')
.select('*', { count: 'exact', head: true });
if (compatibilityError) {
console.error('β Error counting compatibility records:', compatibilityError);
} else {
console.log(`β
Compatibility records in database: ${compatibilityCount}`);
}
}
async function main(): Promise<void> {
console.log('π Starting WebForge database seeding...');
try {
// Test connection
const isConnected = await supabase.testConnection();
if (!isConnected) {
throw new Error('Failed to connect to Supabase');
}
// Create tables (or verify they exist)
await createTables();
// Seed data
await seedStyles();
await seedPalettes();
await seedCompatibility();
// Verify the data was inserted
await verifyData();
console.log('π Database seeding completed successfully!');
} catch (error) {
console.error('π₯ Seeding failed:', error);
process.exit(1);
}
}
// Run if called directly
if (import.meta.url === `file://${process.argv[1]}`) {
main();
}