providerrefactor part1

This commit is contained in:
seb
2026-09-21 03:33:55 +02:00
parent 53a20c4353
commit 4ed6260e91
57 changed files with 1662 additions and 145 deletions

View File

@@ -0,0 +1,51 @@
function quoteIdentifiers(sql) {
return sql.replace(/\[([^\]]+)]/g, '"$1"');
}
function moveReturning(sql) {
const output = /\bOUTPUT\s+([\s\S]*?)(?=\bVALUES\b|\bWHERE\b)/i.exec(sql);
if (!output) return sql;
const columns = output[1]
.split(',')
.map((column) => column.trim().replace(/\bINSERTED\./gi, ''))
.join(', ');
const withoutOutput = sql.slice(0, output.index) + sql.slice(output.index + output[0].length);
return `${withoutOutput.trim().replace(/;$/, '')}\nRETURNING ${columns}`;
}
function moveTop(sql) {
const matches = [...sql.matchAll(/\bTOP\s*\(?\s*(\d+)\s*\)?\s*/gi)];
if (matches.length === 0) return sql;
if (matches.length > 1) {
// Complex nested queries are supplied as compatibility exports until
// their provider-specific store paths are converted. Do not corrupt them
// by appending one LIMIT to the outer statement.
return sql;
}
return `${sql.replace(matches[0][0], '').trim().replace(/;$/, '')}\nLIMIT ${matches[0][1]}`;
}
/** Convert the common, context-free subset of MSSQL query syntax to SQLite. */
export function sqliteQuery(sql) {
if (typeof sql !== 'string') return sql;
let result = quoteIdentifiers(sql)
.replace(/\bISNULL\s*\(/gi, 'IFNULL(')
.replace(/\bSYSUTCDATETIME\s*\(\s*\)/gi, "strftime('%Y-%m-%dT%H:%M:%fZ', 'now')")
.replace(/\bCAST\s*\(([^()]+?)\s+AS\s+INT\s*\)/gi, 'CAST($1 AS INTEGER)');
result = moveReturning(result);
result = moveTop(result);
return result;
}
export function translateQueries(module, moduleName) {
return Object.fromEntries(
Object.entries(module).map(([name, value]) => [
name,
typeof value === 'string' && /\s/.test(value)
? sqliteQuery(value)
: value,
]),
);
}