Skip to main content
Glama
sascodiego

MCP Vibe Coding Knowledge Graph

by sascodiego
queryTemplates.js29.3 kB
import { logger } from '../utils/logger.js'; import CypherQueryBuilder from './cypherQueryBuilder.js'; /** * CONTEXT: Query template system for common Kuzu database operations * REASON: Provide standardized, optimized queries for frequent operations * CHANGE: Comprehensive template library with customizable parameters * PREVENTION: Query duplication, inconsistencies, and performance issues */ export class QueryTemplateManager { constructor(client, optimizer = null) { this.client = client; this.optimizer = optimizer; this.templates = new Map(); this.customTemplates = new Map(); this.templateStats = new Map(); this.initializeBuiltinTemplates(); logger.info('QueryTemplateManager initialized', { builtinTemplates: this.templates.size }); } /** * Initialize built-in query templates */ initializeBuiltinTemplates() { // Entity Management Templates this.registerTemplate('findEntityById', { description: 'Find a specific entity by ID', parameters: ['entityId'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .where('e.id = $entityId', { entityId: params.entityId }) .return(['e.*']), category: 'entity', complexity: 1 }); this.registerTemplate('findEntitiesByType', { description: 'Find all entities of a specific type', parameters: ['entityType', 'limit?'], template: (params) => { const builder = new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .where('e.type = $entityType', { entityType: params.entityType }) .return(['e.id', 'e.name', 'e.filePath', 'e.type']) .orderBy('e.name'); if (params.limit) { builder.limit(params.limit); } return builder; }, category: 'entity', complexity: 2 }); this.registerTemplate('findEntitiesByFile', { description: 'Find all entities in a specific file', parameters: ['filePath'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .where('e.filePath = $filePath', { filePath: params.filePath }) .return(['e.id', 'e.name', 'e.type', 'e.lineStart', 'e.lineEnd']) .orderBy('e.lineStart'), category: 'entity', complexity: 2 }); this.registerTemplate('createEntity', { description: 'Create a new code entity', parameters: ['id', 'type', 'name', 'filePath', 'properties?'], template: (params) => { const properties = { id: params.id, type: params.type, name: params.name, filePath: params.filePath, lastModified: Date.now(), ...params.properties }; return new CypherQueryBuilder(this.client) .create('(e:CodeEntity $properties)', { properties }) .return(['e']); }, category: 'entity', complexity: 2, type: 'WRITE' }); this.registerTemplate('updateEntityProperties', { description: 'Update properties of an existing entity', parameters: ['entityId', 'properties'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .where('e.id = $entityId', { entityId: params.entityId }) .setProperties('e', { ...params.properties, lastModified: Date.now() }) .return(['e']), category: 'entity', complexity: 2, type: 'WRITE' }); // Pattern Analysis Templates this.registerTemplate('findPatternsForEntity', { description: 'Find all patterns implemented by an entity', parameters: ['entityId'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)-[impl:IMPLEMENTS]->(p:Pattern)') .where('e.id = $entityId', { entityId: params.entityId }) .return(['p.name', 'p.description', 'p.category', 'impl.confidence']) .orderBy('impl.confidence', 'DESC'), category: 'pattern', complexity: 3 }); this.registerTemplate('findEntitiesImplementingPattern', { description: 'Find entities that implement a specific pattern', parameters: ['patternName', 'minConfidence?'], template: (params) => { const builder = new CypherQueryBuilder(this.client) .match('(e:CodeEntity)-[impl:IMPLEMENTS]->(p:Pattern)') .where('p.name = $patternName', { patternName: params.patternName }); if (params.minConfidence) { builder.where('impl.confidence >= $minConfidence', { minConfidence: params.minConfidence }, 'AND'); } return builder .return(['e.id', 'e.name', 'e.type', 'e.filePath', 'impl.confidence']) .orderBy('impl.confidence', 'DESC'); }, category: 'pattern', complexity: 3 }); this.registerTemplate('createPatternImplementation', { description: 'Create a relationship between entity and pattern', parameters: ['entityId', 'patternName', 'confidence'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity), (p:Pattern)') .where('e.id = $entityId AND p.name = $patternName', { entityId: params.entityId, patternName: params.patternName }) .create('(e)-[impl:IMPLEMENTS {confidence: $confidence, timestamp: $timestamp}]->(p)', { confidence: params.confidence, timestamp: Date.now() }) .return(['impl']), category: 'pattern', complexity: 3, type: 'WRITE' }); // Dependency Analysis Templates this.registerTemplate('findDirectDependencies', { description: 'Find direct dependencies of an entity', parameters: ['entityId'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)-[dep:DEPENDS_ON]->(target:CodeEntity)') .where('e.id = $entityId', { entityId: params.entityId }) .return(['target.id', 'target.name', 'target.type', 'dep.type', 'dep.strength']) .orderBy('dep.strength', 'DESC'), category: 'dependency', complexity: 3 }); this.registerTemplate('findTransitiveDependencies', { description: 'Find transitive dependencies of an entity', parameters: ['entityId', 'maxDepth?'], template: (params) => { const depth = params.maxDepth || 3; return new CypherQueryBuilder(this.client) .match(`(e:CodeEntity)-[:DEPENDS_ON*1..${depth}]->(target:CodeEntity)`) .where('e.id = $entityId', { entityId: params.entityId }) .return(['target.id', 'target.name', 'target.type']) .returnDistinct(['target.id', 'target.name', 'target.type']) .orderBy('target.name'); }, category: 'dependency', complexity: 5 }); this.registerTemplate('findDependents', { description: 'Find entities that depend on this entity', parameters: ['entityId'], template: (params) => new CypherQueryBuilder(this.client) .match('(dependent:CodeEntity)-[dep:DEPENDS_ON]->(e:CodeEntity)') .where('e.id = $entityId', { entityId: params.entityId }) .return(['dependent.id', 'dependent.name', 'dependent.type', 'dep.type']) .orderBy('dependent.name'), category: 'dependency', complexity: 3 }); this.registerTemplate('createDependency', { description: 'Create a dependency relationship between entities', parameters: ['fromEntityId', 'toEntityId', 'dependencyType', 'strength?'], template: (params) => new CypherQueryBuilder(this.client) .match('(from:CodeEntity), (to:CodeEntity)') .where('from.id = $fromEntityId AND to.id = $toEntityId', { fromEntityId: params.fromEntityId, toEntityId: params.toEntityId }) .create('(from)-[dep:DEPENDS_ON {type: $depType, strength: $strength}]->(to)', { depType: params.dependencyType, strength: params.strength || 1.0 }) .return(['dep']), category: 'dependency', complexity: 3, type: 'WRITE' }); // Rule Violation Templates this.registerTemplate('findViolationsByEntity', { description: 'Find rule violations for a specific entity', parameters: ['entityId'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)-[viol:VIOLATES]->(r:Rule)') .where('e.id = $entityId', { entityId: params.entityId }) .return(['r.id', 'r.description', 'r.category', 'viol.severity', 'viol.message']) .orderBy('viol.severity', 'DESC'), category: 'validation', complexity: 3 }); this.registerTemplate('findViolationsByRule', { description: 'Find all violations of a specific rule', parameters: ['ruleId'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)-[viol:VIOLATES]->(r:Rule)') .where('r.id = $ruleId', { ruleId: params.ruleId }) .return(['e.id', 'e.name', 'e.filePath', 'viol.severity', 'viol.message']) .orderBy('viol.severity', 'DESC'), category: 'validation', complexity: 3 }); this.registerTemplate('findViolationsBySeverity', { description: 'Find violations by severity level', parameters: ['severity', 'limit?'], template: (params) => { const builder = new CypherQueryBuilder(this.client) .match('(e:CodeEntity)-[viol:VIOLATES]->(r:Rule)') .where('viol.severity = $severity', { severity: params.severity }) .return(['e.id', 'e.name', 'e.filePath', 'r.description', 'viol.message']) .orderBy('e.filePath'); if (params.limit) { builder.limit(params.limit); } return builder; }, category: 'validation', complexity: 3 }); this.registerTemplate('createViolation', { description: 'Create a rule violation relationship', parameters: ['entityId', 'ruleId', 'severity', 'message?'], template: (params) => new CypherQueryBuilder(this.client) .match('(e:CodeEntity), (r:Rule)') .where('e.id = $entityId AND r.id = $ruleId', { entityId: params.entityId, ruleId: params.ruleId }) .create('(e)-[viol:VIOLATES {severity: $severity, message: $message, timestamp: $timestamp}]->(r)', { severity: params.severity, message: params.message || '', timestamp: Date.now() }) .return(['viol']), category: 'validation', complexity: 3, type: 'WRITE' }); // Analytics Templates this.registerTemplate('getEntityStatistics', { description: 'Get comprehensive statistics about entities', parameters: [], template: () => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .return([ 'count(e) as totalEntities', 'count(DISTINCT e.type) as entityTypes', 'count(DISTINCT e.filePath) as filesWithEntities', 'avg(e.complexity) as avgComplexity' ]), category: 'analytics', complexity: 4 }); this.registerTemplate('getPatternStatistics', { description: 'Get statistics about pattern implementations', parameters: [], template: () => new CypherQueryBuilder(this.client) .match('(p:Pattern)<-[impl:IMPLEMENTS]-(e:CodeEntity)') .return([ 'p.name as pattern', 'count(impl) as implementations', 'avg(impl.confidence) as avgConfidence', 'max(impl.confidence) as maxConfidence' ]) .orderBy('count(impl)', 'DESC'), category: 'analytics', complexity: 4 }); this.registerTemplate('getViolationStatistics', { description: 'Get statistics about rule violations', parameters: [], template: () => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)-[viol:VIOLATES]->(r:Rule)') .return([ 'viol.severity as severity', 'count(viol) as violationCount', 'count(DISTINCT e) as affectedEntities', 'count(DISTINCT r) as violatedRules' ]) .orderBy('violationCount', 'DESC'), category: 'analytics', complexity: 4 }); this.registerTemplate('getDependencyComplexity', { description: 'Analyze dependency complexity for entities', parameters: ['entityType?'], template: (params) => { const builder = new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .optionalMatch('(e)-[:DEPENDS_ON]->(out:CodeEntity)') .optionalMatch('(in:CodeEntity)-[:DEPENDS_ON]->(e)'); if (params.entityType) { builder.where('e.type = $entityType', { entityType: params.entityType }); } return builder .return([ 'e.id as entityId', 'e.name as entityName', 'e.type as entityType', 'count(DISTINCT out) as outgoingDependencies', 'count(DISTINCT in) as incomingDependencies', '(count(DISTINCT out) + count(DISTINCT in)) as totalConnections' ]) .orderBy('totalConnections', 'DESC'); }, category: 'analytics', complexity: 5 }); // Search Templates this.registerTemplate('searchEntitiesByName', { description: 'Search entities by name pattern', parameters: ['searchTerm', 'limit?'], template: (params) => { const builder = new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .where('toLower(e.name) CONTAINS toLower($searchTerm)', { searchTerm: params.searchTerm }) .return(['e.id', 'e.name', 'e.type', 'e.filePath']) .orderBy('e.name'); if (params.limit) { builder.limit(params.limit); } return builder; }, category: 'search', complexity: 3 }); this.registerTemplate('searchByContext', { description: 'Search entities by context information', parameters: ['contextTerm', 'limit?'], template: (params) => { const builder = new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .where('toLower(e.context) CONTAINS toLower($contextTerm)', { contextTerm: params.contextTerm }) .return(['e.id', 'e.name', 'e.type', 'e.context']) .orderBy('e.name'); if (params.limit) { builder.limit(params.limit); } return builder; }, category: 'search', complexity: 3 }); // Maintenance Templates this.registerTemplate('cleanupOrphanedEntities', { description: 'Find entities without any relationships', parameters: [], template: () => new CypherQueryBuilder(this.client) .match('(e:CodeEntity)') .where('NOT (e)-[]-() AND NOT ()-[]-(e)') .return(['e.id', 'e.name', 'e.type', 'e.filePath']) .orderBy('e.filePath'), category: 'maintenance', complexity: 4 }); this.registerTemplate('findDuplicateEntities', { description: 'Find potentially duplicate entities', parameters: [], template: () => new CypherQueryBuilder(this.client) .match('(e1:CodeEntity), (e2:CodeEntity)') .where('e1.name = e2.name AND e1.type = e2.type AND e1.id <> e2.id') .return(['e1.id as id1', 'e2.id as id2', 'e1.name as name', 'e1.type as type']) .orderBy('e1.name'), category: 'maintenance', complexity: 5 }); logger.info('Built-in query templates initialized', { templateCount: this.templates.size, categories: this.getTemplateCategories() }); } /** * Register a new query template */ registerTemplate(name, templateConfig) { if (!name || typeof name !== 'string') { throw new Error('Template name must be a non-empty string'); } if (!templateConfig.template || typeof templateConfig.template !== 'function') { throw new Error('Template must have a template function'); } const template = { name, description: templateConfig.description || '', parameters: templateConfig.parameters || [], template: templateConfig.template, category: templateConfig.category || 'custom', complexity: templateConfig.complexity || 1, type: templateConfig.type || 'READ', customizable: templateConfig.customizable !== false, createdAt: Date.now(), ...templateConfig }; // Validate template by testing with dummy parameters try { const dummyParams = this.generateDummyParameters(template.parameters); const builder = template.template(dummyParams); if (!(builder instanceof CypherQueryBuilder)) { throw new Error('Template must return a CypherQueryBuilder instance'); } // Test that we can build the query builder.build(); } catch (error) { throw new Error(`Template validation failed: ${error.message}`); } this.templates.set(name, template); // Initialize statistics this.templateStats.set(name, { usageCount: 0, totalExecutionTime: 0, averageExecutionTime: 0, errors: 0, lastUsed: null }); logger.debug('Template registered', { name, category: template.category, complexity: template.complexity }); return template; } /** * Execute a template with parameters */ async executeTemplate(templateName, parameters = {}, options = {}) { const template = this.templates.get(templateName); if (!template) { throw new Error(`Template not found: ${templateName}`); } const startTime = Date.now(); try { // Validate parameters this.validateTemplateParameters(template, parameters); // Create query builder from template const builder = template.template(parameters); if (!(builder instanceof CypherQueryBuilder)) { throw new Error(`Template ${templateName} did not return a CypherQueryBuilder`); } // Apply optimization if optimizer is available if (this.optimizer && !options.skipOptimization) { const builtQuery = builder.build(); const optimization = await this.optimizer.optimizeQuery( builtQuery.query, builtQuery.parameters, { template: templateName, ...builtQuery.metadata } ); // Use optimized query if significantly better if (optimization.estimatedImprovement > 10) { const result = await this.client.query( optimization.optimizedQuery, optimization.parameters, options ); const executionTime = Date.now() - startTime; this.updateTemplateStats(templateName, executionTime, true); return { result, template: templateName, optimized: true, executionTime, estimatedImprovement: optimization.estimatedImprovement }; } } // Execute original query const result = await builder.execute(options); const executionTime = Date.now() - startTime; this.updateTemplateStats(templateName, executionTime, true); logger.debug('Template executed successfully', { templateName, executionTime: `${executionTime}ms`, resultCount: result.length }); return { result, template: templateName, optimized: false, executionTime }; } catch (error) { const executionTime = Date.now() - startTime; this.updateTemplateStats(templateName, executionTime, false); logger.error('Template execution failed', { templateName, error: error.message, parameters }); throw new Error(`Template execution failed: ${error.message}`); } } /** * Get a template builder without executing */ getTemplate(templateName, parameters = {}) { const template = this.templates.get(templateName); if (!template) { throw new Error(`Template not found: ${templateName}`); } this.validateTemplateParameters(template, parameters); return template.template(parameters); } /** * List available templates */ listTemplates(category = null) { const templates = Array.from(this.templates.values()); if (category) { return templates.filter(t => t.category === category); } return templates.map(t => ({ name: t.name, description: t.description, category: t.category, parameters: t.parameters, complexity: t.complexity, type: t.type })); } /** * Get template categories */ getTemplateCategories() { const categories = new Set(); for (const template of this.templates.values()) { categories.add(template.category); } return Array.from(categories); } /** * Get template statistics */ getTemplateStatistics(templateName = null) { if (templateName) { const stats = this.templateStats.get(templateName); const template = this.templates.get(templateName); if (!stats || !template) { return null; } return { template: templateName, ...stats, successRate: stats.usageCount > 0 ? ((stats.usageCount - stats.errors) / stats.usageCount * 100) : 0 }; } // Return all statistics const allStats = {}; for (const [name, stats] of this.templateStats) { allStats[name] = { ...stats, successRate: stats.usageCount > 0 ? ((stats.usageCount - stats.errors) / stats.usageCount * 100) : 0 }; } return allStats; } /** * Create a custom template from an existing query */ createCustomTemplate(name, query, parameters = [], options = {}) { const template = { description: options.description || `Custom template: ${name}`, parameters, template: (params) => { // Create a new builder and parse the query const builder = new CypherQueryBuilder(this.client); // This is a simplified approach - in practice you'd need // a more sophisticated query parser const { query: processedQuery, parameters: processedParams } = this.processCustomQuery(query, params); return builder.reset().match('').build = () => ({ query: processedQuery, parameters: processedParams }); }, category: options.category || 'custom', complexity: options.complexity || this.estimateQueryComplexity(query), type: options.type || this.detectQueryType(query), customizable: true }; return this.registerTemplate(name, template); } /** * Export templates to JSON */ exportTemplates(category = null) { const templates = this.listTemplates(category); const stats = this.getTemplateStatistics(); return { templates: templates.map(t => ({ ...t, statistics: stats[t.name] || null })), exportedAt: new Date().toISOString(), category }; } /** * Validate template parameters */ validateTemplateParameters(template, parameters) { const requiredParams = template.parameters.filter(p => !p.endsWith('?')); const optionalParams = template.parameters.filter(p => p.endsWith('?')) .map(p => p.slice(0, -1)); // Check required parameters for (const param of requiredParams) { if (!(param in parameters)) { throw new Error(`Required parameter missing: ${param}`); } if (parameters[param] === null || parameters[param] === undefined) { throw new Error(`Parameter ${param} cannot be null or undefined`); } } // Check for unknown parameters const allValidParams = [...requiredParams, ...optionalParams]; for (const param of Object.keys(parameters)) { if (!allValidParams.includes(param)) { logger.warn(`Unknown parameter provided to template ${template.name}: ${param}`); } } } /** * Generate dummy parameters for template validation */ generateDummyParameters(parameterNames) { const dummyParams = {}; for (const param of parameterNames) { const cleanParam = param.endsWith('?') ? param.slice(0, -1) : param; // Generate appropriate dummy values based on parameter name if (cleanParam.includes('Id')) { dummyParams[cleanParam] = 'dummy-id-123'; } else if (cleanParam.includes('Type')) { dummyParams[cleanParam] = 'function'; } else if (cleanParam.includes('Name')) { dummyParams[cleanParam] = 'dummyName'; } else if (cleanParam.includes('Path')) { dummyParams[cleanParam] = '/dummy/path.js'; } else if (cleanParam.includes('limit') || cleanParam.includes('Limit')) { dummyParams[cleanParam] = 10; } else if (cleanParam.includes('confidence') || cleanParam.includes('Confidence')) { dummyParams[cleanParam] = 0.8; } else { dummyParams[cleanParam] = 'dummy-value'; } } return dummyParams; } /** * Update template usage statistics */ updateTemplateStats(templateName, executionTime, success) { const stats = this.templateStats.get(templateName); if (stats) { stats.usageCount++; stats.lastUsed = Date.now(); if (success) { stats.totalExecutionTime += executionTime; stats.averageExecutionTime = stats.totalExecutionTime / (stats.usageCount - stats.errors); } else { stats.errors++; } } } /** * Process custom query with parameter substitution */ processCustomQuery(query, parameters) { let processedQuery = query; const processedParams = {}; // Simple parameter substitution - in practice this would be more sophisticated for (const [key, value] of Object.entries(parameters)) { const paramRegex = new RegExp(`\\$${key}\\b`, 'g'); if (processedQuery.includes(`$${key}`)) { processedParams[key] = value; } } return { query: processedQuery, parameters: processedParams }; } /** * Estimate query complexity */ estimateQueryComplexity(query) { let complexity = 1; complexity += (query.match(/MATCH/gi) || []).length; complexity += (query.match(/-\[.*?\]-/g) || []).length * 2; complexity += (query.match(/\*\d*\.\.\d*/g) || []).length * 5; return Math.min(complexity, 10); } /** * Detect query type */ detectQueryType(query) { const upperQuery = query.toUpperCase(); if (upperQuery.includes('CREATE') || upperQuery.includes('MERGE')) { return 'WRITE'; } else if (upperQuery.includes('DELETE') || upperQuery.includes('REMOVE')) { return 'DELETE'; } else if (upperQuery.includes('SET')) { return 'UPDATE'; } else { return 'READ'; } } /** * Clear template statistics */ clearStatistics(templateName = null) { if (templateName) { const stats = this.templateStats.get(templateName); if (stats) { Object.assign(stats, { usageCount: 0, totalExecutionTime: 0, averageExecutionTime: 0, errors: 0, lastUsed: null }); } } else { for (const stats of this.templateStats.values()) { Object.assign(stats, { usageCount: 0, totalExecutionTime: 0, averageExecutionTime: 0, errors: 0, lastUsed: null }); } } logger.debug('Template statistics cleared', { templateName }); } /** * Remove a template */ removeTemplate(templateName) { const removed = this.templates.delete(templateName); this.templateStats.delete(templateName); if (removed) { logger.debug('Template removed', { templateName }); } return removed; } } export default QueryTemplateManager;

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/sascodiego/KGsMCP'

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