Skip to main content
Glama
create-table.tsโ€ข4.93 kB
import { BaseTool, type ToolExecutionContext, type ToolExecutionResult } from '../lib/base-tool.js'; import { formatPerformanceMetrics } from '../utils/performance.js'; import { CreateTableInputSchema, type CreateTableInput } from '../schemas/create-table.js'; export class CreateTableTool extends BaseTool { readonly name = 'create-table'; readonly description = 'Execute CREATE TABLE DDL statements on the libSQL database. Supports table creation with automatic IF NOT EXISTS handling and transaction support for safety.'; readonly inputSchema = CreateTableInputSchema; protected async executeImpl(context: ToolExecutionContext): Promise<ToolExecutionResult> { const { query, parameters, useTransaction, ifNotExists } = context.arguments as CreateTableInput; try { const startTime = Date.now(); // Process the query to add IF NOT EXISTS if requested let processedQuery = query; if (ifNotExists && !query.toLowerCase().includes('if not exists')) { // Insert IF NOT EXISTS after CREATE TABLE processedQuery = query.replace(/create\s+table\s+/i, 'CREATE TABLE IF NOT EXISTS '); } // Validate the processed query this.validateCreateTableQuery(processedQuery); let result; if (useTransaction) { // Use transaction for automatic rollback on errors result = await context.connection.transaction(async tx => { return parameters && parameters.length > 0 ? await tx.execute({ sql: processedQuery, args: parameters }) : await tx.execute(processedQuery); }); } else { // Execute directly without transaction result = parameters && parameters.length > 0 ? await context.connection.execute(processedQuery, parameters) : await context.connection.execute(processedQuery); } const executionTime = Date.now() - startTime; const metrics = formatPerformanceMetrics({ executionTime, rowsAffected: result.rowsAffected }); // Extract table name from query for user feedback const tableName = this.extractTableName(processedQuery); let output = `Table created successfully${useTransaction ? ' (with transaction)' : ''}\n\n`; output += `Table name: ${tableName}\n`; if (ifNotExists && !query.toLowerCase().includes('if not exists')) { output += 'Note: Added IF NOT EXISTS clause\n'; } if (result.rowsAffected !== undefined) { output += `Rows affected: ${result.rowsAffected}\n`; } output += `\n${metrics}`; return { content: [ { type: 'text', text: output } ] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const rollbackMessage = useTransaction ? ' (transaction rolled back)' : ''; return { content: [ { type: 'text', text: `Error creating table: ${errorMessage}${rollbackMessage}` } ], isError: true }; } } /** * Additional validation for CREATE TABLE statements */ private validateCreateTableQuery(query: string): void { const lowerQuery = query.toLowerCase(); // Check for trigger or view patterns that don't belong in CREATE TABLE if (lowerQuery.includes(' trigger ') || lowerQuery.includes(' view ')) { throw new Error('CREATE TABLE cannot contain TRIGGER or VIEW clauses'); } // Validate parentheses balance const openParens = (query.match(/\(/g) || []).length; const closeParens = (query.match(/\)/g) || []).length; if (openParens !== closeParens) { throw new Error('Unbalanced parentheses in CREATE TABLE statement'); } // Check for minimum required elements if (!lowerQuery.includes('(') || !lowerQuery.includes(')')) { throw new Error('CREATE TABLE must include column definitions in parentheses'); } } /** * Extract table name from CREATE TABLE statement */ private extractTableName(query: string): string { // Remove IF NOT EXISTS and normalize whitespace const normalizedQuery = query .replace(/\s+/g, ' ') .replace(/create\s+table\s+if\s+not\s+exists\s+/i, 'CREATE TABLE ') .replace(/create\s+table\s+/i, 'CREATE TABLE '); // Extract table name - handle quoted and unquoted names const patterns = [ /CREATE TABLE "([^"]+)"/i, // Double quotes /CREATE TABLE '([^']+)'/i, // Single quotes /CREATE TABLE `([^`]+)`/i, // Backticks /CREATE TABLE \[([^\]]+)\]/i, // Square brackets /CREATE TABLE (\w+)/i // Unquoted ]; for (const pattern of patterns) { const match = normalizedQuery.match(pattern); if (match && match[1]) { return match[1]; } } return 'unknown'; } }

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/Xexr/mcp-libsql'

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