refactor(desktop): organize lib modules by domain
This commit is contained in:
1 parent
90f0594e93
commit
7e7c4944e9
700 files changed
+1292
-1264
No files matched your search
@@ -0,0 +1,130 @@
|
||||
export function sqlServerStatementForDerivedTable(statement: string): string {
|
||||
const orderBy = findTopLevelTrailingOrderBy(statement);
|
||||
if (orderBy === undefined) return statement;
|
||||
if (hasTopLevelSelectTop(statement) || hasTopLevelForXml(statement)) return statement;
|
||||
return statement.slice(0, orderBy).trimEnd();
|
||||
}
|
||||
|
||||
function findTopLevelTrailingOrderBy(sql: string): number | undefined {
|
||||
const tokens = topLevelSqlTokens(sql);
|
||||
for (let i = tokens.length - 2; i >= 0; i--) {
|
||||
if (tokens[i].text === "ORDER" && tokens[i + 1]?.text === "BY") {
|
||||
return tokens[i].start;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function hasTopLevelSelectTop(sql: string): boolean {
|
||||
const tokens = topLevelSqlTokens(sql);
|
||||
const selectIndex = tokens.findIndex((token) => token.text === "SELECT");
|
||||
if (selectIndex < 0) return false;
|
||||
const fromIndex = tokens.findIndex((token, index) => index > selectIndex && token.text === "FROM");
|
||||
const end = fromIndex < 0 ? tokens.length : fromIndex;
|
||||
return tokens.slice(selectIndex + 1, end).some((token) => token.text === "TOP");
|
||||
}
|
||||
|
||||
function hasTopLevelForXml(sql: string): boolean {
|
||||
const tokens = topLevelSqlTokens(sql);
|
||||
return tokens.some((token, index) => token.text === "FOR" && tokens[index + 1]?.text === "XML");
|
||||
}
|
||||
|
||||
function topLevelSqlTokens(sql: string): Array<{ text: string; start: number }> {
|
||||
const tokens: Array<{ text: string; start: number }> = [];
|
||||
let i = 0;
|
||||
let depth = 0;
|
||||
|
||||
while (i < sql.length) {
|
||||
const ch = sql[i];
|
||||
const next = sql[i + 1];
|
||||
|
||||
if (ch === "-" && next === "-") {
|
||||
i += 2;
|
||||
while (i < sql.length && sql[i] !== "\n") i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === "/" && next === "*") {
|
||||
i += 2;
|
||||
while (i < sql.length - 1 && !(sql[i] === "*" && sql[i + 1] === "/")) i++;
|
||||
i = Math.min(i + 2, sql.length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === "'" || ch === '"' || ch === "`") {
|
||||
i = skipSqlQuoted(sql, i, ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === "[") {
|
||||
i = skipSqlBracketIdentifier(sql, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === "(") {
|
||||
depth++;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === ")") {
|
||||
depth = Math.max(0, depth - 1);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth === 0 && isSqlTokenStart(ch)) {
|
||||
const start = i;
|
||||
i++;
|
||||
while (i < sql.length && isSqlTokenPart(sql[i])) i++;
|
||||
tokens.push({ text: sql.slice(start, i).toUpperCase(), start });
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function skipSqlQuoted(sql: string, pos: number, quote: string): number {
|
||||
let i = pos + 1;
|
||||
while (i < sql.length) {
|
||||
if (sql[i] === quote) {
|
||||
if (sql[i + 1] === quote) {
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
if (quote === "'" && sql[i] === "\\") {
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return sql.length;
|
||||
}
|
||||
|
||||
function skipSqlBracketIdentifier(sql: string, pos: number): number {
|
||||
let i = pos + 1;
|
||||
while (i < sql.length) {
|
||||
if (sql[i] === "]") {
|
||||
if (sql[i + 1] === "]") {
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return sql.length;
|
||||
}
|
||||
|
||||
function isSqlTokenStart(ch: string | undefined): boolean {
|
||||
return !!ch && /[A-Za-z_]/.test(ch);
|
||||
}
|
||||
|
||||
function isSqlTokenPart(ch: string | undefined): boolean {
|
||||
return !!ch && /[A-Za-z0-9_$#]/.test(ch);
|
||||
}
|
||||
Reference in new issue
Block a user