package storages import ( "context" "database/sql" "errors" "backend/database/fields" "backend/database/schemas/public/model" "backend/database/schemas/public/table" "backend/providers/otel" . "github.com/go-jet/jet/v2/postgres" "github.com/samber/lo" log "github.com/sirupsen/logrus" "github.com/spf13/afero" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" ) // @provider:except type Service struct { db *sql.DB log *log.Entry `inject:"false"` } func (svc *Service) Prepare() error { svc.log = log.WithField("module", "storages.service") _ = Int(1) return nil } // GetStorages func (svc *Service) GetStorages(ctx context.Context) ([]model.Storages, error) { _, span := otel.Start(ctx, "storages.service.GetStorages") defer span.End() tbl := table.Storages stmt := tbl.SELECT(tbl.AllColumns) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) var storages []model.Storages if err := stmt.QueryContext(ctx, svc.db, &storages); err != nil { return nil, err } return storages, nil } // GetStorageByID func (svc *Service) GetStorageByID(ctx context.Context, id int64) (*model.Storages, error) { _, span := otel.Start(ctx, "storages.service.GetStorageByID") defer span.End() tbl := table.Storages stmt := tbl.SELECT(tbl.AllColumns).WHERE(tbl.ID.EQ(Int64(id))) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) var storage model.Storages if err := stmt.QueryContext(ctx, svc.db, &storage); err != nil { return nil, err } return &storage, nil } // DeleteStorageByID func (svc *Service) DeleteStorageByID(ctx context.Context, id int64) error { _, span := otel.Start(ctx, "storages.service.DeleteStorageByID") defer span.End() tbl := table.Storages stmt := tbl.DELETE().WHERE(tbl.ID.EQ(Int64(id))) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) _, err := stmt.ExecContext(ctx, svc.db) return err } // Create func (svc *Service) Create(ctx context.Context, req *model.Storages) error { _, span := otel.Start(ctx, "storages.service.Create") defer span.End() tbl := table.Storages stmt := tbl.INSERT(tbl.Name, tbl.Type, tbl.Config).VALUES(req.Name, req.Type, req.Config) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) _, err := stmt.ExecContext(ctx, svc.db) return err } // SetDefault func (svc *Service) SetDefault(ctx context.Context, id int64) error { _, span := otel.Start(ctx, "storages.service.SetDefault") defer span.End() // Start transaction tx, err := svc.db.BeginTx(ctx, nil) if err != nil { return err } defer tx.Rollback() tbl := table.Storages // First, set all storages' is_default to false resetStmt := tbl. UPDATE(tbl.IsDefault). SET(tbl.IsDefault.SET(Bool(false))) span.SetAttributes(semconv.DBStatementKey.String(resetStmt.DebugSql())) if _, err := resetStmt.ExecContext(ctx, tx); err != nil { return err } // Then, set the specified storage's is_default to true setDefaultStmt := tbl. UPDATE(tbl.IsDefault). SET(tbl.IsDefault.SET(Bool(true))). WHERE(tbl.ID.EQ(Int64(id))) span.SetAttributes(semconv.DBStatementKey.String(setDefaultStmt.DebugSql())) if _, err := setDefaultStmt.ExecContext(ctx, tx); err != nil { return err } // Commit transaction return tx.Commit() } // GetDefault func (svc *Service) GetDefault(ctx context.Context) (*model.Storages, error) { _, span := otel.Start(ctx, "storages.service.GetDefault") defer span.End() tbl := table.Storages stmt := tbl.SELECT(tbl.AllColumns).WHERE(tbl.IsDefault.EQ(Bool(true))) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) var storage model.Storages if err := stmt.QueryContext(ctx, svc.db, &storage); err != nil { return nil, err } return &storage, nil } // GetStoragesByID func (svc *Service) GetStoragesByID(ctx context.Context, ids ...int64) ([]model.Storages, error) { if len(ids) == 0 { return nil, nil } ids = lo.Uniq(ids) _, span := otel.Start(ctx, "storages.service.GetStoragesByID") defer span.End() tbl := table.Storages stmt := tbl.SELECT(tbl.AllColumns).WHERE(tbl.ID.IN(lo.Map(ids, func(i int64, _ int) Expression { return Int64(i) })...)) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) var storages []model.Storages if err := stmt.QueryContext(ctx, svc.db, &storages); err != nil { return nil, err } return storages, nil } func (svc *Service) GetDefaultFS(ctx context.Context) (afero.Fs, error) { st, err := svc.GetDefault(ctx) if err != nil { return nil, err } return svc.BuildFS(st) } func (svc *Service) GetFSMapByIDs(ctx context.Context, ids ...int64) (map[int64]afero.Fs, error) { _, span := otel.Start(ctx, "storages.service.GetFSByID") defer span.End() storages, err := svc.GetStoragesByID(ctx, ids...) if err != nil { return nil, err } maps := make(map[int64]afero.Fs) for _, s := range storages { fs, err := svc.BuildFS(&s) if err != nil { return nil, err } maps[s.ID] = fs } return maps, nil } // GetFSByID func (svc *Service) GetFSByID(ctx context.Context, id int64) (afero.Fs, error) { _, span := otel.Start(ctx, "storages.service.GetFSByID") defer span.End() storage, err := svc.GetStorageByID(ctx, id) if err != nil { return nil, err } return svc.BuildFS(storage) } func (svc *Service) BuildFS(storage *model.Storages) (afero.Fs, error) { switch storage.Type { case fields.StorageTypeLocal: return afero.NewBasePathFs(afero.NewOsFs(), storage.Config.Local.Path), nil } return nil, errors.New("invalid storage type") }