podzahr/lib/db.ts
nfel acbaebb947
main: fix build issues
Signed-off-by: nfel <nfilsaraee@gmail.com>
2025-12-27 23:37:46 +03:30

234 lines
6.3 KiB
TypeScript

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 db = getDatabase();
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 db = getDatabase();
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 {
const db = getDatabase();
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 {
const db = getDatabase();
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 {
const db = getDatabase();
db.prepare('DELETE FROM albums WHERE id = ?').run(id);
},
};
// Purchase operations
export const purchaseDb = {
getAll(): Purchase[] {
const db = getDatabase();
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 db = getDatabase();
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 db = getDatabase();
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, 'id'>): Purchase {
const db = getDatabase();
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 {
const db = getDatabase();
db.prepare('DELETE FROM purchases WHERE id = ?').run(id);
},
};