Skip to content

Commit 4b90181

Browse files
authored
fix: feature delete (#3522)
1 parent ee91abb commit 4b90181

File tree

4 files changed

+61
-23
lines changed

4 files changed

+61
-23
lines changed

openmeter/productcatalog/adapter/feature.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
subscriptionrepo "github.com/openmeterio/openmeter/openmeter/subscription/repo"
2121
"github.com/openmeterio/openmeter/pkg/clock"
2222
"github.com/openmeterio/openmeter/pkg/framework/entutils"
23-
"github.com/openmeterio/openmeter/pkg/models"
2423
"github.com/openmeterio/openmeter/pkg/pagination"
2524
)
2625

@@ -86,19 +85,28 @@ func (c *featureDBAdapter) GetByIdOrKey(ctx context.Context, namespace string, i
8685
return &res, nil
8786
}
8887

89-
func (c *featureDBAdapter) ArchiveFeature(ctx context.Context, featureID models.NamespacedID) error {
90-
f, err := c.GetByIdOrKey(ctx, featureID.Namespace, featureID.ID, true)
88+
func (c *featureDBAdapter) ArchiveFeature(ctx context.Context, params feature.ArchiveFeatureInput) error {
89+
f, err := c.GetByIdOrKey(ctx, params.Namespace, params.ID, true)
9190
if err != nil {
9291
return err
9392
}
9493

94+
archivedAt := clock.Now()
95+
if params.At != nil {
96+
if params.At.Before(f.UpdatedAt) {
97+
return &feature.ForbiddenError{Msg: "cannot archive feature at a time before it was last updated", ID: f.ID}
98+
}
99+
100+
archivedAt = *params.At
101+
}
102+
95103
// FIXME: (OM-1055) we should marry productcatalog/plan with feature so we can do this check outside the db layer
96104
planReferencesIt, err := c.db.Plan.Query().
97105
WithPhases(func(qp *db.PlanPhaseQuery) {
98106
qp.WithRatecards()
99107
}).
100108
Where(
101-
dbplan.Namespace(featureID.Namespace),
109+
dbplan.Namespace(params.Namespace),
102110
dbplan.EffectiveFromNotNil(),
103111
dbplan.Or(dbplan.EffectiveToGT(clock.Now()), dbplan.EffectiveToIsNil()),
104112
dbplan.HasPhasesWith(dbplanphase.HasRatecardsWith(
@@ -118,7 +126,7 @@ func (c *featureDBAdapter) ArchiveFeature(ctx context.Context, featureID models.
118126
subscriptionrepo.SubscriptionActiveAfter(clock.Now())...,
119127
).
120128
Where(
121-
dbsub.Namespace(featureID.Namespace),
129+
dbsub.Namespace(params.Namespace),
122130
dbsub.HasPhasesWith(dbsubphase.HasItemsWith(dbsubitem.FeatureKey(f.Key))),
123131
).
124132
Exist(ctx)
@@ -137,9 +145,9 @@ func (c *featureDBAdapter) ArchiveFeature(ctx context.Context, featureID models.
137145
}
138146

139147
err = c.db.Feature.Update().
140-
SetArchivedAt(clock.Now()).
141-
Where(db_feature.ID(featureID.ID)).
142-
Where(db_feature.Namespace(featureID.Namespace)).
148+
SetArchivedAt(archivedAt).
149+
Where(db_feature.ID(params.ID)).
150+
Where(db_feature.Namespace(params.Namespace)).
143151
Exec(ctx)
144152
if err != nil {
145153
return fmt.Errorf("failed to archive feature: %w", err)

openmeter/productcatalog/adapter/feature_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,15 @@ func TestCreateFeature(t *testing.T) {
9494
assert.NoError(t, err)
9595

9696
// archives the feature
97-
err = connector.ArchiveFeature(ctx, models.NamespacedID{
97+
err = connector.ArchiveFeature(ctx, feature.ArchiveFeatureInput{
9898
Namespace: featureIn.Namespace,
9999
ID: createFeatureOut.ID,
100100
})
101101
assert.NoError(t, err)
102102

103103
// errors on a feature that doesn't exist
104104
fakeID := ulid.Make().String()
105-
err = connector.ArchiveFeature(ctx, models.NamespacedID{
105+
err = connector.ArchiveFeature(ctx, feature.ArchiveFeatureInput{
106106
Namespace: featureIn.Namespace,
107107
ID: fakeID,
108108
})
@@ -160,7 +160,7 @@ func TestCreateFeature(t *testing.T) {
160160
assert.Len(t, features.Items, 1)
161161
assert.Equal(t, "feature-2", features.Items[0].Name)
162162

163-
err = connector.ArchiveFeature(ctx, models.NamespacedID{
163+
err = connector.ArchiveFeature(ctx, feature.ArchiveFeatureInput{
164164
Namespace: namespace,
165165
ID: features.Items[0].ID,
166166
})
@@ -206,7 +206,7 @@ func TestCreateFeature(t *testing.T) {
206206

207207
assert.Equal(t, "feature-1", foundFeature.Name)
208208

209-
err = connector.ArchiveFeature(ctx, models.NamespacedID{
209+
err = connector.ArchiveFeature(ctx, feature.ArchiveFeatureInput{
210210
Namespace: namespace,
211211
ID: foundFeature.ID,
212212
})
@@ -358,7 +358,7 @@ func TestArchiveFeature(t *testing.T) {
358358
createFeatureOut, err := connector.CreateFeature(ctx, featureIn)
359359
assert.NoError(t, err)
360360

361-
err = connector.ArchiveFeature(ctx, models.NamespacedID{
361+
err = connector.ArchiveFeature(ctx, feature.ArchiveFeatureInput{
362362
Namespace: createFeatureOut.Namespace,
363363
ID: createFeatureOut.ID,
364364
})
@@ -416,7 +416,7 @@ func TestFetchingArchivedFeature(t *testing.T) {
416416
createFeatureOutArchived, err := connector.CreateFeature(ctx, featureIn)
417417
assert.NoError(t, err)
418418

419-
err = connector.ArchiveFeature(ctx, models.NamespacedID{
419+
err = connector.ArchiveFeature(ctx, feature.ArchiveFeatureInput{
420420
Namespace: createFeatureOutArchived.Namespace,
421421
ID: createFeatureOutArchived.ID,
422422
})

openmeter/productcatalog/feature/connector.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import (
66
"slices"
77

88
"github.com/oklog/ulid/v2"
9+
"github.com/samber/lo"
910

1011
meterpkg "github.com/openmeterio/openmeter/openmeter/meter"
1112
"github.com/openmeterio/openmeter/openmeter/watermill/eventbus"
13+
"github.com/openmeterio/openmeter/pkg/clock"
1214
"github.com/openmeterio/openmeter/pkg/models"
1315
"github.com/openmeterio/openmeter/pkg/pagination"
1416
"github.com/openmeterio/openmeter/pkg/sortx"
@@ -163,25 +165,27 @@ func (c *featureConnector) CreateFeature(ctx context.Context, feature CreateFeat
163165
// ArchiveFeature archives a feature
164166
func (c *featureConnector) ArchiveFeature(ctx context.Context, featureID models.NamespacedID) error {
165167
// Get the feature
166-
_, err := c.GetFeature(ctx, featureID.Namespace, featureID.ID, false)
168+
feat, err := c.GetFeature(ctx, featureID.Namespace, featureID.ID, false)
167169
if err != nil {
168170
return err
169171
}
170172

173+
archivedAt := lo.ToPtr(clock.Now())
174+
171175
// Archive the feature
172-
err = c.featureRepo.ArchiveFeature(ctx, featureID)
176+
err = c.featureRepo.ArchiveFeature(ctx, ArchiveFeatureInput{
177+
Namespace: feat.Namespace,
178+
ID: feat.ID,
179+
At: archivedAt,
180+
})
173181
if err != nil {
174182
return err
175183
}
176184

177-
// Get the archived feature
178-
archivedFeature, err := c.GetFeature(ctx, featureID.Namespace, featureID.ID, true)
179-
if err != nil {
180-
return err
181-
}
185+
feat.ArchivedAt = archivedAt
182186

183187
// Publish the feature archived event
184-
featureArchivedEvent := NewFeatureArchiveEvent(ctx, archivedFeature)
188+
featureArchivedEvent := NewFeatureArchiveEvent(ctx, feat)
185189
if err := c.publisher.Publish(ctx, featureArchivedEvent); err != nil {
186190
return fmt.Errorf("failed to publish feature archived event: %w", err)
187191
}

openmeter/productcatalog/feature/repository.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,41 @@ package feature
22

33
import (
44
"context"
5+
"errors"
6+
"time"
57

68
"github.com/openmeterio/openmeter/pkg/framework/entutils"
79
"github.com/openmeterio/openmeter/pkg/models"
810
"github.com/openmeterio/openmeter/pkg/pagination"
911
)
1012

13+
type ArchiveFeatureInput struct {
14+
Namespace string
15+
ID string
16+
At *time.Time
17+
}
18+
19+
func (i ArchiveFeatureInput) Validate() error {
20+
var errs []error
21+
22+
if i.Namespace == "" {
23+
errs = append(errs, errors.New("namespace is required"))
24+
}
25+
26+
if i.ID == "" {
27+
errs = append(errs, errors.New("id is required"))
28+
}
29+
30+
if i.At != nil && i.At.IsZero() {
31+
errs = append(errs, errors.New("at must not be zero"))
32+
}
33+
34+
return models.NewNillableGenericValidationError(errors.Join(errs...))
35+
}
36+
1137
type FeatureRepo interface {
1238
CreateFeature(ctx context.Context, feature CreateFeatureInputs) (Feature, error)
13-
ArchiveFeature(ctx context.Context, featureID models.NamespacedID) error
39+
ArchiveFeature(ctx context.Context, params ArchiveFeatureInput) error
1440
ListFeatures(ctx context.Context, params ListFeaturesParams) (pagination.Result[Feature], error)
1541
HasActiveFeatureForMeter(ctx context.Context, namespace string, meterSlug string) (bool, error)
1642

0 commit comments

Comments
 (0)