Skip to content

refactor:don't throw error when adding existing relations#1076

Open
Aliexe-code wants to merge 4 commits intocloudoperators:mainfrom
Aliexe-code:fix/1057-existing-relations
Open

refactor:don't throw error when adding existing relations#1076
Aliexe-code wants to merge 4 commits intocloudoperators:mainfrom
Aliexe-code:fix/1057-existing-relations

Conversation

@Aliexe-code
Copy link

Title:
refactor: don't throw error when adding existing relations

Description
If the relation already exists, don't throw an error message. This prevents polluting our logs with duplicate entry errors.
Modified 5 Add* functions to return nil instead of error when relation already exists:

  • AddComponentVersionToIssue (internal/database/mariadb/issue.go)
  • AddOwnerToService (internal/database/mariadb/service.go)
  • AddIssueRepositoryToService (internal/database/mariadb/service.go)
  • AddServiceToSupportGroup (internal/database/mariadb/support_group.go)
  • AddUserToSupportGroup (internal/database/mariadb/support_group.go)
    What type of PR is this? (check all applicable)
  • 🍕 Feature
  • 🐛 Bug Fix
  • 📝 Documentation Update
  • 🎨 Style
  • 🧑‍💻 Code Refactor
  • 🔥 Performance Improvements
  • ✅ Test
  • 🤖 Build
  • 🔁 CI
  • 📦 Chore (Release)
  • ⏩ Revert

Related Tickets & Documents
Fixes #1057
Added tests?

  • 👍 yes
  • 🙅 no, because they aren't needed
  • 🙋 no, because I need help
  • Separate ticket for tests # (issue/pr)
    Changes verified with go build ./... - existing tests cover this functionality.
    Added to documentation?
  • 📜 README.md
  • 🤝 Documentation pages updated
  • 🙅 no documentation needed
  • (if applicable) generated OpenAPI docs for CRD changes
    Checklist
  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes


