const LocalDatabase = require('../config/LocalDatabase'); const logger = require('../utils/logger'); /** * Mod Model - Handles mod data in local database */ class ModModel { static async create(modData) { const { name, version, author, description, filePath, checksum, dependencies, config } = modData; const sql = ` INSERT INTO mods (name, version, author, description, file_path, checksum, dependencies, config) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `; const result = await LocalDatabase.run(sql, [ name, version, author, description || null, filePath, checksum || null, dependencies ? JSON.stringify(dependencies) : null, config ? JSON.stringify(config) : null ]); return await this.findById(result.id); } static async findById(id) { const sql = 'SELECT * FROM mods WHERE id = ?'; const mod = await LocalDatabase.get(sql, [id]); return this.parseMod(mod); } static async findByName(name) { const sql = 'SELECT * FROM mods WHERE name = ?'; const mod = await LocalDatabase.get(sql, [name]); return this.parseMod(mod); } static async findAll(enabledOnly = false) { const sql = enabledOnly ? 'SELECT * FROM mods WHERE enabled = 1 ORDER BY name' : 'SELECT * FROM mods ORDER BY name'; const mods = await LocalDatabase.all(sql); return mods.map(mod => this.parseMod(mod)); } static async update(id, updates) { const fields = []; const values = []; Object.keys(updates).forEach(key => { if (key === 'dependencies' || key === 'config') { fields.push(`${key} = ?`); values.push(JSON.stringify(updates[key])); } else { fields.push(`${key} = ?`); values.push(updates[key]); } }); if (fields.length === 0) return false; fields.push('updated_at = CURRENT_TIMESTAMP'); values.push(id); const sql = `UPDATE mods SET ${fields.join(', ')} WHERE id = ?`; const result = await LocalDatabase.run(sql, values); return result.changes > 0; } static async delete(id) { const sql = 'DELETE FROM mods WHERE id = ?'; const result = await LocalDatabase.run(sql, [id]); return result.changes > 0; } static async enable(id) { return await this.update(id, { enabled: 1 }); } static async disable(id) { return await this.update(id, { enabled: 0 }); } static async getLoadOrder() { const sql = ` SELECT m.*, ml.load_order FROM mods m LEFT JOIN mod_load_order ml ON m.id = ml.mod_id WHERE m.enabled = 1 ORDER BY ml.load_order ASC, m.name ASC `; const mods = await LocalDatabase.all(sql); return mods.map(mod => this.parseMod(mod)); } static async setLoadOrder(modIds) { await LocalDatabase.run('DELETE FROM mod_load_order'); for (let i = 0; i < modIds.length; i++) { await LocalDatabase.run( 'INSERT INTO mod_load_order (mod_id, load_order) VALUES (?, ?)', [modIds[i], i + 1] ); } return true; } static parseMod(mod) { if (!mod) return null; return { ...mod, enabled: Boolean(mod.enabled), dependencies: mod.dependencies ? JSON.parse(mod.dependencies) : null, config: mod.config ? JSON.parse(mod.config) : null }; } } /** * ModAsset Model - Handles mod assets in local database */ class ModAssetModel { static async create(assetData) { const { modId, assetType, assetId, assetData: data } = assetData; const sql = ` INSERT OR REPLACE INTO mod_assets (mod_id, asset_type, asset_id, asset_data) VALUES (?, ?, ?, ?) `; const result = await LocalDatabase.run(sql, [ modId, assetType, assetId, JSON.stringify(data) ]); return await this.findById(result.id); } static async findById(id) { const sql = 'SELECT * FROM mod_assets WHERE id = ?'; const asset = await LocalDatabase.get(sql, [id]); return this.parseAsset(asset); } static async findByModId(modId) { const sql = 'SELECT * FROM mod_assets WHERE mod_id = ?'; const assets = await LocalDatabase.all(sql, [modId]); return assets.map(asset => this.parseAsset(asset)); } static async findByType(assetType) { const sql = ` SELECT ma.*, m.name as mod_name, m.enabled as mod_enabled FROM mod_assets ma JOIN mods m ON ma.mod_id = m.id WHERE ma.asset_type = ? AND m.enabled = 1 ORDER BY m.name, ma.asset_id `; const assets = await LocalDatabase.all(sql, [assetType]); return assets.map(asset => this.parseAsset(asset)); } static async findByTypeAndId(assetType, assetId) { const sql = ` SELECT ma.*, m.name as mod_name, m.enabled as mod_enabled FROM mod_assets ma JOIN mods m ON ma.mod_id = m.id WHERE ma.asset_type = ? AND ma.asset_id = ? AND m.enabled = 1 `; const asset = await LocalDatabase.get(sql, [assetType, assetId]); return this.parseAsset(asset); } static async delete(id) { const sql = 'DELETE FROM mod_assets WHERE id = ?'; const result = await LocalDatabase.run(sql, [id]); return result.changes > 0; } static async deleteByModId(modId) { const sql = 'DELETE FROM mod_assets WHERE mod_id = ?'; const result = await LocalDatabase.run(sql, [modId]); return result.changes > 0; } static parseAsset(asset) { if (!asset) return null; return { ...asset, assetData: JSON.parse(asset.asset_data), modEnabled: Boolean(asset.mod_enabled) }; } } /** * ServerModPreferences Model - Handles server mod preferences */ class ServerModPreferencesModel { static async set(key, value) { const sql = ` INSERT OR REPLACE INTO server_mod_preferences (key, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP) `; const result = await LocalDatabase.run(sql, [key, JSON.stringify(value)]); return result.changes > 0; } static async get(key) { const sql = 'SELECT * FROM server_mod_preferences WHERE key = ?'; const pref = await LocalDatabase.get(sql, [key]); if (!pref) return null; return JSON.parse(pref.value); } static async getAll() { const sql = 'SELECT * FROM server_mod_preferences'; const prefs = await LocalDatabase.all(sql); const result = {}; prefs.forEach(pref => { result[pref.key] = JSON.parse(pref.value); }); return result; } static async delete(key) { const sql = 'DELETE FROM server_mod_preferences WHERE key = ?'; const result = await LocalDatabase.run(sql, [key]); return result.changes > 0; } } module.exports = { ModModel, ModAssetModel, ServerModPreferencesModel };