diff --git a/services/user-service/internal/storage/mysql/user/invite_referrer.go b/services/user-service/internal/storage/mysql/user/invite_referrer.go index 9f46803b..84dbef38 100644 --- a/services/user-service/internal/storage/mysql/user/invite_referrer.go +++ b/services/user-service/internal/storage/mysql/user/invite_referrer.go @@ -27,12 +27,16 @@ func (r *Repository) FindInviteReferrerByCode(ctx context.Context, appCode strin row := r.db.QueryRowContext(ctx, ` SELECT `+userSelectColumns+` FROM users - INNER JOIN user_invite_codes codes - ON codes.app_code = users.app_code - AND codes.owner_user_id = users.user_id WHERE users.app_code = ? - AND codes.code = ? - AND codes.status = ? + AND EXISTS ( + SELECT 1 + FROM user_invite_codes codes + WHERE codes.app_code = users.app_code + AND codes.owner_user_id = users.user_id + AND codes.code = ? + AND codes.status = ? + LIMIT 1 + ) LIMIT 1 `, appCode, inviteCode, invitedomain.CodeStatusActive) inviter, err := ScanUser(row) diff --git a/services/user-service/internal/storage/mysql/user/invite_referrer_test.go b/services/user-service/internal/storage/mysql/user/invite_referrer_test.go new file mode 100644 index 00000000..58322797 --- /dev/null +++ b/services/user-service/internal/storage/mysql/user/invite_referrer_test.go @@ -0,0 +1,61 @@ +package user_test + +import ( + "context" + "testing" + + userdomain "hyapp/services/user-service/internal/domain/user" + "hyapp/services/user-service/internal/testutil/mysqltest" +) + +func TestFindInviteReferrerByCodeDoesNotAmbiguouslySelectUserProjection(t *testing.T) { + repo := mysqltest.NewRepository(t) + ctx := context.Background() + + createInviteReferrerUser(t, repo, 12001, "166001", 1000) + inviter, err := repo.GetUser(ctx, 12001) + if err != nil { + t.Fatalf("get inviter failed: %v", err) + } + if inviter.InviteOverview.MyInviteCode == "" { + t.Fatalf("expected inviter primary invite code") + } + + found, err := repo.FindInviteReferrerByCode(ctx, "lalu", inviter.InviteOverview.MyInviteCode) + if err != nil { + t.Fatalf("find invite referrer by code failed: %v", err) + } + if found.UserID != inviter.UserID { + t.Fatalf("invite referrer mismatch: got=%d want=%d", found.UserID, inviter.UserID) + } +} + +func createInviteReferrerUser(t *testing.T, repo *mysqltest.Repository, userID int64, displayUserID string, nowMs int64) { + t.Helper() + err := repo.CreateUserWithIdentity(context.Background(), userdomain.User{ + AppCode: "lalu", + UserID: userID, + DefaultDisplayUserID: displayUserID, + CurrentDisplayUserID: displayUserID, + CurrentDisplayUserIDKind: userdomain.DisplayUserIDKindDefault, + Username: "invite-referrer", + Gender: "male", + Country: "SG", + ProfileCompleted: true, + ProfileCompletedAtMs: nowMs, + Status: userdomain.StatusActive, + OnboardingStatus: userdomain.OnboardingStatusCompleted, + CreatedAtMs: nowMs, + UpdatedAtMs: nowMs, + }, userdomain.Identity{ + AppCode: "lalu", + UserID: userID, + DisplayUserID: displayUserID, + DefaultDisplayUserID: displayUserID, + DisplayUserIDKind: userdomain.DisplayUserIDKindDefault, + Status: userdomain.DisplayUserIDStatusActive, + }) + if err != nil { + t.Fatalf("create invite referrer user %d failed: %v", userID, err) + } +}