Preview
Preview Feature — This feature is currently in preview and under active development. APIs and functionality may change. We recommend testing thoroughly before using in production.
Graph Actions
Create reusable graph query templates that can be executed with different input parameters. Graph actions allow you to define graph operations once and reuse them across your application with variable interpolation.
Quick Example
// Create a graph action template
await ductape.graph.action.create({
name: 'Find User Friends',
tag: 'social-graph:find-user-friends',
operation: GraphActionTypes.FIND_RELATIONSHIPS,
description: 'Get all friends of a user with pagination',
template: {
startNodeId: '{{userId}}',
type: 'FRIENDS_WITH',
direction: 'OUTGOING',
limit: '{{limit}}',
skip: '{{offset}}',
},
});
// Execute the action with different inputs
const friends = await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'find-user-friends',
input: {
userId: 'user-123',
limit: 20,
offset: 0,
},
});
Why Use Graph Actions?
Benefits:
- Reusability - Define graph operations once, use everywhere
- Type Safety - Template validation at creation time
- Variable Interpolation - Dynamic queries with
{{placeholder}}syntax - Maintainability - Update logic in one place
- Consistency - Standardize graph access patterns
- Testing - Easy to test query templates
Action Types
Node Operations
CREATE_NODE - Create Nodes
await ductape.graph.action.create({
name: 'Create User Node',
tag: 'social-graph:create-user',
operation: GraphActionTypes.CREATE_NODE,
template: {
labels: ['User', 'Person'],
properties: {
name: '{{name}}',
email: '{{email}}',
age: '{{age}}',
status: 'active',
createdAt: '{{createdAt}}',
},
},
});
// Execute
const user = await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'create-user',
input: {
name: 'Alice Johnson',
email: 'alice@example.com',
age: 28,
createdAt: new Date().toISOString(),
},
});
FIND_NODES - Query Nodes
await ductape.graph.action.create({
name: 'Find Users by City',
tag: 'social-graph:find-users-by-city',
operation: GraphActionTypes.FIND_NODES,
template: {
labels: ['User'],
where: {
city: '{{city}}',
age: { $GTE: '{{minAge}}' },
status: 'active',
},
limit: '{{limit}}',
skip: '{{offset}}',
},
});
// Execute
const users = await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'find-users-by-city',
input: {
city: 'New York',
minAge: 18,
limit: 50,
offset: 0,
},
});
FIND_NODE_BY_ID - Get Single Node
await ductape.graph.action.create({
name: 'Get User by ID',
tag: 'social-graph:get-user-by-id',
operation: GraphActionTypes.FIND_NODE_BY_ID,
template: {
id: '{{userId}}',
},
});
// Execute
const user = await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'get-user-by-id',
input: {
userId: 'user-123',
},
});
UPDATE_NODE - Modify Nodes
await ductape.graph.action.create({
name: 'Update User Profile',
tag: 'social-graph:update-user-profile',
operation: GraphActionTypes.UPDATE_NODE,
template: {
id: '{{userId}}',
properties: {
name: '{{name}}',
bio: '{{bio}}',
avatar: '{{avatar}}',
updatedAt: '{{updatedAt}}',
},
},
});
// Execute
await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'update-user-profile',
input: {
userId: 'user-123',
name: 'Alice Smith',
bio: 'Software Engineer',
avatar: 'https://...',
updatedAt: new Date().toISOString(),
},
});
DELETE_NODE - Remove Nodes
await ductape.graph.action.create({
name: 'Delete User',
tag: 'social-graph:delete-user',
operation: GraphActionTypes.DELETE_NODE,
template: {
id: '{{userId}}',
detach: true, // Also delete relationships
},
});
// Execute
await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'delete-user',
input: {
userId: 'user-123',
},
});
MERGE_NODE - Upsert Nodes
await ductape.graph.action.create({
name: 'Merge User',
tag: 'social-graph:merge-user',
operation: GraphActionTypes.MERGE_NODE,
template: {
labels: ['User'],
matchProperties: {
email: '{{email}}',
},
onCreate: {
name: '{{name}}',
email: '{{email}}',
createdAt: '{{createdAt}}',
},
onMatch: {
lastSeen: '{{lastSeen}}',
},
},
});
// Execute
await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'merge-user',
input: {
email: 'alice@example.com',
name: 'Alice Johnson',
createdAt: new Date().toISOString(),
lastSeen: new Date().toISOString(),
},
});
Relationship Operations
CREATE_RELATIONSHIP - Create Connections
await ductape.graph.action.create({
name: 'Create Friendship',
tag: 'social-graph:create-friendship',
operation: GraphActionTypes.CREATE_RELATIONSHIP,
template: {
type: 'FRIENDS_WITH',
startNodeId: '{{userId1}}',
endNodeId: '{{userId2}}',
properties: {
since: '{{since}}',
closeness: '{{closeness}}',
},
},
});
// Execute
await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'create-friendship',
input: {
userId1: 'user-123',
userId2: 'user-456',
since: '2024-01-15',
closeness: 'high',
},
});
FIND_RELATIONSHIPS - Query Connections
await ductape.graph.action.create({
name: 'Get User Followers',
tag: 'social-graph:get-user-followers',
operation: GraphActionTypes.FIND_RELATIONSHIPS,
template: {
endNodeId: '{{userId}}',
type: 'FOLLOWS',
direction: 'INCOMING',
where: {
active: true,
},
limit: '{{limit}}',
},
});
// Execute
const followers = await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'get-user-followers',
input: {
userId: 'user-123',
limit: 100,
},
});
UPDATE_RELATIONSHIP - Modify Connections
await ductape.graph.action.create({
name: 'Update Friendship',
tag: 'social-graph:update-friendship',
operation: GraphActionTypes.UPDATE_RELATIONSHIP,
template: {
id: '{{relationshipId}}',
properties: {
closeness: '{{closeness}}',
lastInteraction: '{{lastInteraction}}',
},
},
});
DELETE_RELATIONSHIP - Remove Connections
await ductape.graph.action.create({
name: 'Remove Friendship',
tag: 'social-graph:remove-friendship',
operation: GraphActionTypes.DELETE_RELATIONSHIP,
template: {
id: '{{relationshipId}}',
},
});
Traversal Operations
TRAVERSE - Explore Graph
await ductape.graph.action.create({
name: 'Get User Network',
tag: 'social-graph:get-user-network',
operation: GraphActionTypes.TRAVERSE,
template: {
startNodeId: '{{userId}}',
direction: 'OUTGOING',
relationshipTypes: ['FRIENDS_WITH', 'WORKS_WITH'],
maxDepth: '{{maxDepth}}',
nodeFilter: {
labels: ['User'],
where: {
status: 'active',
},
},
},
});
// Execute
const network = await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'get-user-network',
input: {
userId: 'user-123',
maxDepth: 2,
},
});
SHORTEST_PATH - Find Paths
await ductape.graph.action.create({
name: 'Find Connection Path',
tag: 'social-graph:find-connection-path',
operation: GraphActionTypes.SHORTEST_PATH,
template: {
startNodeId: '{{userId1}}',
endNodeId: '{{userId2}}',
relationshipTypes: ['FRIENDS_WITH', 'KNOWS'],
maxDepth: 6,
},
});
// Execute
const path = await ductape.graph.execute({
product: 'my-product',
env: 'prd',
graph: 'social-graph',
action: 'find-connection-path',
input: {
userId1: 'user-123',
userId2: 'user-789',
},
});
if (path.path) {
console.log(`${path.path.length} degrees of separation`);
}
Variable Interpolation
Basic Placeholders
Use {{variableName}} syntax:
template: {
labels: ['User'],
properties: {
name: '{{name}}',
email: '{{email}}',
age: '{{age}}',
},
}
Nested Placeholders
Work in nested structures:
template: {
where: {
$AND: {
city: '{{city}}',
age: { $GTE: '{{minAge}}', $LTE: '{{maxAge}}' },
status: { $IN: ['{{status1}}', '{{status2}}'] },
},
},
}
Filter Placeholders
Use in complex filters:
template: {
startNodeId: '{{userId}}',
relationshipTypes: ['{{relType1}}', '{{relType2}}'],
nodeFilter: {
where: {
city: '{{city}}',
age: { $GT: '{{minAge}}' },
},
},
}
Managing Actions
Create Action
await ductape.graph.action.create({
name: 'Action Name',
tag: 'graph-tag:action-tag', // Format: graph:action
operation: GraphActionTypes.FIND_NODES,
description: 'Optional description',
template: {
// Your operation template
},
});
Required Fields:
| Field | Type | Description |
|---|---|---|
name | string | Display name for the action |
tag | string | Unique identifier (format: graph:action) |
operation | GraphActionTypes | Action operation (FIND_NODES, etc.) |
template | object | Operation template with placeholders |
Optional Fields:
| Field | Type | Description |
|---|---|---|
description | string | Action description |
filterTemplate | object | Additional filter criteria |
Update Action
await ductape.graph.action.update({
tag: 'social-graph:find-users',
template: {
// Updated template
labels: ['User'],
where: {
status: '{{status}}',
},
},
});
Fetch Action
const action = await ductape.graph.action.fetch('social-graph:find-users');
console.log('Action:', action);
List Actions for Graph
const actions = await ductape.graph.action.fetchAll('social-graph');
console.log(`Found ${actions.length} actions`);
actions.forEach(action => {
console.log(`${action.tag}: ${action.name} (${action.type})`);
});