Skip to content

Commit 794bac0

Browse files
committed
tested all neo4j tools
1 parent d1774ec commit 794bac0

10 files changed

Lines changed: 114 additions & 34 deletions

File tree

apps/docs/components/icons.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4035,7 +4035,7 @@ export function ApolloIcon(props: SVGProps<SVGSVGElement>) {
40354035

40364036
export function Neo4jIcon(props: SVGProps<SVGSVGElement>) {
40374037
return (
4038-
<svg {...props} viewBox='0 0 128 128' fill='none' xmlns='http://www.w3.org/2000/svg'>
4038+
<svg {...props} viewBox='0 0 128 128' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
40394039
<path
40404040
d='M63.333 32.567c-5.2.866-9.566 3-12.833 6.266-3.867 3.867-5.833 8.5-6.5 15.367-.3 3.133-.467 15.467-.2 15.467.067 0 .7-.234 1.4-.534 1.633-.7 5.167-.7 7-.033l1.4.5.167-8.033c.166-8.567.366-9.867 1.966-13.067 1.1-2.133 3.767-4.633 6.034-5.667 2.6-1.2 6.4-1.666 9.333-1.2 6.267 1.034 10 4.434 11.567 10.5.633 2.434.666 3.7.666 17.1v14.434H93.4L93.233 67.9c-.1-14.9-.166-15.9-.866-18.567-1.9-7.4-6.5-12.766-12.934-15.2-3.433-1.3-6.7-1.8-11.2-1.766-2.233.033-4.433.133-4.9.2z'
40414041
fill='#000'

apps/sim/app/api/tools/neo4j/create/route.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { randomUUID } from 'crypto'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { z } from 'zod'
44
import { createLogger } from '@/lib/logs/console/logger'
5-
import { createNeo4jDriver, validateCypherQuery } from '../utils'
5+
import {
6+
convertNeo4jTypesToJSON,
7+
createNeo4jDriver,
8+
validateCypherQuery,
9+
} from '@/app/api/tools/neo4j/utils'
610

711
const logger = createLogger('Neo4jCreateAPI')
812

@@ -14,7 +18,7 @@ const CreateSchema = z.object({
1418
password: z.string().min(1, 'Password is required'),
1519
encryption: z.enum(['enabled', 'disabled']).default('disabled'),
1620
cypherQuery: z.string().min(1, 'Cypher query is required'),
17-
parameters: z.record(z.unknown()).optional().default({}),
21+
parameters: z.record(z.unknown()).nullable().optional().default({}),
1822
})
1923

2024
export async function POST(request: NextRequest) {
@@ -52,6 +56,16 @@ export async function POST(request: NextRequest) {
5256

5357
const result = await session.run(params.cypherQuery, params.parameters)
5458

59+
const records = result.records.map((record) => {
60+
const obj: Record<string, unknown> = {}
61+
record.keys.forEach((key) => {
62+
if (typeof key === 'string') {
63+
obj[key] = convertNeo4jTypesToJSON(record.get(key))
64+
}
65+
})
66+
return obj
67+
})
68+
5569
const summary = {
5670
resultAvailableAfter: result.summary.resultAvailableAfter.toNumber(),
5771
resultConsumedAfter: result.summary.resultConsumedAfter.toNumber(),
@@ -71,11 +85,13 @@ export async function POST(request: NextRequest) {
7185
}
7286

7387
logger.info(
74-
`[${requestId}] Create executed successfully, created ${summary.counters.nodesCreated} nodes and ${summary.counters.relationshipsCreated} relationships`
88+
`[${requestId}] Create executed successfully, created ${summary.counters.nodesCreated} nodes and ${summary.counters.relationshipsCreated} relationships, returned ${records.length} records`
7589
)
7690

7791
return NextResponse.json({
7892
message: `Created ${summary.counters.nodesCreated} nodes and ${summary.counters.relationshipsCreated} relationships`,
93+
records,
94+
recordCount: records.length,
7995
summary,
8096
})
8197
} catch (error) {

apps/sim/app/api/tools/neo4j/delete/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { randomUUID } from 'crypto'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { z } from 'zod'
44
import { createLogger } from '@/lib/logs/console/logger'
5-
import { createNeo4jDriver, validateCypherQuery } from '../utils'
5+
import { createNeo4jDriver, validateCypherQuery } from '@/app/api/tools/neo4j/utils'
66

77
const logger = createLogger('Neo4jDeleteAPI')
88

@@ -14,7 +14,7 @@ const DeleteSchema = z.object({
1414
password: z.string().min(1, 'Password is required'),
1515
encryption: z.enum(['enabled', 'disabled']).default('disabled'),
1616
cypherQuery: z.string().min(1, 'Cypher query is required'),
17-
parameters: z.record(z.unknown()).optional().default({}),
17+
parameters: z.record(z.unknown()).nullable().optional().default({}),
1818
detach: z.boolean().optional().default(false),
1919
})
2020

apps/sim/app/api/tools/neo4j/execute/route.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { randomUUID } from 'crypto'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { z } from 'zod'
44
import { createLogger } from '@/lib/logs/console/logger'
5-
import { convertNeo4jTypesToJSON, createNeo4jDriver, validateCypherQuery } from '../utils'
5+
import {
6+
convertNeo4jTypesToJSON,
7+
createNeo4jDriver,
8+
validateCypherQuery,
9+
} from '@/app/api/tools/neo4j/utils'
610

711
const logger = createLogger('Neo4jExecuteAPI')
812

@@ -14,7 +18,7 @@ const ExecuteSchema = z.object({
1418
password: z.string().min(1, 'Password is required'),
1519
encryption: z.enum(['enabled', 'disabled']).default('disabled'),
1620
cypherQuery: z.string().min(1, 'Cypher query is required'),
17-
parameters: z.record(z.unknown()).optional().default({}),
21+
parameters: z.record(z.unknown()).nullable().optional().default({}),
1822
})
1923

2024
export async function POST(request: NextRequest) {

apps/sim/app/api/tools/neo4j/merge/route.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { randomUUID } from 'crypto'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { z } from 'zod'
44
import { createLogger } from '@/lib/logs/console/logger'
5-
import { createNeo4jDriver, validateCypherQuery } from '../utils'
5+
import {
6+
convertNeo4jTypesToJSON,
7+
createNeo4jDriver,
8+
validateCypherQuery,
9+
} from '@/app/api/tools/neo4j/utils'
610

711
const logger = createLogger('Neo4jMergeAPI')
812

@@ -14,7 +18,7 @@ const MergeSchema = z.object({
1418
password: z.string().min(1, 'Password is required'),
1519
encryption: z.enum(['enabled', 'disabled']).default('disabled'),
1620
cypherQuery: z.string().min(1, 'Cypher query is required'),
17-
parameters: z.record(z.unknown()).optional().default({}),
21+
parameters: z.record(z.unknown()).nullable().optional().default({}),
1822
})
1923

2024
export async function POST(request: NextRequest) {
@@ -52,6 +56,16 @@ export async function POST(request: NextRequest) {
5256

5357
const result = await session.run(params.cypherQuery, params.parameters)
5458

59+
const records = result.records.map((record) => {
60+
const obj: Record<string, unknown> = {}
61+
record.keys.forEach((key) => {
62+
if (typeof key === 'string') {
63+
obj[key] = convertNeo4jTypesToJSON(record.get(key))
64+
}
65+
})
66+
return obj
67+
})
68+
5569
const summary = {
5670
resultAvailableAfter: result.summary.resultAvailableAfter.toNumber(),
5771
resultConsumedAfter: result.summary.resultConsumedAfter.toNumber(),
@@ -71,11 +85,13 @@ export async function POST(request: NextRequest) {
7185
}
7286

7387
logger.info(
74-
`[${requestId}] Merge executed successfully, created ${summary.counters.nodesCreated} nodes, ${summary.counters.relationshipsCreated} relationships`
88+
`[${requestId}] Merge executed successfully, created ${summary.counters.nodesCreated} nodes, ${summary.counters.relationshipsCreated} relationships, returned ${records.length} records`
7589
)
7690

7791
return NextResponse.json({
7892
message: `Merge completed: ${summary.counters.nodesCreated} nodes created, ${summary.counters.relationshipsCreated} relationships created`,
93+
records,
94+
recordCount: records.length,
7995
summary,
8096
})
8197
} catch (error) {

apps/sim/app/api/tools/neo4j/query/route.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { randomUUID } from 'crypto'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { z } from 'zod'
44
import { createLogger } from '@/lib/logs/console/logger'
5-
import { convertNeo4jTypesToJSON, createNeo4jDriver, validateCypherQuery } from '../utils'
5+
import {
6+
convertNeo4jTypesToJSON,
7+
createNeo4jDriver,
8+
validateCypherQuery,
9+
} from '@/app/api/tools/neo4j/utils'
610

711
const logger = createLogger('Neo4jQueryAPI')
812

@@ -14,7 +18,7 @@ const QuerySchema = z.object({
1418
password: z.string().min(1, 'Password is required'),
1519
encryption: z.enum(['enabled', 'disabled']).default('disabled'),
1620
cypherQuery: z.string().min(1, 'Cypher query is required'),
17-
parameters: z.record(z.unknown()).optional().default({}),
21+
parameters: z.record(z.unknown()).nullable().optional().default({}),
1822
limit: z
1923
.union([z.coerce.number().int().positive(), z.literal(''), z.undefined()])
2024
.optional()

apps/sim/app/api/tools/neo4j/update/route.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { randomUUID } from 'crypto'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { z } from 'zod'
44
import { createLogger } from '@/lib/logs/console/logger'
5-
import { createNeo4jDriver, validateCypherQuery } from '../utils'
5+
import {
6+
convertNeo4jTypesToJSON,
7+
createNeo4jDriver,
8+
validateCypherQuery,
9+
} from '@/app/api/tools/neo4j/utils'
610

711
const logger = createLogger('Neo4jUpdateAPI')
812

@@ -14,7 +18,7 @@ const UpdateSchema = z.object({
1418
password: z.string().min(1, 'Password is required'),
1519
encryption: z.enum(['enabled', 'disabled']).default('disabled'),
1620
cypherQuery: z.string().min(1, 'Cypher query is required'),
17-
parameters: z.record(z.unknown()).optional().default({}),
21+
parameters: z.record(z.unknown()).nullable().optional().default({}),
1822
})
1923

2024
export async function POST(request: NextRequest) {
@@ -52,6 +56,16 @@ export async function POST(request: NextRequest) {
5256

5357
const result = await session.run(params.cypherQuery, params.parameters)
5458

59+
const records = result.records.map((record) => {
60+
const obj: Record<string, unknown> = {}
61+
record.keys.forEach((key) => {
62+
if (typeof key === 'string') {
63+
obj[key] = convertNeo4jTypesToJSON(record.get(key))
64+
}
65+
})
66+
return obj
67+
})
68+
5569
const summary = {
5670
resultAvailableAfter: result.summary.resultAvailableAfter.toNumber(),
5771
resultConsumedAfter: result.summary.resultConsumedAfter.toNumber(),
@@ -71,11 +85,13 @@ export async function POST(request: NextRequest) {
7185
}
7286

7387
logger.info(
74-
`[${requestId}] Update executed successfully, ${summary.counters.propertiesSet} properties set`
88+
`[${requestId}] Update executed successfully, ${summary.counters.propertiesSet} properties set, returned ${records.length} records`
7589
)
7690

7791
return NextResponse.json({
7892
message: `Updated ${summary.counters.propertiesSet} properties`,
93+
records,
94+
recordCount: records.length,
7995
summary,
8096
})
8197
} catch (error) {

apps/sim/app/api/tools/neo4j/utils.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,27 @@ import neo4j from 'neo4j-driver'
22
import type { Neo4jConnectionConfig } from '@/tools/neo4j/types'
33

44
export async function createNeo4jDriver(config: Neo4jConnectionConfig) {
5-
const protocol = config.encryption === 'enabled' ? 'neo4j+s' : 'neo4j'
5+
const isAuraHost = config.host.includes('.databases.neo4j.io')
6+
7+
let protocol: string
8+
if (isAuraHost) {
9+
protocol = 'neo4j+s'
10+
} else {
11+
protocol = config.encryption === 'enabled' ? 'bolt+s' : 'bolt'
12+
}
13+
614
const uri = `${protocol}://${config.host}:${config.port}`
715

8-
const driver = neo4j.driver(uri, neo4j.auth.basic(config.username, config.password), {
9-
encrypted: config.encryption === 'enabled' ? 'ENCRYPTION_ON' : 'ENCRYPTION_OFF',
16+
const driverConfig: any = {
1017
maxConnectionPoolSize: 1,
1118
connectionTimeout: 10000,
12-
})
19+
}
20+
21+
if (!protocol.endsWith('+s')) {
22+
driverConfig.encrypted = config.encryption === 'enabled' ? 'ENCRYPTION_ON' : 'ENCRYPTION_OFF'
23+
}
24+
25+
const driver = neo4j.driver(uri, neo4j.auth.basic(config.username, config.password), driverConfig)
1326

1427
await driver.verifyConnectivity()
1528

apps/sim/blocks/blocks/neo4j.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const Neo4jBlock: BlockConfig<Neo4jResponse> = {
3333
type: 'short-input',
3434
placeholder: 'localhost or your.neo4j.host',
3535
required: true,
36+
password: true,
3637
},
3738
{
3839
id: 'port',
@@ -455,7 +456,7 @@ Return ONLY the Cypher query.`,
455456
},
456457
{
457458
id: 'parameters',
458-
title: 'Parameters (JSON)',
459+
title: 'Parameters',
459460
type: 'code',
460461
placeholder: '{"name": "Alice", "minAge": 21}',
461462
wandConfig: {
@@ -607,20 +608,28 @@ Return ONLY valid JSON.`,
607608
}
608609
},
609610
params: (params) => {
610-
const { operation, ...rest } = params
611+
const { operation, parameters, ...rest } = params
611612

612613
let parsedParameters
613-
if (rest.parameters && typeof rest.parameters === 'string' && rest.parameters.trim()) {
614-
try {
615-
parsedParameters = JSON.parse(rest.parameters)
616-
} catch (parseError) {
617-
const errorMsg = parseError instanceof Error ? parseError.message : 'Unknown JSON error'
618-
throw new Error(
619-
`Invalid JSON parameters format: ${errorMsg}. Please check your JSON syntax.`
620-
)
614+
if (typeof parameters === 'string') {
615+
const trimmed = parameters.trim()
616+
if (trimmed === '') {
617+
parsedParameters = undefined
618+
} else {
619+
try {
620+
parsedParameters = JSON.parse(trimmed)
621+
} catch (parseError) {
622+
const errorMsg =
623+
parseError instanceof Error ? parseError.message : 'Unknown JSON error'
624+
throw new Error(
625+
`Invalid JSON parameters format: ${errorMsg}. Please check your JSON syntax.`
626+
)
627+
}
621628
}
622-
} else if (rest.parameters && typeof rest.parameters === 'object') {
623-
parsedParameters = rest.parameters
629+
} else if (parameters && typeof parameters === 'object') {
630+
parsedParameters = parameters
631+
} else {
632+
parsedParameters = undefined
624633
}
625634

626635
const connectionConfig = {
@@ -638,8 +647,10 @@ Return ONLY valid JSON.`,
638647
result.cypherQuery = rest.cypherQuery
639648
}
640649

641-
if (parsedParameters !== undefined) {
650+
if (parsedParameters !== undefined && parsedParameters !== null) {
642651
result.parameters = parsedParameters
652+
} else {
653+
result.parameters = undefined
643654
}
644655

645656
if (rest.limit && rest.limit !== '') {

apps/sim/components/icons.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4035,7 +4035,7 @@ export function ApolloIcon(props: SVGProps<SVGSVGElement>) {
40354035

40364036
export function Neo4jIcon(props: SVGProps<SVGSVGElement>) {
40374037
return (
4038-
<svg {...props} viewBox='0 0 128 128' fill='none' xmlns='http://www.w3.org/2000/svg'>
4038+
<svg {...props} viewBox='0 0 128 128' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
40394039
<path
40404040
d='M63.333 32.567c-5.2.866-9.566 3-12.833 6.266-3.867 3.867-5.833 8.5-6.5 15.367-.3 3.133-.467 15.467-.2 15.467.067 0 .7-.234 1.4-.534 1.633-.7 5.167-.7 7-.033l1.4.5.167-8.033c.166-8.567.366-9.867 1.966-13.067 1.1-2.133 3.767-4.633 6.034-5.667 2.6-1.2 6.4-1.666 9.333-1.2 6.267 1.034 10 4.434 11.567 10.5.633 2.434.666 3.7.666 17.1v14.434H93.4L93.233 67.9c-.1-14.9-.166-15.9-.866-18.567-1.9-7.4-6.5-12.766-12.934-15.2-3.433-1.3-6.7-1.8-11.2-1.766-2.233.033-4.433.133-4.9.2z'
40414041
fill='#000'

0 commit comments

Comments
 (0)