mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 00:31:35 +00:00
332 lines
10 KiB
Go
332 lines
10 KiB
Go
package db
|
|
|
|
import (
|
|
"gorm.io/gorm"
|
|
models2 "tercul/internal/models"
|
|
"tercul/internal/platform/log"
|
|
)
|
|
|
|
// RunMigrations runs all database migrations
|
|
func RunMigrations(db *gorm.DB) error {
|
|
log.LogInfo("Running database migrations")
|
|
|
|
// First, create all tables using GORM AutoMigrate
|
|
if err := createTables(db); err != nil {
|
|
log.LogError("Failed to create tables", log.F("error", err))
|
|
return err
|
|
}
|
|
|
|
// Then add indexes to improve query performance
|
|
if err := addIndexes(db); err != nil {
|
|
log.LogError("Failed to add indexes", log.F("error", err))
|
|
return err
|
|
}
|
|
|
|
log.LogInfo("Database migrations completed successfully")
|
|
return nil
|
|
}
|
|
|
|
// createTables creates all database tables using GORM AutoMigrate
|
|
func createTables(db *gorm.DB) error {
|
|
log.LogInfo("Creating database tables")
|
|
|
|
// Enable recommended extensions
|
|
if err := db.Exec("CREATE EXTENSION IF NOT EXISTS pg_trgm").Error; err != nil {
|
|
log.LogError("Failed to enable pg_trgm extension", log.F("error", err))
|
|
return err
|
|
}
|
|
|
|
// Create all models/tables
|
|
err := db.AutoMigrate(
|
|
// User-related models
|
|
&models2.User{},
|
|
&models2.UserProfile{},
|
|
&models2.UserSession{},
|
|
&models2.PasswordReset{},
|
|
&models2.EmailVerification{},
|
|
|
|
// Literary models
|
|
&models2.Work{},
|
|
&models2.Translation{},
|
|
&models2.Author{},
|
|
&models2.Book{},
|
|
&models2.Publisher{},
|
|
&models2.Source{},
|
|
&models2.Edition{},
|
|
&models2.Series{},
|
|
&models2.WorkSeries{},
|
|
|
|
// Organization models
|
|
&models2.Tag{},
|
|
&models2.Category{},
|
|
|
|
// Interaction models
|
|
&models2.Comment{},
|
|
&models2.Like{},
|
|
&models2.Bookmark{},
|
|
&models2.Collection{},
|
|
&models2.Contribution{},
|
|
&models2.InteractionEvent{},
|
|
|
|
// Location models
|
|
&models2.Country{},
|
|
&models2.City{},
|
|
&models2.Place{},
|
|
&models2.Address{},
|
|
&models2.Language{},
|
|
|
|
// Linguistic models
|
|
&models2.ReadabilityScore{},
|
|
&models2.WritingStyle{},
|
|
&models2.LinguisticLayer{},
|
|
&models2.TextMetadata{},
|
|
&models2.PoeticAnalysis{},
|
|
&models2.Word{},
|
|
&models2.Concept{},
|
|
&models2.LanguageEntity{},
|
|
&models2.TextBlock{},
|
|
&models2.WordOccurrence{},
|
|
&models2.EntityOccurrence{},
|
|
|
|
// Relationship models
|
|
&models2.Edge{},
|
|
&models2.Embedding{},
|
|
&models2.Media{},
|
|
&models2.BookWork{},
|
|
&models2.AuthorCountry{},
|
|
&models2.WorkAuthor{},
|
|
&models2.BookAuthor{},
|
|
|
|
// System models
|
|
&models2.Notification{},
|
|
&models2.EditorialWorkflow{},
|
|
&models2.Admin{},
|
|
&models2.Vote{},
|
|
&models2.Contributor{},
|
|
&models2.HybridEntityWork{},
|
|
&models2.ModerationFlag{},
|
|
&models2.AuditLog{},
|
|
|
|
// Rights models
|
|
&models2.Copyright{},
|
|
&models2.CopyrightClaim{},
|
|
&models2.Monetization{},
|
|
&models2.License{},
|
|
|
|
// Analytics models
|
|
&models2.WorkStats{},
|
|
&models2.TranslationStats{},
|
|
&models2.UserStats{},
|
|
&models2.BookStats{},
|
|
&models2.CollectionStats{},
|
|
&models2.MediaStats{},
|
|
|
|
// Metadata models
|
|
&models2.LanguageAnalysis{},
|
|
&models2.Gamification{},
|
|
&models2.Stats{},
|
|
&models2.SearchDocument{},
|
|
|
|
// Psychological models
|
|
&models2.Emotion{},
|
|
&models2.Mood{},
|
|
&models2.TopicCluster{},
|
|
)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.LogInfo("Database tables created successfully")
|
|
return nil
|
|
}
|
|
|
|
// addIndexes adds indexes to frequently queried columns
|
|
func addIndexes(db *gorm.DB) error {
|
|
// Work table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_works_language ON works(language)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_works_title ON works(title)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_works_status ON works(status)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_works_slug ON works(slug)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Translation table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_translations_work_id ON translations(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_translations_language ON translations(language)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_translations_translator_id ON translations(translator_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE UNIQUE INDEX IF NOT EXISTS ux_translations_entity_lang ON translations(translatable_type, translatable_id, language)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// User table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_users_username ON users(username)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_users_role ON users(role)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Author table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_authors_name ON authors(name)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Category table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_categories_name ON categories(name)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_categories_slug ON categories(slug)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_categories_path ON categories(path)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Tag table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_tags_name ON tags(name)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_tags_slug ON tags(slug)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Comment table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_comments_user_id ON comments(user_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_comments_work_id ON comments(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_comments_translation_id ON comments(translation_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Like table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_likes_user_id ON likes(user_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_likes_work_id ON likes(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_likes_translation_id ON likes(translation_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Bookmark table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_bookmarks_user_id ON bookmarks(user_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_bookmarks_work_id ON bookmarks(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Collection table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_collections_user_id ON collections(user_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Contribution table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_contributions_user_id ON contributions(user_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_contributions_work_id ON contributions(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_contributions_status ON contributions(status)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Edge table indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_edges_source_table_id ON edges(source_table, source_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_edges_target_table_id ON edges(target_table, target_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_edges_relation ON edges(relation)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// WorkAuthor unique pair and order index
|
|
if err := db.Exec("CREATE UNIQUE INDEX IF NOT EXISTS ux_work_authors_pair ON work_authors(work_id, author_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_work_authors_ordinal ON work_authors(ordinal)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// BookAuthor unique pair and order index
|
|
if err := db.Exec("CREATE UNIQUE INDEX IF NOT EXISTS ux_book_authors_pair ON book_authors(book_id, author_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_book_authors_ordinal ON book_authors(ordinal)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// InteractionEvent indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_interaction_events_target ON interaction_events(target_type, target_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_interaction_events_kind ON interaction_events(kind)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_interaction_events_user ON interaction_events(user_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// SearchDocument indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_search_documents_entity ON search_documents(entity_type, entity_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_search_documents_lang ON search_documents(language_code)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Linguistic analysis indexes
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_text_metadata_work_id ON text_metadata(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_readability_scores_work_id ON readability_scores(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_language_analyses_work_id ON language_analyses(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_poetic_analyses_work_id ON poetic_analyses(work_id)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Timestamps indexes for frequently queried tables
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_works_created_at ON works(created_at)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_translations_created_at ON translations(created_at)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_comments_created_at ON comments(created_at)").Error; err != nil {
|
|
return err
|
|
}
|
|
if err := db.Exec("CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at)").Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
log.LogInfo("Database indexes added successfully")
|
|
return nil
|
|
}
|