Skip to main content
Glama
OptimizationService.ts•6.7 kB
import { Optimization } from '../entities/Optimization'; import type { Relationship } from '../entities/Relationship'; import type { TableInfo } from '../entities/TableInfo'; /** * 🎯 SEMANTIC INTENT: OptimizationService generates schema improvement recommendations * * WHY: Domain service for schema optimization analysis * - Based on observable schema patterns (NOT runtime metrics) * - Identifies missing indexes, primary keys, and design issues * - Semantic rules for database best practices * * DOMAIN SERVICE: Stateless optimization logic * OBSERVABLE ANCHORING: Based on schema structure, not query performance * NO INFRASTRUCTURE: Pure business logic */ export class OptimizationService { /** * Analyze schema and generate all optimizations * * Semantic: Comprehensive schema health check */ analyzeSchema(tables: TableInfo[], relationships: Relationship[]): Optimization[] { const optimizations: Optimization[] = []; optimizations.push(...this.checkMissingPrimaryKeys(tables)); optimizations.push(...this.checkMissingIndexes(tables, relationships)); optimizations.push(...this.checkNullableForeignKeys(tables)); return optimizations; } /** * Check for tables without primary keys * * Semantic: Primary keys establish entity identity - tables without them are incomplete */ checkMissingPrimaryKeys(tables: TableInfo[]): Optimization[] { return tables .filter((table) => !table.hasPrimaryKey() && !table.isView()) .map( (table) => new Optimization( 'missing_primary_key', table.name, 'Table without primary key may cause replication and uniqueness issues', `ALTER TABLE ${table.name} ADD COLUMN id INTEGER PRIMARY KEY`, 'high' ) ); } /** * Check for foreign keys without indexes * * Semantic: Foreign key columns without indexes cause slow joins */ checkMissingIndexes(tables: TableInfo[], relationships: Relationship[]): Optimization[] { const optimizations: Optimization[] = []; for (const table of tables) { const fkColumns = table.getForeignKeyColumns(); for (const column of fkColumns) { if (!table.hasIndexOnColumn(column)) { const rel = relationships.find((r) => r.fromTable === table.name && r.fromColumn === column); optimizations.push( new Optimization( 'missing_index', table.name, `Foreign key column '${column}' without index may cause slow joins`, `CREATE INDEX idx_${table.name}_${column} ON ${table.name}(${column})`, 'high', column ) ); } } } return optimizations; } /** * Check for nullable foreign key columns * * Semantic: Nullable FKs indicate optional relationships - may be intentional but worth reviewing */ checkNullableForeignKeys(tables: TableInfo[]): Optimization[] { const optimizations: Optimization[] = []; for (const table of tables) { const fkColumns = table.getForeignKeyColumns(); for (const columnName of fkColumns) { const column = table.getColumn(columnName); if (column && column.isNullable) { optimizations.push( new Optimization( 'nullable_foreign_key', table.name, `Foreign key column '${columnName}' is nullable - consider if relationship is truly optional`, `Review business logic: Should ${table.name}.${columnName} always reference ${table.name}?`, 'medium', columnName ) ); } } } return optimizations; } /** * Find redundant indexes (covered by other indexes) * * Semantic: Index on (A) is redundant if index on (A, B) exists */ checkRedundantIndexes(table: TableInfo): Optimization[] { const optimizations: Optimization[] = []; const indexes = Array.from(table.indexes); for (let i = 0; i < indexes.length; i++) { for (let j = 0; j < indexes.length; j++) { if (i === j) continue; const index1 = indexes[i]; const index2 = indexes[j]; // Check if index1 is a prefix of index2 if (this.isIndexPrefix(index1.columns, index2.columns)) { optimizations.push( new Optimization( 'redundant_index', table.name, `Index ${index1.name} is redundant - covered by ${index2.name}`, `DROP INDEX ${index1.name}`, 'low' ) ); } } } return optimizations; } /** * Get optimizations filtered by priority */ filterByPriority(optimizations: Optimization[], priority: 'high' | 'medium' | 'low'): Optimization[] { return optimizations.filter((opt) => opt.priority === priority); } /** * Get optimizations filtered by type */ filterByType(optimizations: Optimization[], type: Optimization['type']): Optimization[] { return optimizations.filter((opt) => opt.type === type); } /** * Get optimizations for specific table */ filterByTable(optimizations: Optimization[], tableName: string): Optimization[] { return optimizations.filter((opt) => opt.table === tableName); } /** * Sort optimizations by priority (high -> medium -> low) */ sortByPriority(optimizations: Optimization[]): Optimization[] { const priorityOrder = { high: 0, medium: 1, low: 2 }; return [...optimizations].sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]); } /** * Get summary statistics of optimizations */ getSummary(optimizations: Optimization[]): { total: number; byPriority: { high: number; medium: number; low: number }; byType: Map<string, number>; } { const byType = new Map<string, number>(); for (const opt of optimizations) { byType.set(opt.type, (byType.get(opt.type) || 0) + 1); } return { total: optimizations.length, byPriority: { high: this.filterByPriority(optimizations, 'high').length, medium: this.filterByPriority(optimizations, 'medium').length, low: this.filterByPriority(optimizations, 'low').length, }, byType, }; } /** * Check if columns1 is a prefix of columns2 */ private isIndexPrefix(columns1: readonly string[], columns2: readonly string[]): boolean { if (columns1.length >= columns2.length) return false; for (let i = 0; i < columns1.length; i++) { if (columns1[i] !== columns2[i]) return false; } return true; } }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/semanticintent/semantic-d1-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server