feat: Add PUT and PATCH datasets endpoints

This commit is contained in:
2026-07-21 00:19:52 +05:00
parent 47b2e8653d
commit 00a0cd1b8e
5 changed files with 451 additions and 4 deletions

View File

@@ -35,6 +35,7 @@ var (
type DatasetRepository interface {
Create(ctx context.Context, d domain.Dataset) (domain.Dataset, error)
GetByID(ctx context.Context, id uuid.UUID) (domain.Dataset, error)
UpdateFields(ctx context.Context, id, categoryID uuid.UUID, name string, description, unit *string) (domain.Dataset, error)
ListSummaries(ctx context.Context, filter domain.DatasetFilter, limit, offset int) ([]domain.DatasetSummary, error)
Count(ctx context.Context, filter domain.DatasetFilter) (int, error)
Delete(ctx context.Context, id uuid.UUID) error
@@ -183,10 +184,7 @@ func (s *DatasetService) Upload(ctx context.Context, in UploadInput) (domain.Dat
}
content := io.MultiReader(bytes.NewReader(head), in.Reader)
if _, err := s.categories.GetByID(ctx, in.CategoryID); err != nil {
if errors.Is(err, domain.ErrNotFound) {
return domain.Dataset{}, fmt.Errorf("%w: category does not exist", domain.ErrValidation)
}
if err := s.ensureCategoryExists(ctx, in.CategoryID); err != nil {
return domain.Dataset{}, err
}
@@ -946,6 +944,81 @@ func (s *DatasetService) Get(ctx context.Context, id uuid.UUID) (domain.Dataset,
return s.repo.GetByID(ctx, id)
}
// DatasetUpdateInput carries the full set of editable metadata fields for a
// PUT replace. Description and Unit being nil clears those (nullable)
// columns.
type DatasetUpdateInput struct {
CategoryID uuid.UUID
Name string
Description *string
Unit *string
}
// Update replaces a dataset's editable metadata (category, name, description,
// unit). File-related and lifecycle fields are untouched.
func (s *DatasetService) Update(ctx context.Context, id uuid.UUID, in DatasetUpdateInput) (domain.Dataset, error) {
if err := s.ensureCategoryExists(ctx, in.CategoryID); err != nil {
return domain.Dataset{}, err
}
return s.repo.UpdateFields(ctx, id, in.CategoryID, in.Name, in.Description, in.Unit)
}
// DatasetPatchInput carries a sparse set of metadata field changes. A nil
// CategoryID/Name leaves that column unchanged. Description/Unit are only
// applied when their paired Set flag is true; a nil value with Set true
// clears the (nullable) column.
type DatasetPatchInput struct {
CategoryID *uuid.UUID
Name *string
Description *string
DescriptionSet bool
Unit *string
UnitSet bool
}
// Patch applies a sparse update to a dataset's editable metadata (category,
// name, description, unit). Fields absent from the input are left unchanged.
func (s *DatasetService) Patch(ctx context.Context, id uuid.UUID, in DatasetPatchInput) (domain.Dataset, error) {
current, err := s.repo.GetByID(ctx, id)
if err != nil {
return domain.Dataset{}, err
}
categoryID := current.CategoryID
if in.CategoryID != nil {
categoryID = *in.CategoryID
if err := s.ensureCategoryExists(ctx, categoryID); err != nil {
return domain.Dataset{}, err
}
}
name := current.Name
if in.Name != nil {
name = *in.Name
}
description := current.Description
if in.DescriptionSet {
description = in.Description
}
unit := current.Unit
if in.UnitSet {
unit = in.Unit
}
return s.repo.UpdateFields(ctx, id, categoryID, name, description, unit)
}
// ensureCategoryExists validates that categoryID references an existing
// category, mirroring the check performed on upload.
func (s *DatasetService) ensureCategoryExists(ctx context.Context, categoryID uuid.UUID) error {
if _, err := s.categories.GetByID(ctx, categoryID); err != nil {
if errors.Is(err, domain.ErrNotFound) {
return fmt.Errorf("%w: category does not exist", domain.ErrValidation)
}
return err
}
return nil
}
// Status-wait bounds and polling cadence for long polling.
const (
DefaultStatusWait = 25 * time.Second