Files
spsays-bff/internal/repository/transcription_repo.go
T

234 lines
8.1 KiB
Go

package repository
import (
"context"
"encoding/json"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
type TranscriptionRepo struct {
col *mongo.Collection
}
func NewTranscriptionRepo(db *MongoDB) *TranscriptionRepo {
return &TranscriptionRepo{col: db.Collection("transcriptions")}
}
type ContentBlockDoc struct {
Text string `bson:"text" json:"text"`
Format string `bson:"format" json:"format"`
Alignment string `bson:"alignment" json:"alignment"`
Speaker *string `bson:"speaker,omitempty" json:"speaker,omitempty"`
}
type TranscriptionDoc struct {
ID bson.ObjectID `bson:"_id" json:"id"`
Slug string `bson:"slug" json:"slug"`
Name string `bson:"name" json:"name"`
Type string `bson:"type" json:"type"`
Date *string `bson:"date,omitempty" json:"date,omitempty"`
Year *int `bson:"year,omitempty" json:"year,omitempty"`
Month *int `bson:"month,omitempty" json:"month,omitempty"`
Day *int `bson:"day,omitempty" json:"day,omitempty"`
Place *string `bson:"place,omitempty" json:"place,omitempty"`
Context *string `bson:"context,omitempty" json:"context,omitempty"`
Reference *string `bson:"reference,omitempty" json:"reference,omitempty"`
DurationMinutes *int `bson:"durationMinutes,omitempty" json:"duration_minutes,omitempty"`
AudioUrl *string `bson:"audioUrl,omitempty" json:"audio_url,omitempty"`
Participants []string `bson:"participants" json:"participants"`
Content []ContentBlockDoc `bson:"content" json:"content"`
ContentJson *string `bson:"contentJson,omitempty" json:"-"`
Tags []string `bson:"tags" json:"tags"`
Language string `bson:"language" json:"language"`
Source *string `bson:"source,omitempty" json:"source,omitempty"`
IsPublished bool `bson:"isPublished" json:"is_published"`
}
type TranscriptionSummaryDoc struct {
ID bson.ObjectID `bson:"_id" json:"id"`
Slug string `bson:"slug" json:"slug"`
Name string `bson:"name" json:"name"`
Type string `bson:"type" json:"type"`
Date *string `bson:"date,omitempty" json:"date,omitempty"`
Year *int `bson:"year,omitempty" json:"year,omitempty"`
Month *int `bson:"month,omitempty" json:"month,omitempty"`
Day *int `bson:"day,omitempty" json:"day,omitempty"`
Place *string `bson:"place,omitempty" json:"place,omitempty"`
Context *string `bson:"context,omitempty" json:"context,omitempty"`
Reference *string `bson:"reference,omitempty" json:"reference,omitempty"`
DurationMinutes *int `bson:"durationMinutes,omitempty" json:"duration_minutes,omitempty"`
AudioUrl *string `bson:"audioUrl,omitempty" json:"audio_url,omitempty"`
Participants []string `bson:"participants" json:"participants"`
}
var publishedFilter = bson.M{"isPublished": true}
var transcriptionSummaryProjection = bson.M{
"slug": 1, "name": 1, "type": 1, "date": 1,
"year": 1, "month": 1, "day": 1, "place": 1,
"context": 1, "reference": 1, "durationMinutes": 1,
"audioUrl": 1, "participants": 1,
}
func (r *TranscriptionRepo) GetBySlug(ctx context.Context, slug string) (*TranscriptionDoc, error) {
filter := bson.M{"slug": slug, "isPublished": true}
var doc TranscriptionDoc
err := r.col.FindOne(ctx, filter).Decode(&doc)
if err != nil {
if err == mongo.ErrNoDocuments {
return nil, nil
}
return nil, err
}
if len(doc.Content) == 0 && doc.ContentJson != nil && *doc.ContentJson != "" {
var blocks []ContentBlockDoc
if err := json.Unmarshal([]byte(*doc.ContentJson), &blocks); err == nil {
doc.Content = blocks
}
}
doc.ContentJson = nil
return &doc, nil
}
func (r *TranscriptionRepo) GetByYear(ctx context.Context, year int) ([]TranscriptionSummaryDoc, error) {
filter := bson.M{"year": year, "isPublished": true}
opts := options.Find().
SetSort(bson.D{{Key: "month", Value: 1}, {Key: "day", Value: 1}}).
SetProjection(transcriptionSummaryProjection)
cursor, err := r.col.Find(ctx, filter, opts)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var results []TranscriptionSummaryDoc
if err := cursor.All(ctx, &results); err != nil {
return nil, err
}
return results, nil
}
func (r *TranscriptionRepo) GetByPlace(ctx context.Context, place string) ([]TranscriptionSummaryDoc, error) {
filter := bson.M{"place": place, "isPublished": true}
opts := options.Find().
SetSort(bson.D{{Key: "year", Value: 1}, {Key: "month", Value: 1}, {Key: "day", Value: 1}}).
SetProjection(transcriptionSummaryProjection)
cursor, err := r.col.Find(ctx, filter, opts)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var results []TranscriptionSummaryDoc
if err := cursor.All(ctx, &results); err != nil {
return nil, err
}
return results, nil
}
func (r *TranscriptionRepo) GetByType(ctx context.Context, docType string) ([]TranscriptionSummaryDoc, error) {
filter := bson.M{"type": docType, "isPublished": true}
opts := options.Find().
SetSort(bson.D{{Key: "year", Value: 1}, {Key: "month", Value: 1}, {Key: "day", Value: 1}}).
SetProjection(transcriptionSummaryProjection)
cursor, err := r.col.Find(ctx, filter, opts)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var results []TranscriptionSummaryDoc
if err := cursor.All(ctx, &results); err != nil {
return nil, err
}
return results, nil
}
func (r *TranscriptionRepo) GetYears(ctx context.Context) ([]bson.M, error) {
pipeline := bson.A{
bson.M{"$match": bson.M{"isPublished": true, "year": bson.M{"$ne": nil}}},
bson.M{"$group": bson.M{"_id": "$year", "count": bson.M{"$sum": 1}}},
bson.M{"$sort": bson.M{"_id": 1}},
}
cursor, err := r.col.Aggregate(ctx, pipeline)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var results []bson.M
if err := cursor.All(ctx, &results); err != nil {
return nil, err
}
return results, nil
}
func (r *TranscriptionRepo) GetPlaces(ctx context.Context) ([]bson.M, error) {
pipeline := bson.A{
bson.M{"$match": bson.M{"isPublished": true, "place": bson.M{"$ne": nil}}},
bson.M{"$group": bson.M{"_id": "$place", "count": bson.M{"$sum": 1}}},
bson.M{"$sort": bson.M{"count": -1}},
}
cursor, err := r.col.Aggregate(ctx, pipeline)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var results []bson.M
if err := cursor.All(ctx, &results); err != nil {
return nil, err
}
return results, nil
}
func (r *TranscriptionRepo) GetTypeDistribution(ctx context.Context) (int64, int64, error) {
lectureCount, err := r.col.CountDocuments(ctx, bson.M{"type": "lecture", "isPublished": true})
if err != nil {
return 0, 0, err
}
conversationCount, err := r.col.CountDocuments(ctx, bson.M{"type": "conversation", "isPublished": true})
if err != nil {
return 0, 0, err
}
return lectureCount, conversationCount, nil
}
func (r *TranscriptionRepo) Count(ctx context.Context) (int64, error) {
return r.col.CountDocuments(ctx, publishedFilter)
}
func (r *TranscriptionRepo) GetAdjacent(ctx context.Context, slug string, year int) (*TranscriptionSummaryDoc, *TranscriptionSummaryDoc, error) {
filter := bson.M{"year": year, "isPublished": true}
opts := options.Find().
SetSort(bson.D{{Key: "month", Value: 1}, {Key: "day", Value: 1}}).
SetProjection(transcriptionSummaryProjection)
cursor, err := r.col.Find(ctx, filter, opts)
if err != nil {
return nil, nil, err
}
defer cursor.Close(ctx)
var summaries []TranscriptionSummaryDoc
if err := cursor.All(ctx, &summaries); err != nil {
return nil, nil, err
}
idx := -1
for i, s := range summaries {
if s.Slug == slug {
idx = i
break
}
}
if idx < 0 {
return nil, nil, nil
}
var prev, next *TranscriptionSummaryDoc
if idx > 0 {
prev = &summaries[idx-1]
}
if idx < len(summaries)-1 {
next = &summaries[idx+1]
}
return prev, next, nil
}