Skip to main content
Glama
DatabaseSchema.ts•3.68 kB
import { Environment } from '../value-objects/Environment'; import { TableInfo } from './TableInfo'; /** * 🎯 SEMANTIC INTENT: DatabaseSchema is the aggregate root for complete database metadata * * WHY: Database schema represents the complete structural snapshot at a point in time * - Aggregate root: Coordinates all tables, relationships, indexes * - Semantic boundary: Database is the consistency boundary for schema operations * - Observable from D1 REST API (sqlite_master + PRAGMA statements) * - Environment semantic preserved: dev/staging/prod context * * AGGREGATE ROOT: Top-level entity coordinating all schema metadata * OBSERVABLE PROPERTIES: All metadata directly observable from database * IMMUTABILITY: Frozen snapshot - schema doesn't change after fetch * INTENT PRESERVATION: Environment semantic maintained through lifecycle */ export class DatabaseSchema { public readonly name: string; public readonly environment: Environment; public readonly tables: readonly TableInfo[]; public readonly fetchedAt: Date; constructor(name: string, environment: Environment, tables: TableInfo[], fetchedAt: Date) { if (!name || name.trim().length === 0) { throw new Error('Database name cannot be empty'); } if (tables.length === 0) { throw new Error('Database must have at least one table'); } this.name = name.trim(); this.environment = environment; this.tables = Object.freeze([...tables]); this.fetchedAt = fetchedAt; Object.freeze(this); } /** * Get table by name * * @returns TableInfo or undefined if not found */ getTable(tableName: string): TableInfo | undefined { return this.tables.find((t) => t.name === tableName); } /** * Get all tables that reference a specific table * * Semantic: Find dependent tables (children in relationships) */ getTablesThatReference(tableName: string): TableInfo[] { return this.tables.filter((t) => t.getReferencedTables().includes(tableName)); } /** * Get all tables that a specific table references * * Semantic: Find dependencies (parents in relationships) */ getTablesReferencedBy(tableName: string): string[] { const table = this.getTable(tableName); return table ? table.getReferencedTables() : []; } /** * Get table count */ getTableCount(): number { return this.tables.length; } /** * Get tables without primary keys * * Semantic: Primary keys establish entity identity - tables without them are incomplete */ getTablesWithoutPrimaryKey(): TableInfo[] { return this.tables.filter((t) => !t.hasPrimaryKey()); } /** * Get tables with foreign keys (has relationships) */ getTablesWithForeignKeys(): TableInfo[] { return this.tables.filter((t) => t.hasForeignKeys()); } /** * Get all views (non-base tables) */ getViews(): TableInfo[] { return this.tables.filter((t) => t.isView()); } /** * Get all base tables (non-views) */ getBaseTables(): TableInfo[] { return this.tables.filter((t) => !t.isView()); } /** * Check if schema was fetched recently (within specified minutes) * * Semantic: Fresh schema data vs stale data (for caching decisions) */ isFresh(withinMinutes: number = 10): boolean { const now = new Date(); const ageMs = now.getTime() - this.fetchedAt.getTime(); const ageMinutes = ageMs / (1000 * 60); return ageMinutes <= withinMinutes; } /** * Get schema age in minutes */ getAgeInMinutes(): number { const now = new Date(); const ageMs = now.getTime() - this.fetchedAt.getTime(); return ageMs / (1000 * 60); } }

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