Files
gia-gve-certificates/src/db.js
2026-07-01 09:18:06 +05:00

140 lines
3.5 KiB
JavaScript

const initSqlJs = require('sql.js');
const path = require('path');
const fs = require('fs');
const DATA_DIR = path.join(__dirname, '..', 'data');
const DB_PATH = path.join(DATA_DIR, 'exams.db');
let db = null;
async function initDb() {
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR, { recursive: true });
}
const SQL = await initSqlJs();
if (fs.existsSync(DB_PATH)) {
const buffer = fs.readFileSync(DB_PATH);
db = new SQL.Database(buffer);
} else {
db = new SQL.Database();
}
db.run('PRAGMA foreign_keys = ON');
db.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
login TEXT UNIQUE NOT NULL,
password TEXT,
name TEXT NOT NULL,
email TEXT,
role TEXT DEFAULT 'teacher',
auth_type TEXT DEFAULT 'local',
groups TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
last_login DATETIME
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
last_name TEXT NOT NULL,
first_name TEXT NOT NULL,
patronymic TEXT DEFAULT '',
class TEXT DEFAULT '',
school_code TEXT DEFAULT '',
passport_series TEXT DEFAULT '',
passport_number TEXT DEFAULT '',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE(last_name, first_name, patronymic, class)
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS subjects (
code TEXT PRIMARY KEY,
name TEXT NOT NULL,
exam_date TEXT DEFAULT '',
is_mandatory INTEGER DEFAULT 0
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS exam_results (
id INTEGER PRIMARY KEY AUTOINCREMENT,
student_id INTEGER NOT NULL,
subject_code TEXT NOT NULL,
primary_score INTEGER,
grade INTEGER,
FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE,
FOREIGN KEY (subject_code) REFERENCES subjects(code),
UNIQUE(student_id, subject_code)
)
`);
db.run('INSERT OR IGNORE INTO subjects (code, name, is_mandatory) VALUES (?, ?, 1)', ['01', 'Русский язык']);
db.run('INSERT OR IGNORE INTO subjects (code, name, is_mandatory) VALUES (?, ?, 1)', ['02', 'Математика']);
saveDb();
console.log('БД инициализирована');
return db;
}
function saveDb() {
if (!db) return;
const data = db.export();
const buffer = Buffer.from(data);
fs.writeFileSync(DB_PATH, buffer);
}
function getDb() {
if (!db) throw new Error('БД не инициализирована.');
return db;
}
// Wrappers emulating better-sqlite3 API
function dbGet(sql, params = []) {
const st = db.prepare(sql);
st.bind(params);
const hasRow = st.step();
const row = hasRow ? st.getAsObject() : null;
st.free();
return row;
}
function dbAll(sql, params = []) {
const st = db.prepare(sql);
st.bind(params);
const rows = [];
while (st.step()) {
rows.push(st.getAsObject());
}
st.free();
return rows;
}
function dbRun(sql, params = []) {
const before = db.getRowsModified();
db.run(sql, params);
const after = db.getRowsModified();
return { changes: after - before };
}
function dbLastInsertId() {
const r = db.exec('SELECT last_insert_rowid() as id');
return r.length ? r[0].values[0][0] : null;
}
function dbExec(sql) {
db.run(sql);
}
function dbBegin() { db.run('BEGIN'); }
function dbCommit() { db.run('COMMIT'); }
function dbRollback() { try { db.run('ROLLBACK'); } catch (e) {} }
module.exports = { initDb, getDb, saveDb, dbGet, dbAll, dbRun, dbLastInsertId, dbExec, dbBegin, dbCommit, dbRollback };