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 7a8fae5211d0401f64ae9ed226c503226933c3c1 Author: Stephen Mallette <[email protected]> AuthorDate: Mon Sep 29 14:30:59 2025 -0400 TinkerPop prefers the use of the term vertex over node. --- gremlin-tools/gremlin-mcp/README.md | 20 +++--- .../gremlin-mcp/src/gremlin/models/graph-schema.ts | 32 ++++----- .../src/gremlin/relationship-patterns.ts | 10 +-- .../gremlin-mcp/src/gremlin/schema-assembly.ts | 58 ++++++++-------- .../gremlin-mcp/src/gremlin/schema-generator.ts | 10 +-- .../tests/integration/mcp-integration.test.ts | 6 +- gremlin-tools/gremlin-mcp/tests/models.test.ts | 20 +++--- .../tests/relationship-patterns.test.ts | 58 ++++++++-------- .../gremlin-mcp/tests/schema-assembly.test.ts | 80 +++++++++++----------- 9 files changed, 147 insertions(+), 147 deletions(-) diff --git a/gremlin-tools/gremlin-mcp/README.md b/gremlin-tools/gremlin-mcp/README.md index 4b71b6d09e..82692282fb 100644 --- a/gremlin-tools/gremlin-mcp/README.md +++ b/gremlin-tools/gremlin-mcp/README.md @@ -41,14 +41,14 @@ 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 nodes, edges, and relationships | -| ⚡ **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 | +| 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 | +| 🔄 **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 | ## 🚀 Quick Setup @@ -152,7 +152,7 @@ Restart your AI client and try asking: **You ask:** _"What's the structure of my graph database?"_ -**AI response:** The AI calls `get_graph_schema` and tells you about your node types, edge types, and how they're connected. +**AI response:** The AI calls `get_graph_schema` and tells you about your vertex types, edge types, and how they're connected. ### Data Analysis @@ -164,7 +164,7 @@ Restart your AI client and try asking: **You ask:** _"Give me some statistics about my graph"_ -**AI response:** The AI runs multiple queries to count nodes, edges, and analyze the distribution, then presents a summary. +**AI response:** The AI runs multiple queries to count vertices, edges, and analyze the distribution, then presents a summary. ### Data Import 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 b329c1ec77..60845d4c44 100644 --- a/gremlin-tools/gremlin-mcp/src/gremlin/models/graph-schema.ts +++ b/gremlin-tools/gremlin-mcp/src/gremlin/models/graph-schema.ts @@ -43,18 +43,18 @@ export const PropertySchema = z.object({ export type Property = z.infer<typeof PropertySchema>; /** - * Node type in the graph schema. + * Vertex type in the graph schema. */ -export const NodeSchema = z.object({ - /** The label(s) that categorize this node type */ +export const VertexSchema = z.object({ + /** The label(s) that categorize this vertex type */ labels: z.string(), - /** List of properties that can be assigned to this node type */ + /** List of properties that can be assigned to this vertex type */ properties: z.array(PropertySchema).default([]), /** Count of vertices with this label */ count: z.number().optional(), }); -export type Node = z.infer<typeof NodeSchema>; +export type Vertex = z.infer<typeof VertexSchema>; /** * Relationship type in the graph schema. @@ -71,14 +71,14 @@ export const RelationshipSchema = z.object({ export type Relationship = z.infer<typeof RelationshipSchema>; /** - * Valid relationship pattern between nodes. + * Valid relationship pattern between vertices. */ export const RelationshipPatternSchema = z.object({ - /** The label of the source/starting node */ - left_node: z.string(), - /** The label of the target/ending node */ - right_node: z.string(), - /** The type of relationship connecting the nodes */ + /** 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 */ relation: z.string(), }); @@ -90,8 +90,8 @@ export type RelationshipPattern = z.infer<typeof RelationshipPatternSchema>; export const SchemaMetadataSchema = z.object({ /** Total size of the schema in bytes */ schema_size_bytes: z.number().optional(), - /** Number of node types */ - node_count: z.number(), + /** Number of vertex types */ + vertex_count: z.number(), /** Number of relationship types */ relationship_count: z.number(), /** Number of relationship patterns */ @@ -117,11 +117,11 @@ export type SchemaMetadata = z.infer<typeof SchemaMetadataSchema>; * Complete graph schema definition. */ export const GraphSchemaSchema = z.object({ - /** List of all node types defined in the schema */ - nodes: z.array(NodeSchema), + /** 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 nodes */ + /** List of valid relationship patterns between vertices */ relationship_patterns: z.array(RelationshipPatternSchema), /** Schema metadata and optimization information */ metadata: SchemaMetadataSchema.optional(), diff --git a/gremlin-tools/gremlin-mcp/src/gremlin/relationship-patterns.ts b/gremlin-tools/gremlin-mcp/src/gremlin/relationship-patterns.ts index 66e914e42b..6f1c33738f 100644 --- a/gremlin-tools/gremlin-mcp/src/gremlin/relationship-patterns.ts +++ b/gremlin-tools/gremlin-mcp/src/gremlin/relationship-patterns.ts @@ -156,8 +156,8 @@ const isValidPattern = (pattern: RawPatternData): pattern is Required<RawPattern * @returns Relationship pattern object */ const convertToRelationshipPattern = (pattern: Required<RawPatternData>): RelationshipPattern => ({ - left_node: pattern.from as string, - right_node: pattern.to as string, + left_vertex: pattern.from as string, + right_vertex: pattern.to as string, relation: pattern.label as string, }); @@ -173,11 +173,11 @@ export const analyzePatternStatistics = (patterns: RelationshipPattern[]) => { const connections = new Map<string, number>(); patterns.forEach(pattern => { - vertexTypes.add(pattern.left_node); - vertexTypes.add(pattern.right_node); + vertexTypes.add(pattern.left_vertex); + vertexTypes.add(pattern.right_vertex); edgeTypes.add(pattern.relation); - const connectionKey = `${pattern.left_node}->${pattern.right_node}`; + const connectionKey = `${pattern.left_vertex}->${pattern.right_vertex}`; connections.set(connectionKey, (connections.get(connectionKey) || 0) + 1); }); diff --git a/gremlin-tools/gremlin-mcp/src/gremlin/schema-assembly.ts b/gremlin-tools/gremlin-mcp/src/gremlin/schema-assembly.ts index 9e2eb43e25..626e4c077d 100644 --- a/gremlin-tools/gremlin-mcp/src/gremlin/schema-assembly.ts +++ b/gremlin-tools/gremlin-mcp/src/gremlin/schema-assembly.ts @@ -29,7 +29,7 @@ import { Effect } from 'effect'; import { GraphSchemaSchema, type GraphSchema, - type Node, + type Vertex, type Relationship, type RelationshipPattern, } from './models/index.js'; @@ -42,7 +42,7 @@ import type { SchemaConfig } from './types.js'; export interface SchemaMetadata { generated_at: string; generation_time_ms: number; - node_count: number; + vertex_count: number; relationship_count: number; pattern_count: number; optimization_settings: { @@ -58,7 +58,7 @@ export interface SchemaMetadata { /** * Assembles and validates the final graph schema from analyzed components. * - * @param nodes - Analyzed vertex nodes + * @param vertices - Analyzed vertex types * @param relationships - Analyzed edge relationships * @param patterns - Relationship patterns * @param config - Schema generation configuration @@ -66,7 +66,7 @@ export interface SchemaMetadata { * @returns Effect with validated graph schema */ export const assembleGraphSchema = ( - nodes: Node[], + vertices: Vertex[], relationships: Relationship[], patterns: RelationshipPattern[], config: SchemaConfig, @@ -74,18 +74,18 @@ export const assembleGraphSchema = ( ): Effect.Effect<GraphSchema, GremlinQueryError> => Effect.gen(function* () { // Create metadata - const metadata = createSchemaMetadata(nodes, relationships, patterns, config, startTime); + const metadata = createSchemaMetadata(vertices, relationships, patterns, config, startTime); // Assemble schema data const schemaData = { - nodes, + vertices, relationships, relationship_patterns: patterns, metadata, }; yield* Effect.logDebug('Schema assembly completed', { - nodeCount: nodes.length, + vertexCount: vertices.length, relationshipCount: relationships.length, patternCount: patterns.length, generationTimeMs: metadata.generation_time_ms, @@ -98,7 +98,7 @@ export const assembleGraphSchema = ( /** * Creates schema metadata with generation statistics and configuration. * - * @param nodes - Analyzed nodes + * @param vertices - Analyzed vertices * @param relationships - Analyzed relationships * @param patterns - Relationship patterns * @param config - Configuration used for generation @@ -106,7 +106,7 @@ export const assembleGraphSchema = ( * @returns Schema metadata object */ const createSchemaMetadata = ( - nodes: Node[], + vertices: Vertex[], relationships: Relationship[], patterns: RelationshipPattern[], config: SchemaConfig, @@ -114,7 +114,7 @@ const createSchemaMetadata = ( ): SchemaMetadata => ({ generated_at: new Date().toISOString(), generation_time_ms: Date.now() - startTime, - node_count: nodes.length, + vertex_count: vertices.length, relationship_count: relationships.length, pattern_count: patterns.length, optimization_settings: { @@ -164,37 +164,37 @@ const safeStringify = (obj: unknown): string => { }; /** - * Validates node data consistency and completeness. + * Validates vertex data consistency and completeness. * - * @param nodes - Array of nodes to validate + * @param vertices - Array of vertices to validate * @returns Effect with validation result */ -export const validateNodes = (nodes: Node[]): Effect.Effect<void, GremlinQueryError> => +export const validateVertices = (vertices: Vertex[]): Effect.Effect<void, GremlinQueryError> => Effect.gen(function* () { const issues: string[] = []; - nodes.forEach((node, index) => { - if (!node.labels || typeof node.labels !== 'string') { - issues.push(`Node ${index}: Invalid or missing labels`); + vertices.forEach((vertex, index) => { + if (!vertex.labels || typeof vertex.labels !== 'string') { + issues.push(`Vertex ${index}: Invalid or missing labels`); } - if (!Array.isArray(node.properties)) { - issues.push(`Node ${index}: Properties must be an array`); + if (!Array.isArray(vertex.properties)) { + issues.push(`Vertex ${index}: Properties must be an array`); } - node.properties?.forEach((prop, propIndex) => { + vertex.properties?.forEach((prop, propIndex) => { if (!prop.name || typeof prop.name !== 'string') { - issues.push(`Node ${index}, Property ${propIndex}: Invalid or missing name`); + issues.push(`Vertex ${index}, Property ${propIndex}: Invalid or missing name`); } if (!Array.isArray(prop.type)) { - issues.push(`Node ${index}, Property ${propIndex}: Type must be an array`); + issues.push(`Vertex ${index}, Property ${propIndex}: Type must be an array`); } }); }); if (issues.length > 0) { return yield* Effect.fail( - Errors.query('Node validation failed', 'node-validation', { issues }) + Errors.query('Vertex validation failed', 'vertex-validation', { issues }) ); } }); @@ -250,11 +250,11 @@ export const validateRelationshipPatterns = ( const issues: string[] = []; patterns.forEach((pattern, index) => { - if (!pattern.left_node || typeof pattern.left_node !== 'string') { - issues.push(`Pattern ${index}: Invalid or missing left_node`); + if (!pattern.left_vertex || typeof pattern.left_vertex !== 'string') { + issues.push(`Pattern ${index}: Invalid or missing left_vertex`); } - if (!pattern.right_node || typeof pattern.right_node !== 'string') { - issues.push(`Pattern ${index}: Invalid or missing right_node`); + if (!pattern.right_vertex || typeof pattern.right_vertex !== 'string') { + issues.push(`Pattern ${index}: Invalid or missing right_vertex`); } if (!pattern.relation || typeof pattern.relation !== 'string') { issues.push(`Pattern ${index}: Invalid or missing relation`); @@ -271,18 +271,18 @@ export const validateRelationshipPatterns = ( /** * Performs comprehensive validation of all schema components. * - * @param nodes - Nodes to validate + * @param vertices - Vertices to validate * @param relationships - Relationships to validate * @param patterns - Patterns to validate * @returns Effect with validation result */ export const validateAllComponents = ( - nodes: Node[], + vertices: Vertex[], relationships: Relationship[], patterns: RelationshipPattern[] ): Effect.Effect<void, GremlinQueryError> => Effect.gen(function* () { - yield* validateNodes(nodes); + yield* validateVertices(vertices); yield* validateRelationships(relationships); yield* validateRelationshipPatterns(patterns); diff --git a/gremlin-tools/gremlin-mcp/src/gremlin/schema-generator.ts b/gremlin-tools/gremlin-mcp/src/gremlin/schema-generator.ts index 9ce1877921..9022da0cda 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 Node, type Relationship } from './models/index.js'; +import { type GraphSchema, type Vertex, type Relationship } from './models/index.js'; import { Errors, type GremlinConnectionError, type GremlinQueryError } from '../errors.js'; import type { ConnectionState, SchemaConfig } from './types.js'; import { @@ -88,7 +88,7 @@ const executeSchemaGeneration = ( // Step 3: Analyze properties and patterns in parallel yield* Effect.logInfo('Analyzing properties and relationship patterns'); - const [rawNodes, rawRelationships, patterns] = yield* Effect.all( + const [rawVertices, rawRelationships, patterns] = yield* Effect.all( [ analyzeElementProperties(g, vertexLabels, getVertexPropertyKeys, config, true), analyzeElementProperties(g, edgeLabels, getEdgePropertyKeys, config, false), @@ -98,7 +98,7 @@ const executeSchemaGeneration = ( ); // Step 4: Add count information - const nodes = addElementCounts<Node>(rawNodes, vertexCounts, config, 'labels'); + const vertices = addElementCounts<Vertex>(rawVertices, vertexCounts, config, 'labels'); const relationships = addElementCounts<Relationship>( rawRelationships, edgeCounts, @@ -107,7 +107,7 @@ const executeSchemaGeneration = ( ); // Step 5: Assemble final schema - return yield* assembleGraphSchema(nodes, relationships, patterns, config, startTime); + return yield* assembleGraphSchema(vertices, relationships, patterns, config, startTime); }); /** @@ -127,7 +127,7 @@ const getElementCounts = ( /** * Adds count information to analysis results. */ -const addElementCounts = <T extends Node | Relationship>( +const addElementCounts = <T extends Vertex | Relationship>( rawElements: unknown[], counts: SchemaCountData, config: SchemaConfig, 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 96a6a59200..5bee436780 100644 --- a/gremlin-tools/gremlin-mcp/tests/integration/mcp-integration.test.ts +++ b/gremlin-tools/gremlin-mcp/tests/integration/mcp-integration.test.ts @@ -169,9 +169,9 @@ describe('MCP Server Integration Tests', () => { } expect(schema).toBeDefined(); - expect(schema.nodes).toBeDefined(); + expect(schema.vertices).toBeDefined(); expect(schema.relationships).toBeDefined(); - expect(Array.isArray(schema.nodes)).toBe(true); + expect(Array.isArray(schema.vertices)).toBe(true); expect(Array.isArray(schema.relationships)).toBe(true); // Verify relationship_patterns is present and adjacency_list is removed @@ -181,7 +181,7 @@ describe('MCP Server Integration Tests', () => { // Verify metadata structure if (schema.metadata) { - expect(schema.metadata.node_count).toBeGreaterThanOrEqual(0); + expect(schema.metadata.vertex_count).toBeGreaterThanOrEqual(0); expect(schema.metadata.relationship_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 4f9f545964..3ac4550526 100644 --- a/gremlin-tools/gremlin-mcp/tests/models.test.ts +++ b/gremlin-tools/gremlin-mcp/tests/models.test.ts @@ -24,7 +24,7 @@ import { PropertySchema, - NodeSchema, + VertexSchema, RelationshipSchema, GraphSchemaSchema, GremlinConfigSchema, @@ -55,9 +55,9 @@ describe('Models and Schemas', () => { }); }); - describe('NodeSchema', () => { - it('should validate a valid node', () => { - const validNode = { + describe('VertexSchema', () => { + it('should validate a valid vertex', () => { + const validVertex = { labels: 'person', properties: [ { @@ -69,7 +69,7 @@ describe('Models and Schemas', () => { count: 100, }; - expect(() => NodeSchema.parse(validNode)).not.toThrow(); + expect(() => VertexSchema.parse(validVertex)).not.toThrow(); }); }); @@ -88,7 +88,7 @@ describe('Models and Schemas', () => { describe('GraphSchemaSchema', () => { it('should validate a complete graph schema with relationship_patterns', () => { const validSchema = { - nodes: [ + vertices: [ { labels: 'person', properties: [ @@ -108,13 +108,13 @@ describe('Models and Schemas', () => { ], relationship_patterns: [ { - left_node: 'person', - right_node: 'person', + left_vertex: 'person', + right_vertex: 'person', relation: 'knows', }, ], metadata: { - node_count: 1, + vertex_count: 1, relationship_count: 1, pattern_count: 1, schema_size_bytes: 1024, @@ -177,7 +177,7 @@ describe('Models and Schemas', () => { describe('SchemaMetadataSchema', () => { it('should validate schema metadata', () => { const validMetadata = { - node_count: 10, + vertex_count: 10, relationship_count: 5, pattern_count: 8, schema_size_bytes: 2048, diff --git a/gremlin-tools/gremlin-mcp/tests/relationship-patterns.test.ts b/gremlin-tools/gremlin-mcp/tests/relationship-patterns.test.ts index 9b6b5742c4..eea75c892b 100644 --- a/gremlin-tools/gremlin-mcp/tests/relationship-patterns.test.ts +++ b/gremlin-tools/gremlin-mcp/tests/relationship-patterns.test.ts @@ -63,9 +63,9 @@ describe('relationship-patterns', () => { ]; const expectedPatterns: RelationshipPattern[] = [ - { left_node: 'person', right_node: 'company', relation: 'worksAt' }, - { left_node: 'person', right_node: 'person', relation: 'knows' }, - { left_node: 'company', right_node: 'project', relation: 'sponsors' }, + { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, + { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, + { left_vertex: 'company', right_vertex: 'project', relation: 'sponsors' }, ]; mockExecuteGremlinQuery.mockReturnValue(Effect.succeed(mockRawPatterns)); @@ -120,13 +120,13 @@ describe('relationship-patterns', () => { // Should filter out invalid patterns and process only valid ones expect(result).toHaveLength(2); // Only valid patterns processed expect(result[0]).toEqual({ - left_node: 'person', - right_node: 'company', + left_vertex: 'person', + right_vertex: 'company', relation: 'worksAt', }); expect(result[1]).toEqual({ - left_node: 'company', - right_node: 'project', + left_vertex: 'company', + right_vertex: 'project', relation: 'sponsors', }); }); @@ -156,15 +156,15 @@ describe('relationship-patterns', () => { expect(result).toHaveLength(5); // Verify self-referencing patterns - const selfReferencingPatterns = result.filter(p => p.left_node === p.right_node); + const selfReferencingPatterns = result.filter(p => p.left_vertex === p.right_vertex); expect(selfReferencingPatterns).toHaveLength(3); // Verify bidirectional potential const personToCompany = result.find( - p => p.left_node === 'person' && p.right_node === 'company' + p => p.left_vertex === 'person' && p.right_vertex === 'company' ); const companyToPerson = result.find( - p => p.left_node === 'company' && p.right_node === 'person' + p => p.left_vertex === 'company' && p.right_vertex === 'person' ); expect(personToCompany).toBeDefined(); expect(companyToPerson).toBeUndefined(); // Not in this dataset @@ -174,9 +174,9 @@ describe('relationship-patterns', () => { describe('analyzePatternStatistics', () => { it('should analyze basic pattern statistics', () => { const patterns: RelationshipPattern[] = [ - { left_node: 'person', right_node: 'company', relation: 'worksAt' }, - { left_node: 'person', right_node: 'person', relation: 'knows' }, - { left_node: 'company', right_node: 'project', relation: 'sponsors' }, + { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, + { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, + { left_vertex: 'company', right_vertex: 'project', relation: 'sponsors' }, ]; const stats = analyzePatternStatistics(patterns); @@ -204,10 +204,10 @@ describe('relationship-patterns', () => { it('should count connection frequencies correctly', () => { const patterns: RelationshipPattern[] = [ - { left_node: 'person', right_node: 'company', relation: 'worksAt' }, - { left_node: 'person', right_node: 'company', relation: 'contractsWith' }, - { left_node: 'person', right_node: 'person', relation: 'knows' }, - { left_node: 'company', right_node: 'project', relation: 'sponsors' }, + { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, + { left_vertex: 'person', right_vertex: 'company', relation: 'contractsWith' }, + { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, + { left_vertex: 'company', right_vertex: 'project', relation: 'sponsors' }, ]; const stats = analyzePatternStatistics(patterns); @@ -219,9 +219,9 @@ describe('relationship-patterns', () => { it('should handle duplicate patterns correctly', () => { const patterns: RelationshipPattern[] = [ - { left_node: 'person', right_node: 'company', relation: 'worksAt' }, - { left_node: 'person', right_node: 'company', relation: 'worksAt' }, // Duplicate - { left_node: 'person', right_node: 'company', relation: 'contractsWith' }, + { 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' }, ]; const stats = analyzePatternStatistics(patterns); @@ -234,12 +234,12 @@ describe('relationship-patterns', () => { it('should calculate averages correctly for complex patterns', () => { const patterns: RelationshipPattern[] = [ - { left_node: 'person', right_node: 'company', relation: 'worksAt' }, - { left_node: 'person', right_node: 'project', relation: 'owns' }, - { left_node: 'person', right_node: 'person', relation: 'knows' }, - { left_node: 'company', right_node: 'project', relation: 'sponsors' }, - { left_node: 'project', right_node: 'person', relation: 'managedBy' }, - { left_node: 'organization', right_node: 'person', relation: 'employs' }, + { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, + { left_vertex: 'person', right_vertex: 'project', relation: 'owns' }, + { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, + { left_vertex: 'company', right_vertex: 'project', relation: 'sponsors' }, + { left_vertex: 'project', right_vertex: 'person', relation: 'managedBy' }, + { left_vertex: 'organization', right_vertex: 'person', relation: 'employs' }, ]; const stats = analyzePatternStatistics(patterns); @@ -252,9 +252,9 @@ describe('relationship-patterns', () => { it('should sort vertex and edge types alphabetically', () => { const patterns: RelationshipPattern[] = [ - { left_node: 'zebra', right_node: 'apple', relation: 'eats' }, - { left_node: 'banana', right_node: 'cherry', relation: 'grows' }, - { left_node: 'apple', right_node: 'banana', relation: 'becomes' }, + { left_vertex: 'zebra', right_vertex: 'apple', relation: 'eats' }, + { left_vertex: 'banana', right_vertex: 'cherry', relation: 'grows' }, + { left_vertex: 'apple', right_vertex: 'banana', relation: 'becomes' }, ]; const stats = analyzePatternStatistics(patterns); diff --git a/gremlin-tools/gremlin-mcp/tests/schema-assembly.test.ts b/gremlin-tools/gremlin-mcp/tests/schema-assembly.test.ts index 85e0e1649c..1fb06b0147 100644 --- a/gremlin-tools/gremlin-mcp/tests/schema-assembly.test.ts +++ b/gremlin-tools/gremlin-mcp/tests/schema-assembly.test.ts @@ -29,12 +29,12 @@ import { Effect } from 'effect'; import { describe, it, expect, beforeEach, jest } from '@jest/globals'; import { assembleGraphSchema, - validateNodes, + validateVertices, validateRelationships, validateRelationshipPatterns, validateAllComponents, } from '../src/gremlin/schema-assembly.js'; -import type { Node, Relationship, RelationshipPattern } from '../src/gremlin/models.js'; +import type { Vertex, Relationship, RelationshipPattern } from '../src/gremlin/models.js'; import type { SchemaConfig } from '../src/gremlin/types.js'; describe('schema-assembly', () => { @@ -48,7 +48,7 @@ describe('schema-assembly', () => { batchSize: 10, }; - const sampleNodes: Node[] = [ + const sampleVertices: Vertex[] = [ { labels: 'person', properties: [ @@ -80,8 +80,8 @@ describe('schema-assembly', () => { ]; const samplePatterns: RelationshipPattern[] = [ - { left_node: 'person', right_node: 'company', relation: 'worksAt' }, - { left_node: 'person', right_node: 'person', relation: 'knows' }, + { left_vertex: 'person', right_vertex: 'company', relation: 'worksAt' }, + { left_vertex: 'person', right_vertex: 'person', relation: 'knows' }, ]; beforeEach(() => { @@ -93,17 +93,17 @@ describe('schema-assembly', () => { const startTime = Date.now(); const result = await Effect.runPromise( - assembleGraphSchema(sampleNodes, sampleRelationships, samplePatterns, mockConfig, startTime) + assembleGraphSchema(sampleVertices, sampleRelationships, samplePatterns, mockConfig, startTime) ); // Verify schema structure - expect(result.nodes).toEqual(sampleNodes); + expect(result.vertices).toEqual(sampleVertices); expect(result.relationships).toEqual(sampleRelationships); expect(result.relationship_patterns).toEqual(samplePatterns); // Verify metadata expect(result.metadata).toBeDefined(); - expect(result.metadata!.node_count).toBe(2); + expect(result.metadata!.vertex_count).toBe(2); expect(result.metadata!.relationship_count).toBe(2); expect(result.metadata!.pattern_count).toBe(2); expect(result.metadata!.generated_at).toBeDefined(); @@ -127,10 +127,10 @@ describe('schema-assembly', () => { assembleGraphSchema([], [], [], mockConfig, startTime) ); - expect(result.nodes).toEqual([]); + expect(result.vertices).toEqual([]); expect(result.relationships).toEqual([]); expect(result.relationship_patterns).toEqual([]); - expect(result.metadata!.node_count).toBe(0); + expect(result.metadata!.vertex_count).toBe(0); expect(result.metadata!.relationship_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(sampleNodes, sampleRelationships, samplePatterns, mockConfig, startTime) + assembleGraphSchema(sampleVertices, sampleRelationships, samplePatterns, mockConfig, startTime) ); expect(result.metadata!.generation_time_ms).toBeGreaterThanOrEqual(1000); @@ -147,7 +147,7 @@ describe('schema-assembly', () => { }); it('should handle schema validation failures', async () => { - const invalidNodes: Node[] = [ + const invalidVertices: Vertex[] = [ { labels: '', // Invalid empty label - but this might pass basic assembly properties: [], @@ -156,7 +156,7 @@ describe('schema-assembly', () => { const result = await Effect.runPromiseExit( assembleGraphSchema( - invalidNodes, + invalidVertices, sampleRelationships, samplePatterns, mockConfig, @@ -171,54 +171,54 @@ describe('schema-assembly', () => { }); }); - describe('validateNodes', () => { - it('should validate correct nodes successfully', async () => { - const result = await Effect.runPromise(validateNodes(sampleNodes)); + describe('validateVertices', () => { + it('should validate correct vertices successfully', async () => { + const result = await Effect.runPromise(validateVertices(sampleVertices)); expect(result).toBeUndefined(); // Void return on success }); it('should detect missing labels', async () => { - const invalidNodes: Node[] = [ + const invalidVertices: Vertex[] = [ { labels: '', // Invalid empty label properties: [{ name: 'test', type: ['string'] }], }, ]; - const result = await Effect.runPromiseExit(validateNodes(invalidNodes)); + const result = await Effect.runPromiseExit(validateVertices(invalidVertices)); expect(result._tag).toBe('Failure'); }); it('should detect invalid labels type', async () => { - const invalidNodes: Node[] = [ + const invalidVertices: Vertex[] = [ { labels: null as any, // Invalid null label properties: [], }, ]; - const result = await Effect.runPromiseExit(validateNodes(invalidNodes)); + const result = await Effect.runPromiseExit(validateVertices(invalidVertices)); expect(result._tag).toBe('Failure'); }); it('should detect missing properties', async () => { - const invalidNodes: Node[] = [ + const invalidVertices: Vertex[] = [ { labels: 'person', properties: undefined as any, // Missing properties }, ]; - const result = await Effect.runPromiseExit(validateNodes(invalidNodes)); + const result = await Effect.runPromiseExit(validateVertices(invalidVertices)); expect(result._tag).toBe('Failure'); }); it('should detect invalid property structure', async () => { - const invalidNodes: Node[] = [ + const invalidVertices: Vertex[] = [ { labels: 'person', properties: [ @@ -228,7 +228,7 @@ describe('schema-assembly', () => { }, ]; - const result = await Effect.runPromiseExit(validateNodes(invalidNodes)); + const result = await Effect.runPromiseExit(validateVertices(invalidVertices)); expect(result._tag).toBe('Failure'); }); @@ -293,18 +293,18 @@ describe('schema-assembly', () => { it('should detect missing pattern fields', async () => { const invalidPatterns: RelationshipPattern[] = [ { - left_node: '', // Empty left node - right_node: 'company', + left_vertex: '', // Empty left vertex + right_vertex: 'company', relation: 'worksAt', }, { - left_node: 'person', - right_node: '', // Empty right node + left_vertex: 'person', + right_vertex: '', // Empty right vertex relation: 'knows', }, { - left_node: 'person', - right_node: 'company', + left_vertex: 'person', + right_vertex: 'company', relation: '', // Empty relation }, ]; @@ -317,8 +317,8 @@ describe('schema-assembly', () => { it('should detect invalid pattern field types', async () => { const invalidPatterns: RelationshipPattern[] = [ { - left_node: null as any, // Invalid type - right_node: 'company', + left_vertex: null as any, // Invalid type + right_vertex: 'company', relation: 'worksAt', }, ]; @@ -332,14 +332,14 @@ describe('schema-assembly', () => { describe('validateAllComponents', () => { it('should validate all components successfully', async () => { const result = await Effect.runPromise( - validateAllComponents(sampleNodes, sampleRelationships, samplePatterns) + validateAllComponents(sampleVertices, sampleRelationships, samplePatterns) ); expect(result).toBeUndefined(); // Void return on success }); it('should detect any invalid component', async () => { - const invalidNodes: Node[] = [ + const invalidVertices: Vertex[] = [ { labels: '', // Invalid properties: [], @@ -347,14 +347,14 @@ describe('schema-assembly', () => { ]; const result = await Effect.runPromiseExit( - validateAllComponents(invalidNodes, sampleRelationships, samplePatterns) + validateAllComponents(invalidVertices, sampleRelationships, samplePatterns) ); expect(result._tag).toBe('Failure'); }); it('should validate each component type independently', async () => { - // Test with valid nodes but invalid relationships + // Test with valid vertices but invalid relationships const invalidRelationships: Relationship[] = [ { type: '', // Invalid @@ -363,7 +363,7 @@ describe('schema-assembly', () => { ]; const result = await Effect.runPromiseExit( - validateAllComponents(sampleNodes, invalidRelationships, samplePatterns) + validateAllComponents(sampleVertices, invalidRelationships, samplePatterns) ); expect(result._tag).toBe('Failure'); @@ -375,7 +375,7 @@ describe('schema-assembly', () => { const startTime = Date.now() - 500; const result = await Effect.runPromise( - assembleGraphSchema(sampleNodes, sampleRelationships, samplePatterns, mockConfig, startTime) + assembleGraphSchema(sampleVertices, sampleRelationships, samplePatterns, mockConfig, startTime) ); const metadata = result.metadata!; @@ -383,7 +383,7 @@ describe('schema-assembly', () => { // Check required fields 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.node_count).toBe(sampleNodes.length); + expect(metadata.vertex_count).toBe(sampleVertices.length); expect(metadata.relationship_count).toBe(sampleRelationships.length); expect(metadata.pattern_count).toBe(samplePatterns.length); @@ -409,7 +409,7 @@ describe('schema-assembly', () => { const result = await Effect.runPromise( assembleGraphSchema( - sampleNodes, + sampleVertices, sampleRelationships, samplePatterns, minimalConfig,
