181 lines
4.6 KiB
Go
181 lines
4.6 KiB
Go
package repository
|
|
|
|
import (
|
|
mgo "code.30cm.net/digimon/library-go/mongo"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/zeromicro/go-zero/core/stores/cache"
|
|
"github.com/zeromicro/go-zero/core/stores/mon"
|
|
"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"
|
|
"time"
|
|
"url_generate/internal/module/url/domain"
|
|
"url_generate/internal/module/url/domain/entity"
|
|
"url_generate/internal/module/url/domain/repository"
|
|
)
|
|
|
|
type URLRepositoryParam struct {
|
|
Conf *mgo.Conf
|
|
CacheConf cache.CacheConf
|
|
DbOpts []mon.Option
|
|
CacheOpts []cache.Option
|
|
}
|
|
|
|
type URLRepository struct {
|
|
DB mgo.DocumentDBWithCacheUseCase
|
|
}
|
|
|
|
func NewURLRepository(param URLRepositoryParam) repository.URLRepository {
|
|
e := entity.URLTable{}
|
|
documentDB, err := mgo.MustDocumentDBWithCache(
|
|
param.Conf,
|
|
e.CollectionName(),
|
|
param.CacheConf,
|
|
param.DbOpts,
|
|
param.CacheOpts,
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return &URLRepository{
|
|
DB: documentDB,
|
|
}
|
|
}
|
|
|
|
func (repo *URLRepository) BindOne(ctx context.Context, url string) (string, error) {
|
|
filter := bson.M{"url": bson.M{"$eq": ""}}
|
|
// 排序條件:按 `create_at` 降序排列
|
|
sort := bson.D{{"create_at", -1}}
|
|
// 定義變量存儲查詢結果
|
|
var existing entity.URLTable
|
|
|
|
// 查詢 MongoDB
|
|
err := repo.DB.GetClient().FindOne(ctx, &existing, filter, options.FindOne().SetSort(sort))
|
|
if errors.Is(err, mon.ErrNotFound) {
|
|
// 如果沒有符合條件的記錄
|
|
return "", fmt.Errorf("no available empty records found")
|
|
}
|
|
if err != nil {
|
|
// 處理其他錯誤
|
|
return "", fmt.Errorf("failed to query empty record: %w", err)
|
|
}
|
|
|
|
// 更新該記錄的 URL 並返回短碼
|
|
rk := domain.GetURLCodeRedisKey(existing.ShortCode)
|
|
_, err = repo.DB.UpdateOne(ctx, rk, bson.M{"_id": existing.ID}, bson.M{"$set": bson.M{
|
|
"url": url,
|
|
"update_at": time.Now().UTC().UnixNano(),
|
|
}})
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to update URL record: %w", err)
|
|
}
|
|
|
|
// 返回分配的短碼
|
|
return existing.ShortCode, nil
|
|
}
|
|
|
|
func (repo *URLRepository) Insert(ctx context.Context, data *entity.URLTable) error {
|
|
if data.ID.IsZero() {
|
|
now := time.Now().UTC().UnixNano()
|
|
data.ID = primitive.NewObjectID()
|
|
data.CreateAt = &now
|
|
data.UpdateAt = &now
|
|
}
|
|
rk := domain.GetURLCodeRedisKey(data.ShortCode)
|
|
_, err := repo.DB.InsertOne(ctx, rk, data)
|
|
|
|
return err
|
|
}
|
|
|
|
func (repo *URLRepository) FindOne(ctx context.Context, shortCode string) (*entity.URLTable, error) {
|
|
var data entity.URLTable
|
|
rk := domain.GetURLCodeRedisKey(shortCode)
|
|
err := repo.DB.FindOne(ctx, rk, &data, bson.M{"short_code": shortCode})
|
|
|
|
switch {
|
|
case err == nil:
|
|
return &data, nil
|
|
case errors.Is(err, mon.ErrNotFound):
|
|
return nil, ErrNotFound
|
|
default:
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
func (repo *URLRepository) Delete(ctx context.Context, shortCode string) (int64, error) {
|
|
rk := domain.GetURLCodeRedisKey(shortCode)
|
|
|
|
return repo.DB.DeleteOne(ctx, rk, bson.M{"short_code": shortCode})
|
|
}
|
|
|
|
func (repo *URLRepository) InsertMany(ctx context.Context, urls []*entity.URLTable) error {
|
|
if len(urls) == 0 {
|
|
return nil
|
|
}
|
|
|
|
now := time.Now().UTC().UnixNano()
|
|
var documents []interface{}
|
|
for _, url := range urls {
|
|
u := url
|
|
u.ID = primitive.NewObjectID()
|
|
u.CreateAt = &now
|
|
u.UpdateAt = &now
|
|
documents = append(documents, u)
|
|
}
|
|
|
|
_, err := repo.DB.GetClient().InsertMany(ctx, documents)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to insert many URLs: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (repo *URLRepository) Update(ctx context.Context, shortCode string, newURL string) error {
|
|
filter := bson.M{"short_code": shortCode}
|
|
update := bson.M{
|
|
"$set": bson.M{
|
|
"url": newURL,
|
|
"update_at": time.Now().UTC().UnixNano(),
|
|
},
|
|
}
|
|
|
|
rk := domain.GetURLCodeRedisKey(shortCode)
|
|
result, err := repo.DB.UpdateOne(ctx, rk, filter, update, options.Update().SetUpsert(false))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update URL for short code %s: %w", shortCode, err)
|
|
}
|
|
|
|
if result.MatchedCount == 0 {
|
|
return ErrNotFound
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (repo *URLRepository) EmptyCount(ctx context.Context) (int, error) {
|
|
filter := bson.M{"url": ""}
|
|
count, err := repo.DB.GetClient().CountDocuments(ctx, filter)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to count empty URLs: %w", err)
|
|
}
|
|
|
|
return int(count), nil
|
|
}
|
|
|
|
func (repo *URLRepository) Index20241226001UP(ctx context.Context) (*mongo.Cursor, error) {
|
|
// 等價於 db.createIndex({"short_code": 1},{unique: true})
|
|
repo.DB.PopulateIndex(ctx, "short_code", 1, true)
|
|
|
|
return repo.DB.GetClient().Indexes().List(ctx)
|
|
}
|
|
|
|
// ptr 是一個幫助函數,用於生成指針
|
|
func ptr[T any](v T) *T {
|
|
return &v
|
|
}
|