return err
if err != nil {
if strings.Contains(err.Error(), "Error 1062") || strings.Contains(err.Error(), "Duplicate entry") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we use this:

_, err := sqlExec(s, query, args, l)
if err != nil {
    var mysqlErr *mysql.MySQLError
    if errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 {
        return nil // duplicate entry
    }
    return err
}

If the relation already exists, don't throw an error message.
This prevents polluting logs with duplicate entry errors
Fixes cloudoperators#1057
@Aliexe-code Aliexe-code force-pushed the fix/1057-existing-relations branch from 543078c to 0fe7000 Compare February 5, 2026 19:11

return err
if err != nil {
if strings.Contains(err.Error(), "Error 1062") || strings.Contains(err.Error(), "Duplicate entry") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same errors.As() approach can be used here as well


return err
if err != nil {
if strings.Contains(err.Error(), "Error 1062") || strings.Contains(err.Error(), "Duplicate entry") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same errors.As() approach can be used here as well

Replace strings.Contains() with errors.As() for more robust MySQL error handling
when detecting duplicate entry errors (error code 1062).

Addresses reviewer feedback from cloudoperators#1076
@MR2011
Copy link
Collaborator

MR2011 commented Feb 6, 2026

After looking at this again, I suggest using the DuplicateEntryDatabaseError. Here's an example how to use it.

When removing a relation, a duplicate error won't happen, so we don't need to add the check there. There might be a Not Found error, but for now it's not required to check for this.

…etection

Replace strings.Contains() and errors.As() with strings.HasPrefix() for MySQL
duplicate entry detection and return DuplicateEntryDatabaseError when a duplicate
is detected, following the pattern in component_version.go.

This allows handlers to catch and handle duplicate entries gracefully with
user-friendly error messages instead of logging raw MySQL errors.

Addresses reviewer feedback from cloudoperators#1076
Copilot AI review requested due to automatic review settings March 20, 2026 13:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to make “Add* relation” operations idempotent by avoiding errors/log noise when a relation already exists (Fixes #1057).

Changes:

  • Added duplicate-key detection for several relation insert operations.
  • Introduced database.NewDuplicateEntryDatabaseError(...) returns for duplicate relations.
  • Updated duplicate detection logic in AddComponentVersionToIssue.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
internal/database/mariadb/support_group.go Adds duplicate handling in support-group relation insert helpers (currently introduces missing import + still returns an error on duplicates).
internal/database/mariadb/service.go Adds duplicate handling in service relation insert helpers (currently introduces missing import + still returns an error on duplicates).
internal/database/mariadb/issue.go Adjusts duplicate handling for issue ↔ component version relation insert (still returns an error on duplicates).
Comments suppressed due to low confidence (2)

internal/database/mariadb/support_group.go:13

  • strings.HasPrefix is used in this file, but strings is not imported in the import block. This will not compile; add the missing strings import (or avoid using strings.*).
import (
	"fmt"

	"github.com/cloudoperators/heureka/internal/database"
	"github.com/cloudoperators/heureka/internal/entity"
	"github.com/samber/lo"
	"github.com/sirupsen/logrus"
)

internal/database/mariadb/service.go:13

  • strings.HasPrefix is used in this file, but strings is not imported in the import block. This will not compile; add the missing strings import (or avoid using strings.*).
import (
	"fmt"

	"github.com/cloudoperators/heureka/internal/database"
	"github.com/cloudoperators/heureka/internal/entity"
	"github.com/samber/lo"
	"github.com/sirupsen/logrus"
)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +497 to +500
if err != nil {
if strings.HasPrefix(err.Error(), "Error 1062") {
return database.NewDuplicateEntryDatabaseError(fmt.Sprintf("IssueRepository %d already associated with Service %d", issueRepositoryId, serviceId))
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function still returns a DuplicateEntryDatabaseError on duplicate relations. Per the PR/issue goal (“don't throw error when adding existing relations”), duplicates should be treated as a no-op and return nil here (otherwise callers will continue to handle/log it as an error).

Copilot uses AI. Check for mistakes.
Comment on lines 559 to 562
if err != nil {
// Replace string-based error detection with proper error type checking
if strings.Contains(err.Error(), "Error 1062") || strings.Contains(err.Error(), "Duplicate entry") {
return database.NewDuplicateEntryDatabaseError(fmt.Sprintf("ComponentVersion %d already associated with Issue %d", componentVersionId, issueId))
if strings.HasPrefix(err.Error(), "Error 1062") {
return database.NewDuplicateEntryDatabaseError(fmt.Sprintf("Issue %d already associated with ComponentVersion %d", issueId, componentVersionId))
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function still returns a DuplicateEntryDatabaseError on duplicate relations. Per the PR/issue goal (“don't throw error when adding existing relations”), duplicates should be treated as a no-op and return nil instead; otherwise the handler layer will continue to treat/log this as an error.

Copilot uses AI. Check for mistakes.
Comment on lines +244 to +247
if err != nil {
if strings.HasPrefix(err.Error(), "Error 1062") {
return database.NewDuplicateEntryDatabaseError(fmt.Sprintf("Service %d already in SupportGroup %d", serviceId, supportGroupId))
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function still returns a DuplicateEntryDatabaseError on duplicate relations. Per the PR/issue goal (“don't throw error when adding existing relations”), this should be treated as a no-op and return nil instead (or the higher layers will continue logging an error for duplicates).

Copilot uses AI. Check for mistakes.
Comment on lines +299 to +302
if err != nil {
if strings.HasPrefix(err.Error(), "Error 1062") {
return database.NewDuplicateEntryDatabaseError(fmt.Sprintf("User %d already in SupportGroup %d", userId, supportGroupId))
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function still returns a DuplicateEntryDatabaseError on duplicate relations. Per the PR/issue goal (“don't throw error when adding existing relations”), this should be treated as a no-op and return nil instead (or the higher layers will continue logging an error for duplicates).

Copilot uses AI. Check for mistakes.
Comment on lines +439 to +442
if err != nil {
if strings.HasPrefix(err.Error(), "Error 1062") {
return database.NewDuplicateEntryDatabaseError(fmt.Sprintf("User %d already an owner of Service %d", userId, serviceId))
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function still returns a DuplicateEntryDatabaseError on duplicate relations. Per the PR/issue goal (“don't throw error when adding existing relations”), duplicates should be treated as a no-op and return nil here (otherwise callers will continue to handle/log it as an error).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: add existing relations

4 participants