Skip to content

Instantly share code, notes, and snippets.

@taksenov
Created April 23, 2020 15:06
Show Gist options
  • Save taksenov/91806584b070c3e3fc7c01d310fc4418 to your computer and use it in GitHub Desktop.
Save taksenov/91806584b070c3e3fc7c01d310fc4418 to your computer and use it in GitHub Desktop.
package posts
import (
"context"
"fmt"
"math"
"net/http"
"reflect"
"time"
"redditcloneapp/pkg/user"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Author автор поста или комментария
type Author struct {
ID string `json:"id" bson:"id"`
Username string `json:"username" bson:"username"`
}
// PostVote голоса отданные посту
type PostVote struct {
User string `json:"user" bson:"user"`
Vote int32 `json:"vote" bson:"vote"`
}
// PostComment комментарий
type PostComment struct {
ID string `json:"id" bson:"id"`
Created string `json:"created" bson:"created"`
Author *Author `json:"author" bson:"author"`
Body string `json:"body" bson:"body"`
}
// Post пост
type Post struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Score int32 `json:"score" bson:"score"`
Views int32 `json:"views" bson:"views"`
Type string `json:"type" bson:"type"`
Title string `json:"title" bson:"title"`
Text string `json:"text,omitempty" bson:"text,omitempty"`
URL string `json:"url" bson:"url"`
Category string `json:"category" bson:"category"`
Created string `json:"created" bson:"created"`
UpvotePercentage int32 `json:"upvotePercentage" bson:"upvotePercentage"`
Author *Author `json:"author" bson:"author"`
Votes []*PostVote `json:"votes" bson:"votes"`
Comments []*PostComment `json:"comments" bson:"comments"`
}
// User структура для данных пользователя
type User struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
UserName string `json:"username" bson:"username"`
Password string `json:"password" bson:"password"`
Admin bool `json:"admin" bson:"admin"`
}
// ResPost результаты, когда для поста не нужно возвращать сам пост
type ResPost struct {
Message string
}
// PostFormPayload форма создания поста
type PostFormPayload struct {
Category string
Type string
Title string
Text string
URL string
}
// PostsRepo репозиторий для работы с пользователями системы
type PostsRepo struct {
DB *mongo.Database
Posts *mongo.Collection
}
// NewPostsRepo инициализация репозитория Posts
func NewPostsRepo(db *mongo.Database) *PostsRepo {
postsCollection := db.Collection("posts")
return &PostsRepo{
Posts: postsCollection,
}
}
// ==========================
type DatabaseHelper interface {
Collection(name string) CollectionHelper
}
type CollectionHelper interface {
CustomFindOne(context.Context, interface{}) SingleResultHelper
}
type SingleResultHelper interface {
CustomDecode(v interface{}) error
}
type mongoCollection struct {
coll *mongo.Collection
}
type mongoSingleResult struct {
sr *mongo.SingleResult
}
func (mc *mongoCollection) CustomFindOne(ctx context.Context, filter interface{}) SingleResultHelper {
singleResult := mc.coll.FindOne(ctx, filter)
return &mongoSingleResult{sr: singleResult}
}
func (sr *mongoSingleResult) CustomDecode(v interface{}) error {
return sr.sr.Decode(v)
}
// ==========================
// AddPost добавить в пост в БД
func (repo *PostsRepo) AddPost(formData PostFormPayload, userData *user.LocalUser) (*Post, error) {
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
// IDEA: Т.к. фронтенд не умеет работать с ISODate,
// поэтому дата формируется в виде строки "2009-11-10T23:00:00Z"
timeNow, err := time.Now().MarshalText()
if err != nil {
return nil, err
}
timeNowForDB := string(timeNow)
// Структура нового поста
create := bson.D{
primitive.E{Key: "score", Value: 0},
primitive.E{Key: "views", Value: 0},
primitive.E{Key: "type", Value: formData.Type},
primitive.E{Key: "title", Value: formData.Title},
primitive.E{Key: "text", Value: formData.Text},
primitive.E{Key: "url", Value: formData.URL},
primitive.E{Key: "category", Value: formData.Category},
primitive.E{Key: "created", Value: timeNowForDB},
primitive.E{Key: "upvotePercentage", Value: 0},
primitive.E{
Key: "author",
Value: bson.D{
primitive.E{Key: "username", Value: userData.UserName},
primitive.E{Key: "id", Value: userData.ID.Hex()},
},
},
primitive.E{Key: "votes", Value: []*PostVote{}},
primitive.E{Key: "comments", Value: []*PostComment{}},
}
// Добавить пост в БД
postDB, err := repo.Posts.InsertOne(ctx, create)
if err != nil {
return nil, err
}
// Получить созданный пост из БД и вернуть "наверх"
createdDocument := &Post{}
customColl := mongoCollection{
coll: repo.Posts,
}
err = customColl.CustomFindOne(ctx, bson.M{"_id": postDB.InsertedID}).CustomDecode(&createdDocument)
// err = repo.Posts.FindOne(ctx, bson.M{"_id": postDB.InsertedID}).Decode(&createdDocument)
if err != nil {
fmt.Printf("DB ERR= %#v \n", err)
return nil, err
}
fmt.Printf("DB DOCUMENT= %#v \n", createdDocument)
return createdDocument, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment