package v1 import ( "context" "fmt" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" v1pb "github.com/usememos/memos/proto/gen/api/v1" "github.com/usememos/memos/store" ) func (s *APIV1Service) SetMemoRelations(ctx context.Context, request *v1pb.SetMemoRelationsRequest) (*emptypb.Empty, error) { id, err := ExtractMemoIDFromName(request.Name) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "invalid memo name: %v", err) } referenceType := store.MemoRelationReference // Delete all reference relations first. if err := s.Store.DeleteMemoRelation(ctx, &store.DeleteMemoRelation{ MemoID: &id, Type: &referenceType, }); err != nil { return nil, status.Errorf(codes.Internal, "failed to delete memo relation") } for _, relation := range request.Relations { // Ignore reflexive relations. if request.Name == relation.RelatedMemo { continue } // Ignore comment relations as there's no need to update a comment's relation. // Inserting/Deleting a comment is handled elsewhere. if relation.Type == v1pb.MemoRelation_COMMENT { continue } relatedMemoID, err := ExtractMemoIDFromName(relation.RelatedMemo) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "invalid related memo name: %v", err) } if _, err := s.Store.UpsertMemoRelation(ctx, &store.MemoRelation{ MemoID: id, RelatedMemoID: relatedMemoID, Type: convertMemoRelationTypeToStore(relation.Type), }); err != nil { return nil, status.Errorf(codes.Internal, "failed to upsert memo relation") } } return &emptypb.Empty{}, nil } func (s *APIV1Service) ListMemoRelations(ctx context.Context, request *v1pb.ListMemoRelationsRequest) (*v1pb.ListMemoRelationsResponse, error) { id, err := ExtractMemoIDFromName(request.Name) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "invalid memo name: %v", err) } relationList := []*v1pb.MemoRelation{} tempList, err := s.Store.ListMemoRelations(ctx, &store.FindMemoRelation{ MemoID: &id, }) if err != nil { return nil, err } for _, relation := range tempList { relationList = append(relationList, convertMemoRelationFromStore(relation)) } tempList, err = s.Store.ListMemoRelations(ctx, &store.FindMemoRelation{ RelatedMemoID: &id, }) if err != nil { return nil, err } for _, relation := range tempList { relationList = append(relationList, convertMemoRelationFromStore(relation)) } response := &v1pb.ListMemoRelationsResponse{ Relations: relationList, } return response, nil } func convertMemoRelationFromStore(memoRelation *store.MemoRelation) *v1pb.MemoRelation { return &v1pb.MemoRelation{ Memo: fmt.Sprintf("%s%d", MemoNamePrefix, memoRelation.MemoID), RelatedMemo: fmt.Sprintf("%s%d", MemoNamePrefix, memoRelation.RelatedMemoID), Type: convertMemoRelationTypeFromStore(memoRelation.Type), } } func convertMemoRelationTypeFromStore(relationType store.MemoRelationType) v1pb.MemoRelation_Type { switch relationType { case store.MemoRelationReference: return v1pb.MemoRelation_REFERENCE case store.MemoRelationComment: return v1pb.MemoRelation_COMMENT default: return v1pb.MemoRelation_TYPE_UNSPECIFIED } } func convertMemoRelationTypeToStore(relationType v1pb.MemoRelation_Type) store.MemoRelationType { switch relationType { case v1pb.MemoRelation_REFERENCE: return store.MemoRelationReference case v1pb.MemoRelation_COMMENT: return store.MemoRelationComment default: return store.MemoRelationReference } }