tercul-backend/internal/store/db.go
Damir Mukimov 4957117cb6 Initial commit: Tercul Go project with comprehensive architecture
- Core Go application with GraphQL API using gqlgen
- Comprehensive data models for literary works, authors, translations
- Repository pattern with caching layer
- Authentication and authorization system
- Linguistics analysis capabilities with multiple adapters
- Vector search integration with Weaviate
- Docker containerization support
- Python data migration and analysis scripts
- Clean architecture with proper separation of concerns
- Production-ready configuration and middleware
- Proper .gitignore excluding vendor/, database files, and build artifacts
2025-08-13 07:42:32 +02:00

147 lines
4.1 KiB
Go

package store
import (
"gorm.io/gorm"
"strings"
"tercul/models"
)
// DB represents a database connection
type DB struct {
*gorm.DB
}
// Connect creates a new database connection
func Connect() *DB {
// In a real application, this would use configuration from environment variables
// or a configuration file to connect to the database
// For this example, we'll assume the DB connection is passed in from main.go
return nil
}
// ListPendingWorks returns a list of works that need to be enriched
func ListPendingWorks(db *DB) []Work {
var works []Work
// Query for works that haven't been enriched yet
var modelWorks []models.Work
db.Where("id NOT IN (SELECT work_id FROM language_analyses)").Find(&modelWorks)
// Convert to store.Work
for _, work := range modelWorks {
// Prefer original language translation; fallback to work language; then any
var content string
var t models.Translation
// Try original
if err := db.Where("translatable_type = ? AND translatable_id = ? AND is_original_language = ?", "Work", work.ID, true).
First(&t).Error; err == nil {
content = t.Content
} else {
// Try same language
if err := db.Where("translatable_type = ? AND translatable_id = ? AND language = ?", "Work", work.ID, work.Language).
First(&t).Error; err == nil {
content = t.Content
} else {
// Any translation
if err := db.Where("translatable_type = ? AND translatable_id = ?", "Work", work.ID).
First(&t).Error; err == nil {
content = t.Content
}
}
}
works = append(works, Work{
ID: work.ID,
Body: content,
})
}
return works
}
// UpsertWord creates or updates a word in the database
func UpsertWord(db *DB, workID uint, text, lemma, pos, phonetic string) error {
// Check if the word already exists
var word models.Word
result := db.Where("text = ? AND language = ?", text, "auto").First(&word)
if result.Error != nil && result.Error != gorm.ErrRecordNotFound {
return result.Error
}
// Create or update the word
if result.Error == gorm.ErrRecordNotFound {
// Create new word
word = models.Word{
Text: text,
Language: "auto", // This would be set to the detected language
PartOfSpeech: pos,
Lemma: lemma,
}
if err := db.Create(&word).Error; err != nil {
return err
}
} else {
// Update existing word
word.PartOfSpeech = pos
word.Lemma = lemma
if err := db.Save(&word).Error; err != nil {
return err
}
}
// Associate the word with the work
return db.Exec("INSERT INTO work_words (work_id, word_id) VALUES (?, ?) ON CONFLICT DO NOTHING", workID, word.ID).Error
}
// SaveKeywords saves keywords for a work
func SaveKeywords(db *DB, workID uint, keywords []string) error {
// Clear existing keywords
if err := db.Exec("DELETE FROM work_topic_clusters WHERE work_id = ?", workID).Error; err != nil {
return err
}
// Create a topic cluster for the keywords
cluster := models.TopicCluster{
Name: "Auto-generated",
Description: "Automatically generated keywords",
Keywords: strings.Join(keywords, ", "),
}
if err := db.Create(&cluster).Error; err != nil {
return err
}
// Associate the cluster with the work
return db.Exec("INSERT INTO work_topic_clusters (work_id, topic_cluster_id) VALUES (?, ?)", workID, cluster.ID).Error
}
// SavePoetics saves poetic analysis for a work
func SavePoetics(db *DB, workID uint, metrics PoeticMetrics) error {
poetics := models.PoeticAnalysis{
WorkID: workID,
Language: "auto", // This would be set to the detected language
RhymeScheme: metrics.RhymeScheme,
MeterType: metrics.MeterType,
StanzaCount: metrics.StanzaCount,
LineCount: metrics.LineCount,
Structure: metrics.Structure,
}
return db.Create(&poetics).Error
}
// MarkEnriched marks a work as enriched with the detected language
func MarkEnriched(db *DB, workID uint, language string) error {
// Create a language analysis record to mark the work as processed
analysis := models.LanguageAnalysis{
WorkID: workID,
Language: language,
Analysis: models.JSONB{
"enriched": true,
"language": language,
},
}
return db.Create(&analysis).Error
}