A Regular added from a recipe link stores recipe_url, and its grounding job grounds that link. Renaming the dinner while still pending kept the link, so the job queued for the new name still attached the old link's recipe and photo. UpdateDinner now sets recipe_url, and renaming a pending dinner clears it: the fresh job grounds the new name by search, and the household can give a link by hand to fix up the recipe if they want a specific one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -190,6 +190,7 @@ func TestDinners(t *testing.T) {
|
||||
Difficulty: str("medium"),
|
||||
Cuisine: sql.NullString{},
|
||||
RecipeID: sql.NullString{},
|
||||
RecipeUrl: str("https://example.com/tacos"),
|
||||
PhotoID: str(photo.ID),
|
||||
GroundingStatus: "failed",
|
||||
UpdatedBy: str("sam@example.com"),
|
||||
|
||||
@@ -543,6 +543,7 @@ SET name = ?,
|
||||
difficulty = ?,
|
||||
cuisine = ?,
|
||||
recipe_id = ?,
|
||||
recipe_url = ?,
|
||||
photo_id = ?,
|
||||
grounding_status = ?,
|
||||
updated_by = ?,
|
||||
@@ -561,6 +562,7 @@ type UpdateDinnerParams struct {
|
||||
Difficulty sql.NullString
|
||||
Cuisine sql.NullString
|
||||
RecipeID sql.NullString
|
||||
RecipeUrl sql.NullString
|
||||
PhotoID sql.NullString
|
||||
GroundingStatus string
|
||||
UpdatedBy sql.NullString
|
||||
@@ -580,6 +582,7 @@ func (q *Queries) UpdateDinner(ctx context.Context, arg UpdateDinnerParams) (Din
|
||||
arg.Difficulty,
|
||||
arg.Cuisine,
|
||||
arg.RecipeID,
|
||||
arg.RecipeUrl,
|
||||
arg.PhotoID,
|
||||
arg.GroundingStatus,
|
||||
arg.UpdatedBy,
|
||||
|
||||
@@ -294,8 +294,9 @@ func (s *Service) List(ctx context.Context, status string) ([]Dinner, error) {
|
||||
// Update applies p to dinner id, recording updatedBy. An invalid patch is a
|
||||
// *ValidationError and a new name repeating another unarchived dinner a
|
||||
// *DuplicateError; either changes nothing. Renaming a dinner still pending
|
||||
// enqueues a fresh KindGroundDinner job for the new name: the job already
|
||||
// running was for the old name, and its result no longer applies.
|
||||
// clears its recipe_url and enqueues a fresh KindGroundDinner job that
|
||||
// grounds the new name: the job already running was for the old name or
|
||||
// link, and its result no longer applies.
|
||||
func (s *Service) Update(ctx context.Context, id string, p Patch, updatedBy string) (Dinner, error) {
|
||||
if updatedBy == "" {
|
||||
return Dinner{}, errors.New("dinners: update: no member to record as updated_by")
|
||||
@@ -327,6 +328,7 @@ func (s *Service) Update(ctx context.Context, id string, p Patch, updatedBy stri
|
||||
Difficulty: cur.Difficulty,
|
||||
Cuisine: cur.Cuisine,
|
||||
RecipeID: cur.RecipeID,
|
||||
RecipeUrl: cur.RecipeUrl,
|
||||
PhotoID: cur.PhotoID,
|
||||
GroundingStatus: cur.GroundingStatus,
|
||||
UpdatedBy: sql.NullString{String: updatedBy, Valid: true},
|
||||
@@ -338,6 +340,11 @@ func (s *Service) Update(ctx context.Context, id string, p Patch, updatedBy stri
|
||||
}
|
||||
params.Name = name
|
||||
params.NormalizedName = harness.Normalize(name)
|
||||
if cur.GroundingStatus == GroundingPending && params.NormalizedName != cur.NormalizedName {
|
||||
// The link was the old dinner's recipe; the new name is
|
||||
// grounded by name, and a link can be given by hand.
|
||||
params.RecipeUrl = sql.NullString{}
|
||||
}
|
||||
}
|
||||
if p.Method != nil {
|
||||
params.Method = sql.NullString{String: *p.Method, Valid: true}
|
||||
|
||||
@@ -349,6 +349,44 @@ func TestRenameWhilePendingGroundsNewName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestRenameLinkWhilePendingGroundsNewName: a Regular added from a link and
|
||||
// renamed while still pending drops the link and grounds its new name, not
|
||||
// the old link's recipe and photo.
|
||||
func TestRenameLinkWhilePendingGroundsNewName(t *testing.T) {
|
||||
t.Parallel()
|
||||
e := newUnstartedEnv(t)
|
||||
e.search.Results["Beef stew"] = []recipes.Candidate{{URL: stew}}
|
||||
e.model.QueueGenerate(recipestest.NormalizedReply("oven", 150))
|
||||
|
||||
c, err := e.svc.CreateRegular(t.Context(), dinners.NewRegular{RecipeURL: ptr(curryA)}, member)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d, err := e.svc.Update(t.Context(), c.ID, dinners.Patch{Name: ptr("Beef stew")}, member)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.GroundingStatus != dinners.GroundingPending || d.RecipeURL != nil {
|
||||
t.Fatalf("renamed = %+v, want still pending with no recipe_url", d)
|
||||
}
|
||||
e.start(t)
|
||||
|
||||
row := e.waitGrounding(t, c.ID)
|
||||
if row.GroundingStatus != dinners.GroundingGrounded {
|
||||
t.Fatalf("dinner = %+v, want grounded for the new name", row)
|
||||
}
|
||||
rec, err := db.New(e.st.Reader).GetRecipe(t.Context(), row.RecipeID.String)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if rec.SourceUrl != stew || rec.PhotoID != row.PhotoID || row.Method.String != "oven" || row.MinutesTotal.Int64 != 150 {
|
||||
t.Errorf("dinner = %+v recipe %s, want grounded in %s, not the old link %s", row, rec.SourceUrl, stew, curryA)
|
||||
}
|
||||
if got := e.search.Queries(); !slices.Equal(got, []string{"Beef stew"}) {
|
||||
t.Errorf("searched %q, want only the new name", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRenameWhilePendingEnqueueFailure: a pending Regular renamed when the
|
||||
// job for its new name cannot be enqueued is failed, not left pending.
|
||||
func TestRenameWhilePendingEnqueueFailure(t *testing.T) {
|
||||
|
||||
@@ -42,6 +42,7 @@ SET name = ?,
|
||||
difficulty = ?,
|
||||
cuisine = ?,
|
||||
recipe_id = ?,
|
||||
recipe_url = ?,
|
||||
photo_id = ?,
|
||||
grounding_status = ?,
|
||||
updated_by = ?,
|
||||
|
||||
Reference in New Issue
Block a user