Files
WaifuBoard/electron/shared/schemas.js

218 lines
7.0 KiB
JavaScript

"use strict";
const sqlite3 = require('sqlite3').verbose();
const path = require("path");
const fs = require("fs");
async function ensureUserDataDB(dbPath) {
const dir = path.dirname(dbPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE);
return new Promise((resolve, reject) => {
const schema = `
CREATE TABLE IF NOT EXISTS User (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
profile_picture_url TEXT,
email TEXT UNIQUE,
password_hash TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS UserIntegration (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL UNIQUE,
platform TEXT NOT NULL DEFAULT 'AniList',
access_token TEXT NOT NULL,
refresh_token TEXT NOT NULL,
token_type TEXT NOT NULL,
anilist_user_id INTEGER NOT NULL,
expires_at DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS ListEntry (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
entry_id INTEGER NOT NULL,
source TEXT NOT NULL,
entry_type TEXT NOT NULL,
status TEXT NOT NULL,
progress INTEGER NOT NULL DEFAULT 0,
score INTEGER,
start_date DATE,
end_date DATE,
repeat_count INTEGER NOT NULL DEFAULT 0,
notes TEXT,
is_private BOOLEAN NOT NULL DEFAULT 0,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (user_id, entry_id),
FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE CASCADE
);
`;
db.exec(schema, (err) => {
if (err)
reject(err);
else
resolve(true);
});
});
}
async function ensureAnilistSchema(db) {
return new Promise((resolve, reject) => {
const schema = `
CREATE TABLE IF NOT EXISTS anime (
id INTEGER PRIMARY KEY,
title TEXT,
updatedAt INTEGER,
cache_created_at INTEGER DEFAULT 0,
cache_ttl_ms INTEGER DEFAULT 0,
full_data JSON
);
CREATE TABLE IF NOT EXISTS trending (
rank INTEGER PRIMARY KEY,
id INTEGER,
full_data JSON,
updated_at INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS top_airing (
rank INTEGER PRIMARY KEY,
id INTEGER,
full_data JSON,
updated_at INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY,
title TEXT,
updatedAt INTEGER,
full_data JSON
);
CREATE TABLE IF NOT EXISTS trending_books (
rank INTEGER PRIMARY KEY,
id INTEGER,
full_data JSON,
updated_at INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS popular_books (
rank INTEGER PRIMARY KEY,
id INTEGER,
full_data JSON,
updated_at INTEGER NOT NULL DEFAULT 0
);
`;
db.exec(schema, (err) => {
if (err)
reject(err);
else
resolve(true);
});
});
}
async function ensureExtensionsTable(db) {
return new Promise((resolve, reject) => {
db.exec(`
CREATE TABLE IF NOT EXISTS extension (
ext_name TEXT NOT NULL,
id TEXT NOT NULL,
title TEXT NOT NULL,
metadata TEXT NOT NULL,
updated_at INTEGER NOT NULL,
PRIMARY KEY(ext_name, id)
);
`, (err) => {
if (err)
reject(err);
else
resolve(true);
});
});
}
async function ensureCacheTable(db) {
return new Promise((resolve, reject) => {
db.exec(`
CREATE TABLE IF NOT EXISTS cache (
key TEXT PRIMARY KEY,
result TEXT NOT NULL,
created_at INTEGER NOT NULL,
ttl_ms INTEGER NOT NULL
);
`, (err) => {
if (err)
reject(err);
else
resolve(true);
});
});
}
function ensureFavoritesDB(dbPath) {
const dir = path.dirname(dbPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
const exists = fs.existsSync(dbPath);
const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE);
return new Promise((resolve, reject) => {
if (!exists) {
const schema = `
CREATE TABLE IF NOT EXISTS favorites (
id TEXT NOT NULL,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
image_url TEXT NOT NULL,
thumbnail_url TEXT NOT NULL DEFAULT "",
tags TEXT NOT NULL DEFAULT "",
headers TEXT NOT NULL DEFAULT "",
provider TEXT NOT NULL DEFAULT "",
PRIMARY KEY (id, user_id)
);
`;
db.exec(schema, (err) => {
if (err)
reject(err);
else
resolve(true);
});
return;
}
db.all(`PRAGMA table_info(favorites)`, (err, cols) => {
if (err)
return reject(err);
const hasHeaders = cols.some(c => c.name === "headers");
const hasProvider = cols.some(c => c.name === "provider");
const hasUserId = cols.some(c => c.name === "user_id");
const queries = [];
if (!hasHeaders) {
queries.push(`ALTER TABLE favorites ADD COLUMN headers TEXT NOT NULL DEFAULT ""`);
}
if (!hasProvider) {
queries.push(`ALTER TABLE favorites ADD COLUMN provider TEXT NOT NULL DEFAULT ""`);
}
if (!hasUserId) {
queries.push(`ALTER TABLE favorites ADD COLUMN user_id INTEGER NOT NULL DEFAULT 1`);
}
if (queries.length === 0) {
return resolve(false);
}
db.exec(queries.join(";"), (err) => {
if (err)
reject(err);
else
resolve(true);
});
});
});
}
module.exports = {
ensureUserDataDB,
ensureAnilistSchema,
ensureExtensionsTable,
ensureCacheTable,
ensureFavoritesDB
};