From e0d7741376af2eefe0c180aef4b172c525ad31a6 Mon Sep 17 00:00:00 2001 From: Sven Urbanski Date: Wed, 26 Jun 2024 16:20:49 +0200 Subject: [PATCH] chore(db): move db transactions into own file (#1703) --- pkg/db/db.go | 63 -------------------------------- pkg/db/transactions.go | 83 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 63 deletions(-) create mode 100644 pkg/db/transactions.go diff --git a/pkg/db/db.go b/pkg/db/db.go index f678c23b0..30a9da53b 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -200,8 +200,6 @@ func SqliteToPostgresQuery(query string) string { return q } -type DBFunction func(ctx context.Context, transaction *sql.Tx) error - func Remove(s []string, r string) []string { for i, v := range s { if v == r { @@ -211,67 +209,6 @@ func Remove(s []string, r string) []string { return s } -// WithTransaction opens a transaction, runs `f` and then calls either Commit or Rollback. -// Use this if the only thing to return from `f` is an error. -func (h *DBHandler) WithTransaction(ctx context.Context, f DBFunction) error { - _, err := WithTransactionT(h, ctx, func(ctx context.Context, transaction *sql.Tx) (*interface{}, error) { - err2 := f(ctx, transaction) - if err2 != nil { - return nil, err2 - } - return nil, nil - }) - if err != nil { - return err - } - return nil -} - -type DBFunctionT[T any] func(ctx context.Context, transaction *sql.Tx) (*T, error) - -// WithTransactionT is the same as WithTransaction, but you can also return data, not just the error. -func WithTransactionT[T any](h *DBHandler, ctx context.Context, f DBFunctionT[T]) (*T, error) { - res, err := WithTransactionMultipleEntriesT(h, ctx, func(ctx context.Context, transaction *sql.Tx) ([]T, error) { - fRes, err2 := f(ctx, transaction) - if err2 != nil { - return nil, err2 - } - if fRes == nil { - return make([]T, 0), nil - } - return []T{*fRes}, nil - }) - if err != nil || len(res) == 0 { - return nil, err - } - return &res[0], err -} - -type DBFunctionMultipleEntriesT[T any] func(ctx context.Context, transaction *sql.Tx) ([]T, error) - -// WithTransactionMultipleEntriesT is the same as WithTransaction, but you can also return and array of data, not just the error. -func WithTransactionMultipleEntriesT[T any](h *DBHandler, ctx context.Context, f DBFunctionMultipleEntriesT[T]) ([]T, error) { - tx, err := h.DB.BeginTx(ctx, nil) - if err != nil { - return nil, err - } - defer func(tx *sql.Tx) { - _ = tx.Rollback() - // we ignore the error returned from Rollback() here, - // because it is always set when Commit() was successful - }(tx) - - result, err := f(ctx, tx) - if err != nil { - return nil, err - } - err = tx.Commit() - if err != nil { - return nil, err - } - return result, nil -} - func closeRows(rows *sql.Rows) error { err := rows.Close() if err != nil { diff --git a/pkg/db/transactions.go b/pkg/db/transactions.go new file mode 100644 index 000000000..95c1ca68b --- /dev/null +++ b/pkg/db/transactions.go @@ -0,0 +1,83 @@ +/*This file is part of kuberpult. + +Kuberpult is free software: you can redistribute it and/or modify +it under the terms of the Expat(MIT) License as published by +the Free Software Foundation. + +Kuberpult is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +MIT License for more details. + +You should have received a copy of the MIT License +along with kuberpult. If not, see . + +Copyright freiheit.com*/ + +package db + +import ( + "context" + "database/sql" +) + +type DBFunction func(ctx context.Context, transaction *sql.Tx) error +type DBFunctionT[T any] func(ctx context.Context, transaction *sql.Tx) (*T, error) +type DBFunctionMultipleEntriesT[T any] func(ctx context.Context, transaction *sql.Tx) ([]T, error) + +// WithTransaction opens a transaction, runs `f` and then calls either Commit or Rollback. +// Use this if the only thing to return from `f` is an error. +func (h *DBHandler) WithTransaction(ctx context.Context, f DBFunction) error { + _, err := WithTransactionT(h, ctx, func(ctx context.Context, transaction *sql.Tx) (*interface{}, error) { + err2 := f(ctx, transaction) + if err2 != nil { + return nil, err2 + } + return nil, nil + }) + if err != nil { + return err + } + return nil +} + +// WithTransactionT is the same as WithTransaction, but you can also return data, not just the error. +func WithTransactionT[T any](h *DBHandler, ctx context.Context, f DBFunctionT[T]) (*T, error) { + res, err := WithTransactionMultipleEntriesT(h, ctx, func(ctx context.Context, transaction *sql.Tx) ([]T, error) { + fRes, err2 := f(ctx, transaction) + if err2 != nil { + return nil, err2 + } + if fRes == nil { + return make([]T, 0), nil + } + return []T{*fRes}, nil + }) + if err != nil || len(res) == 0 { + return nil, err + } + return &res[0], err +} + +// WithTransactionMultipleEntriesT is the same as WithTransaction, but you can also return and array of data, not just the error. +func WithTransactionMultipleEntriesT[T any](h *DBHandler, ctx context.Context, f DBFunctionMultipleEntriesT[T]) ([]T, error) { + tx, err := h.DB.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + defer func(tx *sql.Tx) { + _ = tx.Rollback() + // we ignore the error returned from Rollback() here, + // because it is always set when Commit() was successful + }(tx) + + result, err := f(ctx, tx) + if err != nil { + return nil, err + } + err = tx.Commit() + if err != nil { + return nil, err + } + return result, nil +}