import Database from 'better-sqlite3'; import path from 'path'; import { albums as initialAlbums } from './data'; import { Album, Purchase } from './types'; // Database path const dbPath = path.join(process.cwd(), 'data', 'parsa.db'); // Initialize database let db: Database.Database; export function getDatabase(): Database.Database { if (!db) { // Create data directory if it doesn't exist const fs = require('fs'); const dataDir = path.join(process.cwd(), 'data'); if (!fs.existsSync(dataDir)) { fs.mkdirSync(dataDir, { recursive: true }); } db = new Database(dbPath); db.pragma('journal_mode = WAL'); initializeDatabase(); } return db; } function initializeDatabase() { // Create albums table db.exec(` CREATE TABLE IF NOT EXISTS albums ( id TEXT PRIMARY KEY, title TEXT NOT NULL, coverImage TEXT NOT NULL, year INTEGER NOT NULL, genre TEXT NOT NULL, description TEXT NOT NULL, price REAL NOT NULL, songs TEXT NOT NULL, createdAt INTEGER DEFAULT (strftime('%s', 'now')), updatedAt INTEGER DEFAULT (strftime('%s', 'now')) ) `); // Create purchases table db.exec(` CREATE TABLE IF NOT EXISTS purchases ( id INTEGER PRIMARY KEY AUTOINCREMENT, albumId TEXT NOT NULL, transactionId TEXT NOT NULL UNIQUE, customerName TEXT, email TEXT, phoneNumber TEXT, txReceipt TEXT, purchaseDate INTEGER NOT NULL, createdAt INTEGER DEFAULT (strftime('%s', 'now')), FOREIGN KEY (albumId) REFERENCES albums(id) ON DELETE CASCADE ) `); // Create indexes db.exec(` CREATE INDEX IF NOT EXISTS idx_purchases_albumId ON purchases(albumId); CREATE INDEX IF NOT EXISTS idx_purchases_transactionId ON purchases(transactionId); `); // Seed initial data if albums table is empty const count = db.prepare('SELECT COUNT(*) as count FROM albums').get() as { count: number }; if (count.count === 0) { seedInitialData(); } } function seedInitialData() { const insert = db.prepare(` INSERT INTO albums (id, title, coverImage, year, genre, description, price, songs) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `); const insertMany = db.transaction((albums: Album[]) => { for (const album of albums) { insert.run( album.id, album.title, album.coverImage, album.year, album.genre, album.description, album.price, JSON.stringify(album.songs) ); } }); insertMany(initialAlbums); } // Album operations export const albumDb = { getAll(): Album[] { const rows = db.prepare('SELECT * FROM albums ORDER BY year DESC').all(); return rows.map((row: any) => ({ ...row, songs: JSON.parse(row.songs), })); }, getById(id: string): Album | null { const row = db.prepare('SELECT * FROM albums WHERE id = ?').get(id) as any; if (!row) return null; return { ...row, songs: JSON.parse(row.songs), }; }, create(album: Album): void { db.prepare(` INSERT INTO albums (id, title, coverImage, year, genre, description, price, songs) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `).run( album.id, album.title, album.coverImage, album.year, album.genre, album.description, album.price, JSON.stringify(album.songs) ); }, update(id: string, album: Album): void { db.prepare(` UPDATE albums SET title = ?, coverImage = ?, year = ?, genre = ?, description = ?, price = ?, songs = ?, updatedAt = strftime('%s', 'now') WHERE id = ? `).run( album.title, album.coverImage, album.year, album.genre, album.description, album.price, JSON.stringify(album.songs), id ); }, delete(id: string): void { db.prepare('DELETE FROM albums WHERE id = ?').run(id); }, }; // Purchase operations export const purchaseDb = { getAll(): Purchase[] { const rows = db.prepare('SELECT * FROM purchases ORDER BY purchaseDate DESC').all(); return rows.map((row: any) => ({ id: row.id, albumId: row.albumId, transactionId: row.transactionId, customerName: row.customerName, email: row.email, phoneNumber: row.phoneNumber, txReceipt: row.txReceipt, purchaseDate: new Date(row.purchaseDate), })); }, getByAlbumId(albumId: string): Purchase[] { const rows = db.prepare('SELECT * FROM purchases WHERE albumId = ? ORDER BY purchaseDate DESC').all(albumId); return rows.map((row: any) => ({ id: row.id, albumId: row.albumId, transactionId: row.transactionId, customerName: row.customerName, email: row.email, phoneNumber: row.phoneNumber, txReceipt: row.txReceipt, purchaseDate: new Date(row.purchaseDate), })); }, getByTransactionId(transactionId: string): Purchase | null { const row = db.prepare('SELECT * FROM purchases WHERE transactionId = ?').get(transactionId) as any; if (!row) return null; return { id: row.id, albumId: row.albumId, transactionId: row.transactionId, customerName: row.customerName, email: row.email, phoneNumber: row.phoneNumber, txReceipt: row.txReceipt, purchaseDate: new Date(row.purchaseDate), }; }, create(purchase: Omit): Purchase { const result = db.prepare(` INSERT INTO purchases (albumId, transactionId, customerName, email, phoneNumber, txReceipt, purchaseDate) VALUES (?, ?, ?, ?, ?, ?, ?) `).run( purchase.albumId, purchase.transactionId, purchase.customerName || null, purchase.email || null, purchase.phoneNumber || null, purchase.txReceipt || null, purchase.purchaseDate instanceof Date ? purchase.purchaseDate.getTime() : purchase.purchaseDate ); return { id: result.lastInsertRowid as number, ...purchase, }; }, delete(id: number): void { db.prepare('DELETE FROM purchases WHERE id = ?').run(id); }, }; // Initialize database on import getDatabase();