feat: 增加对neo4j的增改查
This commit is contained in:
@@ -3,6 +3,7 @@ package services
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
|
||||
|
||||
@@ -299,3 +300,354 @@ func getInt(record *neo4j.Record, key string) int {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// CreateNode 创建新节点
|
||||
func (s *Neo4jService) CreateNode(req models.CreateNodeRequest) (models.Node, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
// 检查节点是否已存在
|
||||
checkQuery := "MATCH (n {id: $id}) RETURN n"
|
||||
checkResult, err := neo4j.ExecuteQuery(ctx, s.driver, checkQuery,
|
||||
map[string]any{"id": req.ID}, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
return models.Node{}, fmt.Errorf("error checking node existence: %w", err)
|
||||
}
|
||||
if len(checkResult.Records) > 0 {
|
||||
return models.Node{}, fmt.Errorf("node with id %s already exists", req.ID)
|
||||
}
|
||||
|
||||
// 构建创建属性
|
||||
props := map[string]any{
|
||||
"id": req.ID,
|
||||
"label": req.Label,
|
||||
}
|
||||
|
||||
if req.Type != "" {
|
||||
props["type"] = req.Type
|
||||
}
|
||||
if req.X != 0 {
|
||||
props["x"] = req.X
|
||||
}
|
||||
if req.Y != 0 {
|
||||
props["y"] = req.Y
|
||||
}
|
||||
|
||||
// 合并自定义属性(避免覆盖系统属性)
|
||||
if req.Properties != nil {
|
||||
for k, v := range req.Properties {
|
||||
if k != "id" && k != "label" && k != "type" && k != "x" && k != "y" {
|
||||
props[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行创建
|
||||
nodeType := "Node"
|
||||
if req.Type != "" {
|
||||
nodeType = req.Type
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
CREATE (n:%s)
|
||||
SET n = $props
|
||||
RETURN n`, nodeType)
|
||||
|
||||
result, err := neo4j.ExecuteQuery(ctx, s.driver, query,
|
||||
map[string]any{"props": props}, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating node: %v\n", err)
|
||||
return models.Node{}, fmt.Errorf("failed to create node: %w", err)
|
||||
}
|
||||
|
||||
if len(result.Records) == 0 {
|
||||
return models.Node{}, fmt.Errorf("failed to create node: no result returned")
|
||||
}
|
||||
|
||||
v, _ := result.Records[0].Get("n")
|
||||
if n, ok := v.(neo4j.Node); ok {
|
||||
return neo4jNodeToModel(n), nil
|
||||
}
|
||||
|
||||
return models.Node{}, fmt.Errorf("unexpected result type while creating node")
|
||||
}
|
||||
|
||||
// CreateNodeV2 创建新节点(改进版)
|
||||
func (s *Neo4jService) CreateNodeV2(req models.CreateNodeRequest) (models.Node, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
// 先检查节点是否已存在
|
||||
checkQuery := "MATCH (n {id: $id}) RETURN n"
|
||||
checkResult, err := neo4j.ExecuteQuery(ctx, s.driver, checkQuery,
|
||||
map[string]any{"id": req.ID}, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
if len(checkResult.Records) > 0 {
|
||||
return models.Node{}, fmt.Errorf("node with id %s already exists", req.ID)
|
||||
}
|
||||
|
||||
// 构建创建属性
|
||||
props := map[string]any{
|
||||
"id": req.ID,
|
||||
"label": req.Label,
|
||||
}
|
||||
|
||||
if req.Type != "" {
|
||||
props["type"] = req.Type
|
||||
}
|
||||
if req.X != 0 {
|
||||
props["x"] = req.X
|
||||
}
|
||||
if req.Y != 0 {
|
||||
props["y"] = req.Y
|
||||
}
|
||||
|
||||
// 合并自定义属性(避免覆盖系统属性)
|
||||
if req.Properties != nil {
|
||||
for k, v := range req.Properties {
|
||||
if k != "id" && k != "label" && k != "type" && k != "x" && k != "y" {
|
||||
props[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行创建
|
||||
nodeType := "Node"
|
||||
if req.Type != "" {
|
||||
nodeType = req.Type
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
CREATE (n:%s)
|
||||
SET n = $props
|
||||
RETURN n`, nodeType)
|
||||
|
||||
result, err := neo4j.ExecuteQuery(ctx, s.driver, query,
|
||||
map[string]any{"props": props}, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating node: %v\n", err)
|
||||
return models.Node{}, err
|
||||
}
|
||||
|
||||
if len(result.Records) == 0 {
|
||||
return models.Node{}, fmt.Errorf("failed to create node")
|
||||
}
|
||||
|
||||
v, _ := result.Records[0].Get("n")
|
||||
if n, ok := v.(neo4j.Node); ok {
|
||||
return neo4jNodeToModel(n), nil
|
||||
}
|
||||
|
||||
return models.Node{}, fmt.Errorf("unexpected result type while creating node")
|
||||
}
|
||||
|
||||
// UpdateNode 更新节点
|
||||
func (s *Neo4jService) UpdateNode(id string, req models.UpdateNodeRequest) (models.Node, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
// 检查节点是否存在
|
||||
_, exists := s.GetNodeByID(id)
|
||||
if !exists {
|
||||
return models.Node{}, fmt.Errorf("node with id %s not found", id)
|
||||
}
|
||||
|
||||
// 构建更新语句
|
||||
setClauses := []string{}
|
||||
params := map[string]any{"id": id}
|
||||
|
||||
if req.Label != "" {
|
||||
setClauses = append(setClauses, "n.label = $label")
|
||||
params["label"] = req.Label
|
||||
}
|
||||
|
||||
if req.Type != "" {
|
||||
setClauses = append(setClauses, "n.type = $type")
|
||||
params["type"] = req.Type
|
||||
}
|
||||
|
||||
if req.X != nil {
|
||||
setClauses = append(setClauses, "n.x = $x")
|
||||
params["x"] = *req.X
|
||||
}
|
||||
if req.Y != nil {
|
||||
setClauses = append(setClauses, "n.y = $y")
|
||||
params["y"] = *req.Y
|
||||
}
|
||||
|
||||
query := `MATCH (n {id: $id})`
|
||||
|
||||
// 处理自定义属性(不管是否有标准字段更新)
|
||||
if req.Properties != nil && len(req.Properties) > 0 {
|
||||
for key, value := range req.Properties {
|
||||
// 跳过系统属性,避免冲突
|
||||
if key != "id" && key != "label" && key != "type" && key != "x" && key != "y" {
|
||||
setClauses = append(setClauses, fmt.Sprintf("n.%s = $%s", key, key))
|
||||
params[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(setClauses) > 0 {
|
||||
query += ` SET ` + fmt.Sprintf("%s", strings.Join(setClauses, ", "))
|
||||
}
|
||||
query += ` RETURN n`
|
||||
|
||||
result, err := neo4j.ExecuteQuery(ctx, s.driver, query, params, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
fmt.Printf("Error updating node: %v\n", err)
|
||||
return models.Node{}, err
|
||||
}
|
||||
|
||||
if len(result.Records) == 0 {
|
||||
return models.Node{}, fmt.Errorf("failed to update node")
|
||||
}
|
||||
|
||||
v, _ := result.Records[0].Get("n")
|
||||
if n, ok := v.(neo4j.Node); ok {
|
||||
return neo4jNodeToModel(n), nil
|
||||
}
|
||||
|
||||
return models.Node{}, fmt.Errorf("unexpected result type while updating node")
|
||||
}
|
||||
|
||||
// DeleteNode 删除节点
|
||||
func (s *Neo4jService) DeleteNode(id string) error {
|
||||
ctx := context.Background()
|
||||
|
||||
// 检查节点是否存在
|
||||
_, exists := s.GetNodeByID(id)
|
||||
if !exists {
|
||||
return fmt.Errorf("node with id %s not found", id)
|
||||
}
|
||||
|
||||
// 先删除与该节点相关的所有关系
|
||||
deleteRelationsQuery := `
|
||||
MATCH (n {id: $id})-[r]-(m)
|
||||
DELETE r`
|
||||
|
||||
_, err := neo4j.ExecuteQuery(ctx, s.driver, deleteRelationsQuery,
|
||||
map[string]any{"id": id}, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
fmt.Printf("Error deleting relations: %v\n", err)
|
||||
// 继续尝试删除节点
|
||||
}
|
||||
|
||||
// 删除节点
|
||||
deleteNodeQuery := `
|
||||
MATCH (n {id: $id})
|
||||
DELETE n`
|
||||
|
||||
_, err = neo4j.ExecuteQuery(ctx, s.driver, deleteNodeQuery,
|
||||
map[string]any{"id": id}, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
fmt.Printf("Error deleting node: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateEdge 创建新边
|
||||
func (s *Neo4jService) CreateEdge(req models.CreateEdgeRequest) (models.Edge, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
// 检查源节点和目标节点是否存在
|
||||
_, sourceExists := s.GetNodeByID(req.Source)
|
||||
if !sourceExists {
|
||||
return models.Edge{}, fmt.Errorf("source node with id %s not found", req.Source)
|
||||
}
|
||||
_, targetExists := s.GetNodeByID(req.Target)
|
||||
if !targetExists {
|
||||
return models.Edge{}, fmt.Errorf("target node with id %s not found", req.Target)
|
||||
}
|
||||
|
||||
// 构建创建属性
|
||||
|
||||
// 构建创建属性
|
||||
props := map[string]any{
|
||||
"id": req.ID,
|
||||
"label": req.Label,
|
||||
}
|
||||
|
||||
// 合并自定义属性
|
||||
if req.Properties != nil {
|
||||
for k, v := range req.Properties {
|
||||
if k != "id" && k != "label" {
|
||||
props[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 确定边类型
|
||||
relationType := "RELATED_TO"
|
||||
if req.Type != "" {
|
||||
relationType = strings.ToUpper(req.Type)
|
||||
}
|
||||
|
||||
// 执行创建
|
||||
query := fmt.Sprintf(`
|
||||
MATCH (a {id: $source}), (b {id: $target})
|
||||
CREATE (a)-[r:%s]->(b)
|
||||
SET r = $props
|
||||
RETURN r`, relationType)
|
||||
|
||||
params := map[string]any{
|
||||
"source": req.Source,
|
||||
"target": req.Target,
|
||||
"props": props,
|
||||
}
|
||||
|
||||
result, err := neo4j.ExecuteQuery(ctx, s.driver, query, params, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating edge: %v\n", err)
|
||||
return models.Edge{}, err
|
||||
}
|
||||
|
||||
if len(result.Records) == 0 {
|
||||
return models.Edge{}, fmt.Errorf("failed to create edge")
|
||||
}
|
||||
|
||||
v, _ := result.Records[0].Get("r")
|
||||
if r, ok := v.(neo4j.Relationship); ok {
|
||||
edge := neo4jRelToModel(r)
|
||||
edge.Source = req.Source
|
||||
edge.Target = req.Target
|
||||
return edge, nil
|
||||
}
|
||||
|
||||
return models.Edge{}, fmt.Errorf("unexpected result type while creating edge")
|
||||
}
|
||||
|
||||
// DeleteEdge 删除边
|
||||
func (s *Neo4jService) DeleteEdge(edgeID string) error {
|
||||
ctx := context.Background()
|
||||
|
||||
// 检查边是否存在
|
||||
checkQuery := `
|
||||
MATCH ()-[r]-()
|
||||
WHERE r.id = $id
|
||||
RETURN r`
|
||||
checkResult, err := neo4j.ExecuteQuery(ctx, s.driver, checkQuery,
|
||||
map[string]any{"id": edgeID}, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(checkResult.Records) == 0 {
|
||||
return fmt.Errorf("edge with id %s not found", edgeID)
|
||||
}
|
||||
|
||||
// 删除边
|
||||
deleteQuery := `
|
||||
MATCH ()-[r]-()
|
||||
WHERE r.id = $id
|
||||
DELETE r`
|
||||
|
||||
_, err = neo4j.ExecuteQuery(ctx, s.driver, deleteQuery,
|
||||
map[string]any{"id": edgeID}, neo4j.EagerResultTransformer)
|
||||
if err != nil {
|
||||
fmt.Printf("Error deleting edge: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user