package storage import ( "context" "fmt" "git.obamna.ru/erius/ozon-task/graph/model" ) type InMemory struct { postId uint commentId uint posts []*model.Post comments []*model.Comment } func InitInMemory() *InMemory { return &InMemory{ postId: 0, commentId: 0, posts: make([]*model.Post, 0), comments: make([]*model.Comment, 0), } } func (s *InMemory) AddPost(input *model.PostInput) (*model.AddResult, error) { post := model.PostFromInput(input) s.insertPost(post) return &model.AddResult{ItemID: &post.ID}, nil } 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) 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) comment.RootComment = true 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, cursor *uint, ctx context.Context) (*model.PostsConnection, error) { start := uint(0) if cursor != nil { start = *cursor + 1 } if !s.postExists(start) { return &model.EmptyPostsConnections, nil } nextPage, until := true, start+first if !s.postExists(until) { nextPage = false until = uint(len(s.posts)) } info, edges := &model.PageInfo{ StartCursor: start, EndCursor: until - 1, HasNextPage: nextPage, }, make([]*model.PostsEdge, until-start) for i, p := range s.posts[start: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, cursor *uint, ctx context.Context) (*model.CommentsConnection, error) { return getCommentsFrom(post.Comments, first, cursor), nil } func (s *InMemory) GetReplies(comment *model.Comment, first uint, cursor *uint, ctx context.Context) (*model.CommentsConnection, error) { return getCommentsFrom(comment.Replies, first, cursor), nil } func getCommentsFrom(source []*model.Comment, first uint, cursor *uint) *model.CommentsConnection { start := uint(0) if cursor != nil { start = *cursor + 1 } if start >= uint(len(source)) { return &model.EmptyCommentsConnection } nextPage, until := true, start+first if until >= uint(len(source)) { nextPage = false until = uint(len(source)) } info, edges := &model.PageInfo{ StartCursor: start, EndCursor: until - 1, HasNextPage: nextPage, }, make([]*model.CommentsEdge, until-start) for i, c := range source[start:until] { edges[i] = &model.CommentsEdge{ Cursor: c.ID, Node: c, } } return &model.CommentsConnection{ Edges: edges, PageInfo: info, } } 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++ }