main: add many things to app :)
Signed-off-by: nfel <nfilsaraee@gmail.com>
This commit is contained in:
@@ -1,25 +1,40 @@
|
||||
import { Database } from 'bun:sqlite';
|
||||
import path from 'path';
|
||||
import { albums as initialAlbums } from './data';
|
||||
import { Album, Purchase } from './types';
|
||||
import { Database } from "bun:sqlite";
|
||||
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');
|
||||
const dbPath = path.join(process.cwd(), "data", "parsa.db");
|
||||
|
||||
// Initialize database
|
||||
let db: Database;
|
||||
let db: any;
|
||||
|
||||
export function getDatabase(): Database {
|
||||
function createDatabase() {
|
||||
// Use Bun's native SQLite if available, otherwise use better-sqlite3
|
||||
const isBun = typeof Bun !== "undefined";
|
||||
const { Database } = require("bun:sqlite");
|
||||
return new Database(dbPath, { create: true });
|
||||
|
||||
if (isBun) {
|
||||
const { Database } = require("bun:sqlite");
|
||||
return new Database(dbPath, { create: true });
|
||||
} else {
|
||||
const Database = require("better-sqlite3");
|
||||
return new Database(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
export function getDatabase(): any {
|
||||
if (!db) {
|
||||
// Create data directory if it doesn't exist
|
||||
const fs = require('fs');
|
||||
const dataDir = path.join(process.cwd(), 'data');
|
||||
const fs = require("fs");
|
||||
const dataDir = path.join(process.cwd(), "data");
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
}
|
||||
|
||||
db = new Database(dbPath, { create: true });
|
||||
db.exec('PRAGMA journal_mode = WAL');
|
||||
db = createDatabase();
|
||||
db.exec("PRAGMA journal_mode = WAL");
|
||||
initializeDatabase();
|
||||
}
|
||||
return db;
|
||||
@@ -56,19 +71,58 @@ function initializeDatabase() {
|
||||
phoneNumber TEXT,
|
||||
txReceipt TEXT,
|
||||
purchaseDate INTEGER NOT NULL,
|
||||
approvalStatus TEXT DEFAULT 'pending',
|
||||
paymentMethod TEXT DEFAULT 'card-to-card',
|
||||
createdAt INTEGER DEFAULT (strftime('%s', 'now')),
|
||||
FOREIGN KEY (albumId) REFERENCES albums(id) ON DELETE CASCADE
|
||||
)
|
||||
`);
|
||||
|
||||
// Create payment authorities table for ZarinPal tracking
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS payment_authorities (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
authority TEXT NOT NULL UNIQUE,
|
||||
albumId TEXT NOT NULL,
|
||||
amount INTEGER NOT NULL,
|
||||
customerName TEXT,
|
||||
email TEXT,
|
||||
phoneNumber TEXT,
|
||||
status TEXT DEFAULT 'pending',
|
||||
refId TEXT,
|
||||
cardPan TEXT,
|
||||
fee INTEGER,
|
||||
createdAt INTEGER DEFAULT (strftime('%s', 'now')),
|
||||
verifiedAt INTEGER,
|
||||
FOREIGN KEY (albumId) REFERENCES albums(id) ON DELETE CASCADE
|
||||
)
|
||||
`);
|
||||
|
||||
// Add columns if they don't exist (migration)
|
||||
try {
|
||||
db.exec(`ALTER TABLE purchases ADD COLUMN approvalStatus TEXT DEFAULT 'pending'`);
|
||||
} catch (e) {
|
||||
// Column already exists
|
||||
}
|
||||
try {
|
||||
db.exec(`ALTER TABLE purchases ADD COLUMN paymentMethod TEXT DEFAULT 'card-to-card'`);
|
||||
} catch (e) {
|
||||
// Column already exists
|
||||
}
|
||||
|
||||
// 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);
|
||||
CREATE INDEX IF NOT EXISTS idx_purchases_approvalStatus ON purchases(approvalStatus);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_authorities_authority ON payment_authorities(authority);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_authorities_status ON payment_authorities(status);
|
||||
`);
|
||||
|
||||
// Seed initial data if albums table is empty
|
||||
const count = db.prepare('SELECT COUNT(*) as count FROM albums').get() as { count: number };
|
||||
const count = db.prepare("SELECT COUNT(*) as count FROM albums").get() as {
|
||||
count: number;
|
||||
};
|
||||
if (count.count === 0) {
|
||||
seedInitialData();
|
||||
}
|
||||
@@ -93,7 +147,7 @@ function seedInitialData() {
|
||||
album.tag,
|
||||
album.format,
|
||||
album.bitrate,
|
||||
JSON.stringify(album.songs)
|
||||
JSON.stringify(album.songs),
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -105,7 +159,7 @@ function seedInitialData() {
|
||||
export const albumDb = {
|
||||
getAll(): Album[] {
|
||||
const db = getDatabase();
|
||||
const rows = db.prepare('SELECT * FROM albums ORDER BY year DESC').all();
|
||||
const rows = db.prepare("SELECT * FROM albums ORDER BY year DESC").all();
|
||||
return rows.map((row: any) => ({
|
||||
...row,
|
||||
songs: JSON.parse(row.songs),
|
||||
@@ -114,7 +168,7 @@ export const albumDb = {
|
||||
|
||||
getById(id: string): Album | null {
|
||||
const db = getDatabase();
|
||||
const row = db.prepare('SELECT * FROM albums WHERE id = ?').get(id) as any;
|
||||
const row = db.prepare("SELECT * FROM albums WHERE id = ?").get(id) as any;
|
||||
if (!row) return null;
|
||||
return {
|
||||
...row,
|
||||
@@ -124,10 +178,12 @@ export const albumDb = {
|
||||
|
||||
create(album: Album): void {
|
||||
const db = getDatabase();
|
||||
db.prepare(`
|
||||
db.prepare(
|
||||
`
|
||||
INSERT INTO albums (id, title, coverImage, year, genre, description, price, tag, format, bitrate, songs)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
`,
|
||||
).run(
|
||||
album.id,
|
||||
album.title,
|
||||
album.coverImage,
|
||||
@@ -138,17 +194,19 @@ export const albumDb = {
|
||||
album.tag,
|
||||
album.format,
|
||||
album.bitrate,
|
||||
JSON.stringify(album.songs)
|
||||
JSON.stringify(album.songs),
|
||||
);
|
||||
},
|
||||
|
||||
update(id: string, album: Album): void {
|
||||
const db = getDatabase();
|
||||
db.prepare(`
|
||||
db.prepare(
|
||||
`
|
||||
UPDATE albums
|
||||
SET title = ?, coverImage = ?, year = ?, genre = ?, description = ?, price = ?, tag = ?, format = ?, bitrate = ?, songs = ?, updatedAt = strftime('%s', 'now')
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
`,
|
||||
).run(
|
||||
album.title,
|
||||
album.coverImage,
|
||||
album.year,
|
||||
@@ -159,13 +217,13 @@ export const albumDb = {
|
||||
album.format,
|
||||
album.bitrate,
|
||||
JSON.stringify(album.songs),
|
||||
id
|
||||
id,
|
||||
);
|
||||
},
|
||||
|
||||
delete(id: string): void {
|
||||
const db = getDatabase();
|
||||
db.prepare('DELETE FROM albums WHERE id = ?').run(id);
|
||||
db.prepare("DELETE FROM albums WHERE id = ?").run(id);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -173,7 +231,9 @@ export const albumDb = {
|
||||
export const purchaseDb = {
|
||||
getAll(): Purchase[] {
|
||||
const db = getDatabase();
|
||||
const rows = db.prepare('SELECT * FROM purchases ORDER BY purchaseDate DESC').all();
|
||||
const rows = db
|
||||
.prepare("SELECT * FROM purchases ORDER BY purchaseDate DESC")
|
||||
.all();
|
||||
return rows.map((row: any) => ({
|
||||
id: row.id,
|
||||
albumId: row.albumId,
|
||||
@@ -183,12 +243,18 @@ export const purchaseDb = {
|
||||
phoneNumber: row.phoneNumber,
|
||||
txReceipt: row.txReceipt,
|
||||
purchaseDate: new Date(row.purchaseDate),
|
||||
approvalStatus: row.approvalStatus,
|
||||
paymentMethod: row.paymentMethod,
|
||||
}));
|
||||
},
|
||||
|
||||
getByAlbumId(albumId: string): Purchase[] {
|
||||
const db = getDatabase();
|
||||
const rows = db.prepare('SELECT * FROM purchases WHERE albumId = ? ORDER BY purchaseDate DESC').all(albumId);
|
||||
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,
|
||||
@@ -198,12 +264,16 @@ export const purchaseDb = {
|
||||
phoneNumber: row.phoneNumber,
|
||||
txReceipt: row.txReceipt,
|
||||
purchaseDate: new Date(row.purchaseDate),
|
||||
approvalStatus: row.approvalStatus,
|
||||
paymentMethod: row.paymentMethod,
|
||||
}));
|
||||
},
|
||||
|
||||
getByTransactionId(transactionId: string): Purchase | null {
|
||||
const db = getDatabase();
|
||||
const row = db.prepare('SELECT * FROM purchases WHERE transactionId = ?').get(transactionId) as any;
|
||||
const row = db
|
||||
.prepare("SELECT * FROM purchases WHERE transactionId = ?")
|
||||
.get(transactionId) as any;
|
||||
if (!row) return null;
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -214,23 +284,33 @@ export const purchaseDb = {
|
||||
phoneNumber: row.phoneNumber,
|
||||
txReceipt: row.txReceipt,
|
||||
purchaseDate: new Date(row.purchaseDate),
|
||||
approvalStatus: row.approvalStatus,
|
||||
paymentMethod: row.paymentMethod,
|
||||
};
|
||||
},
|
||||
|
||||
create(purchase: Omit<Purchase, 'id'>): Purchase {
|
||||
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
|
||||
);
|
||||
const result = db
|
||||
.prepare(
|
||||
`
|
||||
INSERT INTO purchases (albumId, transactionId, customerName, email, phoneNumber, txReceipt, purchaseDate, approvalStatus, paymentMethod)
|
||||
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,
|
||||
purchase.approvalStatus || 'pending',
|
||||
purchase.paymentMethod || 'card-to-card',
|
||||
);
|
||||
|
||||
return {
|
||||
id: result.lastInsertRowid as number,
|
||||
@@ -240,6 +320,6 @@ export const purchaseDb = {
|
||||
|
||||
delete(id: number): void {
|
||||
const db = getDatabase();
|
||||
db.prepare('DELETE FROM purchases WHERE id = ?').run(id);
|
||||
db.prepare("DELETE FROM purchases WHERE id = ?").run(id);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user