// Vibe coded since I needed more resources on my VPS :/ const Database = require('better-sqlite3'); // 1. Connect to the file (creates it if missing) const db = new Database('project.db'); db.pragma('journal_mode = WAL'); // Faster, safer writes class FakeMssqlRequest { constructor(db) { this.db = db; this.params = {}; // Stores your inputs: .input('id', 123) } // Mimic the .input() method // We ignore 'type' because SQLite is loosely typed input(name, type, value) { // Handle case where value is passed as 2nd arg (omitting type) if (value === undefined) value = type; this.params[name] = value; return this; // Return 'this' to allow chaining (.input().input()) } // Mimic the .query() method async query(sqlString) { try { let cleanSql = sqlString; // --- FIX 1: Handle TOP -> LIMIT --- // Regex detects: SELECT TOP (@amount) ... OR SELECT TOP 10 ... // It captures the value (@amount or 10) const topRegex = /SELECT\s+TOP\s*\(?(@?\w+)\)?/i; const topMatch = cleanSql.match(topRegex); if (topMatch) { const limitValue = topMatch[1]; // Extracts '@amount' or '10' // 1. Remove "TOP (@amount)" from the start cleanSql = cleanSql.replace(topRegex, 'SELECT '); // 2. Remove any trailing semicolon so we can append cleanSql = cleanSql.replace(/;\s*$/, ''); // 3. Append LIMIT to the end cleanSql += ` LIMIT ${limitValue}`; } // 1. Compatibility Fixes (Optional but helpful) // Replace 'GETDATE()' with SQLite's "datetime('now')" cleanSql = cleanSql.replace(/GETDATE\(\)/gi, "datetime('now', 'localtime')") // MS SQL: SYSUTCDATETIME() -> SQLite: datetime('now') (Already UTC) .replace(/SYSUTCDATETIME\(\)/gi, "datetime('now')") // --- FIX 3: Clean up Square Brackets --- .replace(/\[/g, '"').replace(/\]/g, '"') // --- FIX 4: Handle String Concatenation in LIKE clauses --- // MSSQL: LIKE '%' + @param + '%' // SQLite: LIKE '%' || @param || '%' // This regex looks for: LIKE '%' + @anything + '%' .replace(/LIKE\s+'%'\s*\+\s*(@\w+)\s*\+\s*'%'/gi, "LIKE '%' || $1 || '%'"); // 2. Determine if it's a SELECT or INSERT/UPDATE const stmt = this.db.prepare(cleanSql); if (cleanSql.trim().toUpperCase().startsWith('SELECT')) { // READ: Use .all() const rows = stmt.all(this.params); return { recordset: rows, rowsAffected: [rows.length] }; } else { // WRITE: Use .run() const info = stmt.run(this.params); return { recordset: [], rowsAffected: [info.changes] }; } } catch (err) { console.error("SQLite Error:", err.message); console.error("Query was:", sqlString); throw err; } } } // Mimic the main 'pool' object const pool = { connected: true, request: () => new FakeMssqlRequest(db), close: () => db.close() }; module.exports = { // Mimic the sql.connect() function connect: async () => { console.log("Connected to SQLite (via Wrapper)"); return pool; }, // Export types to prevent "sql.Int is undefined" errors Int: 'Int', NVarChar: 'NVarChar', Bit: 'Bit', DateTime: 'DateTime' };