Switch from MySQL to SQLite database

This commit is contained in:
Your Name
2025-04-29 17:58:42 -04:00
parent d1ecfa9595
commit e89e3d4791
3 changed files with 38 additions and 82 deletions

View File

@@ -11,14 +11,16 @@
}, },
"dependencies": { "dependencies": {
"express": "^4.18.2", "express": "^4.18.2",
"mysql2": "^3.6.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.3.1" "dotenv": "^16.3.1",
"sqlite3": "^5.1.6",
"sqlite": "^4.1.2"
}, },
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
"@types/node": "^20.4.5", "@types/node": "^20.4.5",
"@types/cors": "^2.8.13", "@types/cors": "^2.8.13",
"@types/sqlite3": "^3.1.8",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"nodemon": "^3.0.1", "nodemon": "^3.0.1",
"ts-node": "^10.9.1" "ts-node": "^10.9.1"

View File

@@ -1,6 +1,7 @@
import express, { Request, Response } from 'express'; import express, { Request, Response } from 'express';
import cors from 'cors'; import cors from 'cors';
import mysql, { RowDataPacket, ResultSetHeader } from 'mysql2/promise'; import sqlite3 from 'sqlite3';
import { open } from 'sqlite';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
dotenv.config(); dotenv.config();
@@ -13,40 +14,19 @@ app.use(cors());
app.use(express.json()); app.use(express.json());
// Database connection // Database connection
const pool = mysql.createPool({ let db: any;
host: process.env.DB_HOST || 'mysql',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || 'password',
database: process.env.DB_NAME || 'rsvp_db',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
interface Event extends RowDataPacket { async function connectToDatabase() {
id: number; db = await open({
title: string; filename: './database.sqlite',
description: string; driver: sqlite3.Database
date: string; });
location: string;
slug: string;
}
interface RSVP extends RowDataPacket {
id: number;
event_id: number;
name: string;
attending: string;
bringing_guests: string;
guest_count: number;
guest_names: string;
items_bringing: string;
} }
// Routes // Routes
app.get('/api/events', async (req: Request, res: Response) => { app.get('/api/events', async (req: Request, res: Response) => {
try { try {
const [rows] = await pool.query<Event[]>('SELECT * FROM events'); const rows = await db.all('SELECT * FROM events');
res.json(rows); res.json(rows);
} catch (error) { } catch (error) {
console.error('Error fetching events:', error); console.error('Error fetching events:', error);
@@ -57,7 +37,7 @@ app.get('/api/events', async (req: Request, res: Response) => {
app.get('/api/events/:slug', async (req: Request, res: Response) => { app.get('/api/events/:slug', async (req: Request, res: Response) => {
try { try {
const { slug } = req.params; const { slug } = req.params;
const [rows] = await pool.query<Event[]>('SELECT * FROM events WHERE slug = ?', [slug]); const rows = await db.all('SELECT * FROM events WHERE slug = ?', [slug]);
if (rows.length === 0) { if (rows.length === 0) {
return res.status(404).json({ error: 'Event not found' }); return res.status(404).json({ error: 'Event not found' });
} }
@@ -74,7 +54,7 @@ app.post('/api/events', async (req: Request, res: Response) => {
// Generate a slug from the title // Generate a slug from the title
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, '-'); const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
const [result] = await pool.query<ResultSetHeader>( const result = await db.run(
'INSERT INTO events (title, description, date, location, slug) VALUES (?, ?, ?, ?, ?)', 'INSERT INTO events (title, description, date, location, slug) VALUES (?, ?, ?, ?, ?)',
[title, description, date, location, slug] [title, description, date, location, slug]
); );
@@ -89,14 +69,14 @@ app.post('/api/events', async (req: Request, res: Response) => {
app.get('/api/events/:slug/rsvps', async (req: Request, res: Response) => { app.get('/api/events/:slug/rsvps', async (req: Request, res: Response) => {
try { try {
const { slug } = req.params; const { slug } = req.params;
const [eventRows] = await pool.query<Event[]>('SELECT id FROM events WHERE slug = ?', [slug]); const eventRows = await db.all('SELECT id FROM events WHERE slug = ?', [slug]);
if (eventRows.length === 0) { if (eventRows.length === 0) {
return res.status(404).json({ error: 'Event not found' }); return res.status(404).json({ error: 'Event not found' });
} }
const eventId = eventRows[0].id; const eventId = eventRows[0].id;
const [rows] = await pool.query<RSVP[]>('SELECT * FROM rsvps WHERE event_id = ?', [eventId]); const rows = await db.all('SELECT * FROM rsvps WHERE event_id = ?', [eventId]);
res.json(rows); res.json(rows);
} catch (error) { } catch (error) {
console.error('Error fetching RSVPs:', error); console.error('Error fetching RSVPs:', error);
@@ -109,14 +89,14 @@ app.post('/api/events/:slug/rsvp', async (req: Request, res: Response) => {
const { slug } = req.params; const { slug } = req.params;
const { name, attending, bringing_guests, guest_count, guest_names, items_bringing } = req.body; const { name, attending, bringing_guests, guest_count, guest_names, items_bringing } = req.body;
const [eventRows] = await pool.query<Event[]>('SELECT id FROM events WHERE slug = ?', [slug]); const eventRows = await db.all('SELECT id FROM events WHERE slug = ?', [slug]);
if (eventRows.length === 0) { if (eventRows.length === 0) {
return res.status(404).json({ error: 'Event not found' }); return res.status(404).json({ error: 'Event not found' });
} }
const eventId = eventRows[0].id; const eventId = eventRows[0].id;
const [result] = await pool.query<ResultSetHeader>( const result = await db.run(
'INSERT INTO rsvps (event_id, name, attending, bringing_guests, guest_count, guest_names, items_bringing) VALUES (?, ?, ?, ?, ?, ?, ?)', 'INSERT INTO rsvps (event_id, name, attending, bringing_guests, guest_count, guest_names, items_bringing) VALUES (?, ?, ?, ?, ?, ?, ?)',
[eventId, name, attending, bringing_guests, guest_count, guest_names, items_bringing] [eventId, name, attending, bringing_guests, guest_count, guest_names, items_bringing]
); );
@@ -132,14 +112,14 @@ app.delete('/api/events/:slug/rsvps/:id', async (req: Request, res: Response) =>
const { slug, id } = req.params; const { slug, id } = req.params;
// Verify the RSVP belongs to the correct event // Verify the RSVP belongs to the correct event
const [eventRows] = await pool.query<Event[]>('SELECT id FROM events WHERE slug = ?', [slug]); const eventRows = await db.all('SELECT id FROM events WHERE slug = ?', [slug]);
if (eventRows.length === 0) { if (eventRows.length === 0) {
return res.status(404).json({ error: 'Event not found' }); return res.status(404).json({ error: 'Event not found' });
} }
const eventId = eventRows[0].id; const eventId = eventRows[0].id;
await pool.query('DELETE FROM rsvps WHERE id = ? AND event_id = ?', [id, eventId]); await db.run('DELETE FROM rsvps WHERE id = ? AND event_id = ?', [id, eventId]);
res.status(204).send(); res.status(204).send();
} catch (error) { } catch (error) {
console.error('Error deleting RSVP:', error); console.error('Error deleting RSVP:', error);
@@ -150,26 +130,26 @@ app.delete('/api/events/:slug/rsvps/:id', async (req: Request, res: Response) =>
// Initialize database tables // Initialize database tables
async function initializeDatabase() { async function initializeDatabase() {
try { try {
await pool.query(` await db.exec(`
CREATE TABLE IF NOT EXISTS events ( CREATE TABLE IF NOT EXISTS events (
id INT AUTO_INCREMENT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
title VARCHAR(255) NOT NULL, title TEXT NOT NULL,
description TEXT, description TEXT,
date DATETIME NOT NULL, date TEXT NOT NULL,
location VARCHAR(255), location TEXT,
slug VARCHAR(255) NOT NULL UNIQUE, slug TEXT NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) )
`); `);
await pool.query(` await db.exec(`
CREATE TABLE IF NOT EXISTS rsvps ( CREATE TABLE IF NOT EXISTS rsvps (
id INT AUTO_INCREMENT PRIMARY KEY, id INTEGER PRIMARY KEY AUTOINCREMENT,
event_id INT NOT NULL, event_id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL, name TEXT NOT NULL,
attending VARCHAR(10) NOT NULL, attending TEXT NOT NULL,
bringing_guests VARCHAR(10) NOT NULL, bringing_guests TEXT NOT NULL,
guest_count INT DEFAULT 0, guest_count INTEGER DEFAULT 0,
guest_names TEXT, guest_names TEXT,
items_bringing TEXT, items_bringing TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
@@ -183,7 +163,8 @@ async function initializeDatabase() {
} }
// Start server // Start server
app.listen(port, () => { app.listen(port, async () => {
console.log(`Server running on port ${port}`); console.log(`Server running on port ${port}`);
initializeDatabase(); await connectToDatabase();
await initializeDatabase();
}); });

View File

@@ -10,34 +10,7 @@ services:
- data:/app - data:/app
environment: environment:
- NODE_ENV=development - NODE_ENV=development
- DB_HOST=mysql
- DB_USER=root
- DB_PASSWORD=password
- DB_NAME=rsvp_db
depends_on:
- mysql
restart: unless-stopped restart: unless-stopped
networks:
- rsvp-network
mysql:
image: mysql:8.0
container_name: rsvp_mysql
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=rsvp_db
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3306:3306"
restart: unless-stopped
networks:
- rsvp-network
volumes: volumes:
data: data:
mysql-data:
networks:
rsvp-network:
driver: bridge