github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/repo/unsafe_create.go (about)

     1  package repo
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/pkg/log"
     9  
    10  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    11  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    12  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    13  )
    14  
    15  // UnsafeCreator is used to create new entities in case they do not exist.
    16  // In case they do already exist, no action is taken, hence the provided entity ID is not guaranteed to match the ID in the Compass DB.
    17  type UnsafeCreator interface {
    18  	UnsafeCreate(ctx context.Context, dbEntity interface{}) error
    19  }
    20  
    21  type unsafeCreator struct {
    22  	tableName          string
    23  	resourceType       resource.Type
    24  	insertColumns      []string
    25  	conflictingColumns []string
    26  }
    27  
    28  // NewUnsafeCreator returns a new Creator which supports creation with conflicts.
    29  func NewUnsafeCreator(resourceType resource.Type, tableName string, insertColumns []string, conflictingColumns []string) UnsafeCreator {
    30  	return &unsafeCreator{
    31  		resourceType:       resourceType,
    32  		tableName:          tableName,
    33  		insertColumns:      insertColumns,
    34  		conflictingColumns: conflictingColumns,
    35  	}
    36  }
    37  
    38  // UnsafeCreate adds a new entity in the Compass DB in case it does not exist. If it already exists, no action is taken.
    39  // This creator is not suitable for resources that have m2m tenant relation as it does not maintain tenant accesses.
    40  // Use it for global scoped resources or resources with embedded tenant_id only.
    41  func (u *unsafeCreator) UnsafeCreate(ctx context.Context, dbEntity interface{}) error {
    42  	if dbEntity == nil {
    43  		return apperrors.NewInternalError("item cannot be nil")
    44  	}
    45  
    46  	persist, err := persistence.FromCtx(ctx)
    47  	if err != nil {
    48  		return err
    49  	}
    50  
    51  	values := make([]string, 0, len(u.insertColumns))
    52  	for _, c := range u.insertColumns {
    53  		values = append(values, fmt.Sprintf(":%s", c))
    54  	}
    55  
    56  	insertStmt := fmt.Sprintf("INSERT INTO %s ( %s ) VALUES ( %s )", u.tableName, strings.Join(u.insertColumns, ", "), strings.Join(values, ", "))
    57  	stmt := fmt.Sprintf("%s ON CONFLICT ( %s ) DO NOTHING", insertStmt, strings.Join(u.conflictingColumns, ", "))
    58  
    59  	log.C(ctx).Debugf("Executing DB query: %s", stmt)
    60  	_, err = persist.NamedExecContext(ctx, stmt, dbEntity)
    61  	return persistence.MapSQLError(ctx, err, u.resourceType, resource.Upsert, "while unsafe inserting row to '%s' table", u.tableName)
    62  }