d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
796 lines
28 KiB
TypeScript
796 lines
28 KiB
TypeScript
import { getErrorMessage } from '@sim/utils/errors'
|
|
import { Neo4jIcon } from '@/components/icons'
|
|
import type { BlockConfig, BlockMeta } from '@/blocks/types'
|
|
import { IntegrationType } from '@/blocks/types'
|
|
import type { Neo4jIntrospectResponse, Neo4jResponse } from '@/tools/neo4j/types'
|
|
|
|
export const Neo4jBlock: BlockConfig<Neo4jResponse | Neo4jIntrospectResponse> = {
|
|
type: 'neo4j',
|
|
name: 'Neo4j',
|
|
description: 'Connect to Neo4j graph database',
|
|
longDescription:
|
|
'Integrate Neo4j graph database into the workflow. Can query, create, merge, update, and delete nodes and relationships.',
|
|
docsLink: 'https://docs.sim.ai/integrations/neo4j',
|
|
category: 'tools',
|
|
integrationType: IntegrationType.Databases,
|
|
bgColor: '#FFFFFF',
|
|
icon: Neo4jIcon,
|
|
subBlocks: [
|
|
{
|
|
id: 'operation',
|
|
title: 'Operation',
|
|
type: 'dropdown',
|
|
options: [
|
|
{ label: 'Query (MATCH)', id: 'query' },
|
|
{ label: 'Create Nodes/Relationships', id: 'create' },
|
|
{ label: 'Merge (Find or Create)', id: 'merge' },
|
|
{ label: 'Update Properties (SET)', id: 'update' },
|
|
{ label: 'Delete Nodes/Relationships', id: 'delete' },
|
|
{ label: 'Execute Cypher', id: 'execute' },
|
|
{ label: 'Introspect Schema', id: 'introspect' },
|
|
],
|
|
value: () => 'query',
|
|
},
|
|
{
|
|
id: 'host',
|
|
title: 'Host',
|
|
type: 'short-input',
|
|
placeholder: 'localhost or your.neo4j.host',
|
|
required: true,
|
|
password: true,
|
|
},
|
|
{
|
|
id: 'port',
|
|
title: 'Port',
|
|
type: 'short-input',
|
|
placeholder: '7687',
|
|
value: () => '7687',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'database',
|
|
title: 'Database Name',
|
|
type: 'short-input',
|
|
placeholder: 'neo4j',
|
|
value: () => 'neo4j',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'username',
|
|
title: 'Username',
|
|
type: 'short-input',
|
|
placeholder: 'neo4j',
|
|
value: () => 'neo4j',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'password',
|
|
title: 'Password',
|
|
type: 'short-input',
|
|
password: true,
|
|
placeholder: 'Your database password',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'encryption',
|
|
title: 'Encryption',
|
|
type: 'dropdown',
|
|
options: [
|
|
{ label: 'Disabled', id: 'disabled' },
|
|
{ label: 'Enabled (TLS/SSL)', id: 'enabled' },
|
|
],
|
|
value: () => 'disabled',
|
|
},
|
|
{
|
|
id: 'cypherQuery',
|
|
title: 'Cypher Query',
|
|
type: 'code',
|
|
placeholder: 'MATCH (n:Person) WHERE n.age > 21 RETURN n LIMIT 10',
|
|
required: true,
|
|
condition: { field: 'operation', value: 'query' },
|
|
wandConfig: {
|
|
enabled: true,
|
|
maintainHistory: true,
|
|
prompt: `You are an expert Neo4j and Cypher developer. Generate Cypher queries based on the user's request.
|
|
|
|
### CONTEXT
|
|
{context}
|
|
|
|
### CRITICAL INSTRUCTION
|
|
Return ONLY the Cypher query. Do not include any explanations, markdown formatting, comments, or additional text. Just the raw Cypher query.
|
|
|
|
### QUERY GUIDELINES
|
|
1. **Pattern Matching**: Use MATCH to find patterns in the graph
|
|
2. **Filtering**: Use WHERE clauses for conditions
|
|
3. **Return**: Specify what to return with RETURN
|
|
4. **Performance**: Use indexes when possible
|
|
5. **Limit Results**: ALWAYS include LIMIT to prevent large result sets
|
|
|
|
### IMPORTANT: LIMIT Best Practices
|
|
- Always include LIMIT in your queries to prevent performance issues
|
|
- Use parameterized LIMIT for flexibility: LIMIT $limit
|
|
- Place LIMIT at the end after ORDER BY and SKIP clauses
|
|
- Example: MATCH (n:Person) RETURN n ORDER BY n.name LIMIT $limit
|
|
|
|
### CYPHER QUERY PATTERNS
|
|
|
|
**Basic Node Match with LIMIT**:
|
|
MATCH (n:Person) RETURN n LIMIT 25
|
|
|
|
**Match with Parameterized LIMIT (Recommended)**:
|
|
MATCH (n:Person) RETURN n LIMIT $limit
|
|
|
|
**Match with Properties**:
|
|
MATCH (n:Person {name: "Alice"}) RETURN n
|
|
|
|
**Match with Parameters (Recommended)**:
|
|
MATCH (n:Person {name: $name}) RETURN n LIMIT 100
|
|
|
|
**Match with WHERE and Parameters**:
|
|
MATCH (n:Person) WHERE n.age > $minAge RETURN n.name, n.age LIMIT $limit
|
|
|
|
**Match Relationship**:
|
|
MATCH (p:Person)-[:KNOWS]->(friend:Person) RETURN p.name, friend.name
|
|
|
|
**Match with Relationship Properties**:
|
|
MATCH (p:Person)-[r:RATED {rating: 5}]->(m:Movie) RETURN p.name, m.title
|
|
|
|
**Pattern with Multiple Nodes**:
|
|
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(d:Person) RETURN p.name, m.title, d.name
|
|
|
|
**Variable Length Paths**:
|
|
MATCH (p1:Person)-[:KNOWS*1..3]-(p2:Person) WHERE p1.name = $name RETURN p2.name
|
|
|
|
**Shortest Path**:
|
|
MATCH path = shortestPath((p1:Person)-[:KNOWS*]-(p2:Person)) WHERE p1.name = $name1 AND p2.name = $name2 RETURN path
|
|
|
|
**Complex WHERE with Parameters**:
|
|
MATCH (p:Person) WHERE p.age > $minAge AND p.age < $maxAge AND p.country = $country RETURN p
|
|
|
|
### EXAMPLES
|
|
|
|
**Find all nodes**: MATCH (n:Person) RETURN n LIMIT 10
|
|
**Find by property**: MATCH (n:Person) WHERE n.name = "Alice" RETURN n
|
|
**Find with parameters**: MATCH (n:Person) WHERE n.name = $name AND n.age > $minAge RETURN n
|
|
**Find relationships**: MATCH (p:Person)-[r:KNOWS]->(f:Person) RETURN p.name, type(r), f.name
|
|
**Find with multiple labels**: MATCH (n:Person:Employee) RETURN n
|
|
**Aggregate data**: MATCH (p:Person) RETURN p.country, count(p) as personCount ORDER BY personCount DESC
|
|
**Range query with params**: MATCH (p:Product) WHERE p.price >= $minPrice AND p.price <= $maxPrice RETURN p
|
|
|
|
### NOTE
|
|
Use the Parameters field for dynamic values to improve security and query performance.
|
|
|
|
Return ONLY the Cypher query - no explanations.`,
|
|
placeholder: 'Describe what you want to query...',
|
|
generationType: 'neo4j-cypher',
|
|
},
|
|
},
|
|
{
|
|
id: 'cypherQuery',
|
|
title: 'Cypher CREATE Statement',
|
|
type: 'code',
|
|
placeholder: 'CREATE (n:Person {name: "Alice", age: 30})',
|
|
required: true,
|
|
condition: { field: 'operation', value: 'create' },
|
|
wandConfig: {
|
|
enabled: true,
|
|
maintainHistory: true,
|
|
prompt: `You are an expert Neo4j developer. Generate Cypher CREATE statements to add new nodes and relationships.
|
|
|
|
### CONTEXT
|
|
{context}
|
|
|
|
### CRITICAL INSTRUCTION
|
|
Return ONLY the Cypher CREATE statement. No explanations, no markdown, just the raw Cypher query.
|
|
|
|
### ⚠️ DUPLICATE WARNING
|
|
CREATE always creates new nodes/relationships, even if identical ones exist.
|
|
- Use MERGE operation if you want to avoid duplicates (find-or-create behavior)
|
|
- Use CREATE only when you want to guarantee new entities
|
|
|
|
### CREATE PATTERNS
|
|
|
|
**Create Single Node**:
|
|
CREATE (n:Person {name: "Alice", age: 30, email: "alice@example.com"})
|
|
|
|
**Create with Parameters (Recommended)**:
|
|
CREATE (n:Person {name: $name, age: $age, email: $email}) RETURN n
|
|
|
|
**Create Multiple Nodes**:
|
|
CREATE (n1:Person {name: "Alice"}), (n2:Person {name: "Bob"})
|
|
|
|
**Create Node with Relationship**:
|
|
CREATE (p:Person {name: "Alice"})-[:KNOWS {since: 2020}]->(f:Person {name: "Bob"})
|
|
|
|
**Create Relationship Between Existing Nodes**:
|
|
MATCH (a:Person {name: "Alice"}), (b:Person {name: "Bob"})
|
|
CREATE (a)-[:KNOWS {since: 2024}]->(b)
|
|
|
|
**Create with Parameters and Return**:
|
|
CREATE (n:Person {name: $name, age: $age}) RETURN n
|
|
|
|
**Batch Create with Parameters**:
|
|
UNWIND $users AS user
|
|
CREATE (n:Person {name: user.name, email: user.email})
|
|
|
|
### EXAMPLES
|
|
Create person: CREATE (n:Person {name: "Alice", age: 30})
|
|
Create with params: CREATE (n:Person {name: $name, age: $age}) RETURN n
|
|
Create with relationship: CREATE (p:Person {name: "Alice"})-[:WORKS_AT]->(c:Company {name: "Acme"})
|
|
Create multiple: CREATE (a:Person {name: "Alice"}), (b:Person {name: "Bob"}), (a)-[:KNOWS]->(b)
|
|
Batch create: UNWIND $items AS item CREATE (n:Product {name: item.name, price: item.price})
|
|
|
|
### NOTE
|
|
Use the Parameters field with CREATE for dynamic values and security.
|
|
|
|
Return ONLY the Cypher CREATE statement.`,
|
|
placeholder: 'Describe what you want to create...',
|
|
generationType: 'neo4j-cypher',
|
|
},
|
|
},
|
|
{
|
|
id: 'cypherQuery',
|
|
title: 'Cypher MERGE Statement',
|
|
type: 'code',
|
|
placeholder:
|
|
'MERGE (n:Person {email: "alice@example.com"}) ON CREATE SET n.created = timestamp() RETURN n',
|
|
required: true,
|
|
condition: { field: 'operation', value: 'merge' },
|
|
wandConfig: {
|
|
enabled: true,
|
|
maintainHistory: true,
|
|
prompt: `You are an expert Neo4j developer. Generate Cypher MERGE statements for find-or-create operations.
|
|
|
|
### CONTEXT
|
|
{context}
|
|
|
|
### CRITICAL INSTRUCTION
|
|
Return ONLY the Cypher MERGE statement. No explanations, no markdown, just the raw Cypher query.
|
|
|
|
### MERGE PATTERNS
|
|
|
|
**Basic Merge**:
|
|
MERGE (n:Person {email: "alice@example.com"})
|
|
|
|
**Merge with ON CREATE**:
|
|
MERGE (n:Person {email: "alice@example.com"})
|
|
ON CREATE SET n.created = timestamp(), n.name = "Alice"
|
|
|
|
**Merge with ON MATCH**:
|
|
MERGE (n:Person {email: "alice@example.com"})
|
|
ON MATCH SET n.lastSeen = timestamp()
|
|
|
|
**Merge with Both**:
|
|
MERGE (n:Person {email: "alice@example.com"})
|
|
ON CREATE SET n.created = timestamp(), n.name = "Alice"
|
|
ON MATCH SET n.lastSeen = timestamp()
|
|
|
|
**Merge Relationship**:
|
|
MATCH (p:Person {name: "Alice"}), (c:Company {name: "Acme"})
|
|
MERGE (p)-[:WORKS_AT {since: 2024}]->(c)
|
|
|
|
### EXAMPLES
|
|
Merge person: MERGE (n:Person {email: "alice@example.com"}) ON CREATE SET n.created = timestamp()
|
|
Merge relationship: MERGE (p:Person {name: "Alice"})-[:KNOWS]->(f:Person {name: "Bob"})
|
|
|
|
Return ONLY the Cypher MERGE statement.`,
|
|
placeholder: 'Describe what you want to merge...',
|
|
generationType: 'neo4j-cypher',
|
|
},
|
|
},
|
|
{
|
|
id: 'cypherQuery',
|
|
title: 'Cypher UPDATE Statement',
|
|
type: 'code',
|
|
placeholder: 'MATCH (n:Person {name: "Alice"}) SET n.age = 31, n.updated = timestamp()',
|
|
required: true,
|
|
condition: { field: 'operation', value: 'update' },
|
|
wandConfig: {
|
|
enabled: true,
|
|
maintainHistory: true,
|
|
prompt: `You are an expert Neo4j developer. Generate Cypher UPDATE statements using MATCH and SET.
|
|
|
|
### CONTEXT
|
|
{context}
|
|
|
|
### CRITICAL INSTRUCTION
|
|
Return ONLY the Cypher statement with MATCH and SET. No explanations, no markdown, just the raw Cypher query.
|
|
|
|
### UPDATE PATTERNS
|
|
|
|
**Update Single Property**:
|
|
MATCH (n:Person {name: "Alice"}) SET n.age = 31
|
|
|
|
**Update Multiple Properties**:
|
|
MATCH (n:Person {name: "Alice"}) SET n.age = 31, n.city = "NYC", n.updated = timestamp()
|
|
|
|
**Update with WHERE**:
|
|
MATCH (n:Person) WHERE n.age > 30 SET n.category = "senior"
|
|
|
|
**Update with Parameters**:
|
|
MATCH (n:Person {name: $name}) SET n.age = $age, n.city = $city
|
|
|
|
**Merge Properties (Safe)**:
|
|
MATCH (n:Person {name: "Alice"}) SET n += {age: 31, email: "alice@example.com"}
|
|
|
|
**⚠️ DANGEROUS - Replace All Properties (removes unlisted properties)**:
|
|
MATCH (n:Person {name: "Alice"}) SET n = {name: "Alice", age: 31}
|
|
Note: This removes ALL properties not specified. Use SET n += {...} instead to merge properties safely.
|
|
|
|
**Add Property**:
|
|
MATCH (n:Person {name: "Alice"}) SET n.verified = true
|
|
|
|
**Remove Property**:
|
|
MATCH (n:Person {name: "Alice"}) REMOVE n.temporaryField
|
|
|
|
**Add Label**:
|
|
MATCH (n:Person {name: "Alice"}) SET n:Employee
|
|
|
|
**Increment Counter**:
|
|
MATCH (n:Person {name: "Alice"}) SET n.loginCount = n.loginCount + 1
|
|
|
|
### EXAMPLES
|
|
Update age: MATCH (n:Person {name: "Alice"}) SET n.age = 31
|
|
Update multiple: MATCH (n:Person) WHERE n.city = "NYC" SET n.verified = true, n.updated = timestamp()
|
|
With parameters: MATCH (n:Person) WHERE n.email = $email SET n.lastLogin = timestamp()
|
|
Merge properties safely: MATCH (n:Person {id: $userId}) SET n += {status: "active", verified: true}
|
|
|
|
### SAFETY NOTE
|
|
Use SET n += {...} to merge properties safely. Avoid SET n = {...} unless you explicitly want to replace ALL properties.
|
|
|
|
Return ONLY the Cypher update statement.`,
|
|
placeholder: 'Describe what you want to update...',
|
|
generationType: 'neo4j-cypher',
|
|
},
|
|
},
|
|
{
|
|
id: 'cypherQuery',
|
|
title: 'Cypher DELETE Statement',
|
|
type: 'code',
|
|
placeholder: 'MATCH (n:Person {name: "Alice"}) DETACH DELETE n',
|
|
required: true,
|
|
condition: { field: 'operation', value: 'delete' },
|
|
wandConfig: {
|
|
enabled: true,
|
|
maintainHistory: true,
|
|
prompt: `You are an expert Neo4j developer. Generate Cypher DELETE statements to remove nodes and relationships.
|
|
|
|
### CONTEXT
|
|
{context}
|
|
|
|
### CRITICAL INSTRUCTION
|
|
Return ONLY the Cypher DELETE statement. No explanations, no markdown, just the raw Cypher query.
|
|
|
|
### ⚠️ DELETION WARNING ⚠️
|
|
DELETIONS ARE PERMANENT! Be extremely careful and specific with your criteria.
|
|
|
|
### DELETE PATTERNS
|
|
|
|
**Delete Node (must have no relationships)**:
|
|
MATCH (n:Person {name: "Alice"}) DELETE n
|
|
|
|
**DETACH DELETE (removes relationships first)**:
|
|
MATCH (n:Person {name: "Alice"}) DETACH DELETE n
|
|
|
|
**Delete Relationship Only**:
|
|
MATCH (p:Person {name: "Alice"})-[r:KNOWS]->(f:Person) DELETE r
|
|
|
|
**Delete with WHERE**:
|
|
MATCH (n:Person) WHERE n.status = "inactive" DETACH DELETE n
|
|
|
|
**Delete Multiple Nodes**:
|
|
MATCH (n:TempNode) WHERE n.created < timestamp() - 86400000 DETACH DELETE n
|
|
|
|
### SAFETY
|
|
- Always use DETACH DELETE for nodes with relationships
|
|
- Use specific WHERE clauses to target exact nodes
|
|
- Test with MATCH first to see what will be deleted
|
|
- Prefer unique identifiers when deleting
|
|
|
|
### EXAMPLES
|
|
Delete person: MATCH (n:Person {email: "alice@example.com"}) DETACH DELETE n
|
|
Delete relationship: MATCH (p:Person)-[r:KNOWS]->(f:Person) WHERE p.name = "Alice" DELETE r
|
|
Delete old data: MATCH (n:TempData) WHERE n.created < timestamp() - 2592000000 DETACH DELETE n
|
|
|
|
Return ONLY the Cypher DELETE statement.`,
|
|
placeholder: 'Describe what you want to delete...',
|
|
generationType: 'neo4j-cypher',
|
|
},
|
|
},
|
|
{
|
|
id: 'cypherQuery',
|
|
title: 'Cypher Query',
|
|
type: 'code',
|
|
placeholder: 'MATCH (n:Person) RETURN n LIMIT 10',
|
|
required: true,
|
|
condition: { field: 'operation', value: 'execute' },
|
|
wandConfig: {
|
|
enabled: true,
|
|
maintainHistory: true,
|
|
prompt: `You are an expert Neo4j developer. Generate any Cypher query based on the user's request.
|
|
|
|
### CONTEXT
|
|
{context}
|
|
|
|
### CRITICAL INSTRUCTION
|
|
Return ONLY the Cypher query. No explanations, no markdown, just the raw Cypher query.
|
|
|
|
### ADVANCED PATTERNS
|
|
|
|
**Aggregation**:
|
|
MATCH (p:Person) RETURN p.country, count(p) as total ORDER BY total DESC
|
|
|
|
**Aggregation with COLLECT**:
|
|
MATCH (p:Person)-[:WORKS_AT]->(c:Company) RETURN c.name, collect(p.name) as employees
|
|
|
|
**Complex Relationships**:
|
|
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(d:Person) RETURN p.name, m.title, d.name
|
|
|
|
**WITH Clause for Chaining**:
|
|
MATCH (p:Person) WITH p ORDER BY p.age DESC LIMIT 10 MATCH (p)-[:KNOWS]->(friend) RETURN p.name, collect(friend.name) as friends
|
|
|
|
**Conditional Logic (CASE)**:
|
|
MATCH (p:Person) RETURN p.name, CASE WHEN p.age < 18 THEN 'minor' WHEN p.age < 65 THEN 'adult' ELSE 'senior' END as ageGroup
|
|
|
|
**Subqueries with EXISTS**:
|
|
MATCH (p:Person) WHERE EXISTS { MATCH (p)-[:KNOWS]->(:Person)-[:KNOWS]->(:Person) } RETURN p
|
|
|
|
**Subqueries with CALL**:
|
|
MATCH (p:Person) CALL { WITH p MATCH (p)-[:KNOWS]->(friend) RETURN count(friend) as friendCount } RETURN p.name, friendCount
|
|
|
|
**UNION (Combine Results)**:
|
|
MATCH (p:Person) WHERE p.age > 30 RETURN p.name, p.age UNION MATCH (p:Person) WHERE p.country = "USA" RETURN p.name, p.age
|
|
|
|
**FOREACH for Batch Updates**:
|
|
MATCH (p:Person) WHERE p.status = 'pending' FOREACH (x IN CASE WHEN p.age > 18 THEN [1] ELSE [] END | SET p.verified = true)
|
|
|
|
**Path Patterns**:
|
|
MATCH path = (p1:Person)-[:KNOWS*1..3]-(p2:Person) WHERE p1.name = "Alice" RETURN path, length(path)
|
|
|
|
**Transaction Batching** (5.x+):
|
|
CALL { MATCH (p:Person) WHERE p.status = 'inactive' DETACH DELETE p } IN TRANSACTIONS OF 100 ROWS
|
|
|
|
**Optional Match**:
|
|
MATCH (p:Person) OPTIONAL MATCH (p)-[:MANAGES]->(e:Person) RETURN p.name, collect(e.name) as employees
|
|
|
|
**Map Projections**:
|
|
MATCH (p:Person) RETURN p { .name, .age, friendCount: size((p)-[:KNOWS]->()) }
|
|
|
|
**Parameters in Advanced Query**:
|
|
MATCH (p:Person) WHERE p.age > $minAge WITH p ORDER BY p.age DESC LIMIT $limit MATCH (p)-[:KNOWS]->(friend) RETURN p.name, collect(friend.name) as friends
|
|
|
|
**Pattern Comprehension**:
|
|
MATCH (p:Person) RETURN p.name, [(p)-[:KNOWS]->(friend) WHERE friend.age > 25 | friend.name] as adultFriends
|
|
|
|
Return ONLY the Cypher query.`,
|
|
placeholder: 'Describe your query...',
|
|
generationType: 'neo4j-cypher',
|
|
},
|
|
},
|
|
{
|
|
id: 'parameters',
|
|
title: 'Parameters',
|
|
type: 'code',
|
|
placeholder: '{"name": "Alice", "minAge": 21}',
|
|
wandConfig: {
|
|
enabled: true,
|
|
maintainHistory: true,
|
|
prompt: `Generate JSON parameters for Cypher queries. Parameters are essential for security, performance, and reusability.
|
|
|
|
### CONTEXT
|
|
{context}
|
|
|
|
### CRITICAL INSTRUCTION
|
|
Return ONLY a valid JSON object with parameter values. No explanations, no markdown, just the raw JSON object.
|
|
|
|
### WHY USE PARAMETERS?
|
|
|
|
**Security Benefits:**
|
|
- Prevents Cypher injection attacks
|
|
- Safely handles user input
|
|
- Separates data from query logic
|
|
- No need to escape special characters
|
|
|
|
**Performance Benefits:**
|
|
- Neo4j caches query execution plans
|
|
- Same query structure with different parameters reuses cached plan
|
|
- Significantly faster for repeated queries
|
|
|
|
**Code Quality:**
|
|
- Cleaner, more readable queries
|
|
- Easier to test and maintain
|
|
- Reusable query templates
|
|
|
|
### PARAMETER SYNTAX IN QUERIES
|
|
|
|
In Cypher queries, parameters are prefixed with $ and referenced by name:
|
|
|
|
MATCH (n:Person {name: $name}) WHERE n.age > $minAge RETURN n
|
|
MATCH (p)-[r:KNOWS {since: $year}]->(f) RETURN p, f
|
|
CREATE (n:Person {name: $name, email: $email, age: $age})
|
|
MERGE (n:User {id: $userId}) ON CREATE SET n.created = $timestamp
|
|
|
|
### DATA TYPES
|
|
|
|
**Strings**:
|
|
{"name": "Alice", "email": "alice@example.com", "status": "active"}
|
|
|
|
**Numbers** (integers and floats):
|
|
{"age": 30, "score": 95.5, "count": 1000, "rating": 4.8}
|
|
|
|
**Booleans**:
|
|
{"isActive": true, "verified": false, "premium": true}
|
|
|
|
**Arrays**:
|
|
{"tags": ["neo4j", "database", "graph"], "statuses": ["active", "pending"], "scores": [85, 90, 95]}
|
|
|
|
**Null**:
|
|
{"middleName": null, "company": null}
|
|
|
|
**Mixed Types**:
|
|
{"name": "Alice", "age": 30, "active": true, "tags": ["user", "premium"], "balance": 150.50}
|
|
|
|
### QUERY + PARAMETERS EXAMPLES
|
|
|
|
**Example 1: Simple Property Match**
|
|
Query: MATCH (n:Person {email: $email}) RETURN n
|
|
Parameters: {"email": "alice@example.com"}
|
|
|
|
**Example 2: Range Filter**
|
|
Query: MATCH (n:Person) WHERE n.age >= $minAge AND n.age <= $maxAge RETURN n
|
|
Parameters: {"minAge": 21, "maxAge": 65}
|
|
|
|
**Example 3: Array Membership**
|
|
Query: MATCH (n:Person) WHERE n.status IN $statuses RETURN n
|
|
Parameters: {"statuses": ["active", "pending", "verified"]}
|
|
|
|
**Example 4: Create with Parameters**
|
|
Query: CREATE (n:Person {name: $name, email: $email, age: $age, created: $timestamp})
|
|
Parameters: {"name": "Bob", "email": "bob@example.com", "age": 28, "timestamp": 1704067200000}
|
|
|
|
**Example 5: Update with Parameters**
|
|
Query: MATCH (n:Person {id: $userId}) SET n.lastLogin = $loginTime, n.loginCount = n.loginCount + 1
|
|
Parameters: {"userId": "user123", "loginTime": 1704067200000}
|
|
|
|
**Example 6: Relationship with Parameters**
|
|
Query: MATCH (a:Person {id: $fromId}), (b:Person {id: $toId}) CREATE (a)-[:KNOWS {since: $year}]->(b)
|
|
Parameters: {"fromId": "user1", "toId": "user2", "year": 2024}
|
|
|
|
### LIMITATIONS
|
|
|
|
**Cannot be Parameterized:**
|
|
- Label names: Cannot use $labelName
|
|
- Relationship types: Cannot use $relType
|
|
- Property keys: Cannot use $propertyKey
|
|
- Keywords: Cannot parameterize MATCH, CREATE, etc.
|
|
|
|
**Can be Parameterized:**
|
|
- Property values ✓
|
|
- Numeric constants ✓
|
|
- String literals ✓
|
|
- Arrays and lists ✓
|
|
- WHERE clause conditions ✓
|
|
|
|
### BEST PRACTICES
|
|
|
|
1. **Always use parameters for user input** - Never concatenate user data into queries
|
|
2. **Use descriptive names** - $userId instead of $id, $minAge instead of $min
|
|
3. **Type appropriately** - Use numbers for numeric values, not strings
|
|
4. **Validate before passing** - Ensure data types match expected values
|
|
5. **Reuse parameter names** - Same parameters work across similar queries for plan caching
|
|
|
|
Return ONLY valid JSON.`,
|
|
placeholder: 'Describe the parameter values...',
|
|
generationType: 'neo4j-parameters',
|
|
},
|
|
},
|
|
],
|
|
tools: {
|
|
access: [
|
|
'neo4j_query',
|
|
'neo4j_create',
|
|
'neo4j_merge',
|
|
'neo4j_update',
|
|
'neo4j_delete',
|
|
'neo4j_execute',
|
|
'neo4j_introspect',
|
|
],
|
|
config: {
|
|
tool: (params) => {
|
|
switch (params.operation) {
|
|
case 'query':
|
|
return 'neo4j_query'
|
|
case 'create':
|
|
return 'neo4j_create'
|
|
case 'merge':
|
|
return 'neo4j_merge'
|
|
case 'update':
|
|
return 'neo4j_update'
|
|
case 'delete':
|
|
return 'neo4j_delete'
|
|
case 'execute':
|
|
return 'neo4j_execute'
|
|
case 'introspect':
|
|
return 'neo4j_introspect'
|
|
default:
|
|
throw new Error(`Invalid Neo4j operation: ${params.operation}`)
|
|
}
|
|
},
|
|
params: (params) => {
|
|
const { operation, parameters, ...rest } = params
|
|
|
|
let parsedParameters
|
|
if (typeof parameters === 'string') {
|
|
const trimmed = parameters.trim()
|
|
if (trimmed === '') {
|
|
parsedParameters = undefined
|
|
} else {
|
|
try {
|
|
parsedParameters = JSON.parse(trimmed)
|
|
} catch (parseError) {
|
|
const errorMsg = getErrorMessage(parseError, 'Unknown JSON error')
|
|
throw new Error(
|
|
`Invalid JSON parameters format: ${errorMsg}. Please check your JSON syntax.`
|
|
)
|
|
}
|
|
}
|
|
} else if (parameters && typeof parameters === 'object') {
|
|
parsedParameters = parameters
|
|
} else {
|
|
parsedParameters = undefined
|
|
}
|
|
|
|
const connectionConfig = {
|
|
host: rest.host,
|
|
port: typeof rest.port === 'string' ? Number.parseInt(rest.port, 10) : rest.port || 7687,
|
|
database: rest.database || 'neo4j',
|
|
username: rest.username || 'neo4j',
|
|
password: rest.password,
|
|
encryption: rest.encryption || 'disabled',
|
|
}
|
|
|
|
const result: any = { ...connectionConfig }
|
|
|
|
if (rest.cypherQuery) {
|
|
result.cypherQuery = rest.cypherQuery
|
|
}
|
|
|
|
if (parsedParameters !== undefined && parsedParameters !== null) {
|
|
result.parameters = parsedParameters
|
|
} else {
|
|
result.parameters = undefined
|
|
}
|
|
|
|
if (rest.detach !== undefined) {
|
|
result.detach = rest.detach === 'true' || rest.detach === true
|
|
}
|
|
|
|
return result
|
|
},
|
|
},
|
|
},
|
|
inputs: {
|
|
operation: { type: 'string', description: 'Database operation to perform' },
|
|
host: { type: 'string', description: 'Neo4j host' },
|
|
port: { type: 'string', description: 'Neo4j port (Bolt protocol)' },
|
|
database: { type: 'string', description: 'Database name' },
|
|
username: { type: 'string', description: 'Neo4j username' },
|
|
password: { type: 'string', description: 'Neo4j password' },
|
|
encryption: { type: 'string', description: 'Connection encryption mode' },
|
|
cypherQuery: { type: 'string', description: 'Cypher query to execute' },
|
|
parameters: { type: 'json', description: 'Query parameters as JSON object' },
|
|
detach: { type: 'boolean', description: 'Use DETACH DELETE for delete operations' },
|
|
},
|
|
outputs: {
|
|
message: {
|
|
type: 'string',
|
|
description: 'Success or error message describing the operation outcome',
|
|
},
|
|
records: {
|
|
type: 'array',
|
|
description: 'Array of records returned from the query',
|
|
},
|
|
recordCount: {
|
|
type: 'number',
|
|
description: 'Number of records returned or affected',
|
|
},
|
|
summary: {
|
|
type: 'json',
|
|
description: 'Execution summary with timing and database change counters',
|
|
},
|
|
},
|
|
}
|
|
|
|
export const Neo4jBlockMeta = {
|
|
tags: ['data-warehouse', 'data-analytics'],
|
|
url: 'https://neo4j.com',
|
|
templates: [
|
|
{
|
|
icon: Neo4jIcon,
|
|
title: 'Neo4j relationship exporter',
|
|
prompt:
|
|
'Build a workflow that queries Neo4j for a chosen entity graph, writes the nodes and edges to a structured JSON adjacency file, and shares the file link for a downstream tool to visualize.',
|
|
modules: ['agent', 'files', 'workflows'],
|
|
category: 'engineering',
|
|
tags: ['analysis', 'research'],
|
|
},
|
|
{
|
|
icon: Neo4jIcon,
|
|
title: 'Neo4j fraud-ring detector',
|
|
prompt:
|
|
'Create a scheduled workflow that queries Neo4j for suspicious connection patterns — shared devices, overlapping addresses — writes risk-scored clusters to a fraud table, and pings Slack.',
|
|
modules: ['scheduled', 'tables', 'agent', 'workflows'],
|
|
category: 'operations',
|
|
tags: ['monitoring', 'analysis'],
|
|
alsoIntegrations: ['slack'],
|
|
},
|
|
{
|
|
icon: Neo4jIcon,
|
|
title: 'Neo4j org-chart sync',
|
|
prompt:
|
|
'Build a workflow that pulls Workday or Rippling worker data, upserts employees and reporting relationships into Neo4j, and exposes a queryable org graph for downstream tools.',
|
|
modules: ['scheduled', 'agent', 'workflows'],
|
|
category: 'operations',
|
|
tags: ['hr', 'sync'],
|
|
alsoIntegrations: ['workday', 'rippling'],
|
|
},
|
|
{
|
|
icon: Neo4jIcon,
|
|
title: 'Neo4j knowledge-graph builder',
|
|
prompt:
|
|
'Create a workflow that processes documents from a knowledge base, extracts entities and relationships with an agent, and writes the graph into Neo4j for cross-document insights.',
|
|
modules: ['knowledge-base', 'agent', 'workflows'],
|
|
category: 'engineering',
|
|
tags: ['research', 'enterprise'],
|
|
},
|
|
{
|
|
icon: Neo4jIcon,
|
|
title: 'Neo4j recommendation engine',
|
|
prompt:
|
|
'Build a workflow that runs Neo4j graph algorithms — collaborative filtering, PageRank — on product-purchase data and writes per-user recommendations to a personalization table.',
|
|
modules: ['tables', 'agent', 'workflows'],
|
|
category: 'marketing',
|
|
tags: ['marketing', 'analysis'],
|
|
},
|
|
{
|
|
icon: Neo4jIcon,
|
|
title: 'Neo4j data lineage tracker',
|
|
prompt:
|
|
'Create a workflow that ingests dbt manifest metadata into Neo4j, tracks lineage across tables and pipelines, and queries impact when a source schema changes.',
|
|
modules: ['agent', 'workflows'],
|
|
category: 'engineering',
|
|
tags: ['engineering', 'analysis'],
|
|
},
|
|
{
|
|
icon: Neo4jIcon,
|
|
title: 'Neo4j natural-language graph explorer',
|
|
prompt:
|
|
'Build a chat agent that introspects the Neo4j schema, translates plain-English questions like “which customers share a support agent with churned accounts?” into Cypher queries, runs them, and returns a readable answer with the matching nodes.',
|
|
modules: ['agent', 'workflows'],
|
|
category: 'engineering',
|
|
tags: ['analysis', 'research', 'automation'],
|
|
},
|
|
],
|
|
skills: [
|
|
{
|
|
name: 'answer-graph-question',
|
|
description:
|
|
'Translate a plain-English question into Cypher, run it on Neo4j, and explain the result.',
|
|
content:
|
|
'# Answer Graph Question\n\nTurn a natural-language question into a Cypher query against the Neo4j graph.\n\n## Steps\n1. Run Introspect Schema to learn the node labels, relationship types, and properties.\n2. Translate the question into a Cypher MATCH that uses the real labels and relationships from the schema.\n3. Run the Query operation and read the returned rows.\n4. If the query returns nothing, relax the pattern and explain what was tried.\n\n## Output\nA plain-language answer plus the Cypher used and the key matching nodes or paths.',
|
|
},
|
|
{
|
|
name: 'create-graph-relationship',
|
|
description: 'Create or merge nodes and connect them with a relationship in Neo4j.',
|
|
content:
|
|
'# Create Graph Relationship\n\nAdd nodes and a relationship between them without creating duplicates.\n\n## Steps\n1. Introspect Schema to confirm the labels and relationship type to use.\n2. Use Merge (Find or Create) for each node so existing nodes are reused rather than duplicated.\n3. Create the relationship between them with the requested direction and any properties.\n\n## Output\nConfirm the nodes involved and the relationship created, noting whether each node was found or newly created.',
|
|
},
|
|
{
|
|
name: 'find-connected-nodes',
|
|
description: 'Traverse the Neo4j graph from a starting node to find related entities.',
|
|
content:
|
|
'# Find Connected Nodes\n\nExplore the neighborhood of a node to find connected entities.\n\n## Steps\n1. Introspect Schema to know the relationship types available.\n2. Build a Cypher MATCH that starts at the given node and traverses the relevant relationships to the desired depth.\n3. Run the Query operation and collect the connected nodes.\n\n## Output\nA list of connected nodes grouped by relationship type, with the traversal path described in one line.',
|
|
},
|
|
],
|
|
} as const satisfies BlockMeta
|