Base de données¶
Migrations¶
Le projet utilise GORM AutoMigrate pour simplifier les migrations en développement:
// internal/infrastructure/database/database.go
db.AutoMigrate(
&models.User{},
&models.RefreshToken{},
)
AutoMigrate: - Crée les tables si elles n'existent pas - Ajoute les colonnes manquantes - Crée les indexes - NE supprime PAS de colonnes ou tables
Pour la production, considérer une solution de migrations versionnées:
- golang-migrate/migrate: Migrations SQL ou Go
- pressly/goose: Migrations up/down
- GORM Migrator avancé: API programmatique
Exemple avec golang-migrate:
# Installer migrate
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
# Créer migration
migrate create -ext sql -dir migrations -seq create_users_table
# Fichiers créés:
# migrations/000001_create_users_table.up.sql
# migrations/000001_create_users_table.down.sql
# Run migrations
migrate -path migrations -database "postgresql://user:pass@localhost/dbname?sslmode=disable" up
Modèles GORM¶
Conventions et patterns:
type User struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
Email string `gorm:"uniqueIndex;not null" json:"email" validate:"required,email"`
Password string `gorm:"not null" json:"-"`
}
Tags GORM importants:
| Tag | Description |
|---|---|
primarykey |
Clé primaire |
uniqueIndex |
Index unique |
index |
Index simple |
not null |
Colonne NOT NULL |
default:value |
Valeur par défaut |
size:255 |
Taille de colonne |
type:varchar(100) |
Type SQL custom |
foreignKey:UserID |
Clé étrangère |
references:ID |
Référence FK |
Conventions:
- Soft deletes:
DeletedAt gorm.DeletedAt - Timestamps auto:
CreatedAt,UpdatedAt - JSON hiding:
json:"-"pour password - Index sur FK: Toujours indexer les clés étrangères
Queries avancées¶
Pagination¶
Filtering¶
// Where simple
db.Where("email = ?", "user@example.com").First(&user)
// Where avec multiple conditions
db.Where("created_at > ? AND email LIKE ?", time.Now().Add(-24*time.Hour), "%@example.com").Find(&users)
// Or
db.Where("email = ?", email1).Or("email = ?", email2).Find(&users)
Sorting¶
// Order ASC
db.Order("created_at asc").Find(&users)
// Order DESC
db.Order("created_at desc").Find(&users)
// Multiple sorts
db.Order("created_at desc, email asc").Find(&users)
Joins¶
// Inner join
db.Joins("LEFT JOIN refresh_tokens ON refresh_tokens.user_id = users.id").
Where("refresh_tokens.expires_at > ?", time.Now()).
Find(&users)
// Preload associations
db.Preload("RefreshTokens").Find(&users)
Aggregations¶
// Count
var count int64
db.Model(&models.User{}).Count(&count)
// With where
db.Model(&models.User{}).Where("created_at > ?", yesterday).Count(&count)
Transactions¶
err := db.Transaction(func(tx *gorm.DB) error {
// Create user
if err := tx.Create(&user).Error; err != nil {
return err // Rollback
}
// Create profile
if err := tx.Create(&profile).Error; err != nil {
return err // Rollback
}
return nil // Commit
})
Raw SQL¶
// Raw query
var users []models.User
db.Raw("SELECT * FROM users WHERE email LIKE ?", "%@example.com").Scan(&users)
// Exec
db.Exec("UPDATE users SET email = ? WHERE id = ?", newEmail, userID)
Performance tips¶
-
Index les colonnes fréquemment requêtées:
-
Éviter N+1 queries avec Preload:
-
Select seulement les colonnes nécessaires:
-
Utiliser les connections pools:
Navigation¶
Previous: Tests
Next: Sécurité
Index: Guide Index