Files
2026-09-15 21:27:46 +05:00

214 lines
3.5 KiB
Go

package main
import (
"context"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
const collectionName = "feeds"
type FeedsStorage struct {
collection *mongo.Collection
}
func NewFeedsStorage() FeedsStorage {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://root:password@mongo:27017"))
if err != nil {
panic(err)
}
err = client.Ping(ctx, readpref.Primary())
if err != nil {
panic(err)
}
db := client.Database("example")
names, err := db.ListCollectionNames(ctx, bson.M{})
if err != nil {
panic(err)
}
found := false
for _, n := range names {
if n == collectionName {
found = true
break
}
}
if !found {
err := db.CreateCollection(ctx, collectionName)
if err != nil {
panic(err)
}
}
return FeedsStorage{
collection: db.Collection(collectionName),
}
}
func (s FeedsStorage) Add(ctx context.Context, name string) error {
feed := Feed{
Name: name,
Posts: []Post{},
}
_, err := s.collection.InsertOne(ctx, feed)
if err != nil {
if !isDuplicateError(err) {
return err
}
}
return nil
}
func (s FeedsStorage) All(ctx context.Context) ([]Feed, error) {
cursor, err := s.collection.Find(ctx, bson.M{})
if err != nil {
return nil, err
}
var feeds []Feed
err = cursor.All(ctx, &feeds)
if err != nil {
return nil, err
}
return feeds, nil
}
func (s FeedsStorage) ByName(ctx context.Context, name string) (Feed, error) {
filter := bson.M{
"_id": name,
}
var feed Feed
err := s.collection.FindOne(ctx, filter).Decode(&feed)
if err != nil {
return Feed{}, err
}
return feed, nil
}
func (s FeedsStorage) AppendPost(ctx context.Context, post Post) error {
return s.appendPostIfNotPresent(ctx, post)
}
func (s FeedsStorage) UpdatePost(ctx context.Context, post Post) error {
err := s.updatePostIfPresent(ctx, post)
if err != nil {
return err
}
err = s.appendPostIfNotPresent(ctx, post)
if err != nil {
return err
}
err = s.removePostIfNotInFeed(ctx, post)
if err != nil {
return err
}
return nil
}
func (s FeedsStorage) updatePostIfPresent(ctx context.Context, post Post) error {
if len(post.Tags) == 0 {
return nil
}
filter := bson.M{
"_id": bson.M{
"$in": post.Tags,
},
"posts.id": post.ID,
}
update := bson.M{
"$set": bson.M{
"posts.$": post,
},
}
_, err := s.collection.UpdateMany(ctx, filter, update)
return err
}
func (s FeedsStorage) appendPostIfNotPresent(ctx context.Context, post Post) error {
if len(post.Tags) == 0 {
return nil
}
filter := bson.M{
"_id": bson.M{
"$in": post.Tags,
},
"posts.id": bson.M{
"$ne": post.ID,
},
}
update := bson.M{
"$push": bson.M{
"posts": bson.M{
"$each": bson.A{post},
"$position": 0,
},
},
}
_, err := s.collection.UpdateMany(ctx, filter, update)
return err
}
func (s FeedsStorage) removePostIfNotInFeed(ctx context.Context, post Post) error {
tags := post.Tags
if tags == nil {
tags = []string{}
}
filter := bson.M{
"_id": bson.M{
"$nin": tags,
},
"posts.id": post.ID,
}
update := bson.M{
"$pull": bson.M{
"posts": bson.M{
"id": post.ID,
},
},
}
_, err := s.collection.UpdateMany(ctx, filter, update)
if err != nil {
return err
}
return nil
}
func isDuplicateError(err error) bool {
mErr, ok := err.(mongo.WriteException)
if !ok {
return false
}
return mErr.WriteErrors[0].Code == 11000
}