v0.0.31 Корректно сгенерирован резолвер получения Author для клипов
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
73946da723
commit
c7e109fe99
2
.env
2
.env
@ -13,4 +13,4 @@ SMTP_FROM=info@tailly.ru
|
|||||||
AppURL="https://tailly.ru"
|
AppURL="https://tailly.ru"
|
||||||
MESSAGE_SERVICE_ADDRESS="tailly_messages:50052"
|
MESSAGE_SERVICE_ADDRESS="tailly_messages:50052"
|
||||||
SUBSCRIBE_SERVICE_ADDRESS="tailly_subscribers:50053"
|
SUBSCRIBE_SERVICE_ADDRESS="tailly_subscribers:50053"
|
||||||
CLIP_SERVICE_ADDRESS="tailly_clips:50054"
|
CLIP_SERVICE_ADDRESS="localhost:50054"
|
||||||
@ -8,7 +8,6 @@ type Clip struct {
|
|||||||
VideoURL string `json:"videoUrl"`
|
VideoURL string `json:"videoUrl"`
|
||||||
ThumbnailURL string `json:"thumbnailUrl"`
|
ThumbnailURL string `json:"thumbnailUrl"`
|
||||||
AuthorID int `json:"-"`
|
AuthorID int `json:"-"`
|
||||||
Author *User `json:"author"`
|
|
||||||
LikesCount int `json:"likesCount"`
|
LikesCount int `json:"likesCount"`
|
||||||
CommentsCount int `json:"commentsCount"`
|
CommentsCount int `json:"commentsCount"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"tailly_back_v2/internal/domain"
|
"tailly_back_v2/internal/domain"
|
||||||
"tailly_back_v2/proto"
|
"tailly_back_v2/proto"
|
||||||
"time"
|
"time"
|
||||||
@ -31,47 +30,15 @@ func (r *clipResolver) IsLiked(ctx context.Context, obj *domain.Clip) (bool, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *clipResolver) Author(ctx context.Context, obj *domain.Clip) (*domain.User, error) {
|
func (r *clipResolver) Author(ctx context.Context, obj *domain.Clip) (*domain.User, error) {
|
||||||
log.Printf("Resolving author for clip %d, authorID: %d", obj.ID, obj.AuthorID)
|
|
||||||
|
|
||||||
if obj.AuthorID == 0 {
|
if obj.AuthorID == 0 {
|
||||||
log.Printf("WARNING: Clip %d has no authorID, returning stub", obj.ID)
|
return nil, fmt.Errorf("clip has no author ID")
|
||||||
return &domain.User{
|
|
||||||
ID: 0,
|
|
||||||
Username: "Unknown User",
|
|
||||||
Avatar: "/img/logo.png",
|
|
||||||
Email: "unknown@example.com",
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Получаем пользователя из сервиса
|
|
||||||
author, err := r.Services.User.GetByID(ctx, obj.AuthorID)
|
author, err := r.Services.User.GetByID(ctx, obj.AuthorID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ERROR: Failed to get author %d for clip %d: %v", obj.AuthorID, obj.ID, err)
|
return nil, fmt.Errorf("failed to get author: %w", err)
|
||||||
return &domain.User{
|
|
||||||
ID: obj.AuthorID,
|
|
||||||
Username: "Error Loading User",
|
|
||||||
Avatar: "/img/logo.png",
|
|
||||||
Email: "error@example.com",
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
log.Printf("Resolved author for clip %d", author)
|
|
||||||
if author == nil {
|
|
||||||
log.Printf("WARNING: Author %d not found for clip %d", obj.AuthorID, obj.ID)
|
|
||||||
return &domain.User{
|
|
||||||
ID: obj.AuthorID,
|
|
||||||
Username: "Deleted User",
|
|
||||||
Avatar: "/img/logo.png",
|
|
||||||
Email: "deleted@example.com",
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Successfully resolved author %d for clip %d", obj.AuthorID, obj.ID)
|
|
||||||
return author, nil
|
return author, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,24 +219,10 @@ func (r *queryResolver) Clips(ctx context.Context, limit *int, offset *int) ([]*
|
|||||||
Offset: int32(offsetVal),
|
Offset: int32(offsetVal),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ERROR: Failed to get clips from gRPC service: %v", err)
|
|
||||||
return nil, fmt.Errorf("failed to get clips: %w", err)
|
return nil, fmt.Errorf("failed to get clips: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clips := r.protoClipsToDomain(resp.Clips)
|
return r.protoClipsToDomain(resp.Clips), nil
|
||||||
|
|
||||||
// Детальное логирование
|
|
||||||
log.Printf("Retrieved %d clips from gRPC service", len(clips))
|
|
||||||
for i, clip := range clips {
|
|
||||||
log.Printf("Clip %d: ID=%d, Title=%s, AuthorID=%d", i, clip.ID, clip.Title, clip.AuthorID)
|
|
||||||
|
|
||||||
// Проверяем, что AuthorID заполнен
|
|
||||||
if clip.AuthorID == 0 {
|
|
||||||
log.Printf("ERROR: Clip %d has AuthorID=0!", clip.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return clips, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserClips is the resolver for the userClips field.
|
// UserClips is the resolver for the userClips field.
|
||||||
|
|||||||
@ -303,6 +303,8 @@ type ChatResolver interface {
|
|||||||
UpdatedAt(ctx context.Context, obj *domain.Chat) (string, error)
|
UpdatedAt(ctx context.Context, obj *domain.Chat) (string, error)
|
||||||
}
|
}
|
||||||
type ClipResolver interface {
|
type ClipResolver interface {
|
||||||
|
Author(ctx context.Context, obj *domain.Clip) (*domain.User, error)
|
||||||
|
|
||||||
IsLiked(ctx context.Context, obj *domain.Clip) (bool, error)
|
IsLiked(ctx context.Context, obj *domain.Clip) (bool, error)
|
||||||
CreatedAt(ctx context.Context, obj *domain.Clip) (string, error)
|
CreatedAt(ctx context.Context, obj *domain.Clip) (string, error)
|
||||||
UpdatedAt(ctx context.Context, obj *domain.Clip) (string, error)
|
UpdatedAt(ctx context.Context, obj *domain.Clip) (string, error)
|
||||||
@ -3274,7 +3276,7 @@ func (ec *executionContext) _Clip_author(ctx context.Context, field graphql.Coll
|
|||||||
}()
|
}()
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.Author, nil
|
return ec.resolvers.Clip().Author(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -3295,8 +3297,8 @@ func (ec *executionContext) fieldContext_Clip_author(_ context.Context, field gr
|
|||||||
fc = &graphql.FieldContext{
|
fc = &graphql.FieldContext{
|
||||||
Object: "Clip",
|
Object: "Clip",
|
||||||
Field: field,
|
Field: field,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
IsResolver: false,
|
IsResolver: true,
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "id":
|
case "id":
|
||||||
@ -13905,10 +13907,41 @@ func (ec *executionContext) _Clip(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
atomic.AddUint32(&out.Invalids, 1)
|
atomic.AddUint32(&out.Invalids, 1)
|
||||||
}
|
}
|
||||||
case "author":
|
case "author":
|
||||||
out.Values[i] = ec._Clip_author(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
|
||||||
atomic.AddUint32(&out.Invalids, 1)
|
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
res = ec._Clip_author(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&fs.Invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
if field.Deferrable != nil {
|
||||||
|
dfs, ok := deferred[field.Deferrable.Label]
|
||||||
|
di := 0
|
||||||
|
if ok {
|
||||||
|
dfs.AddField(field)
|
||||||
|
di = len(dfs.Values) - 1
|
||||||
|
} else {
|
||||||
|
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
|
||||||
|
deferred[field.Deferrable.Label] = dfs
|
||||||
|
}
|
||||||
|
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
|
||||||
|
return innerFunc(ctx, dfs)
|
||||||
|
})
|
||||||
|
|
||||||
|
// don't run the out.Concurrently() call below
|
||||||
|
out.Values[i] = graphql.Null
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||||
case "commentsCount":
|
case "commentsCount":
|
||||||
out.Values[i] = ec._Clip_commentsCount(ctx, field, obj)
|
out.Values[i] = ec._Clip_commentsCount(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user