A simple frame for quickly setting up api services based on [go-cloud](https://github.com/google/go-cloud) framework
The Frame datastore component provides a robust database integration layer built on top of GORM. It supports multiple database connections, read/write separation, and multi-tenancy out of the box.
mainDbOption := frame.Datastore(ctx, "postgres://user:secret@primary_server/service_db", false)
readDbOption := frame.Datastore(ctx, "postgres://user:secret@secondary_server/service_db", true)
service := frame.NewService("Data service", mainDbOption, readDbOption)
postgres://[user]:[password]@[host]:[port]/[database]?[options]
Common options:
sslmode=disable|require|verify-ca|verify-full
timezone=UTC
pool_max_conns=10
type User struct {
ID uint
Name string
Email string
TenantID string `gorm:"index"`
}
// Create
db := frame.GetDB(ctx)
user := User{Name: "John", Email: "john@example.com"}
result := db.Create(&user)
// Read
var user User
db.First(&user, 1) // Find user with id 1
// Update
db.Model(&user).Update("Name", "John Doe")
// Delete
db.Delete(&user)
err := frame.GetDB(ctx).Transaction(func(tx *gorm.DB) error {
// Perform multiple operations
if err := tx.Create(&user).Error; err != nil {
return err
}
if err := tx.Create(&userProfile).Error; err != nil {
return err
}
return nil
})
// Tenant context is automatically injected
db := frame.GetDB(ctx)
var users []User
db.Find(&users) // Will automatically filter by tenant
// Override tenant context
db.WithContext(frame.WithTenant(ctx, "tenant-id")).Find(&users)
db := frame.GetDB(ctx) // Instead of accessing DB directly
if err := db.Create(&user).Error; err != nil {
return fmt.Errorf("failed to create user: %w", err)
}
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
type Model struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time `gorm:"index"`
TenantID string `gorm:"index"`
}
type Migration20240207 struct{}
func (m *Migration20240207) Up(db *gorm.DB) error {
return db.AutoMigrate(&User{})
}
func (m *Migration20240207) Down(db *gorm.DB) error {
return db.Migrator().DropTable(&User{})
}
migrator := frame.NewMigrator()
migrator.AddMigration(&Migration20240207{})
db.CreateInBatches(&users, 100)
db.Select("name", "email").Find(&users)
db.Preload("Profile").Find(&users)
db.Debug().Find(&users)
stats := db.DB().Stats()
log.Printf("Open connections: %d", stats.OpenConnections)
db.Statement.Settings.Set("gorm:query_timeout", time.Second*5)