mirror of
https://github.com/databasus/databasus.git
synced 2026-04-06 00:32:03 +02:00
199 lines
6.2 KiB
Go
199 lines
6.2 KiB
Go
package databases
|
|
|
|
import (
|
|
"context"
|
|
"databasus-backend/internal/features/databases/databases/mariadb"
|
|
"databasus-backend/internal/features/databases/databases/mongodb"
|
|
"databasus-backend/internal/features/databases/databases/mysql"
|
|
"databasus-backend/internal/features/databases/databases/postgresql"
|
|
"databasus-backend/internal/features/notifiers"
|
|
"databasus-backend/internal/util/encryption"
|
|
"errors"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Database struct {
|
|
ID uuid.UUID `json:"id" gorm:"column:id;primaryKey;type:uuid;default:gen_random_uuid()"`
|
|
|
|
// WorkspaceID can be null when a database is created via restore operation
|
|
// outside the context of any workspace
|
|
WorkspaceID *uuid.UUID `json:"workspaceId" gorm:"column:workspace_id;type:uuid"`
|
|
Name string `json:"name" gorm:"column:name;type:text;not null"`
|
|
Type DatabaseType `json:"type" gorm:"column:type;type:text;not null"`
|
|
|
|
Postgresql *postgresql.PostgresqlDatabase `json:"postgresql,omitempty" gorm:"foreignKey:DatabaseID"`
|
|
Mysql *mysql.MysqlDatabase `json:"mysql,omitempty" gorm:"foreignKey:DatabaseID"`
|
|
Mariadb *mariadb.MariadbDatabase `json:"mariadb,omitempty" gorm:"foreignKey:DatabaseID"`
|
|
Mongodb *mongodb.MongodbDatabase `json:"mongodb,omitempty" gorm:"foreignKey:DatabaseID"`
|
|
|
|
Notifiers []notifiers.Notifier `json:"notifiers" gorm:"many2many:database_notifiers;"`
|
|
|
|
// these fields are not reliable, but
|
|
// they are used for pretty UI
|
|
LastBackupTime *time.Time `json:"lastBackupTime,omitempty" gorm:"column:last_backup_time;type:timestamp with time zone"`
|
|
LastBackupErrorMessage *string `json:"lastBackupErrorMessage,omitempty" gorm:"column:last_backup_error_message;type:text"`
|
|
|
|
HealthStatus *HealthStatus `json:"healthStatus" gorm:"column:health_status;type:text;not null"`
|
|
|
|
AgentToken *string `json:"-" gorm:"column:agent_token;type:text"`
|
|
IsAgentTokenGenerated bool `json:"isAgentTokenGenerated" gorm:"column:is_agent_token_generated;not null;default:false"`
|
|
}
|
|
|
|
func (d *Database) Validate() error {
|
|
if d.Name == "" {
|
|
return errors.New("name is required")
|
|
}
|
|
|
|
switch d.Type {
|
|
case DatabaseTypePostgres:
|
|
if d.Postgresql == nil {
|
|
return errors.New("postgresql database is required")
|
|
}
|
|
return d.Postgresql.Validate()
|
|
case DatabaseTypeMysql:
|
|
if d.Mysql == nil {
|
|
return errors.New("mysql database is required")
|
|
}
|
|
return d.Mysql.Validate()
|
|
case DatabaseTypeMariadb:
|
|
if d.Mariadb == nil {
|
|
return errors.New("mariadb database is required")
|
|
}
|
|
return d.Mariadb.Validate()
|
|
case DatabaseTypeMongodb:
|
|
if d.Mongodb == nil {
|
|
return errors.New("mongodb database is required")
|
|
}
|
|
return d.Mongodb.Validate()
|
|
default:
|
|
return errors.New("invalid database type: " + string(d.Type))
|
|
}
|
|
}
|
|
|
|
func (d *Database) ValidateUpdate(old, new Database) error {
|
|
// Database type cannot be changed after creation — the entire backup
|
|
// structure (storage files, schedulers, WAL hierarchy, etc.) is tied to
|
|
// the type at creation time. Recreating that state automatically is
|
|
// error-prone; it is safer for the user to create a new database and
|
|
// remove the old one.
|
|
if old.Type != new.Type {
|
|
return errors.New("database type cannot be changed; create a new database instead")
|
|
}
|
|
|
|
if old.Type == DatabaseTypePostgres && old.Postgresql != nil && new.Postgresql != nil {
|
|
if err := new.Postgresql.ValidateUpdate(old.Postgresql); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *Database) TestConnection(
|
|
logger *slog.Logger,
|
|
encryptor encryption.FieldEncryptor,
|
|
) error {
|
|
return d.getSpecificDatabase().TestConnection(logger, encryptor, d.ID)
|
|
}
|
|
|
|
func (d *Database) IsUserReadOnly(
|
|
ctx context.Context,
|
|
logger *slog.Logger,
|
|
encryptor encryption.FieldEncryptor,
|
|
) (bool, []string, error) {
|
|
switch d.Type {
|
|
case DatabaseTypePostgres:
|
|
return d.Postgresql.IsUserReadOnly(ctx, logger, encryptor, d.ID)
|
|
case DatabaseTypeMysql:
|
|
return d.Mysql.IsUserReadOnly(ctx, logger, encryptor, d.ID)
|
|
case DatabaseTypeMariadb:
|
|
return d.Mariadb.IsUserReadOnly(ctx, logger, encryptor, d.ID)
|
|
case DatabaseTypeMongodb:
|
|
return d.Mongodb.IsUserReadOnly(ctx, logger, encryptor, d.ID)
|
|
default:
|
|
return false, nil, errors.New("read-only check not supported for this database type")
|
|
}
|
|
}
|
|
|
|
func (d *Database) HideSensitiveData() {
|
|
d.getSpecificDatabase().HideSensitiveData()
|
|
}
|
|
|
|
func (d *Database) EncryptSensitiveFields(encryptor encryption.FieldEncryptor) error {
|
|
if d.Postgresql != nil {
|
|
return d.Postgresql.EncryptSensitiveFields(d.ID, encryptor)
|
|
}
|
|
if d.Mysql != nil {
|
|
return d.Mysql.EncryptSensitiveFields(d.ID, encryptor)
|
|
}
|
|
if d.Mariadb != nil {
|
|
return d.Mariadb.EncryptSensitiveFields(d.ID, encryptor)
|
|
}
|
|
if d.Mongodb != nil {
|
|
return d.Mongodb.EncryptSensitiveFields(d.ID, encryptor)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *Database) PopulateDbData(
|
|
logger *slog.Logger,
|
|
encryptor encryption.FieldEncryptor,
|
|
) error {
|
|
if d.Postgresql != nil {
|
|
return d.Postgresql.PopulateDbData(logger, encryptor, d.ID)
|
|
}
|
|
if d.Mysql != nil {
|
|
return d.Mysql.PopulateDbData(logger, encryptor, d.ID)
|
|
}
|
|
if d.Mariadb != nil {
|
|
return d.Mariadb.PopulateDbData(logger, encryptor, d.ID)
|
|
}
|
|
if d.Mongodb != nil {
|
|
return d.Mongodb.PopulateDbData(logger, encryptor, d.ID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *Database) Update(incoming *Database) {
|
|
d.Name = incoming.Name
|
|
d.Type = incoming.Type
|
|
d.Notifiers = incoming.Notifiers
|
|
|
|
switch d.Type {
|
|
case DatabaseTypePostgres:
|
|
if d.Postgresql != nil && incoming.Postgresql != nil {
|
|
d.Postgresql.Update(incoming.Postgresql)
|
|
}
|
|
case DatabaseTypeMysql:
|
|
if d.Mysql != nil && incoming.Mysql != nil {
|
|
d.Mysql.Update(incoming.Mysql)
|
|
}
|
|
case DatabaseTypeMariadb:
|
|
if d.Mariadb != nil && incoming.Mariadb != nil {
|
|
d.Mariadb.Update(incoming.Mariadb)
|
|
}
|
|
case DatabaseTypeMongodb:
|
|
if d.Mongodb != nil && incoming.Mongodb != nil {
|
|
d.Mongodb.Update(incoming.Mongodb)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (d *Database) getSpecificDatabase() DatabaseConnector {
|
|
switch d.Type {
|
|
case DatabaseTypePostgres:
|
|
return d.Postgresql
|
|
case DatabaseTypeMysql:
|
|
return d.Mysql
|
|
case DatabaseTypeMariadb:
|
|
return d.Mariadb
|
|
case DatabaseTypeMongodb:
|
|
return d.Mongodb
|
|
}
|
|
|
|
panic("invalid database type: " + string(d.Type))
|
|
}
|