erius
8fce488888
TODO: use dataloaders to reduce amount of sql queries (figure out how to batch query nested paginated data) and add some basic unit or integrated testing
157 lines
4.1 KiB
Go
157 lines
4.1 KiB
Go
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++
|
|
}
|