From 13ed346ba1f659040b2271f8e136444ad0bd56bd Mon Sep 17 00:00:00 2001 From: Daniel Veenstra Date: Sat, 5 Dec 2020 13:07:33 -0600 Subject: [PATCH 1/2] graphql side of adding userRelationships entity --- database/userRelationship.go | 20 ++ graph/Follow.go | 28 ++ graph/generated/generated.go | 570 +++++++++++++++++++++++++++++++++++ graph/model/models_gen.go | 12 + graph/schema.graphql | 16 + graph/schema.resolvers.go | 25 ++ pagination/pageables_gen.go | 2 +- wellinformed.go | 6 + 8 files changed, 678 insertions(+), 1 deletion(-) create mode 100644 database/userRelationship.go create mode 100644 graph/Follow.go diff --git a/database/userRelationship.go b/database/userRelationship.go new file mode 100644 index 0000000..2c5a5ef --- /dev/null +++ b/database/userRelationship.go @@ -0,0 +1,20 @@ +package database + +import ( + "errors" + + "github.com/well-informed/wellinformed/graph/model" +) + +func (db DB) SaveUserRelationship(followerID int64, followeeID int64) (*model.UserRelationship, error) { + return nil, errors.New("not implemented") +} +func (db DB) DeleteUserRelationship(followerID int64, followeeID int64) error { + return errors.New("not implemented") +} +func (db DB) ListUserRelationshipsByFollowerID(followerID int64) ([]*model.UserRelationship, error) { + return nil, errors.New("not implemented") +} +func (db DB) ListUserRelationshipsByFolloweeID(followeeID int64) ([]*model.UserRelationship, error) { + return nil, errors.New("not implemented") +} diff --git a/graph/Follow.go b/graph/Follow.go new file mode 100644 index 0000000..9f5bb73 --- /dev/null +++ b/graph/Follow.go @@ -0,0 +1,28 @@ +package graph + +import ( + "context" + "errors" + + log "github.com/sirupsen/logrus" + "github.com/well-informed/wellinformed/graph/model" +) + +func (r *mutationResolver) followUser(ctx context.Context, user *model.User, input model.UserRelationshipInput) (*model.UserRelationship, error) { + if user.ID != input.FollowerID { + return nil, errors.New("follower must be signed in user") + } + return r.DB.SaveUserRelationship(input.FollowerID, input.FolloweeID) +} + +func (r *mutationResolver) unfollowUser(ctx context.Context, user *model.User, input model.UserRelationshipInput) (*model.DeleteResponse, error) { + if user.ID != input.FollowerID { + return &model.DeleteResponse{Ok: false}, errors.New("follower must be signed in user") + } + err := r.DB.DeleteUserRelationship(input.FollowerID, input.FolloweeID) + if err != nil { + log.Error("unable to delete user relationship") + return &model.DeleteResponse{Ok: false}, err + } + return &model.DeleteResponse{Ok: true}, nil +} diff --git a/graph/generated/generated.go b/graph/generated/generated.go index f90f169..888660d 100644 --- a/graph/generated/generated.go +++ b/graph/generated/generated.go @@ -155,11 +155,13 @@ type ComplexityRoot struct { AddSrcRSSFeed func(childComplexity int, feedLink string, targetFeedID int64) int AddUserFeed func(childComplexity int, input model.AddUserFeedInput) int DeleteSubscription func(childComplexity int, srcRssfeedID int64) int + FollowUser func(childComplexity int, input model.UserRelationshipInput) int Login func(childComplexity int, input model.LoginInput) int Register func(childComplexity int, input model.RegisterInput) int SaveEngine func(childComplexity int, engine model.EngineInput) int SaveInteraction func(childComplexity int, input *model.InteractionInput) int SwitchActiveUserFeed func(childComplexity int, feedID int64) int + UnfollowUser func(childComplexity int, input model.UserRelationshipInput) int } Query struct { @@ -211,6 +213,8 @@ type ComplexityRoot struct { Feed func(childComplexity int) int Feeds func(childComplexity int) int Firstname func(childComplexity int) int + Followers func(childComplexity int) int + Follows func(childComplexity int) int ID func(childComplexity int) int Interactions func(childComplexity int, readState *model.ReadState, input model.InteractionConnectionInput) int Lastname func(childComplexity int) int @@ -233,6 +237,13 @@ type ComplexityRoot struct { UserID func(childComplexity int) int } + UserRelationship struct { + CreatedAt func(childComplexity int) int + Followee func(childComplexity int) int + Follower func(childComplexity int) int + ID func(childComplexity int) int + } + UserSubscription struct { CreatedAt func(childComplexity int) int ID func(childComplexity int) int @@ -282,6 +293,8 @@ type MutationResolver interface { SaveInteraction(ctx context.Context, input *model.InteractionInput) (*model.ContentItem, error) SaveEngine(ctx context.Context, engine model.EngineInput) (*model.Engine, error) SwitchActiveUserFeed(ctx context.Context, feedID int64) (*model.User, error) + FollowUser(ctx context.Context, input model.UserRelationshipInput) (*model.UserRelationship, error) + UnfollowUser(ctx context.Context, input model.UserRelationshipInput) (*model.DeleteResponse, error) } type QueryResolver interface { SrcRSSFeed(ctx context.Context, input *model.SrcRSSFeedInput) (*model.SrcRSSFeed, error) @@ -305,6 +318,8 @@ type UserResolver interface { Subscriptions(ctx context.Context, obj *model.User, input *model.UserSubscriptionConnectionInput) (*model.UserSubscriptionConnection, error) Interactions(ctx context.Context, obj *model.User, readState *model.ReadState, input model.InteractionConnectionInput) (*model.InteractionConnection, error) + Follows(ctx context.Context, obj *model.User) ([]*model.User, error) + Followers(ctx context.Context, obj *model.User) ([]*model.User, error) } type UserFeedResolver interface { User(ctx context.Context, obj *model.UserFeed) (*model.User, error) @@ -793,6 +808,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.DeleteSubscription(childComplexity, args["srcRSSFeedID"].(int64)), true + case "Mutation.followUser": + if e.complexity.Mutation.FollowUser == nil { + break + } + + args, err := ec.field_Mutation_followUser_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.FollowUser(childComplexity, args["input"].(model.UserRelationshipInput)), true + case "Mutation.login": if e.complexity.Mutation.Login == nil { break @@ -853,6 +880,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.SwitchActiveUserFeed(childComplexity, args["feedID"].(int64)), true + case "Mutation.unfollowUser": + if e.complexity.Mutation.UnfollowUser == nil { + break + } + + args, err := ec.field_Mutation_unfollowUser_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UnfollowUser(childComplexity, args["input"].(model.UserRelationshipInput)), true + case "Query.engines": if e.complexity.Query.Engines == nil { break @@ -1114,6 +1153,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.User.Firstname(childComplexity), true + case "User.followers": + if e.complexity.User.Followers == nil { + break + } + + return e.complexity.User.Followers(childComplexity), true + + case "User.follows": + if e.complexity.User.Follows == nil { + break + } + + return e.complexity.User.Follows(childComplexity), true + case "User.id": if e.complexity.User.ID == nil { break @@ -1253,6 +1306,34 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.UserFeed.UserID(childComplexity), true + case "UserRelationship.createdAt": + if e.complexity.UserRelationship.CreatedAt == nil { + break + } + + return e.complexity.UserRelationship.CreatedAt(childComplexity), true + + case "UserRelationship.followee": + if e.complexity.UserRelationship.Followee == nil { + break + } + + return e.complexity.UserRelationship.Followee(childComplexity), true + + case "UserRelationship.follower": + if e.complexity.UserRelationship.Follower == nil { + break + } + + return e.complexity.UserRelationship.Follower(childComplexity), true + + case "UserRelationship.id": + if e.complexity.UserRelationship.ID == nil { + break + } + + return e.complexity.UserRelationship.ID(childComplexity), true + case "UserSubscription.createdAt": if e.complexity.UserSubscription.CreatedAt == nil { break @@ -1523,6 +1604,8 @@ type User { updatedAt: Time! subscriptions(input: UserSubscriptionConnectionInput): UserSubscriptionConnection! interactions(readState: ReadState, input: InteractionConnectionInput!): InteractionConnection! + follows: [User!]! + followers: [User!]! } enum sortType { @@ -1553,6 +1636,18 @@ enum ReadState { unread } +type UserRelationship { + id: ID! + follower: User! + followee: User! + createdAt: Time! +} + +input UserRelationshipInput { + followerID: ID! + followeeID: ID! +} + input InteractionInput { contentItemID: ID! readState: ReadState! @@ -1715,6 +1810,8 @@ type Mutation { saveInteraction(input: InteractionInput): ContentItem! saveEngine(engine: EngineInput!): Engine! switchActiveUserFeed(feedID: ID!): User! + followUser(input: UserRelationshipInput!): UserRelationship! + unfollowUser(input: UserRelationshipInput!): DeleteResponse! } `, BuiltIn: false}, } @@ -1802,6 +1899,20 @@ func (ec *executionContext) field_Mutation_deleteSubscription_args(ctx context.C return args, nil } +func (ec *executionContext) field_Mutation_followUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.UserRelationshipInput + if tmp, ok := rawArgs["input"]; ok { + arg0, err = ec.unmarshalNUserRelationshipInput2githubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserRelationshipInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_login_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1872,6 +1983,20 @@ func (ec *executionContext) field_Mutation_switchActiveUserFeed_args(ctx context return args, nil } +func (ec *executionContext) field_Mutation_unfollowUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.UserRelationshipInput + if tmp, ok := rawArgs["input"]; ok { + arg0, err = ec.unmarshalNUserRelationshipInput2githubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserRelationshipInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -4388,6 +4513,88 @@ func (ec *executionContext) _Mutation_switchActiveUserFeed(ctx context.Context, return ec.marshalNUser2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation_followUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_followUser_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().FollowUser(rctx, args["input"].(model.UserRelationshipInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.UserRelationship) + fc.Result = res + return ec.marshalNUserRelationship2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserRelationship(ctx, field.Selections, res) +} + +func (ec *executionContext) _Mutation_unfollowUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_unfollowUser_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().UnfollowUser(rctx, args["input"].(model.UserRelationshipInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.DeleteResponse) + fc.Result = res + return ec.marshalNDeleteResponse2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐDeleteResponse(ctx, field.Selections, res) +} + func (ec *executionContext) _Query_srcRSSFeed(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -5902,6 +6109,74 @@ func (ec *executionContext) _User_interactions(ctx context.Context, field graphq return ec.marshalNInteractionConnection2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐInteractionConnection(ctx, field.Selections, res) } +func (ec *executionContext) _User_follows(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "User", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.User().Follows(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.User) + fc.Result = res + return ec.marshalNUser2ᚕᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _User_followers(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "User", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.User().Followers(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.User) + fc.Result = res + return ec.marshalNUser2ᚕᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserᚄ(ctx, field.Selections, res) +} + func (ec *executionContext) _UserFeed_id(ctx context.Context, field graphql.CollectedField, obj *model.UserFeed) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -6212,6 +6487,142 @@ func (ec *executionContext) _UserFeed_isActive(ctx context.Context, field graphq return ec.marshalNBoolean2bool(ctx, field.Selections, res) } +func (ec *executionContext) _UserRelationship_id(ctx context.Context, field graphql.CollectedField, obj *model.UserRelationship) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "UserRelationship", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNID2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) _UserRelationship_follower(ctx context.Context, field graphql.CollectedField, obj *model.UserRelationship) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "UserRelationship", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Follower, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) _UserRelationship_followee(ctx context.Context, field graphql.CollectedField, obj *model.UserRelationship) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "UserRelationship", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Followee, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) _UserRelationship_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.UserRelationship) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "UserRelationship", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CreatedAt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + func (ec *executionContext) _UserSubscription_id(ctx context.Context, field graphql.CollectedField, obj *model.UserSubscription) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -8059,6 +8470,30 @@ func (ec *executionContext) unmarshalInputUserInteractionsInput(ctx context.Cont return it, nil } +func (ec *executionContext) unmarshalInputUserRelationshipInput(ctx context.Context, obj interface{}) (model.UserRelationshipInput, error) { + var it model.UserRelationshipInput + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "followerID": + var err error + it.FollowerID, err = ec.unmarshalNID2int64(ctx, v) + if err != nil { + return it, err + } + case "followeeID": + var err error + it.FolloweeID, err = ec.unmarshalNID2int64(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputUserSubscriptionConnectionInput(ctx context.Context, obj interface{}) (model.UserSubscriptionConnectionInput, error) { var it model.UserSubscriptionConnectionInput var asMap = obj.(map[string]interface{}) @@ -8774,6 +9209,16 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } + case "followUser": + out.Values[i] = ec._Mutation_followUser(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } + case "unfollowUser": + out.Values[i] = ec._Mutation_unfollowUser(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -9251,6 +9696,34 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj } return res }) + case "follows": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._User_follows(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) + case "followers": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._User_followers(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -9371,6 +9844,48 @@ func (ec *executionContext) _UserFeed(ctx context.Context, sel ast.SelectionSet, return out } +var userRelationshipImplementors = []string{"UserRelationship"} + +func (ec *executionContext) _UserRelationship(ctx context.Context, sel ast.SelectionSet, obj *model.UserRelationship) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, userRelationshipImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("UserRelationship") + case "id": + out.Values[i] = ec._UserRelationship_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "follower": + out.Values[i] = ec._UserRelationship_follower(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "followee": + out.Values[i] = ec._UserRelationship_followee(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "createdAt": + out.Values[i] = ec._UserRelationship_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var userSubscriptionImplementors = []string{"UserSubscription"} func (ec *executionContext) _UserSubscription(ctx context.Context, sel ast.SelectionSet, obj *model.UserSubscription) graphql.Marshaler { @@ -10330,6 +10845,43 @@ func (ec *executionContext) marshalNUser2githubᚗcomᚋwellᚑinformedᚋwellin return ec._User(ctx, sel, &v) } +func (ec *executionContext) marshalNUser2ᚕᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.User) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNUser2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUser(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + func (ec *executionContext) marshalNUser2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -10391,6 +10943,24 @@ func (ec *executionContext) marshalNUserFeed2ᚖgithubᚗcomᚋwellᚑinformed return ec._UserFeed(ctx, sel, v) } +func (ec *executionContext) marshalNUserRelationship2githubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserRelationship(ctx context.Context, sel ast.SelectionSet, v model.UserRelationship) graphql.Marshaler { + return ec._UserRelationship(ctx, sel, &v) +} + +func (ec *executionContext) marshalNUserRelationship2ᚖgithubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserRelationship(ctx context.Context, sel ast.SelectionSet, v *model.UserRelationship) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._UserRelationship(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNUserRelationshipInput2githubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserRelationshipInput(ctx context.Context, v interface{}) (model.UserRelationshipInput, error) { + return ec.unmarshalInputUserRelationshipInput(ctx, v) +} + func (ec *executionContext) marshalNUserSubscription2githubᚗcomᚋwellᚑinformedᚋwellinformedᚋgraphᚋmodelᚐUserSubscription(ctx context.Context, sel ast.SelectionSet, v model.UserSubscription) graphql.Marshaler { return ec._UserSubscription(ctx, sel, &v) } diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go index 2d14f05..f2641bb 100644 --- a/graph/model/models_gen.go +++ b/graph/model/models_gen.go @@ -158,6 +158,18 @@ type UserInteractionsInput struct { ReadState *ReadState `json:"readState"` } +type UserRelationship struct { + ID int64 `json:"id"` + Follower *User `json:"follower"` + Followee *User `json:"followee"` + CreatedAt time.Time `json:"createdAt"` +} + +type UserRelationshipInput struct { + FollowerID int64 `json:"followerID"` + FolloweeID int64 `json:"followeeID"` +} + type UserSubscriptionConnection struct { Edges []*UserSubscriptionEdge `json:"edges"` PageInfo *UserSubscriptionPageInfo `json:"pageInfo"` diff --git a/graph/schema.graphql b/graph/schema.graphql index c200bb7..7fbf79a 100644 --- a/graph/schema.graphql +++ b/graph/schema.graphql @@ -120,6 +120,8 @@ type User { updatedAt: Time! subscriptions(input: UserSubscriptionConnectionInput): UserSubscriptionConnection! interactions(readState: ReadState, input: InteractionConnectionInput!): InteractionConnection! + follows: [User!]! + followers: [User!]! } enum sortType { @@ -150,6 +152,18 @@ enum ReadState { unread } +type UserRelationship { + id: ID! + follower: User! + followee: User! + createdAt: Time! +} + +input UserRelationshipInput { + followerID: ID! + followeeID: ID! +} + input InteractionInput { contentItemID: ID! readState: ReadState! @@ -312,4 +326,6 @@ type Mutation { saveInteraction(input: InteractionInput): ContentItem! saveEngine(engine: EngineInput!): Engine! switchActiveUserFeed(feedID: ID!): User! + followUser(input: UserRelationshipInput!): UserRelationship! + unfollowUser(input: UserRelationshipInput!): DeleteResponse! } diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go index a7393de..0677180 100644 --- a/graph/schema.resolvers.go +++ b/graph/schema.resolvers.go @@ -6,6 +6,7 @@ package graph import ( "context" "errors" + "fmt" log "github.com/sirupsen/logrus" "github.com/well-informed/wellinformed/auth" @@ -179,6 +180,22 @@ func (r *mutationResolver) SwitchActiveUserFeed(ctx context.Context, feedID int6 return user, nil } +func (r *mutationResolver) FollowUser(ctx context.Context, input model.UserRelationshipInput) (*model.UserRelationship, error) { + user, err := auth.GetCurrentUserFromCTX(ctx) + if err != nil { + return nil, err + } + return r.followUser(ctx, user, input) +} + +func (r *mutationResolver) UnfollowUser(ctx context.Context, input model.UserRelationshipInput) (*model.DeleteResponse, error) { + user, err := auth.GetCurrentUserFromCTX(ctx) + if err != nil { + return nil, err + } + return r.unfollowUser(ctx, user, input) +} + func (r *queryResolver) SrcRSSFeed(ctx context.Context, input *model.SrcRSSFeedInput) (*model.SrcRSSFeed, error) { _, err := auth.GetCurrentUserFromCTX(ctx) if err != nil { @@ -361,6 +378,14 @@ func (r *userResolver) Interactions(ctx context.Context, obj *model.User, readSt return page.BuildInteractionPage(input.First, input.After, interactions) } +func (r *userResolver) Follows(ctx context.Context, obj *model.User) ([]*model.User, error) { + panic(fmt.Errorf("not implemented")) +} + +func (r *userResolver) Followers(ctx context.Context, obj *model.User) ([]*model.User, error) { + panic(fmt.Errorf("not implemented")) +} + func (r *userFeedResolver) User(ctx context.Context, obj *model.UserFeed) (*model.User, error) { return r.DB.GetUserByID(obj.UserID) } diff --git a/pagination/pageables_gen.go b/pagination/pageables_gen.go index 90f3b88..5db396f 100644 --- a/pagination/pageables_gen.go +++ b/pagination/pageables_gen.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated from "pagination/generator/pageables_generator.go" at -// 2020-12-01 17:33:16.325533 -0600 CST m=+0.002081577 +// 2020-12-04 19:18:27.459236 -0600 CST m=+0.001864646 // using types listed in "pagination/generator/pageables.yml" package pagination diff --git a/wellinformed.go b/wellinformed.go index 7d28ff0..399f5c7 100644 --- a/wellinformed.go +++ b/wellinformed.go @@ -58,6 +58,12 @@ type Persistor interface { // FeedSubscription CreateFeedSubscription(feedID int64, sourceID int64, sourceType model.SourceType) (*model.FeedSubscription, error) ListFeedSubscriptionsByFeedID(feedID int64) ([]*model.FeedSubscription, error) + + //UserRelationship + SaveUserRelationship(followerID int64, followeeID int64) (*model.UserRelationship, error) + DeleteUserRelationship(followerID int64, followeeID int64) error + ListUserRelationshipsByFollowerID(followerID int64) ([]*model.UserRelationship, error) + ListUserRelationshipsByFolloweeID(followeeID int64) ([]*model.UserRelationship, error) } type RSS interface { From a1fe6dd2b86f4b2b011ec7cb428e9ff3a626884b Mon Sep 17 00:00:00 2001 From: Daniel Veenstra Date: Tue, 19 Jan 2021 17:56:18 -0600 Subject: [PATCH 2/2] added userRelationships entity to record follower/followee status among users. added listable followers and follows fields on User --- .../000007_create_user_relationships.down.sql | 1 + .../000007_create_user_relationships.up.sql | 9 ++ database/userRelationship.go | 70 ++++++++++++- graph/generated/generated.go | 99 ++++++++++++++++--- graph/model/model.go | 8 ++ graph/model/models_gen.go | 7 -- graph/schema.graphql | 1 + graph/schema.resolvers.go | 49 ++++++++- pagination/generator/pageables.yml | 1 - pagination/pageables_gen.go | 2 +- 10 files changed, 216 insertions(+), 31 deletions(-) create mode 100644 database/migrations/000007_create_user_relationships.down.sql create mode 100644 database/migrations/000007_create_user_relationships.up.sql diff --git a/database/migrations/000007_create_user_relationships.down.sql b/database/migrations/000007_create_user_relationships.down.sql new file mode 100644 index 0000000..afc7697 --- /dev/null +++ b/database/migrations/000007_create_user_relationships.down.sql @@ -0,0 +1 @@ +DROP TABLE user_relationships; \ No newline at end of file diff --git a/database/migrations/000007_create_user_relationships.up.sql b/database/migrations/000007_create_user_relationships.up.sql new file mode 100644 index 0000000..4aa92f9 --- /dev/null +++ b/database/migrations/000007_create_user_relationships.up.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS user_relationships +( + id BIGSERIAL PRIMARY KEY, + follower_id int REFERENCES users(id), + followee_id int REFERENCES users(id), + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + UNIQUE(follower_id, followee_id) +); \ No newline at end of file diff --git a/database/userRelationship.go b/database/userRelationship.go index 2c5a5ef..c76b644 100644 --- a/database/userRelationship.go +++ b/database/userRelationship.go @@ -1,20 +1,80 @@ package database import ( - "errors" + "time" + log "github.com/sirupsen/logrus" "github.com/well-informed/wellinformed/graph/model" ) func (db DB) SaveUserRelationship(followerID int64, followeeID int64) (*model.UserRelationship, error) { - return nil, errors.New("not implemented") + stmt := `INSERT INTO user_relationships + ( + follower_id, + followee_id, + created_at, + updated_at + ) + VALUES($1, $2, $3, $4) + ON CONFLICT (follower_id, followee_id) + DO UPDATE SET + follower_id = $1, + followee_id = $2, + updated_at = $3 + RETURNING id, created_at, updated_at` + var ID int64 + var CreatedAt time.Time + var UpdatedAt time.Time + err := db.QueryRowx(stmt, + followerID, + followeeID, + time.Now(), + time.Now(), + ).Scan(&ID, &CreatedAt, &UpdatedAt) + if err != nil { + log.Error("failed to save interactions entry: err: ", err) + return nil, err + } + userRelationship := &model.UserRelationship{ + ID: ID, + Follower: followerID, + Followee: followeeID, + CreatedAt: CreatedAt, + UpdatedAt: UpdatedAt, + } + return userRelationship, nil } + func (db DB) DeleteUserRelationship(followerID int64, followeeID int64) error { - return errors.New("not implemented") + stmt := `DELETE FROM user_relationships WHERE follower_id = $1 AND followee_id = $2` + _, err := db.Exec(stmt, followerID, followeeID) + if err != nil { + log.Error("unable to delete user relationship", err) + return err + } + return nil } + func (db DB) ListUserRelationshipsByFollowerID(followerID int64) ([]*model.UserRelationship, error) { - return nil, errors.New("not implemented") + stmt := `SELECT * FROM user_relationships WHERE follower_id = $1` + + userRelationships := make([]*model.UserRelationship, 0) + err := db.Select(&userRelationships, stmt, followerID) + if err != nil { + log.Error("error listing relationships by follower ID", err) + return nil, err + } + return userRelationships, nil } + func (db DB) ListUserRelationshipsByFolloweeID(followeeID int64) ([]*model.UserRelationship, error) { - return nil, errors.New("not implemented") + stmt := `SELECT * FROM user_relationships WHERE followee_id = $1` + + userRelationships := make([]*model.UserRelationship, 0) + err := db.Select(&userRelationships, stmt, followeeID) + if err != nil { + log.Error("error listing relationships by followee ID", err) + return nil, err + } + return userRelationships, nil } diff --git a/graph/generated/generated.go b/graph/generated/generated.go index 6fb7055..08bfffd 100644 --- a/graph/generated/generated.go +++ b/graph/generated/generated.go @@ -46,6 +46,7 @@ type ResolverRoot interface { SrcRSSFeed() SrcRSSFeedResolver User() UserResolver UserFeed() UserFeedResolver + UserRelationship() UserRelationshipResolver UserSubscription() UserSubscriptionResolver } @@ -242,6 +243,7 @@ type ComplexityRoot struct { Followee func(childComplexity int) int Follower func(childComplexity int) int ID func(childComplexity int) int + UpdatedAt func(childComplexity int) int } UserSubscription struct { @@ -329,6 +331,10 @@ type UserFeedResolver interface { Engine(ctx context.Context, obj *model.UserFeed) (*model.Engine, error) IsActive(ctx context.Context, obj *model.UserFeed) (bool, error) } +type UserRelationshipResolver interface { + Follower(ctx context.Context, obj *model.UserRelationship) (*model.User, error) + Followee(ctx context.Context, obj *model.UserRelationship) (*model.User, error) +} type UserSubscriptionResolver interface { User(ctx context.Context, obj *model.UserSubscription) (*model.User, error) SrcRSSFeed(ctx context.Context, obj *model.UserSubscription) (*model.SrcRSSFeed, error) @@ -1334,6 +1340,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.UserRelationship.ID(childComplexity), true + case "UserRelationship.updatedAt": + if e.complexity.UserRelationship.UpdatedAt == nil { + break + } + + return e.complexity.UserRelationship.UpdatedAt(childComplexity), true + case "UserSubscription.createdAt": if e.complexity.UserSubscription.CreatedAt == nil { break @@ -1641,6 +1654,7 @@ type UserRelationship { follower: User! followee: User! createdAt: Time! + updatedAt: Time! } input UserRelationshipInput { @@ -6532,13 +6546,13 @@ func (ec *executionContext) _UserRelationship_follower(ctx context.Context, fiel Object: "UserRelationship", Field: field, Args: nil, - IsMethod: false, + IsMethod: true, } ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Follower, nil + return ec.resolvers.UserRelationship().Follower(rctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -6566,13 +6580,13 @@ func (ec *executionContext) _UserRelationship_followee(ctx context.Context, fiel Object: "UserRelationship", Field: field, Args: nil, - IsMethod: false, + IsMethod: true, } ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Followee, nil + return ec.resolvers.UserRelationship().Followee(rctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -6623,6 +6637,40 @@ func (ec *executionContext) _UserRelationship_createdAt(ctx context.Context, fie return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) } +func (ec *executionContext) _UserRelationship_updatedAt(ctx context.Context, field graphql.CollectedField, obj *model.UserRelationship) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "UserRelationship", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.UpdatedAt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + func (ec *executionContext) _UserSubscription_id(ctx context.Context, field graphql.CollectedField, obj *model.UserSubscription) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -9858,22 +9906,45 @@ func (ec *executionContext) _UserRelationship(ctx context.Context, sel ast.Selec case "id": out.Values[i] = ec._UserRelationship_id(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "follower": - out.Values[i] = ec._UserRelationship_follower(ctx, field, obj) - if out.Values[i] == graphql.Null { - invalids++ - } + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._UserRelationship_follower(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) case "followee": - out.Values[i] = ec._UserRelationship_followee(ctx, field, obj) - if out.Values[i] == graphql.Null { - invalids++ - } + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._UserRelationship_followee(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) case "createdAt": out.Values[i] = ec._UserRelationship_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) + } + case "updatedAt": + out.Values[i] = ec._UserRelationship_updatedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) } default: panic("unknown field " + strconv.Quote(field.Name)) diff --git a/graph/model/model.go b/graph/model/model.go index bf08324..87272cb 100644 --- a/graph/model/model.go +++ b/graph/model/model.go @@ -97,3 +97,11 @@ type Interaction struct { CreatedAt time.Time `json:"createdAt" db:"created_at"` UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` } + +type UserRelationship struct { + ID int64 `json:"id"` + Follower int64 `json:"follower" db:"follower_id"` + Followee int64 `json:"followee" db:"followee_id"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + UpdatedAt time.Time `json:"updatedAt" db:"updated_at"` +} diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go index f2641bb..6258c6f 100644 --- a/graph/model/models_gen.go +++ b/graph/model/models_gen.go @@ -158,13 +158,6 @@ type UserInteractionsInput struct { ReadState *ReadState `json:"readState"` } -type UserRelationship struct { - ID int64 `json:"id"` - Follower *User `json:"follower"` - Followee *User `json:"followee"` - CreatedAt time.Time `json:"createdAt"` -} - type UserRelationshipInput struct { FollowerID int64 `json:"followerID"` FolloweeID int64 `json:"followeeID"` diff --git a/graph/schema.graphql b/graph/schema.graphql index 7fbf79a..23c10e9 100644 --- a/graph/schema.graphql +++ b/graph/schema.graphql @@ -157,6 +157,7 @@ type UserRelationship { follower: User! followee: User! createdAt: Time! + updatedAt: Time! } input UserRelationshipInput { diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go index 0677180..38d1aa9 100644 --- a/graph/schema.resolvers.go +++ b/graph/schema.resolvers.go @@ -6,7 +6,6 @@ package graph import ( "context" "errors" - "fmt" log "github.com/sirupsen/logrus" "github.com/well-informed/wellinformed/auth" @@ -379,11 +378,41 @@ func (r *userResolver) Interactions(ctx context.Context, obj *model.User, readSt } func (r *userResolver) Follows(ctx context.Context, obj *model.User) ([]*model.User, error) { - panic(fmt.Errorf("not implemented")) + userRelationships, err := r.DB.ListUserRelationshipsByFollowerID(obj.ID) + if err != nil { + log.Errorf("error while reading user relationships. err: ", err) + } + users := make([]*model.User, 0) + if len(userRelationships) != 0 { + for _, relationship := range userRelationships { + user, err := r.DB.GetUserByID(relationship.Followee) + if err != nil { + log.Error("could not retrieve users to compile follows list", err) + return nil, err + } + users = append(users, user) + } + } + return users, nil } func (r *userResolver) Followers(ctx context.Context, obj *model.User) ([]*model.User, error) { - panic(fmt.Errorf("not implemented")) + userRelationships, err := r.DB.ListUserRelationshipsByFolloweeID(obj.ID) + if err != nil { + log.Errorf("could not list followers for id %v. err: %v", obj.ID, err) + } + followers := make([]*model.User, 0) + if len(userRelationships) != 0 { + for _, relationship := range userRelationships { + follower, err := r.DB.GetUserByID(relationship.Follower) + if err != nil { + log.Error("could not retrieve user for followers list: ", err) + return nil, err + } + followers = append(followers, follower) + } + } + return followers, nil } func (r *userFeedResolver) User(ctx context.Context, obj *model.UserFeed) (*model.User, error) { @@ -418,6 +447,14 @@ func (r *userFeedResolver) IsActive(ctx context.Context, obj *model.UserFeed) (b return false, nil } +func (r *userRelationshipResolver) Follower(ctx context.Context, obj *model.UserRelationship) (*model.User, error) { + return r.DB.GetUserByID(obj.Follower) +} + +func (r *userRelationshipResolver) Followee(ctx context.Context, obj *model.UserRelationship) (*model.User, error) { + return r.DB.GetUserByID(obj.Followee) +} + func (r *userSubscriptionResolver) User(ctx context.Context, obj *model.UserSubscription) (*model.User, error) { user, err := r.DB.GetUserByID(obj.UserID) if err != nil { @@ -466,6 +503,11 @@ func (r *Resolver) User() generated.UserResolver { return &userResolver{r} } // UserFeed returns generated.UserFeedResolver implementation. func (r *Resolver) UserFeed() generated.UserFeedResolver { return &userFeedResolver{r} } +// UserRelationship returns generated.UserRelationshipResolver implementation. +func (r *Resolver) UserRelationship() generated.UserRelationshipResolver { + return &userRelationshipResolver{r} +} + // UserSubscription returns generated.UserSubscriptionResolver implementation. func (r *Resolver) UserSubscription() generated.UserSubscriptionResolver { return &userSubscriptionResolver{r} @@ -480,4 +522,5 @@ type queryResolver struct{ *Resolver } type srcRSSFeedResolver struct{ *Resolver } type userResolver struct{ *Resolver } type userFeedResolver struct{ *Resolver } +type userRelationshipResolver struct{ *Resolver } type userSubscriptionResolver struct{ *Resolver } diff --git a/pagination/generator/pageables.yml b/pagination/generator/pageables.yml index 91224d9..63025ab 100644 --- a/pagination/generator/pageables.yml +++ b/pagination/generator/pageables.yml @@ -3,4 +3,3 @@ types: - "ContentItem" - "SrcRSSFeed" - "UserSubscription" - \ No newline at end of file diff --git a/pagination/pageables_gen.go b/pagination/pageables_gen.go index fb6f0dd..cd9c3fa 100644 --- a/pagination/pageables_gen.go +++ b/pagination/pageables_gen.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated from "pagination/generator/pageables_generator.go" at -// 2020-12-12 17:40:45.353208 -0600 CST m=+0.002004063 +// 2020-12-12 18:33:29.26955 -0600 CST m=+0.002548799 // using types listed in "pagination/generator/pageables.yml" package pagination