From 7ae6060e61ebf7ff398af562137d7d2cfd375c80 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 2 Sep 2025 21:57:58 +0300 Subject: [PATCH] =?UTF-8?q?v0.0.30=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=BE=D0=B1=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=BB=D0=B8=D0=BF=D0=B0=20=D0=B8=20=D0=B0=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B5=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B8=D1=8F=20=D0=BA=20=D0=BD=D0=B5=D0=BC?= =?UTF-8?q?=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/domain/clip.go | 20 ++-- internal/http/graph/clip_resolvers.go | 26 +++++ internal/http/graph/generated.go | 140 ++++++++++++++++++-------- internal/http/graph/schema.graphql | 34 +++---- 4 files changed, 152 insertions(+), 68 deletions(-) diff --git a/internal/domain/clip.go b/internal/domain/clip.go index a3f7dc4..9e613fb 100644 --- a/internal/domain/clip.go +++ b/internal/domain/clip.go @@ -5,14 +5,15 @@ import "time" type Clip struct { ID int `json:"id"` Title string `json:"title"` - VideoURL string `json:"video_url"` - ThumbnailURL string `json:"thumbnail_url"` - Duration int `json:"duration"` // seconds - AuthorID int `json:"author_id"` - LikesCount int `json:"likes_count"` - CommentsCount int `json:"comments_count"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + VideoURL string `json:"videoUrl"` + ThumbnailURL string `json:"thumbnailUrl"` + Duration int `json:"duration"` + AuthorID int `json:"-"` + Author *User `json:"author"` + LikesCount int `json:"likesCount"` + CommentsCount int `json:"commentsCount"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } type ClipLike struct { @@ -25,7 +26,8 @@ type ClipLike struct { type ClipComment struct { ID int `json:"id"` ClipID int `json:"clip_id"` - AuthorID int `json:"author_id"` + AuthorID int `json:"-"` + Author *User `json:"author"` Content string `json:"content"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` diff --git a/internal/http/graph/clip_resolvers.go b/internal/http/graph/clip_resolvers.go index 8059cff..5a6fac9 100644 --- a/internal/http/graph/clip_resolvers.go +++ b/internal/http/graph/clip_resolvers.go @@ -29,6 +29,19 @@ func (r *clipResolver) IsLiked(ctx context.Context, obj *domain.Clip) (bool, err return resp.IsLiked, nil } +func (r *clipResolver) Author(ctx context.Context, obj *domain.Clip) (*domain.User, error) { + if obj.AuthorID == 0 { + return nil, fmt.Errorf("clip has no author ID") + } + + author, err := r.Services.User.GetByID(ctx, obj.AuthorID) + if err != nil { + return nil, fmt.Errorf("failed to get author: %w", err) + } + + return author, nil +} + // CreatedAt is the resolver for the createdAt field. func (r *clipResolver) CreatedAt(ctx context.Context, obj *domain.Clip) (string, error) { return obj.CreatedAt.Format(time.RFC3339), nil @@ -401,3 +414,16 @@ func (r *Resolver) ClipLike() ClipLikeResolver { return &clipLikeResolver{r} } type clipResolver struct{ *Resolver } type clipCommentResolver struct{ *Resolver } type clipLikeResolver struct{ *Resolver } + +func (r *clipCommentResolver) Author(ctx context.Context, obj *domain.ClipComment) (*domain.User, error) { + if obj.AuthorID == 0 { + return nil, fmt.Errorf("comment has no author ID") + } + + author, err := r.Services.User.GetByID(ctx, obj.AuthorID) + if err != nil { + return nil, fmt.Errorf("failed to get author: %w", err) + } + + return author, nil +} diff --git a/internal/http/graph/generated.go b/internal/http/graph/generated.go index aacb8f2..f7afd0f 100644 --- a/internal/http/graph/generated.go +++ b/internal/http/graph/generated.go @@ -71,7 +71,7 @@ type ComplexityRoot struct { } Clip struct { - AuthorID func(childComplexity int) int + Author func(childComplexity int) int CommentsCount func(childComplexity int) int CreatedAt func(childComplexity int) int Duration func(childComplexity int) int @@ -85,7 +85,7 @@ type ComplexityRoot struct { } ClipComment struct { - AuthorID func(childComplexity int) int + Author func(childComplexity int) int ClipID func(childComplexity int) int Content func(childComplexity int) int CreatedAt func(childComplexity int) int @@ -484,12 +484,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Chat.User2ID(childComplexity), true - case "Clip.authorId": - if e.complexity.Clip.AuthorID == nil { + case "Clip.author": + if e.complexity.Clip.Author == nil { break } - return e.complexity.Clip.AuthorID(childComplexity), true + return e.complexity.Clip.Author(childComplexity), true case "Clip.commentsCount": if e.complexity.Clip.CommentsCount == nil { @@ -561,12 +561,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Clip.VideoURL(childComplexity), true - case "ClipComment.authorId": - if e.complexity.ClipComment.AuthorID == nil { + case "ClipComment.author": + if e.complexity.ClipComment.Author == nil { break } - return e.complexity.ClipComment.AuthorID(childComplexity), true + return e.complexity.ClipComment.Author(childComplexity), true case "ClipComment.clipId": if e.complexity.ClipComment.ClipID == nil { @@ -3312,8 +3312,8 @@ func (ec *executionContext) fieldContext_Clip_duration(_ context.Context, field return fc, nil } -func (ec *executionContext) _Clip_authorId(ctx context.Context, field graphql.CollectedField, obj *domain.Clip) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Clip_authorId(ctx, field) +func (ec *executionContext) _Clip_author(ctx context.Context, field graphql.CollectedField, obj *domain.Clip) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Clip_author(ctx, field) if err != nil { return graphql.Null } @@ -3326,7 +3326,7 @@ func (ec *executionContext) _Clip_authorId(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.AuthorID, nil + return obj.Author, nil }) if err != nil { ec.Error(ctx, err) @@ -3338,19 +3338,47 @@ func (ec *executionContext) _Clip_authorId(ctx context.Context, field graphql.Co } return graphql.Null } - res := resTmp.(int) + res := resTmp.(*domain.User) fc.Result = res - return ec.marshalNInt2int(ctx, field.Selections, res) + return ec.marshalNUser2ᚖtailly_back_v2ᚋinternalᚋdomainᚐUser(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Clip_authorId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Clip_author(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Clip", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "username": + return ec.fieldContext_User_username(ctx, field) + case "avatar": + return ec.fieldContext_User_avatar(ctx, field) + case "email": + return ec.fieldContext_User_email(ctx, field) + case "emailConfirmedAt": + return ec.fieldContext_User_emailConfirmedAt(ctx, field) + case "createdAt": + return ec.fieldContext_User_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_User_updatedAt(ctx, field) + case "followersCount": + return ec.fieldContext_User_followersCount(ctx, field) + case "followingCount": + return ec.fieldContext_User_followingCount(ctx, field) + case "isFollowing": + return ec.fieldContext_User_isFollowing(ctx, field) + case "followers": + return ec.fieldContext_User_followers(ctx, field) + case "following": + return ec.fieldContext_User_following(ctx, field) + case "subscriptionNotifications": + return ec.fieldContext_User_subscriptionNotifications(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil @@ -3664,8 +3692,8 @@ func (ec *executionContext) fieldContext_ClipComment_clipId(_ context.Context, f return fc, nil } -func (ec *executionContext) _ClipComment_authorId(ctx context.Context, field graphql.CollectedField, obj *domain.ClipComment) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_ClipComment_authorId(ctx, field) +func (ec *executionContext) _ClipComment_author(ctx context.Context, field graphql.CollectedField, obj *domain.ClipComment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ClipComment_author(ctx, field) if err != nil { return graphql.Null } @@ -3678,7 +3706,7 @@ func (ec *executionContext) _ClipComment_authorId(ctx context.Context, field gra }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return obj.AuthorID, nil + return obj.Author, nil }) if err != nil { ec.Error(ctx, err) @@ -3690,19 +3718,47 @@ func (ec *executionContext) _ClipComment_authorId(ctx context.Context, field gra } return graphql.Null } - res := resTmp.(int) + res := resTmp.(*domain.User) fc.Result = res - return ec.marshalNInt2int(ctx, field.Selections, res) + return ec.marshalNUser2ᚖtailly_back_v2ᚋinternalᚋdomainᚐUser(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ClipComment_authorId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ClipComment_author(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ClipComment", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "username": + return ec.fieldContext_User_username(ctx, field) + case "avatar": + return ec.fieldContext_User_avatar(ctx, field) + case "email": + return ec.fieldContext_User_email(ctx, field) + case "emailConfirmedAt": + return ec.fieldContext_User_emailConfirmedAt(ctx, field) + case "createdAt": + return ec.fieldContext_User_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_User_updatedAt(ctx, field) + case "followersCount": + return ec.fieldContext_User_followersCount(ctx, field) + case "followingCount": + return ec.fieldContext_User_followingCount(ctx, field) + case "isFollowing": + return ec.fieldContext_User_isFollowing(ctx, field) + case "followers": + return ec.fieldContext_User_followers(ctx, field) + case "following": + return ec.fieldContext_User_following(ctx, field) + case "subscriptionNotifications": + return ec.fieldContext_User_subscriptionNotifications(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil @@ -7192,8 +7248,8 @@ func (ec *executionContext) fieldContext_Mutation_createClip(ctx context.Context return ec.fieldContext_Clip_thumbnailUrl(ctx, field) case "duration": return ec.fieldContext_Clip_duration(ctx, field) - case "authorId": - return ec.fieldContext_Clip_authorId(ctx, field) + case "author": + return ec.fieldContext_Clip_author(ctx, field) case "commentsCount": return ec.fieldContext_Clip_commentsCount(ctx, field) case "likesCount": @@ -7440,8 +7496,8 @@ func (ec *executionContext) fieldContext_Mutation_createClipComment(ctx context. return ec.fieldContext_ClipComment_id(ctx, field) case "clipId": return ec.fieldContext_ClipComment_clipId(ctx, field) - case "authorId": - return ec.fieldContext_ClipComment_authorId(ctx, field) + case "author": + return ec.fieldContext_ClipComment_author(ctx, field) case "content": return ec.fieldContext_ClipComment_content(ctx, field) case "createdAt": @@ -9404,8 +9460,8 @@ func (ec *executionContext) fieldContext_Query_clip(ctx context.Context, field g return ec.fieldContext_Clip_thumbnailUrl(ctx, field) case "duration": return ec.fieldContext_Clip_duration(ctx, field) - case "authorId": - return ec.fieldContext_Clip_authorId(ctx, field) + case "author": + return ec.fieldContext_Clip_author(ctx, field) case "commentsCount": return ec.fieldContext_Clip_commentsCount(ctx, field) case "likesCount": @@ -9483,8 +9539,8 @@ func (ec *executionContext) fieldContext_Query_clips(ctx context.Context, field return ec.fieldContext_Clip_thumbnailUrl(ctx, field) case "duration": return ec.fieldContext_Clip_duration(ctx, field) - case "authorId": - return ec.fieldContext_Clip_authorId(ctx, field) + case "author": + return ec.fieldContext_Clip_author(ctx, field) case "commentsCount": return ec.fieldContext_Clip_commentsCount(ctx, field) case "likesCount": @@ -9562,8 +9618,8 @@ func (ec *executionContext) fieldContext_Query_userClips(ctx context.Context, fi return ec.fieldContext_Clip_thumbnailUrl(ctx, field) case "duration": return ec.fieldContext_Clip_duration(ctx, field) - case "authorId": - return ec.fieldContext_Clip_authorId(ctx, field) + case "author": + return ec.fieldContext_Clip_author(ctx, field) case "commentsCount": return ec.fieldContext_Clip_commentsCount(ctx, field) case "likesCount": @@ -9635,8 +9691,8 @@ func (ec *executionContext) fieldContext_Query_clipComments(ctx context.Context, return ec.fieldContext_ClipComment_id(ctx, field) case "clipId": return ec.fieldContext_ClipComment_clipId(ctx, field) - case "authorId": - return ec.fieldContext_ClipComment_authorId(ctx, field) + case "author": + return ec.fieldContext_ClipComment_author(ctx, field) case "content": return ec.fieldContext_ClipComment_content(ctx, field) case "createdAt": @@ -10292,8 +10348,8 @@ func (ec *executionContext) fieldContext_Subscription_clipCreated(_ context.Cont return ec.fieldContext_Clip_thumbnailUrl(ctx, field) case "duration": return ec.fieldContext_Clip_duration(ctx, field) - case "authorId": - return ec.fieldContext_Clip_authorId(ctx, field) + case "author": + return ec.fieldContext_Clip_author(ctx, field) case "commentsCount": return ec.fieldContext_Clip_commentsCount(ctx, field) case "likesCount": @@ -10447,8 +10503,8 @@ func (ec *executionContext) fieldContext_Subscription_commentClipCreated(ctx con return ec.fieldContext_ClipComment_id(ctx, field) case "clipId": return ec.fieldContext_ClipComment_clipId(ctx, field) - case "authorId": - return ec.fieldContext_ClipComment_authorId(ctx, field) + case "author": + return ec.fieldContext_ClipComment_author(ctx, field) case "content": return ec.fieldContext_ClipComment_content(ctx, field) case "createdAt": @@ -13915,8 +13971,8 @@ func (ec *executionContext) _Clip(ctx context.Context, sel ast.SelectionSet, obj if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } - case "authorId": - out.Values[i] = ec._Clip_authorId(ctx, field, obj) + case "author": + out.Values[i] = ec._Clip_author(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } @@ -14082,8 +14138,8 @@ func (ec *executionContext) _ClipComment(ctx context.Context, sel ast.SelectionS if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } - case "authorId": - out.Values[i] = ec._ClipComment_authorId(ctx, field, obj) + case "author": + out.Values[i] = ec._ClipComment_author(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } diff --git a/internal/http/graph/schema.graphql b/internal/http/graph/schema.graphql index 36605e3..ae068fa 100644 --- a/internal/http/graph/schema.graphql +++ b/internal/http/graph/schema.graphql @@ -173,17 +173,17 @@ type MarkNotificationReadResult { # Клип type Clip { - id: Int! # Уникальный идентификатор - title: String! # Заголовок клипа - videoUrl: String! # URL видео - thumbnailUrl: String! # URL превью - duration: Int! # Длительность в секундах - authorId: Int! # ID автора клипа - commentsCount: Int! # Количество комментариев - likesCount: Int! # Количество лайков - isLiked: Boolean! # Лайкнул ли текущий пользователь - createdAt: String! # Дата создания - updatedAt: String! # Дата обновления + id: Int! + title: String! + videoUrl: String! + thumbnailUrl: String! + duration: Int! + author: User! + commentsCount: Int! + likesCount: Int! + isLiked: Boolean! + createdAt: String! + updatedAt: String! } # Лайк клипа @@ -196,12 +196,12 @@ type ClipLike { # Комментарий к клипу type ClipComment { - id: Int! # Уникальный идентификатор - clipId: Int! # ID клипа - authorId: Int! # ID автора комментария - content: String! # Текст комментария - createdAt: String! # Дата создания - updatedAt: String! # Дата обновления + id: Int! + clipId: Int! + author: User! + content: String! + createdAt: String! + updatedAt: String! } scalar Upload