theming, date, time localisation, additional features, seeding initial cleanup
This commit is contained in:
@@ -0,0 +1,662 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
||||
import * as schema from '../lib/db/schema';
|
||||
import { sql, eq } from 'drizzle-orm';
|
||||
import { randomUUID } from 'crypto';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
const sqlite = new Database('./sqlite.db');
|
||||
const db = drizzle(sqlite, { schema });
|
||||
|
||||
interface SetupOptions {
|
||||
reset?: boolean;
|
||||
seedData?: boolean;
|
||||
verbose?: boolean;
|
||||
}
|
||||
|
||||
async function setupDatabase(options: SetupOptions = {}) {
|
||||
const { reset = false, seedData = true, verbose = false } = options;
|
||||
|
||||
try {
|
||||
console.log('🚀 Starting database setup...\n');
|
||||
|
||||
if (reset) {
|
||||
await resetTables(verbose);
|
||||
}
|
||||
|
||||
await createTables(verbose);
|
||||
await seedBasicData(verbose);
|
||||
|
||||
if (seedData) {
|
||||
await seedSampleData(verbose);
|
||||
}
|
||||
|
||||
console.log('✅ Database setup completed successfully!\n');
|
||||
|
||||
// Print summary
|
||||
await printDatabaseSummary();
|
||||
} catch (error) {
|
||||
console.error('❌ Database setup failed:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
sqlite.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function resetTables(verbose: boolean) {
|
||||
if (verbose) console.log('🗑️ Resetting database tables...');
|
||||
|
||||
const tables = [
|
||||
'activity_logs',
|
||||
'metrics',
|
||||
'bookings',
|
||||
'announcements',
|
||||
'time_slots',
|
||||
'settings',
|
||||
'courts',
|
||||
'users',
|
||||
'__drizzle_migrations',
|
||||
'__old_push_courts',
|
||||
'__old_push_users',
|
||||
];
|
||||
|
||||
for (const table of tables) {
|
||||
try {
|
||||
await db.run(sql.raw(`DROP TABLE IF EXISTS ${table}`));
|
||||
if (verbose) console.log(` ✓ Dropped table: ${table}`);
|
||||
} catch (error) {
|
||||
if (verbose) console.log(` - Table ${table} doesn't exist or error dropping`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Tables reset complete\n');
|
||||
}
|
||||
|
||||
async function createTables(verbose: boolean) {
|
||||
if (verbose) console.log('🏗️ Creating database tables...');
|
||||
|
||||
// Users table
|
||||
await db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
surname TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('user', 'admin')),
|
||||
theme_preference TEXT DEFAULT 'system' CHECK (theme_preference IN ('light', 'dark', 'system')),
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
// Courts table
|
||||
await db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS courts (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
// Settings table
|
||||
await db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
id TEXT PRIMARY KEY,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
value TEXT NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
// Time slots table
|
||||
await db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS time_slots (
|
||||
id TEXT PRIMARY KEY,
|
||||
day_of_week INTEGER NOT NULL,
|
||||
start_time TEXT NOT NULL,
|
||||
end_time TEXT NOT NULL,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
// Bookings table
|
||||
await db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS bookings (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
court_id TEXT NOT NULL REFERENCES courts(id) ON DELETE CASCADE,
|
||||
date TEXT NOT NULL,
|
||||
start_time TEXT NOT NULL,
|
||||
end_time TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'cancelled')),
|
||||
notes TEXT,
|
||||
partner_name TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
// Announcements table
|
||||
await db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS announcements (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
priority TEXT NOT NULL DEFAULT 'medium' CHECK (priority IN ('low', 'medium', 'high')),
|
||||
expires_at INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
// Activity logs table
|
||||
await db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS activity_logs (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
|
||||
action TEXT NOT NULL,
|
||||
entity_type TEXT NOT NULL,
|
||||
entity_id TEXT,
|
||||
details TEXT,
|
||||
ip_address TEXT,
|
||||
user_agent TEXT,
|
||||
created_at INTEGER NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
// Metrics table
|
||||
await db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS metrics (
|
||||
id TEXT PRIMARY KEY,
|
||||
metric_type TEXT NOT NULL,
|
||||
period TEXT NOT NULL,
|
||||
value INTEGER NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
if (verbose) console.log(' ✓ All tables created successfully');
|
||||
console.log('✅ Database schema ready\n');
|
||||
}
|
||||
|
||||
async function seedBasicData(verbose: boolean) {
|
||||
console.log('🌱 Seeding essential data...');
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
// Check if users already exist
|
||||
const existingUsers = await db.select().from(schema.users);
|
||||
|
||||
if (existingUsers.length === 0) {
|
||||
// Create admin user
|
||||
const adminPassword = await bcrypt.hash('admin123', 12);
|
||||
const adminId = randomUUID();
|
||||
|
||||
await db.insert(schema.users).values({
|
||||
id: adminId,
|
||||
email: 'admin@tabletennis.com',
|
||||
name: 'Admin',
|
||||
surname: 'User',
|
||||
password: adminPassword,
|
||||
role: 'admin',
|
||||
themePreference: 'system',
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
});
|
||||
|
||||
// Create test user
|
||||
const userPassword = await bcrypt.hash('user123', 12);
|
||||
const userId = randomUUID();
|
||||
|
||||
await db.insert(schema.users).values({
|
||||
id: userId,
|
||||
email: 'user@tabletennis.com',
|
||||
name: 'Test',
|
||||
surname: 'User',
|
||||
password: userPassword,
|
||||
role: 'user',
|
||||
themePreference: 'system',
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
});
|
||||
|
||||
if (verbose) console.log(' ✓ Created admin and test users');
|
||||
} else {
|
||||
if (verbose) console.log(' - Users already exist, skipping user creation');
|
||||
}
|
||||
|
||||
// Check if courts already exist
|
||||
const existingCourts = await db.select().from(schema.courts);
|
||||
|
||||
if (existingCourts.length === 0) {
|
||||
// Create courts
|
||||
const courtIds = [randomUUID(), randomUUID(), randomUUID()];
|
||||
await db.insert(schema.courts).values([
|
||||
{
|
||||
id: courtIds[0],
|
||||
name: 'Court 1',
|
||||
isActive: true,
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
},
|
||||
{
|
||||
id: courtIds[1],
|
||||
name: 'Court 2',
|
||||
isActive: true,
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
},
|
||||
{
|
||||
id: courtIds[2],
|
||||
name: 'Court 3',
|
||||
isActive: true,
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
},
|
||||
]);
|
||||
|
||||
if (verbose) console.log(' ✓ Created 3 courts');
|
||||
} else {
|
||||
if (verbose) console.log(' - Courts already exist, skipping court creation');
|
||||
}
|
||||
|
||||
// Insert system settings
|
||||
const defaultSettings = [
|
||||
{ key: 'booking_window_days', value: '14' },
|
||||
{ key: 'max_booking_duration_hours', value: '2' },
|
||||
{ key: 'max_bookings_per_user_per_hour_per_day', value: '1' },
|
||||
{ key: 'allow_booking_modifications', value: 'true' },
|
||||
{ key: 'booking_modification_hours_before', value: '2' },
|
||||
{ key: 'min_booking_duration_minutes', value: '60' },
|
||||
{ key: 'booking_start_time', value: '08:00' },
|
||||
{ key: 'booking_end_time', value: '22:00' },
|
||||
{ key: 'allow_weekend_bookings', value: 'true' },
|
||||
{ key: 'facility_name', value: 'Table Tennis Club' },
|
||||
{ key: 'facility_email', value: 'info@tabletennis.com' },
|
||||
{ key: 'facility_phone', value: '+353-1-234-5678' },
|
||||
];
|
||||
|
||||
for (const setting of defaultSettings) {
|
||||
const existingSetting = await db
|
||||
.select()
|
||||
.from(schema.settings)
|
||||
.where(eq(schema.settings.key, setting.key))
|
||||
.limit(1);
|
||||
|
||||
if (existingSetting.length === 0) {
|
||||
await db.insert(schema.settings).values({
|
||||
id: randomUUID(),
|
||||
key: setting.key,
|
||||
value: setting.value,
|
||||
updatedAt: new Date(now),
|
||||
});
|
||||
if (verbose) console.log(` ✓ Setting: ${setting.key} = ${setting.value}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if time slots already exist
|
||||
const existingTimeSlots = await db.select().from(schema.timeSlots);
|
||||
|
||||
if (existingTimeSlots.length === 0) {
|
||||
// Create time slots - Operating hours for each day
|
||||
const timeSlotData = [
|
||||
// Sunday: 12:00 - 17:00 (shorter hours)
|
||||
{ dayOfWeek: 0, startTime: '12:00', endTime: '17:00' },
|
||||
|
||||
// Monday to Thursday: 18:00 - 23:00 (evening sessions)
|
||||
{ dayOfWeek: 1, startTime: '18:00', endTime: '23:00' },
|
||||
{ dayOfWeek: 2, startTime: '18:00', endTime: '23:00' },
|
||||
{ dayOfWeek: 3, startTime: '18:00', endTime: '23:00' },
|
||||
{ dayOfWeek: 4, startTime: '18:00', endTime: '23:00' },
|
||||
|
||||
// Friday: 17:00 - 22:00 (earlier end)
|
||||
{ dayOfWeek: 5, startTime: '17:00', endTime: '22:00' },
|
||||
|
||||
// Saturday: 10:00 - 18:00 (full day weekend)
|
||||
{ dayOfWeek: 6, startTime: '10:00', endTime: '18:00' },
|
||||
];
|
||||
|
||||
for (const slot of timeSlotData) {
|
||||
await db.insert(schema.timeSlots).values({
|
||||
id: randomUUID(),
|
||||
dayOfWeek: slot.dayOfWeek,
|
||||
startTime: slot.startTime,
|
||||
endTime: slot.endTime,
|
||||
isActive: true,
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
});
|
||||
}
|
||||
|
||||
if (verbose) console.log(' ✓ Created time slots for all days');
|
||||
} else {
|
||||
if (verbose) console.log(' - Time slots already exist, skipping time slot creation');
|
||||
}
|
||||
|
||||
// Check if announcements already exist
|
||||
const existingAnnouncements = await db.select().from(schema.announcements);
|
||||
|
||||
if (existingAnnouncements.length === 0) {
|
||||
// Create essential announcements
|
||||
const essentialAnnouncements = [
|
||||
{
|
||||
id: randomUUID(),
|
||||
title: 'Welcome to Table Tennis Booking System!',
|
||||
content:
|
||||
'Book your court times easily and manage your games efficiently. Check the time slots for availability and remember to arrive 5 minutes early.',
|
||||
isActive: true,
|
||||
priority: 'high' as const,
|
||||
expiresAt: null,
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
},
|
||||
{
|
||||
id: randomUUID(),
|
||||
title: 'Booking Guidelines',
|
||||
content:
|
||||
'Maximum booking duration is 2 hours. Please cancel bookings you cannot attend to allow others to use the courts.',
|
||||
isActive: true,
|
||||
priority: 'medium' as const,
|
||||
expiresAt: null,
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
},
|
||||
];
|
||||
|
||||
await db.insert(schema.announcements).values(essentialAnnouncements);
|
||||
|
||||
if (verbose) console.log(' ✓ Created essential announcements');
|
||||
} else {
|
||||
if (verbose) console.log(' - Announcements already exist, skipping announcement creation');
|
||||
}
|
||||
|
||||
// Initialize monthly metrics if they don't exist
|
||||
const currentMonth = new Date().toISOString().substring(0, 7);
|
||||
const existingMetrics = await db
|
||||
.select()
|
||||
.from(schema.metrics)
|
||||
.where(eq(schema.metrics.period, currentMonth))
|
||||
.limit(1);
|
||||
|
||||
if (existingMetrics.length === 0) {
|
||||
await db.insert(schema.metrics).values({
|
||||
id: randomUUID(),
|
||||
metricType: 'monthly_bookings',
|
||||
period: currentMonth,
|
||||
value: 0,
|
||||
createdAt: new Date(now),
|
||||
updatedAt: new Date(now),
|
||||
});
|
||||
|
||||
if (verbose) console.log(' ✓ Initialized monthly metrics');
|
||||
} else {
|
||||
if (verbose) console.log(' - Monthly metrics already exist');
|
||||
}
|
||||
|
||||
console.log('✅ Essential data seeded\n');
|
||||
}
|
||||
|
||||
async function seedSampleData(verbose: boolean) {
|
||||
console.log('🎭 Seeding sample data...');
|
||||
|
||||
const now = Date.now();
|
||||
const users = await db.select().from(schema.users);
|
||||
const courts = await db.select().from(schema.courts);
|
||||
|
||||
const adminUser = users.find((u) => u.role === 'admin');
|
||||
const regularUser = users.find((u) => u.role === 'user');
|
||||
|
||||
if (!adminUser || !regularUser) {
|
||||
console.log('⚠️ No users found for sample data');
|
||||
return;
|
||||
}
|
||||
|
||||
// Sample bookings for the next few days
|
||||
const today = new Date();
|
||||
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
|
||||
const dayAfter = new Date(today.getTime() + 48 * 60 * 60 * 1000);
|
||||
|
||||
const sampleBookings = [
|
||||
{
|
||||
id: randomUUID(),
|
||||
userId: regularUser.id,
|
||||
courtId: courts[0].id,
|
||||
date: today.toISOString().split('T')[0],
|
||||
startTime: '19:00',
|
||||
endTime: '20:00',
|
||||
status: 'active' as const,
|
||||
notes: 'Regular evening practice session',
|
||||
partnerName: 'John Smith',
|
||||
createdAt: new Date(now - 2 * 60 * 60 * 1000),
|
||||
updatedAt: new Date(now - 2 * 60 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: randomUUID(),
|
||||
userId: regularUser.id,
|
||||
courtId: courts[1]?.id || courts[0].id,
|
||||
date: tomorrow.toISOString().split('T')[0],
|
||||
startTime: '20:00',
|
||||
endTime: '21:00',
|
||||
status: 'active' as const,
|
||||
notes: 'Tournament preparation',
|
||||
partnerName: null,
|
||||
createdAt: new Date(now - 1 * 60 * 60 * 1000),
|
||||
updatedAt: new Date(now - 1 * 60 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: randomUUID(),
|
||||
userId: adminUser.id,
|
||||
courtId: courts[2]?.id || courts[0].id,
|
||||
date: dayAfter.toISOString().split('T')[0],
|
||||
startTime: '18:00',
|
||||
endTime: '20:00',
|
||||
status: 'active' as const,
|
||||
notes: 'Staff training session',
|
||||
partnerName: 'Staff Team',
|
||||
createdAt: new Date(now - 30 * 60 * 1000),
|
||||
updatedAt: new Date(now - 30 * 60 * 1000),
|
||||
},
|
||||
];
|
||||
|
||||
await db.insert(schema.bookings).values(sampleBookings);
|
||||
|
||||
// Sample activity logs
|
||||
const sampleLogs = [
|
||||
{
|
||||
id: randomUUID(),
|
||||
userId: adminUser.id,
|
||||
action: 'login',
|
||||
entityType: 'user',
|
||||
entityId: adminUser.id,
|
||||
details: JSON.stringify({
|
||||
email: adminUser.email,
|
||||
role: adminUser.role,
|
||||
loginMethod: 'password',
|
||||
}),
|
||||
ipAddress: '192.168.1.100',
|
||||
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
|
||||
createdAt: new Date(now - 3 * 60 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: randomUUID(),
|
||||
userId: regularUser.id,
|
||||
action: 'create_booking',
|
||||
entityType: 'booking',
|
||||
entityId: sampleBookings[0].id,
|
||||
details: JSON.stringify({
|
||||
courtId: courts[0].id,
|
||||
courtName: courts[0].name,
|
||||
date: today.toISOString().split('T')[0],
|
||||
startTime: '19:00',
|
||||
endTime: '20:00',
|
||||
}),
|
||||
ipAddress: '192.168.1.101',
|
||||
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15',
|
||||
createdAt: new Date(now - 2 * 60 * 60 * 1000),
|
||||
},
|
||||
];
|
||||
|
||||
await db.insert(schema.activityLogs).values(sampleLogs);
|
||||
|
||||
// Additional announcements
|
||||
const additionalAnnouncements = [
|
||||
{
|
||||
id: randomUUID(),
|
||||
title: 'New Court Rules',
|
||||
content:
|
||||
'Please remember to clean up after your sessions and respect the time limits. Equipment should be returned to the storage area.',
|
||||
isActive: true,
|
||||
priority: 'medium' as const,
|
||||
expiresAt: new Date(now + 7 * 24 * 60 * 60 * 1000), // 1 week from now
|
||||
createdAt: new Date(now - 4 * 60 * 60 * 1000),
|
||||
updatedAt: new Date(now - 4 * 60 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: randomUUID(),
|
||||
title: 'Tournament Sign-ups Open!',
|
||||
content:
|
||||
'The annual table tennis tournament sign-ups are now open! Register by the end of this month. Prizes for winners in each category.',
|
||||
isActive: true,
|
||||
priority: 'high' as const,
|
||||
expiresAt: new Date(now + 30 * 24 * 60 * 60 * 1000), // 30 days from now
|
||||
createdAt: new Date(now - 24 * 60 * 60 * 1000),
|
||||
updatedAt: new Date(now - 24 * 60 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: randomUUID(),
|
||||
title: 'Equipment Maintenance',
|
||||
content:
|
||||
'New paddles and balls have been added to the equipment collection. Old equipment will be replaced gradually.',
|
||||
isActive: true,
|
||||
priority: 'low' as const,
|
||||
expiresAt: new Date(now + 14 * 24 * 60 * 60 * 1000), // 2 weeks from now
|
||||
createdAt: new Date(now - 6 * 60 * 60 * 1000),
|
||||
updatedAt: new Date(now - 6 * 60 * 60 * 1000),
|
||||
},
|
||||
];
|
||||
|
||||
await db.insert(schema.announcements).values(additionalAnnouncements);
|
||||
|
||||
if (verbose) {
|
||||
console.log(` ✓ Created ${sampleBookings.length} sample bookings`);
|
||||
console.log(` ✓ Created ${sampleLogs.length} activity logs`);
|
||||
console.log(` ✓ Created ${additionalAnnouncements.length} additional announcements`);
|
||||
}
|
||||
|
||||
console.log('✅ Sample data seeded\n');
|
||||
}
|
||||
|
||||
async function printDatabaseSummary() {
|
||||
console.log('📊 Database Summary:');
|
||||
console.log('═══════════════════════════════════════\n');
|
||||
|
||||
const users = await db.select().from(schema.users);
|
||||
const courts = await db.select().from(schema.courts);
|
||||
const bookings = await db.select().from(schema.bookings);
|
||||
const announcements = await db.select().from(schema.announcements);
|
||||
const timeSlots = await db.select().from(schema.timeSlots);
|
||||
const settings = await db.select().from(schema.settings);
|
||||
|
||||
console.log(`👥 Users: ${users.length}`);
|
||||
users.forEach((user) => {
|
||||
console.log(` • ${user.name} ${user.surname} (${user.email}) - ${user.role}`);
|
||||
});
|
||||
|
||||
console.log(`\n🏓 Courts: ${courts.length}`);
|
||||
courts.forEach((court) => {
|
||||
console.log(` • ${court.name} - ${court.isActive ? 'Active' : 'Inactive'}`);
|
||||
});
|
||||
|
||||
console.log(`\n📅 Bookings: ${bookings.length}`);
|
||||
if (bookings.length > 0) {
|
||||
console.log(' Recent bookings:');
|
||||
bookings.slice(0, 3).forEach((booking) => {
|
||||
console.log(` • ${booking.date} ${booking.startTime}-${booking.endTime} (${booking.status})`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`\n📢 Announcements: ${announcements.length}`);
|
||||
const activeAnnouncements = announcements.filter((a) => a.isActive);
|
||||
console.log(` • Active: ${activeAnnouncements.length}`);
|
||||
|
||||
console.log(`\n⏰ Time Slots: ${timeSlots.length}`);
|
||||
const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||
timeSlots.forEach((slot) => {
|
||||
console.log(` • ${dayNames[slot.dayOfWeek]}: ${slot.startTime}-${slot.endTime}`);
|
||||
});
|
||||
|
||||
console.log(`\n⚙️ Settings: ${settings.length} configured`);
|
||||
|
||||
console.log('\n💡 Login Credentials:');
|
||||
console.log(' Admin: admin@tabletennis.com / admin123');
|
||||
console.log(' User: user@tabletennis.com / user123');
|
||||
|
||||
console.log('\n🚀 Ready to start! Run: npm run dev');
|
||||
console.log('═══════════════════════════════════════\n');
|
||||
}
|
||||
|
||||
// Parse command line arguments
|
||||
function parseArgs() {
|
||||
const args = process.argv.slice(2);
|
||||
const options: SetupOptions = {};
|
||||
|
||||
if (args.includes('--reset') || args.includes('-r')) {
|
||||
options.reset = true;
|
||||
}
|
||||
|
||||
if (args.includes('--no-sample-data') || args.includes('--essential-only')) {
|
||||
options.seedData = false;
|
||||
}
|
||||
|
||||
if (args.includes('--verbose') || args.includes('-v')) {
|
||||
options.verbose = true;
|
||||
}
|
||||
|
||||
if (args.includes('--help') || args.includes('-h')) {
|
||||
console.log(`
|
||||
Table Tennis Booking System - Database Setup
|
||||
|
||||
Usage: tsx scripts/setup-database.ts [options]
|
||||
|
||||
Options:
|
||||
--reset, -r Reset/drop all tables before setup
|
||||
--no-sample-data Only seed essential data (no sample bookings/logs)
|
||||
--essential-only Same as --no-sample-data
|
||||
--verbose, -v Show detailed output
|
||||
--help, -h Show this help message
|
||||
|
||||
Examples:
|
||||
tsx scripts/setup-database.ts # Full setup with sample data
|
||||
tsx scripts/setup-database.ts --reset # Reset and full setup
|
||||
tsx scripts/setup-database.ts --essential-only # Only essential data
|
||||
tsx scripts/setup-database.ts --reset --verbose # Reset with detailed output
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
// Main execution
|
||||
if (require.main === module) {
|
||||
const options = parseArgs();
|
||||
|
||||
setupDatabase(options)
|
||||
.then(() => {
|
||||
console.log('🎉 Database setup completed successfully!');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('💥 Database setup failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
export { setupDatabase };
|
||||
Reference in New Issue
Block a user