56 lines
2.1 KiB
JavaScript
56 lines
2.1 KiB
JavaScript
function quoteIdentifiers(sql) {
|
|
return sql.replace(/\[([^\]]+)]/g, '"$1"');
|
|
}
|
|
|
|
function moveReturning(sql) {
|
|
const output = /\bOUTPUT\s+([\s\S]*?)(?=\bVALUES\b|\bWHERE\b|\bDEFAULT\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(/\bWITH\s*\(\s*(?:NOLOCK|UPDLOCK|ROWLOCK|HOLDLOCK|READPAST)(?:\s*,\s*(?:NOLOCK|UPDLOCK|ROWLOCK|HOLDLOCK|READPAST))*\s*\)/gi, '')
|
|
.replace(/\bISNULL\s*\(/gi, 'IFNULL(')
|
|
.replace(/\bLEN\s*\(/gi, 'LENGTH(')
|
|
.replace(/\bSYSUTCDATETIME\s*\(\s*\)/gi, "strftime('%Y-%m-%dT%H:%M:%fZ', 'now')")
|
|
.replace(/\bDATEDIFF_BIG\s*\(\s*second\s*,\s*'1970-01-01'\s*,\s*([^)]+?)\s*\)/gi, "CAST(strftime('%s', $1) AS INTEGER)")
|
|
.replace(/\bCAST\s*\(([^()]+?)\s+AS\s+INT\s*\)/gi, 'CAST($1 AS INTEGER)')
|
|
.replace(/\bCONVERT\s*\(\s*VARBINARY\s*\(\s*MAX\s*\)\s*,\s*([^)]+?)\s*\)/gi, '$1');
|
|
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,
|
|
]),
|
|
);
|
|
}
|