singularity

用户问题

func (ms *metadataService) RecordInteraction(ctx context.Context, email string, interactionType models.EmailCategory, data models.InteractionData) error { newInteraction := data newInteraction.Type = interactionType

_, errInteraction := ms.emailClient.EmailMetadata.Create().
	SetLatestInteractions(&newInteraction).
	SetEmail(email).
	Save(ctx)

if errInteraction != nil {
	return fmt.Errorf("could not create interaction record %w", errInteraction)
}

return nil }

enable upsert instead of create

回答

To enable upsert instead of Create() in Ent, you need to use the OnConflict() API. Here’s how you can modify your RecordInteraction function to perform an upsert on email:

Assuming:

Here’s the modified function:

func (ms *metadataService) RecordInteraction(ctx context.Context, email string, interactionType models.EmailCategory, data models.InteractionData) error {
	newInteraction := data
	newInteraction.Type = interactionType

	_, err := ms.emailClient.EmailMetadata.
		Create().
		SetEmail(email).
		SetLatestInteractions(&newInteraction).
		OnConflict(
			sql.ConflictColumns("email"),
			sql.ResolveWithNewValues(),
			sql.ResolveWith(func(update *ent.EmailMetadataUpsert) {
				update.SetLatestInteractions(&newInteraction)
			}),
		).
		Save(ctx)

	if err != nil {
		return fmt.Errorf("could not upsert interaction record: %w", err)
	}

	return nil
}

Key Points:

Let me know if email is not marked Unique() in the Ent schema — that’s required for this to work.

用户问题

each call to RecordInteraction is supposed to append the interaction to the json field latestinteractions

回答

Perfect — then what you want is append semantics on a JSON field (LatestInteractions). Since Ent’s SetLatestInteractions() replaces the field, you’ll need to:

  1. Query the existing value for that email (if it exists).
  2. Append the new interaction to the slice.
  3. Upsert using Update() if the record exists, or Create() if not.

Here’s the revised version with that logic:

func (ms *metadataService) RecordInteraction(ctx context.Context, email string, interactionType models.EmailCategory, data models.InteractionData) error {
	newInteraction := data
	newInteraction.Type = interactionType

	// Try fetching existing metadata
	existing, err := ms.emailClient.EmailMetadata.
		Query().
		Where(emailmetadata.EmailEQ(email)).
		Only(ctx)

	var interactions []models.InteractionData
	if err == nil {
		// Append to existing slice
		interactions = append(existing.LatestInteractions, newInteraction)

		// Update
		err = ms.emailClient.EmailMetadata.
			UpdateOneID(existing.ID).
			SetLatestInteractions(interactions).
			Exec(ctx)

		if err != nil {
			return fmt.Errorf("could not update interaction record: %w", err)
		}
	} else if ent.IsNotFound(err) {
		// Create new with the interaction
		interactions = []models.InteractionData{newInteraction}

		_, err = ms.emailClient.EmailMetadata.
			Create().
			SetEmail(email).
			SetLatestInteractions(interactions).
			Save(ctx)

		if err != nil {
			return fmt.Errorf("could not create interaction record: %w", err)
		}
	} else {
		// Unexpected query error
		return fmt.Errorf("failed to query metadata: %w", err)
	}

	return nil
}

Assumptions:

Let me know if you need: