110 lines
3.5 KiB
JavaScript
110 lines
3.5 KiB
JavaScript
import Database from 'better-sqlite3';
|
|
import { join } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import fs from 'fs'; // Needed to check if db file exists
|
|
|
|
// Determine the database path relative to this file
|
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
const dbPath = join(__dirname, 'forms.db');
|
|
|
|
let db = null;
|
|
|
|
export function initializeDatabase() {
|
|
if (db) {
|
|
return db;
|
|
}
|
|
|
|
try {
|
|
// Check if the directory exists, create if not (better-sqlite3 might need this)
|
|
const dbDir = join(__dirname);
|
|
if (!fs.existsSync(dbDir)) {
|
|
fs.mkdirSync(dbDir, { recursive: true });
|
|
}
|
|
|
|
// better-sqlite3 constructor opens/creates the database file
|
|
db = new Database(dbPath, { verbose: console.log }); // Enable verbose logging
|
|
|
|
console.log('Connected to the SQLite database using better-sqlite3.');
|
|
|
|
// Ensure WAL mode is enabled for better concurrency
|
|
db.pragma('journal_mode = WAL');
|
|
|
|
// Create tables if they don't exist (run sequentially)
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS forms (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
`);
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS categories (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
formId INTEGER NOT NULL,
|
|
name TEXT NOT NULL,
|
|
sortOrder INTEGER DEFAULT 0,
|
|
FOREIGN KEY (formId) REFERENCES forms (id) ON DELETE CASCADE
|
|
);
|
|
`);
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS fields (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
categoryId INTEGER NOT NULL,
|
|
label TEXT NOT NULL,
|
|
type TEXT NOT NULL CHECK(type IN ('text', 'number', 'date', 'textarea', 'boolean')),
|
|
description TEXT,
|
|
sortOrder INTEGER NOT NULL,
|
|
FOREIGN KEY (categoryId) REFERENCES categories(id) ON DELETE CASCADE
|
|
);
|
|
`);
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS responses (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
formId INTEGER NOT NULL,
|
|
submittedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (formId) REFERENCES forms (id) ON DELETE CASCADE
|
|
);
|
|
`);
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS response_values (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
responseId INTEGER NOT NULL,
|
|
fieldId INTEGER NOT NULL,
|
|
value TEXT,
|
|
FOREIGN KEY (responseId) REFERENCES responses (id) ON DELETE CASCADE,
|
|
FOREIGN KEY (fieldId) REFERENCES fields (id) ON DELETE CASCADE
|
|
);
|
|
`);
|
|
|
|
console.log('Database tables ensured.');
|
|
return db;
|
|
} catch (err) {
|
|
console.error('Error initializing database with better-sqlite3:', err.message);
|
|
throw err; // Re-throw the error
|
|
}
|
|
}
|
|
|
|
export function getDb() {
|
|
if (!db) {
|
|
// Try to initialize if not already done (e.g., during hot reload)
|
|
try {
|
|
initializeDatabase();
|
|
} catch (err) {
|
|
throw new Error('Database not initialized and initialization failed.');
|
|
}
|
|
if (!db) { // Check again after trying to initialize
|
|
throw new Error('Database not initialized. Call initializeDatabase first.');
|
|
}
|
|
}
|
|
return db;
|
|
}
|
|
|
|
// Optional: Add a function to close the database gracefully on server shutdown
|
|
export function closeDatabase() {
|
|
if (db) {
|
|
db.close();
|
|
db = null;
|
|
console.log('Database connection closed.');
|
|
}
|
|
}
|