implement further integration tests on person and relationship creation

This commit is contained in:
2025-04-22 22:47:37 +02:00
parent 23da2c2186
commit 92c1d29ace
26 changed files with 523 additions and 111 deletions

View File

@@ -24,13 +24,19 @@ func CouldSeePersonsProfile(ctx context.Context, session neo4j.SessionWithContex
return fmt.Errorf("could not convert result to map[string]any")
}
people, ok := resMap["people"].([]api.OptimizedPersonNode)
if !ok {
return fmt.Errorf("could not convert people to []api.PersonProperties")
var uniqueIds []int64
var flattenedPeople []any
if err := api.Flatten(resMap["people"], &uniqueIds, &flattenedPeople); err != nil {
return fmt.Errorf("could not convert people to []map[string]any: %w", err)
}
for _, person := range people {
if *person.Id == userId {
for _, person := range flattenedPeople {
person, ok := person.(map[string]any)
if !ok {
return fmt.Errorf("could not convert person to map[string]any")
}
if person["id"].(int64) == int64(userId) {
return nil
}
}

View File

@@ -0,0 +1,29 @@
package api
import (
"fmt"
"github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/pkg/api"
)
type FamilyTree struct {
People []any `json:"people"`
Relationships []any `json:"relationships"`
}
func FlattenFamilyTree(input any, result *FamilyTree) error {
root, ok := input.(map[string]any)
if !ok {
return fmt.Errorf("could not convert result to map[string]any")
}
var uniqueIds []int64
err := api.Flatten(root["people"], &uniqueIds, &result.People)
if err != nil {
return err
}
uniqueIds = []int64{}
return api.Flatten(root["relationships"], &uniqueIds, &result.Relationships)
}

View File

@@ -126,13 +126,6 @@ func (srv *server) CreatePersonAndRelationship(c *gin.Context, id int, params ap
return
}
if err := trs.Commit(c.Request.Context()); err != nil {
srv.logger.Error("failed to commit transaction", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
return
}
relationshipsSingle, err := relationShipResultRaw.Single(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"msg": "no relationship was created" + err.Error()})
@@ -147,8 +140,15 @@ func (srv *server) CreatePersonAndRelationship(c *gin.Context, id int, params ap
return
}
if err := trs.Commit(c.Request.Context()); err != nil {
srv.logger.Error("failed to commit transaction", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
return
}
c.JSON(http.StatusOK, struct {
Person any `json:"person"`
Rel any `json:"relationship"`
}{Person: singleRes, Rel: relationships})
Rel any `json:"relationships"`
}{Person: createdPerson, Rel: relationships})
}

View File

@@ -20,7 +20,17 @@ func (srv *server) GetFamilyTreeById(c *gin.Context, params api.GetFamilyTreeByI
return
}
c.JSON(http.StatusOK, res)
results := FamilyTree{
People: []any{},
Relationships: []any{},
}
err = FlattenFamilyTree(res, &results)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
return
}
c.JSON(http.StatusOK, results)
}
func (srv *server) GetFamilyTreeWithSpousesById(
@@ -36,5 +46,15 @@ func (srv *server) GetFamilyTreeWithSpousesById(
return
}
c.JSON(http.StatusOK, res)
results := FamilyTree{
People: []any{},
Relationships: []any{},
}
err = FlattenFamilyTree(res, &results)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
return
}
c.JSON(http.StatusOK, results)
}

View File

