This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch gremlin-mcp in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit a24b5bc8d039a47d3ae110e2f1c17626618a52ae Author: Stephen Mallette <[email protected]> AuthorDate: Mon Sep 29 16:39:42 2025 -0400 TinkerPop prefers edges to relationships in its naming --- .../javascript/gremlin-javascript/package.json | 7 ++- gremlin-tools/gremlin-mcp/README.md | 4 +- .../{relationship-patterns.ts => edge-patterns.ts} | 20 +++--- .../gremlin-mcp/src/gremlin/models/graph-schema.ts | 30 ++++----- .../gremlin-mcp/src/gremlin/schema-assembly.ts | 72 +++++++++++----------- .../gremlin-mcp/src/gremlin/schema-generator.ts | 16 ++--- ...ship-patterns.test.ts => edge-patterns.test.ts} | 48 +++++++-------- .../tests/integration/mcp-integration.test.ts | 12 ++-- gremlin-tools/gremlin-mcp/tests/models.test.ts | 24 ++++---- .../gremlin-mcp/tests/schema-assembly.test.ts | 72 +++++++++++----------- 10 files changed, 155 insertions(+), 150 deletions(-) diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json index 611a2460ab..6f8b5bde86 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json @@ -2,14 +2,19 @@ "name": "gremlin", "version": "3.8.0-alpha1", "description": "JavaScript Gremlin Language Variant", - "author": "Apache TinkerPop team", + "author": { + "name": "Apache TinkerPop team" + }, "keywords": [ "graph", "gremlin", "tinkerpop", + "apache-tinkerpop", "connection", "glv", "driver", + "graph", + "database", "graphdb" ], "license": "Apache-2.0", diff --git a/gremlin-tools/gremlin-mcp/README.md b/gremlin-tools/gremlin-mcp/README.md index 82692282fb..a42846461f 100644 --- a/gremlin-tools/gremlin-mcp/README.md +++ b/gremlin-tools/gremlin-mcp/README.md @@ -42,10 +42,10 @@ Talk to your graph database naturally: Your AI assistant gets access to these powerful tools: | Tool | Purpose | What It Does | -| --------------------------- | ---------------- |--------------------------------------------------------------| +|-----------------------------| ---------------- |--------------------------------------------------------------| | 🔍 **get_graph_status** | Health Check | Verify database connectivity and server status | | 📋 **get_graph_schema** | Schema Discovery | Get complete graph structure with vertices and edges | -| ⚡ **run_gremlin_query** | Query Execution | Execute any Gremlin traversal query with full syntax support | +| ⚡ **run_gremlin_query** | Query Execution | Execute any Gremlin traversal query with full syntax support | | 🔄 **refresh_schema_cache** | Cache Management | Force immediate refresh of cached schema information | | 📥 **import_graph_data** | Data Import | Load data from GraphSON, CSV, or JSON with batch processing | | 📤 **export_subgraph** | Data Export | Extract subgraphs to JSON, GraphSON, or CSV formats | diff --git a/gremlin-tools/gremlin-mcp/src/gremlin/relationship-patterns.ts b/gremlin-tools/gremlin-mcp/src/gremlin/edge-patterns.ts similarity index 89% rename from gremlin-tools/gremlin-mcp/src/gremlin/relationship-patterns.ts rename to gremlin-tools/gremlin-mcp/src/gremlin/edge-patterns.ts index 6f1c33738f..f70c4fa39e 100644 --- a/gremlin-tools/gremlin-mcp/src/gremlin/relationship-patterns.ts +++ b/gremlin-tools/gremlin-mcp/src/gremlin/edge-patterns.ts @@ -27,7 +27,7 @@ import { Effect } from 'effect'; import gremlin from 'gremlin'; -import type { RelationshipPattern } from './models/index.js'; +import type { EdgePattern } from './models/index.js'; import { executeGremlinQuery } from './query-utils.js'; import type { GremlinQueryError } from '../errors.js'; import type { process } from 'gremlin'; @@ -52,12 +52,12 @@ interface RawPatternData { * @param maxPatterns - Maximum number of patterns to retrieve (default: 1000) * @returns Effect with array of relationship patterns */ -export const generateRelationshipPatterns = ( +export const generateEdgePatterns = ( g: GraphTraversalSource, maxPatterns: number = 1000 -): Effect.Effect<RelationshipPattern[], GremlinQueryError> => +): Effect.Effect<EdgePattern[], GremlinQueryError> => Effect.gen(function* () { - yield* Effect.logInfo('Generating relationship patterns from edge connectivity'); + yield* Effect.logInfo('Generating edge patterns from edge connectivity'); // Get all patterns in a single optimized query const allPatterns = yield* executeGremlinQuery( @@ -71,7 +71,7 @@ export const generateRelationshipPatterns = ( .dedup() .limit(maxPatterns) .toList(), - 'Failed to get relationship patterns', + 'Failed to get edge patterns', `g.E().project('from', 'to', 'label').by(outV().label()).by(inV().label()).by(label()).dedup().limit(${maxPatterns}).toList()` ); @@ -95,12 +95,12 @@ export const generateRelationshipPatterns = ( */ const processRawPatterns = ( rawPatterns: unknown[] -): Effect.Effect<RelationshipPattern[], never> => { +): Effect.Effect<EdgePattern[], never> => { // Extract pattern data handling both Map and object formats const extractedPatterns = rawPatterns.map(extractPatternData); // Filter out invalid patterns and convert to final format - const validPatterns = extractedPatterns.filter(isValidPattern).map(convertToRelationshipPattern); + const validPatterns = extractedPatterns.filter(isValidPattern).map(convertToEdgePattern); return Effect.succeed(validPatterns); }; @@ -150,12 +150,12 @@ const isValidPattern = (pattern: RawPatternData): pattern is Required<RawPattern typeof pattern.label === 'string'; /** - * Converts validated pattern data to final RelationshipPattern format. + * Converts validated pattern data to final EdgePattern format. * * @param pattern - Validated pattern data * @returns Relationship pattern object */ -const convertToRelationshipPattern = (pattern: Required<RawPatternData>): RelationshipPattern => ({ +const convertToEdgePattern = (pattern: Required<RawPatternData>): EdgePattern => ({ left_vertex: pattern.from as string, right_vertex: pattern.to as string, relation: pattern.label as string, @@ -167,7 +167,7 @@ const convertToRelationshipPattern = (pattern: Required<RawPatternData>): Relati * @param patterns - Array of relationship patterns * @returns Pattern analysis statistics */ -export const analyzePatternStatistics = (patterns: RelationshipPattern[]) => { +export const analyzePatternStatistics = (patterns: EdgePattern[]) => { const vertexTypes = new Set<string>(); const edgeTypes = new Set<string>(); const connections = new Map<string, number>(); diff --git a/gremlin-tools/gremlin-mcp/src/gremlin/models/graph-schema.ts b/gremlin-tools/gremlin-mcp/src/gremlin/models/graph-schema.ts index 60845d4c44..b346337381 100644 --- a/gremlin-tools/gremlin-mcp/src/gremlin/models/graph-schema.ts +++ b/gremlin-tools/gremlin-mcp/src/gremlin/models/graph-schema.ts @@ -59,30 +59,30 @@ export type Vertex = z.infer<typeof VertexSchema>; /** * Relationship type in the graph schema. */ -export const RelationshipSchema = z.object({ - /** The type/category of the relationship */ +export const EdgeSchema = z.object({ + /** The type/category of the edge */ type: z.string(), - /** List of properties that can be assigned to this relationship type */ + /** List of properties that can be assigned to this edge type */ properties: z.array(PropertySchema).default([]), /** Count of edges with this label */ count: z.number().optional(), }); -export type Relationship = z.infer<typeof RelationshipSchema>; +export type Edge = z.infer<typeof EdgeSchema>; /** - * Valid relationship pattern between vertices. + * Valid edge pattern between vertices. */ -export const RelationshipPatternSchema = z.object({ +export const EdgePatternSchema = z.object({ /** The label of the source/starting vertex */ left_vertex: z.string(), /** The label of the target/ending vertex */ right_vertex: z.string(), - /** The type of relationship connecting the vertices */ + /** The label/type of the edge connecting the vertices */ relation: z.string(), }); -export type RelationshipPattern = z.infer<typeof RelationshipPatternSchema>; +export type EdgePattern = z.infer<typeof EdgePatternSchema>; /** * Schema metadata and optimization settings. @@ -92,9 +92,9 @@ export const SchemaMetadataSchema = z.object({ schema_size_bytes: z.number().optional(), /** Number of vertex types */ vertex_count: z.number(), - /** Number of relationship types */ - relationship_count: z.number(), - /** Number of relationship patterns */ + /** Number of edge types */ + edge_count: z.number(), + /** Number of edge patterns */ pattern_count: z.number(), /** Time taken to generate the schema in milliseconds */ generation_time_ms: z.number().optional(), @@ -119,10 +119,10 @@ export type SchemaMetadata = z.infer<typeof SchemaMetadataSchema>; export const GraphSchemaSchema = z.object({ /** List of all vertex types defined in the schema */ vertices: z.array(VertexSchema), - /** List of all relationship types defined in the schema */ - relationships: z.array(RelationshipSchema), - /** List of valid relationship patterns between vertices */ - relationship_patterns: z.array(RelationshipPatternSchema), + /** List of all edge types defined in the schema */ + edges: z.array(EdgeSchema), + /** List of valid edge patterns between vertices */ + edge_patterns: z.array(EdgePatternSchema), /** Schema metadata and optimization information */ metadata: SchemaMetadataSchema.optional(), }); diff --git a/gremlin-tools/gremlin-mcp/src/gremlin/schema-assembly.ts b/gremlin-tools/gremlin-mcp/src/gremlin/schema-assembly.ts index 626e4c077d..05345efd70 100644 --- a/gremlin-tools/gremlin-mcp/src/gremlin/schema-assembly.ts +++ b/gremlin-tools/gremlin-mcp/src/gremlin/schema-assembly.ts @@ -30,8 +30,8 @@ import { GraphSchemaSchema, type GraphSchema, type Vertex, - type Relationship, - type RelationshipPattern, + type Edge, + type EdgePattern, } from './models/index.js'; import { Errors, type GremlinQueryError } from '../errors.js'; import type { SchemaConfig } from './types.js'; @@ -43,7 +43,7 @@ export interface SchemaMetadata { generated_at: string; generation_time_ms: number; vertex_count: number; - relationship_count: number; + edge_count: number; pattern_count: number; optimization_settings: { sample_values_included: boolean; @@ -59,34 +59,34 @@ export interface SchemaMetadata { * Assembles and validates the final graph schema from analyzed components. * * @param vertices - Analyzed vertex types - * @param relationships - Analyzed edge relationships - * @param patterns - Relationship patterns + * @param edges - Analyzed edges + * @param patterns - Edge patterns * @param config - Schema generation configuration * @param startTime - Generation start timestamp for performance metrics * @returns Effect with validated graph schema */ export const assembleGraphSchema = ( vertices: Vertex[], - relationships: Relationship[], - patterns: RelationshipPattern[], + edges: Edge[], + patterns: EdgePattern[], config: SchemaConfig, startTime: number ): Effect.Effect<GraphSchema, GremlinQueryError> => Effect.gen(function* () { // Create metadata - const metadata = createSchemaMetadata(vertices, relationships, patterns, config, startTime); + const metadata = createSchemaMetadata(vertices, edges, patterns, config, startTime); // Assemble schema data const schemaData = { vertices, - relationships, - relationship_patterns: patterns, + edges, + edge_patterns: patterns, metadata, }; yield* Effect.logDebug('Schema assembly completed', { vertexCount: vertices.length, - relationshipCount: relationships.length, + edgeCount: edges.length, patternCount: patterns.length, generationTimeMs: metadata.generation_time_ms, }); @@ -107,15 +107,15 @@ export const assembleGraphSchema = ( */ const createSchemaMetadata = ( vertices: Vertex[], - relationships: Relationship[], - patterns: RelationshipPattern[], + edges: Edge[], + patterns: EdgePattern[], config: SchemaConfig, startTime: number ): SchemaMetadata => ({ generated_at: new Date().toISOString(), generation_time_ms: Date.now() - startTime, vertex_count: vertices.length, - relationship_count: relationships.length, + edge_count: edges.length, pattern_count: patterns.length, optimization_settings: { sample_values_included: config.includeSampleValues, @@ -200,51 +200,51 @@ export const validateVertices = (vertices: Vertex[]): Effect.Effect<void, Gremli }); /** - * Validates relationship data consistency and completeness. + * Validates edge data consistency and completeness. * - * @param relationships - Array of relationships to validate + * @param edges - Array of edges to validate * @returns Effect with validation result */ -export const validateRelationships = ( - relationships: Relationship[] +export const validateEdges = ( + edges: Edge[] ): Effect.Effect<void, GremlinQueryError> => Effect.gen(function* () { const issues: string[] = []; - relationships.forEach((rel, index) => { - if (!rel.type || typeof rel.type !== 'string') { - issues.push(`Relationship ${index}: Invalid or missing type`); + edges.forEach((edge, index) => { + if (!edge.type || typeof edge.type !== 'string') { + issues.push(`Edge ${index}: Invalid or missing type`); } - if (!Array.isArray(rel.properties)) { - issues.push(`Relationship ${index}: Properties must be an array`); + if (!Array.isArray(edge.properties)) { + issues.push(`Edge ${index}: Properties must be an array`); } - rel.properties?.forEach((prop, propIndex) => { + edge.properties?.forEach((prop, propIndex) => { if (!prop.name || typeof prop.name !== 'string') { - issues.push(`Relationship ${index}, Property ${propIndex}: Invalid or missing name`); + issues.push(`Edge ${index}, Property ${propIndex}: Invalid or missing name`); } if (!Array.isArray(prop.type)) { - issues.push(`Relationship ${index}, Property ${propIndex}: Type must be an array`); + issues.push(`Edge ${index}, Property ${propIndex}: Type must be an array`); } }); }); if (issues.length > 0) { return yield* Effect.fail( - Errors.query('Relationship validation failed', 'relationship-validation', { issues }) + Errors.query('Edge validation failed', 'edge-validation', { issues }) ); } }); /** - * Validates relationship patterns for consistency. + * Validates edge patterns for consistency. * - * @param patterns - Array of relationship patterns to validate + * @param patterns - Array of edge patterns to validate * @returns Effect with validation result */ -export const validateRelationshipPatterns = ( - patterns: RelationshipPattern[] +export const validateEdgePatterns = ( + patterns: EdgePattern[] ): Effect.Effect<void, GremlinQueryError> => Effect.gen(function* () { const issues: string[] = []; @@ -263,7 +263,7 @@ export const validateRelationshipPatterns = ( if (issues.length > 0) { return yield* Effect.fail( - Errors.query('Relationship pattern validation failed', 'pattern-validation', { issues }) + Errors.query('Edge pattern validation failed', 'pattern-validation', { issues }) ); } }); @@ -278,13 +278,13 @@ export const validateRelationshipPatterns = ( */ export const validateAllComponents = ( vertices: Vertex[], - relationships: Relationship[], - patterns: RelationshipPattern[] + edges: Edge[], + patterns: EdgePattern[] ): Effect.Effect<void, GremlinQueryError> => Effect.gen(function* () { yield* validateVertices(vertices); - yield* validateRelationships(relationships); - yield* validateRelationshipPatterns(patterns); + yield* validateEdges(edges); + yield* validateEdgePatterns(patterns); yield* Effect.logInfo('All schema components validated successfully'); }); diff --git a/gremlin-tools/gremlin-mcp/src/gremlin/schema-generator.ts b/gremlin-tools/gremlin-mcp/src/gremlin/schema-generator.ts index 9022da0cda..03584f85f2 100644 --- a/gremlin-tools/gremlin-mcp/src/gremlin/schema-generator.ts +++ b/gremlin-tools/gremlin-mcp/src/gremlin/schema-generator.ts @@ -27,7 +27,7 @@ */ import { Effect, Duration } from 'effect'; -import { type GraphSchema, type Vertex, type Relationship } from './models/index.js'; +import { type GraphSchema, type Vertex, type Edge } from './models/index.js'; import { Errors, type GremlinConnectionError, type GremlinQueryError } from '../errors.js'; import type { ConnectionState, SchemaConfig } from './types.js'; import { @@ -39,7 +39,7 @@ import { getEdgePropertyKeys, } from './query-utils.js'; import { analyzeElementProperties, withElementCounts } from './property-analyzer.js'; -import { generateRelationshipPatterns } from './relationship-patterns.js'; +import { generateEdgePatterns } from './edge-patterns'; import { assembleGraphSchema } from './schema-assembly.js'; import type { process } from 'gremlin'; @@ -88,26 +88,26 @@ const executeSchemaGeneration = ( // Step 3: Analyze properties and patterns in parallel yield* Effect.logInfo('Analyzing properties and relationship patterns'); - const [rawVertices, rawRelationships, patterns] = yield* Effect.all( + const [rawVertices, rawEdges, patterns] = yield* Effect.all( [ analyzeElementProperties(g, vertexLabels, getVertexPropertyKeys, config, true), analyzeElementProperties(g, edgeLabels, getEdgePropertyKeys, config, false), - generateRelationshipPatterns(g), + generateEdgePatterns(g), ], { concurrency: 3 } ); // Step 4: Add count information const vertices = addElementCounts<Vertex>(rawVertices, vertexCounts, config, 'labels'); - const relationships = addElementCounts<Relationship>( - rawRelationships, + const edges = addElementCounts<Edge>( + rawEdges, edgeCounts, config, 'type' ); // Step 5: Assemble final schema - return yield* assembleGraphSchema(vertices, relationships, patterns, config, startTime); + return yield* assembleGraphSchema(vertices, edges, patterns, config, startTime); }); /** @@ -127,7 +127,7 @@ const getElementCounts = ( /** * Adds count information to analysis results. */ -const addElementCounts = <T extends Vertex | Relationship>( +const addElementCounts = <T extends Vertex | Edge>( rawElements: unknown[], counts: SchemaCountData, config: SchemaConfig, diff --git a/gremlin-tools/gremlin-mcp/tests/relationship-patterns.test.ts b/gremlin-tools/gremlin-mcp/tests/edge-patterns.test.ts similarity index 85% rename from gremlin-tools/gremlin-mcp/tests/relationship-patterns.test.ts rename to gremlin-tools/gremlin-mcp/tests/edge-patterns.test.ts index eea75c892b..5556f005fd 100644 --- a/gremlin-tools/gremlin-mcp/tests/relationship-patterns.test.ts +++ b/gremlin-tools/gremlin-mcp/tests/edge-patterns.test.ts @@ -19,20 +19,20 @@ /** - * @fileoverview Tests for the relationship patterns module. + * @fileoverview Tests for the edge patterns module. * - * Tests relationship pattern analysis including edge connectivity patterns, - * pattern processing, and relationship statistics generation. + * Tests edge pattern analysis including edge connectivity patterns, + * pattern processing, and edge statistics generation. */ import { Effect } from 'effect'; import { describe, it, expect, beforeEach, jest } from '@jest/globals'; import { - generateRelationshipPatterns, + generateEdgePatterns as generateEdgePatterns, analyzePatternStatistics, -} from '../src/gremlin/relationship-patterns.js'; +} from '../src/gremlin/edge-patterns.js'; import { Errors } from '../src/errors.js'; -import type { RelationshipPattern } from '../src/gremlin/models.js'; +import type { EdgePattern } from '../src/gremlin/models.js'; // Mock Gremlin query utilities jest.mock('../src/gremlin/query-utils.js', () => ({ @@ -45,24 +45,24 @@ const mockExecuteGremlinQuery = executeGremlinQuery as jest.MockedFunction< typeof executeGremlinQuery >; -describe('relationship-patterns', () => { +describe('edge-patterns', () => { beforeEach(() => { jest.clearAllMocks(); }); - describe('generateRelationshipPatterns', () => { + describe('generateEdgePatterns', () => { const mockTraversalSource = { E: jest.fn(), } as any; - it('should generate relationship patterns successfully', async () => { + it('should generate edge patterns successfully', async () => { const mockRawPatterns = [ { from: 'person', to: 'company', label: 'worksAt' }, { from: 'person', to: 'person', label: 'knows' }, { from: 'company', to: 'project', label: 'sponsors' }, ]; - const expectedPatterns: RelationshipPattern[] = [ + const expectedPatterns: EdgePattern[] = [ { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, { left_vertex: 'company', right_vertex: 'project', relation: 'sponsors' }, @@ -70,12 +70,12 @@ describe('relationship-patterns', () => { mockExecuteGremlinQuery.mockReturnValue(Effect.succeed(mockRawPatterns)); - const result = await Effect.runPromise(generateRelationshipPatterns(mockTraversalSource)); + const result = await Effect.runPromise(generateEdgePatterns(mockTraversalSource)); expect(result).toEqual(expectedPatterns); expect(mockExecuteGremlinQuery).toHaveBeenCalledWith( expect.any(Function), - 'Failed to get relationship patterns', + 'Failed to get edge patterns', expect.stringContaining('project') ); }); @@ -86,13 +86,13 @@ describe('relationship-patterns', () => { mockExecuteGremlinQuery.mockReturnValue(Effect.succeed(mockRawPatterns)); const result = await Effect.runPromise( - generateRelationshipPatterns(mockTraversalSource, 500) + generateEdgePatterns(mockTraversalSource, 500) ); expect(result).toHaveLength(1); expect(mockExecuteGremlinQuery).toHaveBeenCalledWith( expect.any(Function), - 'Failed to get relationship patterns', + 'Failed to get edge patterns', expect.stringContaining('limit(500)') ); }); @@ -100,7 +100,7 @@ describe('relationship-patterns', () => { it('should handle empty pattern results', async () => { mockExecuteGremlinQuery.mockReturnValue(Effect.succeed([])); - const result = await Effect.runPromise(generateRelationshipPatterns(mockTraversalSource)); + const result = await Effect.runPromise(generateEdgePatterns(mockTraversalSource)); expect(result).toEqual([]); }); @@ -115,7 +115,7 @@ describe('relationship-patterns', () => { mockExecuteGremlinQuery.mockReturnValue(Effect.succeed(mockRawPatterns)); - const result = await Effect.runPromise(generateRelationshipPatterns(mockTraversalSource)); + const result = await Effect.runPromise(generateEdgePatterns(mockTraversalSource)); // Should filter out invalid patterns and process only valid ones expect(result).toHaveLength(2); // Only valid patterns processed @@ -135,7 +135,7 @@ describe('relationship-patterns', () => { const error = Errors.query('Connection failed', 'pattern query', new Error('Network error')); mockExecuteGremlinQuery.mockReturnValue(Effect.fail(error)); - const result = await Effect.runPromiseExit(generateRelationshipPatterns(mockTraversalSource)); + const result = await Effect.runPromiseExit(generateEdgePatterns(mockTraversalSource)); expect(result._tag).toBe('Failure'); }); @@ -151,7 +151,7 @@ describe('relationship-patterns', () => { mockExecuteGremlinQuery.mockReturnValue(Effect.succeed(mockRawPatterns)); - const result = await Effect.runPromise(generateRelationshipPatterns(mockTraversalSource)); + const result = await Effect.runPromise(generateEdgePatterns(mockTraversalSource)); expect(result).toHaveLength(5); @@ -173,7 +173,7 @@ describe('relationship-patterns', () => { describe('analyzePatternStatistics', () => { it('should analyze basic pattern statistics', () => { - const patterns: RelationshipPattern[] = [ + const patterns: EdgePattern[] = [ { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, { left_vertex: 'company', right_vertex: 'project', relation: 'sponsors' }, @@ -190,7 +190,7 @@ describe('relationship-patterns', () => { }); it('should handle empty patterns array', () => { - const patterns: RelationshipPattern[] = []; + const patterns: EdgePattern[] = []; const stats = analyzePatternStatistics(patterns); @@ -203,7 +203,7 @@ describe('relationship-patterns', () => { }); it('should count connection frequencies correctly', () => { - const patterns: RelationshipPattern[] = [ + const patterns: EdgePattern[] = [ { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, { left_vertex: 'person', right_vertex: 'company', relation: 'contractsWith' }, { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, @@ -218,7 +218,7 @@ describe('relationship-patterns', () => { }); it('should handle duplicate patterns correctly', () => { - const patterns: RelationshipPattern[] = [ + const patterns: EdgePattern[] = [ { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, // Duplicate { left_vertex: 'person', right_vertex: 'company', relation: 'contractsWith' }, @@ -233,7 +233,7 @@ describe('relationship-patterns', () => { }); it('should calculate averages correctly for complex patterns', () => { - const patterns: RelationshipPattern[] = [ + const patterns: EdgePattern[] = [ { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, { left_vertex: 'person', right_vertex: 'project', relation: 'owns' }, { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, @@ -251,7 +251,7 @@ describe('relationship-patterns', () => { }); it('should sort vertex and edge types alphabetically', () => { - const patterns: RelationshipPattern[] = [ + const patterns: EdgePattern[] = [ { left_vertex: 'zebra', right_vertex: 'apple', relation: 'eats' }, { left_vertex: 'banana', right_vertex: 'cherry', relation: 'grows' }, { left_vertex: 'apple', right_vertex: 'banana', relation: 'becomes' }, diff --git a/gremlin-tools/gremlin-mcp/tests/integration/mcp-integration.test.ts b/gremlin-tools/gremlin-mcp/tests/integration/mcp-integration.test.ts index 5bee436780..559fff8cec 100644 --- a/gremlin-tools/gremlin-mcp/tests/integration/mcp-integration.test.ts +++ b/gremlin-tools/gremlin-mcp/tests/integration/mcp-integration.test.ts @@ -170,19 +170,19 @@ describe('MCP Server Integration Tests', () => { expect(schema).toBeDefined(); expect(schema.vertices).toBeDefined(); - expect(schema.relationships).toBeDefined(); + expect(schema.edges).toBeDefined(); expect(Array.isArray(schema.vertices)).toBe(true); - expect(Array.isArray(schema.relationships)).toBe(true); + expect(Array.isArray(schema.edges)).toBe(true); - // Verify relationship_patterns is present and adjacency_list is removed - expect(schema.relationship_patterns).toBeDefined(); - expect(Array.isArray(schema.relationship_patterns)).toBe(true); + // Verify edge_patterns is present and adjacency_list is removed + expect(schema.edge_patterns).toBeDefined(); + expect(Array.isArray(schema.edge_patterns)).toBe(true); expect(schema.adjacency_list).toBeUndefined(); // Verify metadata structure if (schema.metadata) { expect(schema.metadata.vertex_count).toBeGreaterThanOrEqual(0); - expect(schema.metadata.relationship_count).toBeGreaterThanOrEqual(0); + expect(schema.metadata.edge_count).toBeGreaterThanOrEqual(0); expect(schema.metadata.optimization_settings).toBeDefined(); } }, diff --git a/gremlin-tools/gremlin-mcp/tests/models.test.ts b/gremlin-tools/gremlin-mcp/tests/models.test.ts index 3ac4550526..efa0cc15c0 100644 --- a/gremlin-tools/gremlin-mcp/tests/models.test.ts +++ b/gremlin-tools/gremlin-mcp/tests/models.test.ts @@ -25,7 +25,7 @@ import { PropertySchema, VertexSchema, - RelationshipSchema, + EdgeSchema, GraphSchemaSchema, GremlinConfigSchema, GremlinQueryResultSchema, @@ -73,20 +73,20 @@ describe('Models and Schemas', () => { }); }); - describe('RelationshipSchema', () => { - it('should validate a valid relationship', () => { - const validRelationship = { + describe('EdgeSchema', () => { + it('should validate a valid edge', () => { + const validEdge = { type: 'knows', properties: [], count: 50, }; - expect(() => RelationshipSchema.parse(validRelationship)).not.toThrow(); + expect(() => EdgeSchema.parse(validEdge)).not.toThrow(); }); }); describe('GraphSchemaSchema', () => { - it('should validate a complete graph schema with relationship_patterns', () => { + it('should validate a complete graph schema with edge_patterns', () => { const validSchema = { vertices: [ { @@ -100,13 +100,13 @@ describe('Models and Schemas', () => { ], }, ], - relationships: [ + edges: [ { type: 'knows', properties: [], }, ], - relationship_patterns: [ + edge_patterns: [ { left_vertex: 'person', right_vertex: 'person', @@ -115,7 +115,7 @@ describe('Models and Schemas', () => { ], metadata: { vertex_count: 1, - relationship_count: 1, + edge_count: 1, pattern_count: 1, schema_size_bytes: 1024, optimization_settings: { @@ -130,9 +130,9 @@ describe('Models and Schemas', () => { expect(() => GraphSchemaSchema.parse(validSchema)).not.toThrow(); - // Verify relationship_patterns is present and adjacency_list is not + // Verify edge_patterns is present and adjacency_list is not const parsed = GraphSchemaSchema.parse(validSchema); - expect('relationship_patterns' in parsed).toBe(true); + expect('edge_patterns' in parsed).toBe(true); expect('adjacency_list' in parsed).toBe(false); }); }); @@ -178,7 +178,7 @@ describe('Models and Schemas', () => { it('should validate schema metadata', () => { const validMetadata = { vertex_count: 10, - relationship_count: 5, + edge_count: 5, pattern_count: 8, schema_size_bytes: 2048, optimization_settings: { diff --git a/gremlin-tools/gremlin-mcp/tests/schema-assembly.test.ts b/gremlin-tools/gremlin-mcp/tests/schema-assembly.test.ts index 1fb06b0147..96975209b3 100644 --- a/gremlin-tools/gremlin-mcp/tests/schema-assembly.test.ts +++ b/gremlin-tools/gremlin-mcp/tests/schema-assembly.test.ts @@ -30,11 +30,11 @@ import { describe, it, expect, beforeEach, jest } from '@jest/globals'; import { assembleGraphSchema, validateVertices, - validateRelationships, - validateRelationshipPatterns, + validateEdges, + validateEdgePatterns, validateAllComponents, } from '../src/gremlin/schema-assembly.js'; -import type { Vertex, Relationship, RelationshipPattern } from '../src/gremlin/models.js'; +import type { Vertex, Edge, EdgePattern } from '../src/gremlin/models.js'; import type { SchemaConfig } from '../src/gremlin/types.js'; describe('schema-assembly', () => { @@ -65,7 +65,7 @@ describe('schema-assembly', () => { }, ]; - const sampleRelationships: Relationship[] = [ + const sampleEdges: Edge[] = [ { type: 'worksAt', properties: [ @@ -79,7 +79,7 @@ describe('schema-assembly', () => { }, ]; - const samplePatterns: RelationshipPattern[] = [ + const samplePatterns: EdgePattern[] = [ { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, ]; @@ -93,18 +93,18 @@ describe('schema-assembly', () => { const startTime = Date.now(); const result = await Effect.runPromise( - assembleGraphSchema(sampleVertices, sampleRelationships, samplePatterns, mockConfig, startTime) + assembleGraphSchema(sampleVertices, sampleEdges, samplePatterns, mockConfig, startTime) ); // Verify schema structure expect(result.vertices).toEqual(sampleVertices); - expect(result.relationships).toEqual(sampleRelationships); - expect(result.relationship_patterns).toEqual(samplePatterns); + expect(result.edges).toEqual(sampleEdges); + expect(result.edge_patterns).toEqual(samplePatterns); // Verify metadata expect(result.metadata).toBeDefined(); expect(result.metadata!.vertex_count).toBe(2); - expect(result.metadata!.relationship_count).toBe(2); + expect(result.metadata!.edge_count).toBe(2); expect(result.metadata!.pattern_count).toBe(2); expect(result.metadata!.generated_at).toBeDefined(); expect(result.metadata!.generation_time_ms).toBeGreaterThanOrEqual(0); @@ -128,10 +128,10 @@ describe('schema-assembly', () => { ); expect(result.vertices).toEqual([]); - expect(result.relationships).toEqual([]); - expect(result.relationship_patterns).toEqual([]); + expect(result.edges).toEqual([]); + expect(result.edge_patterns).toEqual([]); expect(result.metadata!.vertex_count).toBe(0); - expect(result.metadata!.relationship_count).toBe(0); + expect(result.metadata!.edge_count).toBe(0); expect(result.metadata!.pattern_count).toBe(0); }); @@ -139,7 +139,7 @@ describe('schema-assembly', () => { const startTime = Date.now() - 1000; // 1 second ago const result = await Effect.runPromise( - assembleGraphSchema(sampleVertices, sampleRelationships, samplePatterns, mockConfig, startTime) + assembleGraphSchema(sampleVertices, sampleEdges, samplePatterns, mockConfig, startTime) ); expect(result.metadata!.generation_time_ms).toBeGreaterThanOrEqual(1000); @@ -157,7 +157,7 @@ describe('schema-assembly', () => { const result = await Effect.runPromiseExit( assembleGraphSchema( invalidVertices, - sampleRelationships, + sampleEdges, samplePatterns, mockConfig, Date.now() @@ -234,28 +234,28 @@ describe('schema-assembly', () => { }); }); - describe('validateRelationships', () => { + describe('validateEdges', () => { it('should validate correct relationships successfully', async () => { - const result = await Effect.runPromise(validateRelationships(sampleRelationships)); + const result = await Effect.runPromise(validateEdges(sampleEdges)); expect(result).toBeUndefined(); // Void return on success }); it('should detect missing labels', async () => { - const invalidRelationships: Relationship[] = [ + const invalidEdges: Edge[] = [ { type: '', // Invalid empty type properties: [], }, ]; - const result = await Effect.runPromiseExit(validateRelationships(invalidRelationships)); + const result = await Effect.runPromiseExit(validateEdges(invalidEdges)); expect(result._tag).toBe('Failure'); }); it('should detect invalid properties', async () => { - const invalidRelationships: Relationship[] = [ + const invalidEdges: Edge[] = [ { type: 'knows', properties: [ @@ -264,34 +264,34 @@ describe('schema-assembly', () => { }, ]; - const result = await Effect.runPromiseExit(validateRelationships(invalidRelationships)); + const result = await Effect.runPromiseExit(validateEdges(invalidEdges)); expect(result._tag).toBe('Failure'); }); it('should handle missing properties array', async () => { - const invalidRelationships: Relationship[] = [ + const invalidEdges: Edge[] = [ { type: 'knows', properties: undefined as any, // Missing properties }, ]; - const result = await Effect.runPromiseExit(validateRelationships(invalidRelationships)); + const result = await Effect.runPromiseExit(validateEdges(invalidEdges)); expect(result._tag).toBe('Failure'); }); }); - describe('validateRelationshipPatterns', () => { + describe('validateEdgePatterns', () => { it('should validate correct patterns successfully', async () => { - const result = await Effect.runPromise(validateRelationshipPatterns(samplePatterns)); + const result = await Effect.runPromise(validateEdgePatterns(samplePatterns)); expect(result).toBeUndefined(); // Void return on success }); it('should detect missing pattern fields', async () => { - const invalidPatterns: RelationshipPattern[] = [ + const invalidPatterns: EdgePattern[] = [ { left_vertex: '', // Empty left vertex right_vertex: 'company', @@ -309,13 +309,13 @@ describe('schema-assembly', () => { }, ]; - const result = await Effect.runPromiseExit(validateRelationshipPatterns(invalidPatterns)); + const result = await Effect.runPromiseExit(validateEdgePatterns(invalidPatterns)); expect(result._tag).toBe('Failure'); }); it('should detect invalid pattern field types', async () => { - const invalidPatterns: RelationshipPattern[] = [ + const invalidPatterns: EdgePattern[] = [ { left_vertex: null as any, // Invalid type right_vertex: 'company', @@ -323,7 +323,7 @@ describe('schema-assembly', () => { }, ]; - const result = await Effect.runPromiseExit(validateRelationshipPatterns(invalidPatterns)); + const result = await Effect.runPromiseExit(validateEdgePatterns(invalidPatterns)); expect(result._tag).toBe('Failure'); }); @@ -332,7 +332,7 @@ describe('schema-assembly', () => { describe('validateAllComponents', () => { it('should validate all components successfully', async () => { const result = await Effect.runPromise( - validateAllComponents(sampleVertices, sampleRelationships, samplePatterns) + validateAllComponents(sampleVertices, sampleEdges, samplePatterns) ); expect(result).toBeUndefined(); // Void return on success @@ -347,15 +347,15 @@ describe('schema-assembly', () => { ]; const result = await Effect.runPromiseExit( - validateAllComponents(invalidVertices, sampleRelationships, samplePatterns) + validateAllComponents(invalidVertices, sampleEdges, samplePatterns) ); expect(result._tag).toBe('Failure'); }); it('should validate each component type independently', async () => { - // Test with valid vertices but invalid relationships - const invalidRelationships: Relationship[] = [ + // Test with valid vertices but invalid edges + const invalidEdges: Edge[] = [ { type: '', // Invalid properties: [], @@ -363,7 +363,7 @@ describe('schema-assembly', () => { ]; const result = await Effect.runPromiseExit( - validateAllComponents(sampleVertices, invalidRelationships, samplePatterns) + validateAllComponents(sampleVertices, invalidEdges, samplePatterns) ); expect(result._tag).toBe('Failure'); @@ -375,7 +375,7 @@ describe('schema-assembly', () => { const startTime = Date.now() - 500; const result = await Effect.runPromise( - assembleGraphSchema(sampleVertices, sampleRelationships, samplePatterns, mockConfig, startTime) + assembleGraphSchema(sampleVertices, sampleEdges, samplePatterns, mockConfig, startTime) ); const metadata = result.metadata!; @@ -384,7 +384,7 @@ describe('schema-assembly', () => { expect(metadata.generated_at).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/); // ISO format expect(metadata.generation_time_ms).toBeGreaterThanOrEqual(500); expect(metadata.vertex_count).toBe(sampleVertices.length); - expect(metadata.relationship_count).toBe(sampleRelationships.length); + expect(metadata.edge_count).toBe(sampleEdges.length); expect(metadata.pattern_count).toBe(samplePatterns.length); // Check optimization settings @@ -410,7 +410,7 @@ describe('schema-assembly', () => { const result = await Effect.runPromise( assembleGraphSchema( sampleVertices, - sampleRelationships, + sampleEdges, samplePatterns, minimalConfig, Date.now()
