102 lines
3.6 KiB
JavaScript
102 lines
3.6 KiB
JavaScript
|
|
// 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'
|
||
|
|
};
|
||
|
|
|