@@ -52,7 +52,7 @@ func TestCreatePerson(t *testing.T) {
c.Request = httptest.NewRequestWithContext(
t.Context(), http.MethodPost, "/person", io.NopCloser(strings.NewReader(body)),
)
params := api.CreatePersonParams{XUserID: 1, XUserName: "test"}
params := api.CreatePersonParams{XUserID: 1}
srv.CreatePerson(c, params)

View File

@@ -69,6 +69,13 @@ var GetRelationshipCypherQuery string
//go:embed queries/create_child_parent_relationships.cypher
var CreateChildParentRelationshipCypherQuery string
// Requires childId, parentId parameters.
//
// returns relationships
//
//go:embed queries/create_sibling_relationships_based_on_parent.cypher
var CreateSiblingRelationshipsBasedOnParentCypherQuery string
// Requires id1, id2, Relationship1, Relationship1 parameters.
//
// return relationships

View File

@@ -4,14 +4,14 @@ OPTIONAL MATCH (n)-[p:Parent*..]->(family:Person)
OPTIONAL MATCH (family)-[c:Child*1..4]->(children:Person)
OPTIONAL MATCH (family)-[s:Sibling]->(siblings:Person)
OPTIONAL MATCH (n)-[ds:Sibling]->(direct_siblings:Person)
WITH collections.to_set(collect(n)+collect(family)+collect(children)+collect(direct_siblings)) as people,
WITH collections.to_set(collect(n)+collect(family)+collect(children)+collect(direct_siblings)+collect(siblings)) as people,
collections.to_set(collect(c) + collect(p) + collect(s) + collect(ds)) as relationships
UNWIND people as ppl
RETURN collect({
id: id(ppl),
first_name: ppl.first_name,
middle_name: ppl.middle_name,
last_name: ppl.last_name,
last_name: ppl.last_name,
born: ppl.born,
died: ppl.died,
profile_picture: ppl.profile_picture

View File

@@ -7,7 +7,7 @@ OPTIONAL MATCH (n)-[ds:Sibling]->(direct_siblings:Person)
OPTIONAL MATCH (family)-[fsp:Spouse]->(fspouse:Person)
OPTIONAL MATCH (children)-[csp:Spouse]->(cspouse:Person)
OPTIONAL MATCH (n)-[sp:Spouse]->(spouse:Person)
WITH collections.to_set(collect(n) + collect(family) + collect(children) + collect(direct_siblings) + collect(fspouse) + collect(cspouse) + collect(spouse)) as people,
WITH collections.to_set(collect(n) + collect(family) + collect(children) + collect(direct_siblings) + collect(fspouse) + collect(cspouse) + collect(spouse) + collect(siblings)) as people,
collections.to_set(collect(c) + collect(p) + collect(s) + collect(ds) + collect(fsp) + collect(csp) + collect(sp)) as relationships
UNWIND people as ppl
RETURN collect({

View File

@@ -4,6 +4,7 @@ import (
"context"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
"github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype"
"github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/pkg/api"
)
@@ -78,7 +79,40 @@ func CreateChildParentRelationship(
return nil, err
}
return result.Single(ctx)
siblingResult, err := tx.Run(ctx, CreateSiblingRelationshipsBasedOnParentCypherQuery, map[string]any{
"childId": childId,
"parentId": parentId,
})
if err != nil {
return nil, err
}
relationship, err := result.Single(ctx)
if err != nil {
return nil, err
}
relationshipsRaw, ok := relationship.Get("relationships")
if !ok {
return nil, err
}
relationships, rok := relationshipsRaw.([]dbtype.Relationship)
if !rok {
return nil, err
}
siblingRecord, err := siblingResult.Single(ctx)
if err != nil {
siblingRelationship, ok := siblingRecord.Get("relationships")
siblings, ok := siblingRelationship.([]dbtype.Relationship)
if ok {
relationships = append(relationships, siblings...)
}
}
return relationships, nil
}
}

View File

@@ -5,6 +5,7 @@ import (
"time"
"github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype"
openapi_types "github.com/oapi-codegen/runtime/types"
)
// StructToMap recursively converts a struct to a map using JSON tags.
@@ -70,7 +71,12 @@ func StructToMap(input any) map[string]any {
// Recurse into nested structs
switch val.Kind() {
case reflect.Struct:
result[jsonKey] = StructToMap(val.Interface())
switch val.Interface().(type) {
case openapi_types.Date:
result[jsonKey] = val.Interface().(openapi_types.Date).String()
default:
result[jsonKey] = StructToMap(val.Interface())
}
case reflect.Slice, reflect.Array:
result[jsonKey] = processSlice(val)
default:
@@ -114,7 +120,12 @@ func processSlice(val reflect.Value) []any {
if isPreservedType(item) {
slice[i] = item
} else if reflect.ValueOf(item).Kind() == reflect.Struct {
slice[i] = StructToMap(item)
switch item.(type) {
case openapi_types.Date:
slice[i] = item.(openapi_types.Date).String()
default:
slice[i] = StructToMap(item)
}
} else {
slice[i] = item
}