From 7e2ceab4586e98b70994b39cea8ec577fce74afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Eduardo=20Jer=C3=A9z=20Gir=C3=B3n?= Date: Sun, 21 Jul 2024 20:09:11 -0600 Subject: [PATCH] Add soft delete executions functionality --- .../service/executions/delete_execution.go | 13 ------ .../service/executions/delete_execution.sql | 3 -- .../executions/soft_delete_execution.go | 40 +++++++++++++++++++ .../executions/soft_delete_execution.sql | 27 +++++++++++++ .../soft_delete_expired_executions.go | 18 +++++++++ .../soft_delete_expired_executions.sql | 11 +++++ 6 files changed, 96 insertions(+), 16 deletions(-) delete mode 100644 internal/service/executions/delete_execution.go delete mode 100644 internal/service/executions/delete_execution.sql create mode 100644 internal/service/executions/soft_delete_execution.go create mode 100644 internal/service/executions/soft_delete_execution.sql create mode 100644 internal/service/executions/soft_delete_expired_executions.go create mode 100644 internal/service/executions/soft_delete_expired_executions.sql diff --git a/internal/service/executions/delete_execution.go b/internal/service/executions/delete_execution.go deleted file mode 100644 index e55df82..0000000 --- a/internal/service/executions/delete_execution.go +++ /dev/null @@ -1,13 +0,0 @@ -package executions - -import ( - "context" - - "github.com/google/uuid" -) - -func (s *Service) DeleteExecution( - ctx context.Context, id uuid.UUID, -) error { - return s.dbgen.ExecutionsServiceDeleteExecution(ctx, id) -} diff --git a/internal/service/executions/delete_execution.sql b/internal/service/executions/delete_execution.sql deleted file mode 100644 index e163333..0000000 --- a/internal/service/executions/delete_execution.sql +++ /dev/null @@ -1,3 +0,0 @@ --- name: ExecutionsServiceDeleteExecution :exec -DELETE FROM executions -WHERE id = @id; diff --git a/internal/service/executions/soft_delete_execution.go b/internal/service/executions/soft_delete_execution.go new file mode 100644 index 0000000..b45014c --- /dev/null +++ b/internal/service/executions/soft_delete_execution.go @@ -0,0 +1,40 @@ +package executions + +import ( + "context" + "database/sql" + "errors" + + "github.com/eduardolat/pgbackweb/internal/database/dbgen" + "github.com/google/uuid" +) + +func (s *Service) SoftDeleteExecution( + ctx context.Context, executionID uuid.UUID, +) error { + execution, err := s.dbgen.ExecutionsServiceGetExecutionForSoftDelete( + ctx, dbgen.ExecutionsServiceGetExecutionForSoftDeleteParams{ + ExecutionID: executionID, + EncryptionKey: *s.env.PBW_ENCRYPTION_KEY, + }, + ) + if err != nil && errors.Is(err, sql.ErrNoRows) { + return nil + } + if err != nil { + return err + } + + if execution.ExecutionPath.Valid { + err := s.ints.S3Client.Delete( + execution.DestinationAccessKey, execution.DestinationSecretKey, + execution.DestinationRegion, execution.DestinationEndpoint, + execution.DestinationBucketName, execution.ExecutionPath.String, + ) + if err != nil { + return err + } + } + + return s.dbgen.ExecutionsServiceSoftDeleteExecution(ctx, executionID) +} diff --git a/internal/service/executions/soft_delete_execution.sql b/internal/service/executions/soft_delete_execution.sql new file mode 100644 index 0000000..c96f7ac --- /dev/null +++ b/internal/service/executions/soft_delete_execution.sql @@ -0,0 +1,27 @@ +-- name: ExecutionsServiceGetExecutionForSoftDelete :one +SELECT + executions.id as execution_id, + executions.path as execution_path, + + backups.id as backup_id, + + destinations.bucket_name as destination_bucket_name, + destinations.region as destination_region, + destinations.endpoint as destination_endpoint, + pgp_sym_decrypt( + destinations.access_key, @encryption_key + ) AS destination_access_key, + pgp_sym_decrypt( + destinations.secret_key, @encryption_key + ) AS destination_secret_key +FROM executions +JOIN backups ON backups.id = executions.backup_id +JOIN destinations ON destinations.id = backups.destination_id +WHERE executions.id = @execution_id; + +-- name: ExecutionsServiceSoftDeleteExecution :exec +UPDATE executions +SET + status = 'deleted', + deleted_at = NOW() +WHERE id = @id; diff --git a/internal/service/executions/soft_delete_expired_executions.go b/internal/service/executions/soft_delete_expired_executions.go new file mode 100644 index 0000000..2d6dbe9 --- /dev/null +++ b/internal/service/executions/soft_delete_expired_executions.go @@ -0,0 +1,18 @@ +package executions + +import "context" + +func (s *Service) SoftDeleteExpiredExecutions(ctx context.Context) error { + expiredExecutions, err := s.dbgen.ExecutionsServiceGetExpiredExecutions(ctx) + if err != nil { + return err + } + + for _, execution := range expiredExecutions { + if err := s.SoftDeleteExecution(ctx, execution.ID); err != nil { + return err + } + } + + return nil +} diff --git a/internal/service/executions/soft_delete_expired_executions.sql b/internal/service/executions/soft_delete_expired_executions.sql new file mode 100644 index 0000000..b9e92a3 --- /dev/null +++ b/internal/service/executions/soft_delete_expired_executions.sql @@ -0,0 +1,11 @@ +-- name: ExecutionsServiceGetExpiredExecutions :many +SELECT executions.* +FROM executions +JOIN backups ON executions.backup_id = backups.id +WHERE + backups.retention_days > 0 + AND executions.status != 'deleted' + AND executions.finished_at IS NOT NULL + AND ( + executions.finished_at + (backups.retention_days || ' days')::INTERVAL + ) < NOW();