Skip to content

Commit

Permalink
Implement the Delete handler for the datasource service (#5062)
Browse files Browse the repository at this point in the history
  • Loading branch information
rdimitrov authored Nov 27, 2024
1 parent 5170f07 commit 135cf2f
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 4 deletions.
59 changes: 55 additions & 4 deletions internal/datasources/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"fmt"

"github.com/google/uuid"
"github.com/rs/zerolog"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/encoding/protojson"

Expand Down Expand Up @@ -187,7 +188,7 @@ func (d *dataSourceService) Create(
defer func(stx serviceTX) {
err := stx.Rollback()
if err != nil {
fmt.Printf("failed to rollback transaction: %v", err)
zerolog.Ctx(ctx).Error().Err(err).Msg("failed to rollback transaction")
}
}(stx)

Expand Down Expand Up @@ -262,11 +263,61 @@ func (d *dataSourceService) Update(
panic("implement me")
}

// nolint:revive // there is a TODO
// Delete deletes a data source in the given project.
func (d *dataSourceService) Delete(
ctx context.Context, id uuid.UUID, project uuid.UUID, opts *Options) error {
//TODO implement me
panic("implement me")
stx, err := d.txBuilder(d, opts)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer func(stx serviceTX) {
err := stx.Rollback()
if err != nil {
zerolog.Ctx(ctx).Error().Err(err).Msg("failed to rollback transaction")
}
}(stx)

// Get the transaction querier
tx := stx.Q()

// List rule types referencing the data source
ret, err := tx.ListRuleTypesReferencesByDataSource(ctx, db.ListRuleTypesReferencesByDataSourceParams{
DataSourcesID: id,
ProjectID: project,
})
if err != nil {
return fmt.Errorf("failed to list rule types referencing data source %s: %w", id, err)
}

// Check if the data source is in use by any rule types
if len(ret) > 0 {
// Return an error with the rule types that are using the data source
var existingRefs []string
for _, r := range ret {
existingRefs = append(existingRefs, r.RuleTypeID.String())
}
return util.UserVisibleError(codes.FailedPrecondition,
"data source %s is in use by the following rule types: %v", id, existingRefs)
}

// Delete the data source record
_, err = tx.DeleteDataSource(ctx, db.DeleteDataSourceParams{
ID: id,
ProjectID: project,
})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return util.UserVisibleError(codes.NotFound,
"data source with id %s not found in project %s", id, project)
}
return fmt.Errorf("failed to delete data source with id %s: %w", id, err)
}

// Commit the transaction
if err := stx.Commit(); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}

// nolint:revive // there is a TODO
Expand Down
164 changes: 164 additions & 0 deletions internal/datasources/service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -877,3 +877,167 @@ func restDriverToJson(t *testing.T, rs *minderv1.RestDataSource_Def) []byte {

return out
}

func TestDelete(t *testing.T) {
t.Parallel()

type args struct {
id uuid.UUID
project uuid.UUID
opts *Options
}

tests := []struct {
name string
args args
setup func(args args, mockDB *mockdb.MockStore)
wantErr bool
}{
{
name: "Successful deletion",
args: args{
id: uuid.New(),
project: uuid.New(),
opts: &Options{},
},
setup: func(args args, mockDB *mockdb.MockStore) {
// Mock ListRuleTypesReferencesByDataSource to return empty list
mockDB.EXPECT().
ListRuleTypesReferencesByDataSource(gomock.Any(), gomock.Eq(db.ListRuleTypesReferencesByDataSourceParams{
DataSourcesID: args.id,
ProjectID: args.project,
})).
Return([]db.RuleTypeDataSource{}, nil)

// Mock DeleteDataSource to succeed
mockDB.EXPECT().
DeleteDataSource(gomock.Any(), gomock.Eq(db.DeleteDataSourceParams{
ID: args.id,
ProjectID: args.project,
})).
Return(db.DataSource{}, nil)
},
wantErr: false,
},
{
name: "Data source not found",
args: args{
id: uuid.New(),
project: uuid.New(),
opts: &Options{},
},
setup: func(args args, mockDB *mockdb.MockStore) {
// Mock ListRuleTypesReferencesByDataSource to return empty list
mockDB.EXPECT().
ListRuleTypesReferencesByDataSource(gomock.Any(), gomock.Eq(db.ListRuleTypesReferencesByDataSourceParams{
DataSourcesID: args.id,
ProjectID: args.project,
})).
Return([]db.RuleTypeDataSource{}, nil)

// Mock DeleteDataSource to return sql.ErrNoRows
mockDB.EXPECT().
DeleteDataSource(gomock.Any(), gomock.Eq(db.DeleteDataSourceParams{
ID: args.id,
ProjectID: args.project,
})).
Return(db.DataSource{}, sql.ErrNoRows)
},
wantErr: true,
},
{
name: "Data source is in use",
args: args{
id: uuid.New(),
project: uuid.New(),
opts: &Options{},
},
setup: func(args args, mockDB *mockdb.MockStore) {
// Mock ListRuleTypesReferencesByDataSource to return non-empty list
mockDB.EXPECT().
ListRuleTypesReferencesByDataSource(gomock.Any(), gomock.Eq(db.ListRuleTypesReferencesByDataSourceParams{
DataSourcesID: args.id,
ProjectID: args.project,
})).
Return([]db.RuleTypeDataSource{
{RuleTypeID: uuid.New()},
}, nil)
},
wantErr: true,
},
{
name: "Database error when listing references",
args: args{
id: uuid.New(),
project: uuid.New(),
opts: &Options{},
},
setup: func(args args, mockDB *mockdb.MockStore) {
// Mock ListRuleTypesReferencesByDataSource to return an error
mockDB.EXPECT().
ListRuleTypesReferencesByDataSource(gomock.Any(), gomock.Eq(db.ListRuleTypesReferencesByDataSourceParams{
DataSourcesID: args.id,
ProjectID: args.project,
})).
Return(nil, fmt.Errorf("database error"))
},
wantErr: true,
},
{
name: "Database error when deleting data source",
args: args{
id: uuid.New(),
project: uuid.New(),
opts: &Options{},
},
setup: func(args args, mockDB *mockdb.MockStore) {
// Mock ListRuleTypesReferencesByDataSource to return empty list
mockDB.EXPECT().
ListRuleTypesReferencesByDataSource(gomock.Any(), gomock.Eq(db.ListRuleTypesReferencesByDataSourceParams{
DataSourcesID: args.id,
ProjectID: args.project,
})).
Return([]db.RuleTypeDataSource{}, nil)

// Mock DeleteDataSource to return an error
mockDB.EXPECT().
DeleteDataSource(gomock.Any(), gomock.Eq(db.DeleteDataSourceParams{
ID: args.id,
ProjectID: args.project,
})).
Return(db.DataSource{}, fmt.Errorf("database error"))
},
wantErr: true,
},
}

for _, tt := range tests {
tt := tt // capture range variable
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

ctrl := gomock.NewController(t)
defer ctrl.Finish()

// Setup
mockStore := mockdb.NewMockStore(ctrl)

svc := NewDataSourceService(mockStore)
svc.txBuilder = func(_ *dataSourceService, _ txGetter) (serviceTX, error) {
return &fakeTxBuilder{
store: mockStore,
}, nil
}

tt.setup(tt.args, mockStore)

err := svc.Delete(context.Background(), tt.args.id, tt.args.project, tt.args.opts)
if tt.wantErr {
assert.Error(t, err)
return
}

require.NoError(t, err)
})
}
}

0 comments on commit 135cf2f

Please sign in to comment.