diff --git a/Makefile b/Makefile index f872a5d..e5c2934 100644 --- a/Makefile +++ b/Makefile @@ -13,4 +13,6 @@ go-generate: clean: docker-clean docker-clean: - docker container rm postgres-ozon-task-1 postgres-postgres-1 && docker volume rm postgres_postgres-data + -docker container rm postgres-ozon-task-1 postgres-postgres-1 standalone-ozon-task-1;\ + docker volume rm postgres_postgres-data;\ + docker network rm postgres_default standalone_defaul\ diff --git a/deployments/docker-compose/postgres/docker-compose.yml b/deployments/docker-compose/postgres/docker-compose.yml index 119a88f..b4fab78 100644 --- a/deployments/docker-compose/postgres/docker-compose.yml +++ b/deployments/docker-compose/postgres/docker-compose.yml @@ -13,7 +13,7 @@ services: env_file: postgres.env healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] - interval: 5s + interval: 1s timeout: 5s retries: 5 volumes: diff --git a/gqlgen.yml b/gqlgen.yml index 7dec225..052d563 100644 --- a/gqlgen.yml +++ b/gqlgen.yml @@ -1,6 +1,6 @@ # Where are all the schema files located? globs are supported eg src/**/*.graphqls schema: - - graph/*.graphqls + - graph/schema/*.graphqls # Where should the generated server code go? exec: @@ -75,14 +75,6 @@ autobind: # your liking models: ID: - model: - - github.com/99designs/gqlgen/graphql.ID - - github.com/99designs/gqlgen/graphql.Int - - github.com/99designs/gqlgen/graphql.Int64 - - github.com/99designs/gqlgen/graphql.Int32 - - github.com/99designs/gqlgen/graphql.Uint + model: github.com/99designs/gqlgen/graphql.Uint Int: - model: - - github.com/99designs/gqlgen/graphql.Int - - github.com/99designs/gqlgen/graphql.Int64 - - github.com/99designs/gqlgen/graphql.Int32 + model: github.com/99designs/gqlgen/graphql.Int diff --git a/graph/generated.go b/graph/generated.go index 864e4da..68193ca 100644 --- a/graph/generated.go +++ b/graph/generated.go @@ -39,7 +39,9 @@ type Config struct { } type ResolverRoot interface { + Comment() CommentResolver Mutation() MutationResolver + Post() PostResolver Query() QueryResolver } @@ -55,36 +57,70 @@ type ComplexityRoot struct { Author func(childComplexity int) int Contents func(childComplexity int) int ID func(childComplexity int) int - Post func(childComplexity int) int - Replies func(childComplexity int) int - ReplyTo func(childComplexity int) int + Replies func(childComplexity int, first uint, after uint) int + } + + CommentsConnection struct { + Edges func(childComplexity int) int + PageInfo func(childComplexity int) int + } + + CommentsEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int } Mutation struct { - AddComment func(childComplexity int, input *model.CommentInput) int - AddPost func(childComplexity int, input *model.PostInput) int + AddComment func(childComplexity int, input model.CommentInput) int + AddPost func(childComplexity int, input model.PostInput) int + } + + PageInfo struct { + EndCursor func(childComplexity int) int + HasNextPage func(childComplexity int) int + StartCursor func(childComplexity int) int } Post struct { AllowComments func(childComplexity int) int Author func(childComplexity int) int - Comments func(childComplexity int) int + Comments func(childComplexity int, first uint, after uint) int Contents func(childComplexity int) int ID func(childComplexity int) int Title func(childComplexity int) int } + PostsConnection struct { + Edges func(childComplexity int) int + PageInfo func(childComplexity int) int + } + + PostsEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int + } + Query struct { - AllPosts func(childComplexity int) int + Comment func(childComplexity int, id uint) int + Post func(childComplexity int, id uint) int + Posts func(childComplexity int, first uint, after uint) int } } +type CommentResolver interface { + Replies(ctx context.Context, obj *model.Comment, first uint, after uint) (*model.CommentsConnection, error) +} type MutationResolver interface { - AddPost(ctx context.Context, input *model.PostInput) (*model.AddResult, error) - AddComment(ctx context.Context, input *model.CommentInput) (*model.AddResult, error) + AddPost(ctx context.Context, input model.PostInput) (*model.AddResult, error) + AddComment(ctx context.Context, input model.CommentInput) (*model.AddResult, error) +} +type PostResolver interface { + Comments(ctx context.Context, obj *model.Post, first uint, after uint) (*model.CommentsConnection, error) } type QueryResolver interface { - AllPosts(ctx context.Context) ([]*model.Post, error) + Post(ctx context.Context, id uint) (*model.Post, error) + Posts(ctx context.Context, first uint, after uint) (*model.PostsConnection, error) + Comment(ctx context.Context, id uint) (*model.Comment, error) } type executableSchema struct { @@ -134,26 +170,45 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Comment.ID(childComplexity), true - case "Comment.post": - if e.complexity.Comment.Post == nil { - break - } - - return e.complexity.Comment.Post(childComplexity), true - case "Comment.replies": if e.complexity.Comment.Replies == nil { break } - return e.complexity.Comment.Replies(childComplexity), true + args, err := ec.field_Comment_replies_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } - case "Comment.replyTo": - if e.complexity.Comment.ReplyTo == nil { + return e.complexity.Comment.Replies(childComplexity, args["first"].(uint), args["after"].(uint)), true + + case "CommentsConnection.edges": + if e.complexity.CommentsConnection.Edges == nil { break } - return e.complexity.Comment.ReplyTo(childComplexity), true + return e.complexity.CommentsConnection.Edges(childComplexity), true + + case "CommentsConnection.pageInfo": + if e.complexity.CommentsConnection.PageInfo == nil { + break + } + + return e.complexity.CommentsConnection.PageInfo(childComplexity), true + + case "CommentsEdge.cursor": + if e.complexity.CommentsEdge.Cursor == nil { + break + } + + return e.complexity.CommentsEdge.Cursor(childComplexity), true + + case "CommentsEdge.node": + if e.complexity.CommentsEdge.Node == nil { + break + } + + return e.complexity.CommentsEdge.Node(childComplexity), true case "Mutation.addComment": if e.complexity.Mutation.AddComment == nil { @@ -165,7 +220,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Mutation.AddComment(childComplexity, args["input"].(*model.CommentInput)), true + return e.complexity.Mutation.AddComment(childComplexity, args["input"].(model.CommentInput)), true case "Mutation.addPost": if e.complexity.Mutation.AddPost == nil { @@ -177,7 +232,28 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Mutation.AddPost(childComplexity, args["input"].(*model.PostInput)), true + return e.complexity.Mutation.AddPost(childComplexity, args["input"].(model.PostInput)), true + + case "PageInfo.endCursor": + if e.complexity.PageInfo.EndCursor == nil { + break + } + + return e.complexity.PageInfo.EndCursor(childComplexity), true + + case "PageInfo.hasNextPage": + if e.complexity.PageInfo.HasNextPage == nil { + break + } + + return e.complexity.PageInfo.HasNextPage(childComplexity), true + + case "PageInfo.startCursor": + if e.complexity.PageInfo.StartCursor == nil { + break + } + + return e.complexity.PageInfo.StartCursor(childComplexity), true case "Post.allowComments": if e.complexity.Post.AllowComments == nil { @@ -198,7 +274,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - return e.complexity.Post.Comments(childComplexity), true + args, err := ec.field_Post_comments_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Post.Comments(childComplexity, args["first"].(uint), args["after"].(uint)), true case "Post.contents": if e.complexity.Post.Contents == nil { @@ -221,12 +302,69 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Post.Title(childComplexity), true - case "Query.allPosts": - if e.complexity.Query.AllPosts == nil { + case "PostsConnection.edges": + if e.complexity.PostsConnection.Edges == nil { break } - return e.complexity.Query.AllPosts(childComplexity), true + return e.complexity.PostsConnection.Edges(childComplexity), true + + case "PostsConnection.pageInfo": + if e.complexity.PostsConnection.PageInfo == nil { + break + } + + return e.complexity.PostsConnection.PageInfo(childComplexity), true + + case "PostsEdge.cursor": + if e.complexity.PostsEdge.Cursor == nil { + break + } + + return e.complexity.PostsEdge.Cursor(childComplexity), true + + case "PostsEdge.node": + if e.complexity.PostsEdge.Node == nil { + break + } + + return e.complexity.PostsEdge.Node(childComplexity), true + + case "Query.comment": + if e.complexity.Query.Comment == nil { + break + } + + args, err := ec.field_Query_comment_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Comment(childComplexity, args["id"].(uint)), true + + case "Query.post": + if e.complexity.Query.Post == nil { + break + } + + args, err := ec.field_Query_post_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Post(childComplexity, args["id"].(uint)), true + + case "Query.posts": + if e.complexity.Query.Posts == nil { + break + } + + args, err := ec.field_Query_posts_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Posts(childComplexity, args["first"].(uint), args["after"].(uint)), true } return 0, false @@ -334,7 +472,7 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil } -//go:embed "schema.graphqls" +//go:embed "schema/mutation.graphqls" "schema/pagination.graphqls" "schema/query.graphqls" var sourcesFS embed.FS func sourceData(filename string) string { @@ -346,7 +484,9 @@ func sourceData(filename string) string { } var sources = []*ast.Source{ - {Name: "schema.graphqls", Input: sourceData("schema.graphqls"), BuiltIn: false}, + {Name: "schema/mutation.graphqls", Input: sourceData("schema/mutation.graphqls"), BuiltIn: false}, + {Name: "schema/pagination.graphqls", Input: sourceData("schema/pagination.graphqls"), BuiltIn: false}, + {Name: "schema/query.graphqls", Input: sourceData("schema/query.graphqls"), BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) @@ -354,13 +494,37 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...) // region ***************************** args.gotpl ***************************** +func (ec *executionContext) field_Comment_replies_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 uint + if tmp, ok := rawArgs["first"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) + arg0, err = ec.unmarshalNID2uint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["first"] = arg0 + var arg1 uint + if tmp, ok := rawArgs["after"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + arg1, err = ec.unmarshalNID2uint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["after"] = arg1 + return args, nil +} + func (ec *executionContext) field_Mutation_addComment_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *model.CommentInput + var arg0 model.CommentInput if tmp, ok := rawArgs["input"]; ok { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg0, err = ec.unmarshalOCommentInput2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentInput(ctx, tmp) + arg0, err = ec.unmarshalNCommentInput2gitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentInput(ctx, tmp) if err != nil { return nil, err } @@ -372,10 +536,10 @@ func (ec *executionContext) field_Mutation_addComment_args(ctx context.Context, func (ec *executionContext) field_Mutation_addPost_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *model.PostInput + var arg0 model.PostInput if tmp, ok := rawArgs["input"]; ok { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg0, err = ec.unmarshalOPostInput2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostInput(ctx, tmp) + arg0, err = ec.unmarshalNPostInput2gitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostInput(ctx, tmp) if err != nil { return nil, err } @@ -384,6 +548,30 @@ func (ec *executionContext) field_Mutation_addPost_args(ctx context.Context, raw return args, nil } +func (ec *executionContext) field_Post_comments_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 uint + if tmp, ok := rawArgs["first"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) + arg0, err = ec.unmarshalNID2uint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["first"] = arg0 + var arg1 uint + if tmp, ok := rawArgs["after"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + arg1, err = ec.unmarshalNID2uint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["after"] = arg1 + 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{}{} @@ -399,6 +587,60 @@ func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs return args, nil } +func (ec *executionContext) field_Query_comment_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 uint + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2uint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_post_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 uint + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2uint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_posts_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 uint + if tmp, ok := rawArgs["first"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) + arg0, err = ec.unmarshalNID2uint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["first"] = arg0 + var arg1 uint + if tmp, ok := rawArgs["after"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + arg1, err = ec.unmarshalNID2uint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["after"] = arg1 + return args, nil +} + func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -525,64 +767,6 @@ func (ec *executionContext) fieldContext_Comment_id(_ context.Context, field gra return fc, nil } -func (ec *executionContext) _Comment_post(ctx context.Context, field graphql.CollectedField, obj *model.Comment) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Comment_post(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Post, 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.Post) - fc.Result = res - return ec.marshalNPost2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPost(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Comment_post(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Comment", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Post_id(ctx, field) - case "title": - return ec.fieldContext_Post_title(ctx, field) - case "author": - return ec.fieldContext_Post_author(ctx, field) - case "contents": - return ec.fieldContext_Post_contents(ctx, field) - case "comments": - return ec.fieldContext_Post_comments(ctx, field) - case "allowComments": - return ec.fieldContext_Post_allowComments(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Post", field.Name) - }, - } - return fc, nil -} - func (ec *executionContext) _Comment_author(ctx context.Context, field graphql.CollectedField, obj *model.Comment) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Comment_author(ctx, field) if err != nil { @@ -671,61 +855,6 @@ func (ec *executionContext) fieldContext_Comment_contents(_ context.Context, fie return fc, nil } -func (ec *executionContext) _Comment_replyTo(ctx context.Context, field graphql.CollectedField, obj *model.Comment) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Comment_replyTo(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.ReplyTo, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*model.Comment) - fc.Result = res - return ec.marshalOComment2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐComment(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Comment_replyTo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Comment", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Comment_id(ctx, field) - case "post": - return ec.fieldContext_Comment_post(ctx, field) - case "author": - return ec.fieldContext_Comment_author(ctx, field) - case "contents": - return ec.fieldContext_Comment_contents(ctx, field) - case "replyTo": - return ec.fieldContext_Comment_replyTo(ctx, field) - case "replies": - return ec.fieldContext_Comment_replies(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Comment", field.Name) - }, - } - return fc, nil -} - func (ec *executionContext) _Comment_replies(ctx context.Context, field graphql.CollectedField, obj *model.Comment) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Comment_replies(ctx, field) if err != nil { @@ -740,7 +869,7 @@ func (ec *executionContext) _Comment_replies(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Replies, nil + return ec.resolvers.Comment().Replies(rctx, obj, fc.Args["first"].(uint), fc.Args["after"].(uint)) }) if err != nil { ec.Error(ctx, err) @@ -752,29 +881,232 @@ func (ec *executionContext) _Comment_replies(ctx context.Context, field graphql. } return graphql.Null } - res := resTmp.([]*model.Comment) + res := resTmp.(*model.CommentsConnection) fc.Result = res - return ec.marshalNComment2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentᚄ(ctx, field.Selections, res) + return ec.marshalNCommentsConnection2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentsConnection(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Comment_replies(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Comment_replies(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Comment", Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "edges": + return ec.fieldContext_CommentsConnection_edges(ctx, field) + case "pageInfo": + return ec.fieldContext_CommentsConnection_pageInfo(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type CommentsConnection", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Comment_replies_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _CommentsConnection_edges(ctx context.Context, field graphql.CollectedField, obj *model.CommentsConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CommentsConnection_edges(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Edges, 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.CommentsEdge) + fc.Result = res + return ec.marshalNCommentsEdge2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentsEdgeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CommentsConnection_edges(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CommentsConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "cursor": + return ec.fieldContext_CommentsEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_CommentsEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type CommentsEdge", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _CommentsConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *model.CommentsConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CommentsConnection_pageInfo(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PageInfo, 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.PageInfo) + fc.Result = res + return ec.marshalNPageInfo2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CommentsConnection_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CommentsConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "startCursor": + return ec.fieldContext_PageInfo_startCursor(ctx, field) + case "endCursor": + return ec.fieldContext_PageInfo_endCursor(ctx, field) + case "hasNextPage": + return ec.fieldContext_PageInfo_hasNextPage(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _CommentsEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *model.CommentsEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CommentsEdge_cursor(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Cursor, 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.(uint) + fc.Result = res + return ec.marshalNID2uint(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CommentsEdge_cursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CommentsEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _CommentsEdge_node(ctx context.Context, field graphql.CollectedField, obj *model.CommentsEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CommentsEdge_node(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Node, 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.Comment) + fc.Result = res + return ec.marshalNComment2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐComment(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CommentsEdge_node(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CommentsEdge", + Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Comment_id(ctx, field) - case "post": - return ec.fieldContext_Comment_post(ctx, field) case "author": return ec.fieldContext_Comment_author(ctx, field) case "contents": return ec.fieldContext_Comment_contents(ctx, field) - case "replyTo": - return ec.fieldContext_Comment_replyTo(ctx, field) case "replies": return ec.fieldContext_Comment_replies(ctx, field) } @@ -798,7 +1130,7 @@ func (ec *executionContext) _Mutation_addPost(ctx context.Context, field graphql }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AddPost(rctx, fc.Args["input"].(*model.PostInput)) + return ec.resolvers.Mutation().AddPost(rctx, fc.Args["input"].(model.PostInput)) }) if err != nil { ec.Error(ctx, err) @@ -857,7 +1189,7 @@ func (ec *executionContext) _Mutation_addComment(ctx context.Context, field grap }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AddComment(rctx, fc.Args["input"].(*model.CommentInput)) + return ec.resolvers.Mutation().AddComment(rctx, fc.Args["input"].(model.CommentInput)) }) if err != nil { ec.Error(ctx, err) @@ -902,6 +1234,138 @@ func (ec *executionContext) fieldContext_Mutation_addComment(ctx context.Context return fc, nil } +func (ec *executionContext) _PageInfo_startCursor(ctx context.Context, field graphql.CollectedField, obj *model.PageInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PageInfo_startCursor(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.StartCursor, 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.(uint) + fc.Result = res + return ec.marshalNID2uint(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PageInfo_startCursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PageInfo", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PageInfo_endCursor(ctx context.Context, field graphql.CollectedField, obj *model.PageInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PageInfo_endCursor(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.EndCursor, 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.(uint) + fc.Result = res + return ec.marshalNID2uint(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PageInfo_endCursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PageInfo", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PageInfo_hasNextPage(ctx context.Context, field graphql.CollectedField, obj *model.PageInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PageInfo_hasNextPage(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.HasNextPage, 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.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PageInfo_hasNextPage(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PageInfo", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Post_id(ctx context.Context, field graphql.CollectedField, obj *model.Post) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Post_id(ctx, field) if err != nil { @@ -1092,7 +1556,7 @@ func (ec *executionContext) _Post_comments(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Comments, nil + return ec.resolvers.Post().Comments(rctx, obj, fc.Args["first"].(uint), fc.Args["after"].(uint)) }) if err != nil { ec.Error(ctx, err) @@ -1104,35 +1568,38 @@ func (ec *executionContext) _Post_comments(ctx context.Context, field graphql.Co } return graphql.Null } - res := resTmp.([]*model.Comment) + res := resTmp.(*model.CommentsConnection) fc.Result = res - return ec.marshalNComment2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentᚄ(ctx, field.Selections, res) + return ec.marshalNCommentsConnection2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentsConnection(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Post_comments(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Post_comments(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Post", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "id": - return ec.fieldContext_Comment_id(ctx, field) - case "post": - return ec.fieldContext_Comment_post(ctx, field) - case "author": - return ec.fieldContext_Comment_author(ctx, field) - case "contents": - return ec.fieldContext_Comment_contents(ctx, field) - case "replyTo": - return ec.fieldContext_Comment_replyTo(ctx, field) - case "replies": - return ec.fieldContext_Comment_replies(ctx, field) + case "edges": + return ec.fieldContext_CommentsConnection_edges(ctx, field) + case "pageInfo": + return ec.fieldContext_CommentsConnection_pageInfo(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type Comment", field.Name) + return nil, fmt.Errorf("no field named %q was found under type CommentsConnection", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Post_comments_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } @@ -1180,8 +1647,8 @@ func (ec *executionContext) fieldContext_Post_allowComments(_ context.Context, f return fc, nil } -func (ec *executionContext) _Query_allPosts(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_allPosts(ctx, field) +func (ec *executionContext) _PostsConnection_edges(ctx context.Context, field graphql.CollectedField, obj *model.PostsConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PostsConnection_edges(ctx, field) if err != nil { return graphql.Null } @@ -1194,7 +1661,7 @@ func (ec *executionContext) _Query_allPosts(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().AllPosts(rctx) + return obj.Edges, nil }) if err != nil { ec.Error(ctx, err) @@ -1206,12 +1673,216 @@ func (ec *executionContext) _Query_allPosts(ctx context.Context, field graphql.C } return graphql.Null } - res := resTmp.([]*model.Post) + res := resTmp.([]*model.PostsEdge) fc.Result = res - return ec.marshalNPost2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostᚄ(ctx, field.Selections, res) + return ec.marshalNPostsEdge2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostsEdgeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_allPosts(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_PostsConnection_edges(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PostsConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "cursor": + return ec.fieldContext_PostsEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_PostsEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PostsEdge", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _PostsConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *model.PostsConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PostsConnection_pageInfo(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PageInfo, 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.PageInfo) + fc.Result = res + return ec.marshalNPageInfo2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PostsConnection_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PostsConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "startCursor": + return ec.fieldContext_PageInfo_startCursor(ctx, field) + case "endCursor": + return ec.fieldContext_PageInfo_endCursor(ctx, field) + case "hasNextPage": + return ec.fieldContext_PageInfo_hasNextPage(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _PostsEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *model.PostsEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PostsEdge_cursor(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Cursor, 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.(uint) + fc.Result = res + return ec.marshalNID2uint(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PostsEdge_cursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PostsEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PostsEdge_node(ctx context.Context, field graphql.CollectedField, obj *model.PostsEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PostsEdge_node(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Node, 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.Post) + fc.Result = res + return ec.marshalNPost2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPost(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PostsEdge_node(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PostsEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Post_id(ctx, field) + case "title": + return ec.fieldContext_Post_title(ctx, field) + case "author": + return ec.fieldContext_Post_author(ctx, field) + case "contents": + return ec.fieldContext_Post_contents(ctx, field) + case "comments": + return ec.fieldContext_Post_comments(ctx, field) + case "allowComments": + return ec.fieldContext_Post_allowComments(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Post", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_post(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_post(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Post(rctx, fc.Args["id"].(uint)) + }) + 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.Post) + fc.Result = res + return ec.marshalNPost2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPost(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_post(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -1235,6 +1906,143 @@ func (ec *executionContext) fieldContext_Query_allPosts(_ context.Context, field return nil, fmt.Errorf("no field named %q was found under type Post", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_post_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_posts(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_posts(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Posts(rctx, fc.Args["first"].(uint), fc.Args["after"].(uint)) + }) + 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.PostsConnection) + fc.Result = res + return ec.marshalNPostsConnection2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostsConnection(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_posts(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "edges": + return ec.fieldContext_PostsConnection_edges(ctx, field) + case "pageInfo": + return ec.fieldContext_PostsConnection_pageInfo(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PostsConnection", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_posts_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_comment(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_comment(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Comment(rctx, fc.Args["id"].(uint)) + }) + 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.Comment) + fc.Result = res + return ec.marshalNComment2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐComment(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_comment(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Comment_id(ctx, field) + case "author": + return ec.fieldContext_Comment_author(ctx, field) + case "contents": + return ec.fieldContext_Comment_contents(ctx, field) + case "replies": + return ec.fieldContext_Comment_replies(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Comment", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_comment_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } @@ -3301,27 +4109,139 @@ func (ec *executionContext) _Comment(ctx context.Context, sel ast.SelectionSet, case "id": out.Values[i] = ec._Comment_id(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "post": - out.Values[i] = ec._Comment_post(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "author": out.Values[i] = ec._Comment_author(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "contents": out.Values[i] = ec._Comment_contents(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "replies": + field := field + + 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._Comment_replies(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) }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var commentsConnectionImplementors = []string{"CommentsConnection"} + +func (ec *executionContext) _CommentsConnection(ctx context.Context, sel ast.SelectionSet, obj *model.CommentsConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, commentsConnectionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CommentsConnection") + case "edges": + out.Values[i] = ec._CommentsConnection_edges(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "replyTo": - out.Values[i] = ec._Comment_replyTo(ctx, field, obj) - case "replies": - out.Values[i] = ec._Comment_replies(ctx, field, obj) + case "pageInfo": + out.Values[i] = ec._CommentsConnection_pageInfo(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var commentsEdgeImplementors = []string{"CommentsEdge"} + +func (ec *executionContext) _CommentsEdge(ctx context.Context, sel ast.SelectionSet, obj *model.CommentsEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, commentsEdgeImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CommentsEdge") + case "cursor": + out.Values[i] = ec._CommentsEdge_cursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "node": + out.Values[i] = ec._CommentsEdge_node(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -3404,6 +4324,55 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) return out } +var pageInfoImplementors = []string{"PageInfo"} + +func (ec *executionContext) _PageInfo(ctx context.Context, sel ast.SelectionSet, obj *model.PageInfo) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, pageInfoImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PageInfo") + case "startCursor": + out.Values[i] = ec._PageInfo_startCursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "endCursor": + out.Values[i] = ec._PageInfo_endCursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "hasNextPage": + out.Values[i] = ec._PageInfo_hasNextPage(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var postImplementors = []string{"Post"} func (ec *executionContext) _Post(ctx context.Context, sel ast.SelectionSet, obj *model.Post) graphql.Marshaler { @@ -3418,30 +4387,149 @@ func (ec *executionContext) _Post(ctx context.Context, sel ast.SelectionSet, obj case "id": out.Values[i] = ec._Post_id(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "title": out.Values[i] = ec._Post_title(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "author": out.Values[i] = ec._Post_author(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "contents": out.Values[i] = ec._Post_contents(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "comments": - out.Values[i] = ec._Post_comments(ctx, field, obj) + field := field + + 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._Post_comments(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 "allowComments": + out.Values[i] = ec._Post_allowComments(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var postsConnectionImplementors = []string{"PostsConnection"} + +func (ec *executionContext) _PostsConnection(ctx context.Context, sel ast.SelectionSet, obj *model.PostsConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, postsConnectionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PostsConnection") + case "edges": + out.Values[i] = ec._PostsConnection_edges(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "allowComments": - out.Values[i] = ec._Post_allowComments(ctx, field, obj) + case "pageInfo": + out.Values[i] = ec._PostsConnection_pageInfo(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var postsEdgeImplementors = []string{"PostsEdge"} + +func (ec *executionContext) _PostsEdge(ctx context.Context, sel ast.SelectionSet, obj *model.PostsEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, postsEdgeImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PostsEdge") + case "cursor": + out.Values[i] = ec._PostsEdge_cursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "node": + out.Values[i] = ec._PostsEdge_node(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -3487,7 +4575,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Query") - case "allPosts": + case "post": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { @@ -3496,7 +4584,51 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._Query_allPosts(ctx, field) + res = ec._Query_post(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "posts": + field := field + + 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._Query_posts(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "comment": + field := field + + 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._Query_comment(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } @@ -3895,7 +5027,40 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se return res } -func (ec *executionContext) marshalNComment2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Comment) graphql.Marshaler { +func (ec *executionContext) marshalNComment2gitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐComment(ctx context.Context, sel ast.SelectionSet, v model.Comment) graphql.Marshaler { + return ec._Comment(ctx, sel, &v) +} + +func (ec *executionContext) marshalNComment2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐComment(ctx context.Context, sel ast.SelectionSet, v *model.Comment) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Comment(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNCommentInput2gitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentInput(ctx context.Context, v interface{}) (model.CommentInput, error) { + res, err := ec.unmarshalInputCommentInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNCommentsConnection2gitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentsConnection(ctx context.Context, sel ast.SelectionSet, v model.CommentsConnection) graphql.Marshaler { + return ec._CommentsConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNCommentsConnection2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentsConnection(ctx context.Context, sel ast.SelectionSet, v *model.CommentsConnection) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._CommentsConnection(ctx, sel, v) +} + +func (ec *executionContext) marshalNCommentsEdge2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentsEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.CommentsEdge) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -3919,7 +5084,7 @@ func (ec *executionContext) marshalNComment2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋoz if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNComment2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐComment(ctx, sel, v[i]) + ret[i] = ec.marshalNCommentsEdge2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentsEdge(ctx, sel, v[i]) } if isLen1 { f(i) @@ -3939,14 +5104,14 @@ func (ec *executionContext) marshalNComment2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋoz return ret } -func (ec *executionContext) marshalNComment2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐComment(ctx context.Context, sel ast.SelectionSet, v *model.Comment) graphql.Marshaler { +func (ec *executionContext) marshalNCommentsEdge2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentsEdge(ctx context.Context, sel ast.SelectionSet, v *model.CommentsEdge) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } - return ec._Comment(ctx, sel, v) + return ec._CommentsEdge(ctx, sel, v) } func (ec *executionContext) unmarshalNID2uint(ctx context.Context, v interface{}) (uint, error) { @@ -3985,7 +5150,50 @@ func (ec *executionContext) marshalNID2ᚖuint(ctx context.Context, sel ast.Sele return res } -func (ec *executionContext) marshalNPost2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Post) graphql.Marshaler { +func (ec *executionContext) marshalNPageInfo2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPageInfo(ctx context.Context, sel ast.SelectionSet, v *model.PageInfo) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._PageInfo(ctx, sel, v) +} + +func (ec *executionContext) marshalNPost2gitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPost(ctx context.Context, sel ast.SelectionSet, v model.Post) graphql.Marshaler { + return ec._Post(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPost2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPost(ctx context.Context, sel ast.SelectionSet, v *model.Post) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Post(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNPostInput2gitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostInput(ctx context.Context, v interface{}) (model.PostInput, error) { + res, err := ec.unmarshalInputPostInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNPostsConnection2gitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostsConnection(ctx context.Context, sel ast.SelectionSet, v model.PostsConnection) graphql.Marshaler { + return ec._PostsConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPostsConnection2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostsConnection(ctx context.Context, sel ast.SelectionSet, v *model.PostsConnection) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._PostsConnection(ctx, sel, v) +} + +func (ec *executionContext) marshalNPostsEdge2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostsEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.PostsEdge) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -4009,7 +5217,7 @@ func (ec *executionContext) marshalNPost2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozon if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNPost2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPost(ctx, sel, v[i]) + ret[i] = ec.marshalNPostsEdge2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostsEdge(ctx, sel, v[i]) } if isLen1 { f(i) @@ -4029,14 +5237,14 @@ func (ec *executionContext) marshalNPost2ᚕᚖgitᚗobamnaᚗruᚋeriusᚋozon return ret } -func (ec *executionContext) marshalNPost2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPost(ctx context.Context, sel ast.SelectionSet, v *model.Post) graphql.Marshaler { +func (ec *executionContext) marshalNPostsEdge2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostsEdge(ctx context.Context, sel ast.SelectionSet, v *model.PostsEdge) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } - return ec._Post(ctx, sel, v) + return ec._PostsEdge(ctx, sel, v) } func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { @@ -4333,21 +5541,6 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast return res } -func (ec *executionContext) marshalOComment2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐComment(ctx context.Context, sel ast.SelectionSet, v *model.Comment) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Comment(ctx, sel, v) -} - -func (ec *executionContext) unmarshalOCommentInput2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐCommentInput(ctx context.Context, v interface{}) (*model.CommentInput, error) { - if v == nil { - return nil, nil - } - res, err := ec.unmarshalInputCommentInput(ctx, v) - return &res, graphql.ErrorOnPath(ctx, err) -} - func (ec *executionContext) unmarshalOID2ᚖuint(ctx context.Context, v interface{}) (*uint, error) { if v == nil { return nil, nil @@ -4364,14 +5557,6 @@ func (ec *executionContext) marshalOID2ᚖuint(ctx context.Context, sel ast.Sele return res } -func (ec *executionContext) unmarshalOPostInput2ᚖgitᚗobamnaᚗruᚋeriusᚋozonᚑtaskᚋgraphᚋmodelᚐPostInput(ctx context.Context, v interface{}) (*model.PostInput, error) { - if v == nil { - return nil, nil - } - res, err := ec.unmarshalInputPostInput(ctx, v) - return &res, graphql.ErrorOnPath(ctx, err) -} - func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { if v == nil { return nil, nil diff --git a/graph/model/data.go b/graph/model/data.go index f6ca80a..81632d3 100644 --- a/graph/model/data.go +++ b/graph/model/data.go @@ -15,18 +15,10 @@ type Comment struct { UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` - // db foreign key to reference parent post - PostID uint - - Post *Post `json:"post"` - Author string `json:"author"` - Contents string `json:"contents"` - - // db key to reference parent comment - ReplyToID *uint - - ReplyTo *Comment `json:"reply_to,omitempty"` - Replies []*Comment `json:"replies" gorm:"many2many:comment_replies"` + PostID uint `json:"post_id"` + Author string `json:"author"` + Contents string `json:"contents"` + Replies []*Comment `json:"replies" gorm:"many2many:comment_replies"` } type Post struct { @@ -49,6 +41,7 @@ func PostFromInput(input *PostInput) *Post { Title: input.Title, Contents: input.Contents, AllowComments: input.AllowComments, + Comments: make([]*Comment, 0), } } diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go index 475457f..2f0b557 100644 --- a/graph/model/models_gen.go +++ b/graph/model/models_gen.go @@ -2,8 +2,34 @@ package model +type CommentsConnection struct { + Edges []*CommentsEdge `json:"edges"` + PageInfo *PageInfo `json:"pageInfo"` +} + +type CommentsEdge struct { + Cursor uint `json:"cursor"` + Node *Comment `json:"node"` +} + type Mutation struct { } +type PageInfo struct { + StartCursor uint `json:"startCursor"` + EndCursor uint `json:"endCursor"` + HasNextPage bool `json:"hasNextPage"` +} + +type PostsConnection struct { + Edges []*PostsEdge `json:"edges"` + PageInfo *PageInfo `json:"pageInfo"` +} + +type PostsEdge struct { + Cursor uint `json:"cursor"` + Node *Post `json:"node"` +} + type Query struct { } diff --git a/graph/schema.resolvers.go b/graph/mutation.resolvers.go similarity index 60% rename from graph/schema.resolvers.go rename to graph/mutation.resolvers.go index 9088087..b3dfec7 100644 --- a/graph/schema.resolvers.go +++ b/graph/mutation.resolvers.go @@ -12,31 +12,26 @@ import ( ) // AddPost is the resolver for the add_post field. -func (r *mutationResolver) AddPost(ctx context.Context, input *model.PostInput) (*model.AddResult, error) { - return r.Storage.AddPost(input) +func (r *mutationResolver) AddPost(ctx context.Context, input model.PostInput) (*model.AddResult, error) { + return r.Storage.AddPost(&input) } // AddComment is the resolver for the add_comment field. -func (r *mutationResolver) AddComment(ctx context.Context, input *model.CommentInput) (*model.AddResult, error) { +func (r *mutationResolver) AddComment(ctx context.Context, input model.CommentInput) (*model.AddResult, error) { if len(input.Contents) > model.CommentLengthLimit { return nil, fmt.Errorf("exceeded max comment length of %d chars", model.CommentLengthLimit) } - if input.ParentCommentID == nil && input.ParentPostID == nil { + switch { + case input.ParentPostID != nil: + return r.Storage.AddCommentToPost(&input) + case input.ParentCommentID != nil: + return r.Storage.AddReplyToComment(&input) + default: return nil, fmt.Errorf("parent post or parent comment ids weren't specified") } - return r.Storage.AddComment(input) -} - -// AllPosts is the resolver for the all_posts field. -func (r *queryResolver) AllPosts(ctx context.Context) ([]*model.Post, error) { - return r.Storage.GetPosts() } // Mutation returns MutationResolver implementation. func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } -// Query returns QueryResolver implementation. -func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } - type mutationResolver struct{ *Resolver } -type queryResolver struct{ *Resolver } diff --git a/graph/query.resolvers.go b/graph/query.resolvers.go new file mode 100644 index 0000000..7b53909 --- /dev/null +++ b/graph/query.resolvers.go @@ -0,0 +1,49 @@ +package graph + +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.49 + +import ( + "context" + + "git.obamna.ru/erius/ozon-task/graph/model" +) + +// Replies is the resolver for the replies field. +func (r *commentResolver) Replies(ctx context.Context, obj *model.Comment, first uint, after uint) (*model.CommentsConnection, error) { + return r.Storage.GetReplies(obj, first, after, ctx) +} + +// Comments is the resolver for the comments field. +func (r *postResolver) Comments(ctx context.Context, obj *model.Post, first uint, after uint) (*model.CommentsConnection, error) { + return r.Storage.GetComments(obj, first, after, ctx) +} + +// Post is the resolver for the post field. +func (r *queryResolver) Post(ctx context.Context, id uint) (*model.Post, error) { + return r.Storage.GetPost(id, ctx) +} + +// Posts is the resolver for the posts field. +func (r *queryResolver) Posts(ctx context.Context, first uint, after uint) (*model.PostsConnection, error) { + return r.Storage.GetPosts(first, after, ctx) +} + +// Comment is the resolver for the comment field. +func (r *queryResolver) Comment(ctx context.Context, id uint) (*model.Comment, error) { + return r.Storage.GetComment(id, ctx) +} + +// Comment returns CommentResolver implementation. +func (r *Resolver) Comment() CommentResolver { return &commentResolver{r} } + +// Post returns PostResolver implementation. +func (r *Resolver) Post() PostResolver { return &postResolver{r} } + +// Query returns QueryResolver implementation. +func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } + +type commentResolver struct{ *Resolver } +type postResolver struct{ *Resolver } +type queryResolver struct{ *Resolver } diff --git a/graph/schema.graphqls b/graph/schema.graphqls deleted file mode 100644 index 189b1cd..0000000 --- a/graph/schema.graphqls +++ /dev/null @@ -1,44 +0,0 @@ -type Post { - id: ID! - title: String! - author: String! - contents: String! - comments: [Comment!]! - allowComments: Boolean! -} - -type Comment { - id: ID! - post: Post! - author: String! - contents: String! - replyTo: Comment - replies: [Comment!]! -} - -type Query { - allPosts: [Post!]! -} - -type Mutation { - addPost(input: PostInput): AddResult! - addComment(input: CommentInput): AddResult! -} - -input PostInput { - title: String! - author: String! - contents: String! - allowComments: Boolean! = true -} - -input CommentInput { - parentPostId: ID - parentCommentId: ID - author: String! - contents: String! -} - -type AddResult { - itemId: ID! -} diff --git a/graph/schema/mutation.graphqls b/graph/schema/mutation.graphqls new file mode 100644 index 0000000..9f9e661 --- /dev/null +++ b/graph/schema/mutation.graphqls @@ -0,0 +1,22 @@ +type Mutation { + addPost(input: PostInput!): AddResult! + addComment(input: CommentInput!): AddResult! +} + +input PostInput { + title: String! + author: String! + contents: String! + allowComments: Boolean! = true +} + +input CommentInput { + parentPostId: ID + parentCommentId: ID + author: String! + contents: String! +} + +type AddResult { + itemId: ID! +} diff --git a/graph/schema/pagination.graphqls b/graph/schema/pagination.graphqls new file mode 100644 index 0000000..363554b --- /dev/null +++ b/graph/schema/pagination.graphqls @@ -0,0 +1,25 @@ +type PostsConnection { + edges: [PostsEdge!]! + pageInfo: PageInfo! +} + +type CommentsConnection { + edges: [CommentsEdge!]! + pageInfo: PageInfo! +} + +type PostsEdge { + cursor: ID! + node: Post! +} + +type CommentsEdge { + cursor: ID! + node: Comment! +} + +type PageInfo { + startCursor: ID! + endCursor: ID! + hasNextPage: Boolean! +} diff --git a/graph/schema/query.graphqls b/graph/schema/query.graphqls new file mode 100644 index 0000000..c2e8788 --- /dev/null +++ b/graph/schema/query.graphqls @@ -0,0 +1,21 @@ +type Query { + post(id: ID!): Post! + posts(first: ID!, after: ID!): PostsConnection! + comment(id: ID!): Comment! +} + +type Post { + id: ID! + title: String! + author: String! + contents: String! + comments(first: ID!, after: ID!): CommentsConnection! + allowComments: Boolean! +} + +type Comment { + id: ID! + author: String! + contents: String! + replies(first: ID!, after: ID!): CommentsConnection! +} diff --git a/internal/storage/db/database.go b/internal/storage/db/database.go index 19b6197..1de6719 100644 --- a/internal/storage/db/database.go +++ b/internal/storage/db/database.go @@ -1,7 +1,12 @@ package db import ( + "context" + "fmt" + "log" + "git.obamna.ru/erius/ozon-task/graph/model" + "github.com/99designs/gqlgen/graphql" "gorm.io/gorm" ) @@ -15,48 +20,64 @@ func (s *Database) AddPost(input *model.PostInput) (*model.AddResult, error) { return &model.AddResult{ItemID: &post.ID}, err } -func (s *Database) AddComment(input *model.CommentInput) (*model.AddResult, error) { +func (s *Database) AddReplyToComment(input *model.CommentInput) (*model.AddResult, error) { comment := model.CommentFromInput(input) - if input.ParentPostID == nil { - // multiple operations performed in one transaction - err := s.db.Transaction(func(tx *gorm.DB) error { - var parent model.Comment - // find parent comment in db - err := s.db.First(&parent, *input.ParentCommentID).Error - if err != nil { - return err - } - // set new comment fields to reference parent post and comment - comment.ReplyTo = &parent - comment.PostID = parent.PostID - // insert comment - err = s.db.Create(comment).Error - if err != nil { - return err - } - // add new reply to parent and save - parent.Replies = append(parent.Replies, comment) - err = s.db.Save(parent).Error - if err != nil { - return err - } - return nil - }) - if err != nil { - return nil, err - } - } else { - comment.PostID = *input.ParentPostID + // multiple operations performed in one transaction + err := s.db.Transaction(func(tx *gorm.DB) error { + // insert comment err := s.db.Create(comment).Error if err != nil { - return nil, err + return err } - } - return &model.AddResult{ItemID: &comment.ID}, nil + // add new reply to parent + err = s.db.Table("comment_replies").Create(map[string]interface{}{ + "comment_id": *input.ParentCommentID, + "reply_id": comment.ID, + }).Error + if err != nil { + return err + } + return nil + }) + return &model.AddResult{ItemID: &comment.ID}, err } -func (s Database) GetPosts() ([]*model.Post, error) { - var posts []*model.Post - err := s.db.Find(&posts).Error - return posts, err +func (s *Database) AddCommentToPost(input *model.CommentInput) (*model.AddResult, error) { + comment := model.CommentFromInput(input) + var allowComments bool + err := s.db.Table("posts").Select("allow_comments").Where("id = ?", *input.ParentPostID).Scan(&allowComments).Error + if err != nil { + return nil, err + } + if !allowComments { + return nil, fmt.Errorf("author disabled comments for this post") + } + err = s.db.Create(comment).Error + return &model.AddResult{ItemID: &comment.ID}, err +} + +func (s *Database) GetPost(id uint, ctx context.Context) (*model.Post, error) { + log.Println(graphql.CollectAllFields(ctx)) + log.Println(graphql.CollectFieldsCtx(ctx, nil)) + var post model.Post + err := s.db.Find(&post, id).Error + return &post, err +} + +func (s *Database) GetComment(id uint, ctx context.Context) (*model.Comment, error) { + var comment model.Comment + err := s.db.Find(&comment, id).Error + return &comment, err +} + +func (s *Database) GetPosts(first uint, after uint, ctx context.Context) (*model.PostsConnection, error) { + return nil, nil +} + +func (s *Database) GetComments(post *model.Post, first uint, after uint, ctx context.Context) (*model.CommentsConnection, error) { + return nil, nil +} + +func (s *Database) GetReplies(comment *model.Comment, first uint, after uint, ctx context.Context) (*model.CommentsConnection, error) { + return nil, nil } diff --git a/internal/storage/db/postgres.go b/internal/storage/db/postgres.go index 3da0fa8..e19b0c3 100644 --- a/internal/storage/db/postgres.go +++ b/internal/storage/db/postgres.go @@ -8,6 +8,7 @@ import ( "git.obamna.ru/erius/ozon-task/graph/model" "gorm.io/driver/postgres" "gorm.io/gorm" + "gorm.io/gorm/logger" ) var ( @@ -22,7 +23,10 @@ var ( func InitPostgres() (*Database, error) { log.Printf("connecting to PostgreSQL database at %s...", con) // PrepareStmt is true for caching complex sql statements when adding comments or replies - db, err := gorm.Open(postgres.Open(con), &gorm.Config{PrepareStmt: true}) + db, err := gorm.Open(postgres.Open(con), &gorm.Config{ + PrepareStmt: true, + Logger: logger.Default.LogMode(logger.Info), + }) if err != nil { log.Printf("failed to connect to database: %s", err) return nil, err diff --git a/internal/storage/memory.go b/internal/storage/memory.go index ac8a556..7dc8662 100644 --- a/internal/storage/memory.go +++ b/internal/storage/memory.go @@ -1,6 +1,9 @@ package storage import ( + "context" + "fmt" + "git.obamna.ru/erius/ozon-task/graph/model" ) @@ -22,20 +25,142 @@ func InitInMemory() *InMemory { func (s *InMemory) AddPost(input *model.PostInput) (*model.AddResult, error) { post := model.PostFromInput(input) - post.ID = s.postId - s.posts = append(s.posts, post) - s.postId++ + s.insertPost(post) return &model.AddResult{ItemID: &post.ID}, nil } -func (s *InMemory) AddComment(input *model.CommentInput) (*model.AddResult, error) { - comment := model.CommentFromInput(input) - comment.ID = s.commentId - s.comments = append(s.comments, comment) - s.commentId++ +func (s *InMemory) AddReplyToComment(input *model.CommentInput) (*model.AddResult, error) { + if !s.commentExists(*input.ParentCommentID) { + return nil, &IDNotFoundError{objName: "comment", id: *input.ParentCommentID} + } + comment, parent := model.CommentFromInput(input), s.comments[*input.ParentCommentID] + s.insertComment(comment) + parent.Replies = append(parent.Replies, comment) return &model.AddResult{ItemID: &comment.ID}, nil } -func (s InMemory) GetPosts() ([]*model.Post, error) { - return s.posts, nil +func (s *InMemory) AddCommentToPost(input *model.CommentInput) (*model.AddResult, error) { + if !s.postExists(*input.ParentPostID) { + return nil, &IDNotFoundError{objName: "post", id: *input.ParentPostID} + } + parent := s.posts[*input.ParentPostID] + if !parent.AllowComments { + return nil, fmt.Errorf("author disabled comments for this post") + } + comment := model.CommentFromInput(input) + s.insertComment(comment) + parent.Comments = append(parent.Comments, comment) + return &model.AddResult{ItemID: &comment.ID}, nil +} + +func (s *InMemory) GetPost(id uint, ctx context.Context) (*model.Post, error) { + if !s.postExists(id) { + return nil, &IDNotFoundError{objName: "post", id: id} + } + return s.posts[id], nil +} + +func (s *InMemory) GetComment(id uint, ctx context.Context) (*model.Comment, error) { + if !s.commentExists(id) { + return nil, &IDNotFoundError{objName: "comment", id: id} + } + return s.comments[id], nil +} + +func (s *InMemory) GetPosts(first uint, after uint, ctx context.Context) (*model.PostsConnection, error) { + if !s.postExists(after) { + return nil, &IDNotFoundError{objName: "post", id: after} + } + nextPage, until := true, after+first + if !s.postExists(until) { + nextPage = false + until = uint(len(s.posts)) + } + info, edges := &model.PageInfo{ + StartCursor: after, + EndCursor: until - 1, + HasNextPage: nextPage, + }, make([]*model.PostsEdge, until-after) + for i, p := range s.posts[after:until] { + edges[i] = &model.PostsEdge{ + Cursor: p.ID, + Node: p, + } + } + return &model.PostsConnection{ + Edges: edges, + PageInfo: info, + }, nil +} + +func (s *InMemory) GetComments(post *model.Post, first uint, after uint, ctx context.Context) (*model.CommentsConnection, error) { + if !s.commentExists(after) { + return nil, &IDNotFoundError{objName: "comment", id: after} + } + nextPage, until := true, after+first + if !s.commentExists(until) { + nextPage = false + until = uint(len(s.comments)) + } + info, edges := &model.PageInfo{ + StartCursor: after, + EndCursor: until - 1, + HasNextPage: nextPage, + }, make([]*model.CommentsEdge, until-after) + for i, c := range post.Comments[after:until] { + edges[i] = &model.CommentsEdge{ + Cursor: c.ID, + Node: c, + } + } + return &model.CommentsConnection{ + Edges: edges, + PageInfo: info, + }, nil +} + +func (s *InMemory) GetReplies(comment *model.Comment, first uint, after uint, ctx context.Context) (*model.CommentsConnection, error) { + if !s.commentExists(after) { + return nil, &IDNotFoundError{objName: "comment", id: after} + } + nextPage, until := true, after+first + if !s.commentExists(until) { + nextPage = false + until = uint(len(s.comments)) + } + info, edges := &model.PageInfo{ + StartCursor: after, + EndCursor: until - 1, + HasNextPage: nextPage, + }, make([]*model.CommentsEdge, until-after) + for i, c := range comment.Replies[after:until] { + edges[i] = &model.CommentsEdge{ + Cursor: c.ID, + Node: c, + } + } + return &model.CommentsConnection{ + Edges: edges, + PageInfo: info, + }, nil +} + +func (s *InMemory) postExists(id uint) bool { + return id < uint(len(s.posts)) +} + +func (s *InMemory) commentExists(id uint) bool { + return id < uint(len(s.comments)) +} + +func (s *InMemory) insertComment(comment *model.Comment) { + comment.ID = s.commentId + s.comments = append(s.comments, comment) + s.commentId++ +} + +func (s *InMemory) insertPost(post *model.Post) { + post.ID = s.postId + s.posts = append(s.posts, post) + s.postId++ } diff --git a/internal/storage/storage.go b/internal/storage/storage.go index 800bf32..d82552b 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -1,6 +1,8 @@ package storage import ( + "context" + "fmt" "log" "os" @@ -8,20 +10,47 @@ import ( "git.obamna.ru/erius/ozon-task/internal/storage/db" ) +type IDNotFoundError struct { + objName string + id uint +} + +func (e *IDNotFoundError) Error() string { + return fmt.Sprintf("%s with id %d doesn't exist", e.objName, e.id) +} + +// storage types enum const ( inMemory = "inmemory" postgres = "postgres" ) -var storage = os.Getenv("APP_STORAGE") +var storage, storageSpecified = os.LookupEnv("APP_STORAGE") type Storage interface { AddPost(input *model.PostInput) (*model.AddResult, error) - AddComment(input *model.CommentInput) (*model.AddResult, error) - GetPosts() ([]*model.Post, error) + + // assumes that input.ParentCommentID is not nil + AddReplyToComment(input *model.CommentInput) (*model.AddResult, error) + + // assumes that input.ParentPostID is not nil + AddCommentToPost(input *model.CommentInput) (*model.AddResult, error) + + // passing query context to analyze requested fields and prevent overfetching + GetPost(id uint, ctx context.Context) (*model.Post, error) + GetComment(id uint, ctx context.Context) (*model.Comment, error) + + // returns paginated data in the form of model.*Connection (passing context to prevent overfetching) + GetPosts(first uint, after uint, ctx context.Context) (*model.PostsConnection, error) + GetComments(post *model.Post, first uint, after uint, ctx context.Context) (*model.CommentsConnection, error) + GetReplies(comment *model.Comment, first uint, after uint, ctx context.Context) (*model.CommentsConnection, error) } func InitStorage() (Storage, error) { + if !storageSpecified { + log.Println("APP_STORAGE isn't specified, falling back to default in-memory storage", storage) + return InitInMemory(), nil + } log.Printf("initializing storage of type %s...", storage) switch storage { case inMemory: @@ -29,7 +58,6 @@ func InitStorage() (Storage, error) { case postgres: return db.InitPostgres() default: - log.Printf("storage of type %s doesn't exists, falling back to default in-memory storage", storage) - return InitInMemory(), nil + return nil, fmt.Errorf("storage of type %s doesn't exists, change the value of APP_STORAGE env variable", storage) } }