mirror of https://github.com/buster-so/buster.git
fix: replace 'as any' with proper types to resolve linting violations
- Import Select from node-sql-parser for type safety - Replace function parameter types with Record<string, unknown> for dynamic AST objects - Use proper type conversions through 'unknown' for incompatible types - Maintain existing wildcard validation functionality - Resolve all 8 noExplicitAny linting violations Co-Authored-By: Dallin Bentley <dallinbentley98@gmail.com>
This commit is contained in:
parent
b38940939b
commit
3ac9d8b159
|
@ -1,4 +1,4 @@
|
|||
import { Parser } from 'node-sql-parser';
|
||||
import { BaseFrom, ColumnRefItem, Join, Parser, type Select } from 'node-sql-parser';
|
||||
import * as yaml from 'yaml';
|
||||
|
||||
export interface ParsedTable {
|
||||
|
@ -348,7 +348,10 @@ export function extractTablesFromYml(ymlContent: string): ParsedTable[] {
|
|||
* Validates that wildcards (SELECT *) are not used on physical tables
|
||||
* Allows wildcards on CTEs but blocks them on physical database tables
|
||||
*/
|
||||
export function validateWildcardUsage(sql: string, dataSourceSyntax?: string): WildcardValidationResult {
|
||||
export function validateWildcardUsage(
|
||||
sql: string,
|
||||
dataSourceSyntax?: string
|
||||
): WildcardValidationResult {
|
||||
const dialect = getParserDialect(dataSourceSyntax);
|
||||
const parser = new Parser();
|
||||
|
||||
|
@ -380,11 +383,11 @@ export function validateWildcardUsage(sql: string, dataSourceSyntax?: string): W
|
|||
// Simple table name
|
||||
tableAliasMap.set(tableRef.toLowerCase(), tableRef);
|
||||
} else if (tableRef && typeof tableRef === 'object') {
|
||||
const tableRefObj = tableRef as any; // Type assertion to handle dynamic properties
|
||||
const tableRefObj = tableRef as Record<string, unknown>;
|
||||
const tableName = tableRefObj.table || tableRefObj.name;
|
||||
const alias = tableRefObj.as || tableRefObj.alias;
|
||||
if (tableName) {
|
||||
if (alias) {
|
||||
if (tableName && typeof tableName === 'string') {
|
||||
if (alias && typeof alias === 'string') {
|
||||
tableAliasMap.set(alias.toLowerCase(), tableName);
|
||||
}
|
||||
tableAliasMap.set(tableName.toLowerCase(), tableName);
|
||||
|
@ -398,7 +401,10 @@ export function validateWildcardUsage(sql: string, dataSourceSyntax?: string): W
|
|||
|
||||
for (const statement of statements) {
|
||||
if ('type' in statement && statement.type === 'select') {
|
||||
const wildcardTables = findWildcardUsageOnPhysicalTables(statement, cteNames);
|
||||
const wildcardTables = findWildcardUsageOnPhysicalTables(
|
||||
statement as unknown as Record<string, unknown>,
|
||||
cteNames
|
||||
);
|
||||
blockedTables.push(...wildcardTables);
|
||||
}
|
||||
}
|
||||
|
@ -424,40 +430,48 @@ export function validateWildcardUsage(sql: string, dataSourceSyntax?: string): W
|
|||
/**
|
||||
* Recursively finds wildcard usage on physical tables in a SELECT statement
|
||||
*/
|
||||
function findWildcardUsageOnPhysicalTables(selectStatement: any, cteNames: Set<string>): string[] {
|
||||
function findWildcardUsageOnPhysicalTables(
|
||||
selectStatement: Record<string, unknown>,
|
||||
cteNames: Set<string>
|
||||
): string[] {
|
||||
const blockedTables: string[] = [];
|
||||
|
||||
// Build alias mapping for this statement
|
||||
const aliasToTableMap = new Map<string, string>();
|
||||
if (selectStatement.from && Array.isArray(selectStatement.from)) {
|
||||
for (const fromItem of selectStatement.from) {
|
||||
if (fromItem.table && fromItem.as) {
|
||||
const fromItemAny = fromItem as unknown as Record<string, unknown>;
|
||||
if (fromItemAny.table && fromItemAny.as) {
|
||||
let tableName: string;
|
||||
if (typeof fromItem.table === 'string') {
|
||||
tableName = fromItem.table;
|
||||
} else if (fromItem.table && typeof fromItem.table === 'object') {
|
||||
const tableObj = fromItem.table as any;
|
||||
tableName = tableObj.table || tableObj.name || tableObj.value || String(fromItem.table);
|
||||
if (typeof fromItemAny.table === 'string') {
|
||||
tableName = fromItemAny.table;
|
||||
} else if (fromItemAny.table && typeof fromItemAny.table === 'object') {
|
||||
const tableObj = fromItemAny.table as Record<string, unknown>;
|
||||
tableName = String(
|
||||
tableObj.table || tableObj.name || tableObj.value || fromItemAny.table
|
||||
);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
aliasToTableMap.set(fromItem.as.toLowerCase(), tableName.toLowerCase());
|
||||
aliasToTableMap.set(String(fromItemAny.as).toLowerCase(), tableName.toLowerCase());
|
||||
}
|
||||
|
||||
// Handle JOINs
|
||||
if (fromItem.join && Array.isArray(fromItem.join)) {
|
||||
for (const joinItem of fromItem.join) {
|
||||
if (fromItemAny.join && Array.isArray(fromItemAny.join)) {
|
||||
for (const joinItem of fromItemAny.join) {
|
||||
if (joinItem.table && joinItem.as) {
|
||||
let tableName: string;
|
||||
if (typeof joinItem.table === 'string') {
|
||||
tableName = joinItem.table;
|
||||
} else if (joinItem.table && typeof joinItem.table === 'object') {
|
||||
const tableObj = joinItem.table as any;
|
||||
tableName = tableObj.table || tableObj.name || tableObj.value || String(joinItem.table);
|
||||
const tableObj = joinItem.table as Record<string, unknown>;
|
||||
tableName = String(
|
||||
tableObj.table || tableObj.name || tableObj.value || joinItem.table
|
||||
);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
aliasToTableMap.set(joinItem.as.toLowerCase(), tableName.toLowerCase());
|
||||
aliasToTableMap.set(String(joinItem.as).toLowerCase(), tableName.toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -470,7 +484,10 @@ function findWildcardUsageOnPhysicalTables(selectStatement: any, cteNames: Set<s
|
|||
// Check for unqualified wildcard (SELECT *)
|
||||
if (column.expr.column === '*' && !column.expr.table) {
|
||||
// Get all tables in FROM clause that are not CTEs
|
||||
const physicalTables = getPhysicalTablesFromFrom(selectStatement.from, cteNames);
|
||||
const physicalTables = getPhysicalTablesFromFrom(
|
||||
selectStatement.from as unknown as Record<string, unknown>[],
|
||||
cteNames
|
||||
);
|
||||
blockedTables.push(...physicalTables);
|
||||
}
|
||||
// Check for qualified wildcard (SELECT table.*)
|
||||
|
@ -481,8 +498,10 @@ function findWildcardUsageOnPhysicalTables(selectStatement: any, cteNames: Set<s
|
|||
tableName = column.expr.table;
|
||||
} else if (column.expr.table && typeof column.expr.table === 'object') {
|
||||
// Handle object format - could have table property or be the table name itself
|
||||
const tableRefObj = column.expr.table as any;
|
||||
tableName = tableRefObj.table || tableRefObj.name || tableRefObj.value || String(column.expr.table);
|
||||
const tableRefObj = column.expr.table as Record<string, unknown>;
|
||||
tableName = String(
|
||||
tableRefObj.table || tableRefObj.name || tableRefObj.value || column.expr.table
|
||||
);
|
||||
} else {
|
||||
continue; // Skip if we can't determine table name
|
||||
}
|
||||
|
@ -503,21 +522,29 @@ function findWildcardUsageOnPhysicalTables(selectStatement: any, cteNames: Set<s
|
|||
// Check CTEs for nested wildcard usage
|
||||
if (selectStatement.with && Array.isArray(selectStatement.with)) {
|
||||
for (const cte of selectStatement.with) {
|
||||
if (cte.stmt && cte.stmt.type === 'select') {
|
||||
const subBlocked = findWildcardUsageOnPhysicalTables(cte.stmt, cteNames);
|
||||
const cteAny = cte as unknown as Record<string, unknown>;
|
||||
if (cteAny.stmt && typeof cteAny.stmt === 'object' && cteAny.stmt !== null) {
|
||||
const stmt = cteAny.stmt as Record<string, unknown>;
|
||||
if (stmt.type === 'select') {
|
||||
const subBlocked = findWildcardUsageOnPhysicalTables(stmt, cteNames);
|
||||
blockedTables.push(...subBlocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectStatement.from && Array.isArray(selectStatement.from)) {
|
||||
for (const fromItem of selectStatement.from) {
|
||||
if (fromItem.expr && fromItem.expr.type === 'select') {
|
||||
const subBlocked = findWildcardUsageOnPhysicalTables(fromItem.expr, cteNames);
|
||||
const fromItemAny = fromItem as unknown as Record<string, unknown>;
|
||||
if (fromItemAny.expr && typeof fromItemAny.expr === 'object' && fromItemAny.expr !== null) {
|
||||
const expr = fromItemAny.expr as Record<string, unknown>;
|
||||
if (expr.type === 'select') {
|
||||
const subBlocked = findWildcardUsageOnPhysicalTables(expr, cteNames);
|
||||
blockedTables.push(...subBlocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blockedTables;
|
||||
}
|
||||
|
@ -525,7 +552,10 @@ function findWildcardUsageOnPhysicalTables(selectStatement: any, cteNames: Set<s
|
|||
/**
|
||||
* Extracts physical table names from FROM clause, excluding CTEs
|
||||
*/
|
||||
function getPhysicalTablesFromFrom(fromClause: any[], cteNames: Set<string>): string[] {
|
||||
function getPhysicalTablesFromFrom(
|
||||
fromClause: Record<string, unknown>[],
|
||||
cteNames: Set<string>
|
||||
): string[] {
|
||||
const tables: string[] = [];
|
||||
|
||||
if (!fromClause || !Array.isArray(fromClause)) {
|
||||
|
@ -539,15 +569,15 @@ function getPhysicalTablesFromFrom(fromClause: any[], cteNames: Set<string>): st
|
|||
if (typeof fromItem.table === 'string') {
|
||||
tableName = fromItem.table;
|
||||
} else if (fromItem.table && typeof fromItem.table === 'object') {
|
||||
const tableObj = fromItem.table as any;
|
||||
tableName = tableObj.table || tableObj.name || tableObj.value || String(fromItem.table);
|
||||
const tableObj = fromItem.table as Record<string, unknown>;
|
||||
tableName = String(tableObj.table || tableObj.name || tableObj.value || fromItem.table);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tableName && !cteNames.has(tableName.toLowerCase())) {
|
||||
const aliasName = fromItem.as || tableName;
|
||||
tables.push(aliasName);
|
||||
tables.push(String(aliasName));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -559,15 +589,15 @@ function getPhysicalTablesFromFrom(fromClause: any[], cteNames: Set<string>): st
|
|||
if (typeof joinItem.table === 'string') {
|
||||
tableName = joinItem.table;
|
||||
} else if (joinItem.table && typeof joinItem.table === 'object') {
|
||||
const tableObj = joinItem.table as any;
|
||||
tableName = tableObj.table || tableObj.name || tableObj.value || String(joinItem.table);
|
||||
const tableObj = joinItem.table as Record<string, unknown>;
|
||||
tableName = String(tableObj.table || tableObj.name || tableObj.value || joinItem.table);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tableName && !cteNames.has(tableName.toLowerCase())) {
|
||||
const aliasName = joinItem.as || tableName;
|
||||
tables.push(aliasName);
|
||||
tables.push(String(aliasName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue