From b56b833680932143fcfc4ab879e924004ec7b723 Mon Sep 17 00:00:00 2001 From: vallyenfail Date: Mon, 19 Jan 2026 16:42:51 +0300 Subject: [PATCH] add service --- .gitignore | 3 +- api/proto/invite/invite.proto | 7 +- internal/grpc/invite_handler.go | 1 - internal/mocks/invite_repository_mock.go | 357 +------------------- internal/model/invite.go | 1 - internal/repository/interfaces.go | 1 - internal/repository/invite.go | 36 +- migrations/00009_drop_used_count_column.sql | 5 + pkg/pb/invite/invite.pb.go | 26 +- tests/full_flow_test.go | 1 - tests/integration_suite_test.go | 8 +- tests/invite_handler_test.go | 1 - tests/repository_test.go | 13 +- 13 files changed, 42 insertions(+), 418 deletions(-) create mode 100644 migrations/00009_drop_used_count_column.sql diff --git a/.gitignore b/.gitignore index 3272aa1..bf98ce0 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,5 @@ config/config.yaml # Build artifacts /bin/ /dist/ -.gitea \ No newline at end of file +.gitea +.gitea/workflows \ No newline at end of file diff --git a/api/proto/invite/invite.proto b/api/proto/invite/invite.proto index 846d0b7..1a0bede 100644 --- a/api/proto/invite/invite.proto +++ b/api/proto/invite/invite.proto @@ -29,8 +29,7 @@ message GetInfoResponse { string code = 1; int64 user_id = 2; int32 can_be_used_count = 3; - int32 used_count = 4; - google.protobuf.Timestamp expires_at = 5; - bool is_active = 6; - google.protobuf.Timestamp created_at = 7; + google.protobuf.Timestamp expires_at = 4; + bool is_active = 5; + google.protobuf.Timestamp created_at = 6; } diff --git a/internal/grpc/invite_handler.go b/internal/grpc/invite_handler.go index df490d4..546a9de 100644 --- a/internal/grpc/invite_handler.go +++ b/internal/grpc/invite_handler.go @@ -37,7 +37,6 @@ func (h *InviteHandler) GetInfo(ctx context.Context, req *pb.GetInfoRequest) (*p Code: strconv.FormatInt(invite.Code, 10), UserId: int64(invite.UserID), CanBeUsedCount: int32(invite.CanBeUsedCount), - UsedCount: int32(invite.UsedCount), ExpiresAt: timestamppb.New(invite.ExpiresAt), IsActive: invite.IsActive, CreatedAt: timestamppb.New(invite.CreatedAt), diff --git a/internal/mocks/invite_repository_mock.go b/internal/mocks/invite_repository_mock.go index 268d4e5..c952da6 100644 --- a/internal/mocks/invite_repository_mock.go +++ b/internal/mocks/invite_repository_mock.go @@ -68,13 +68,6 @@ type InviteRepositoryMock struct { afterGetUserInvitesCounter uint64 beforeGetUserInvitesCounter uint64 GetUserInvitesMock mInviteRepositoryMockGetUserInvites - - funcIncrementUsedCount func(ctx context.Context, code int64) (err error) - funcIncrementUsedCountOrigin string - inspectFuncIncrementUsedCount func(ctx context.Context, code int64) - afterIncrementUsedCountCounter uint64 - beforeIncrementUsedCountCounter uint64 - IncrementUsedCountMock mInviteRepositoryMockIncrementUsedCount } // NewInviteRepositoryMock returns a mock for mm_repository.InviteRepository @@ -106,9 +99,6 @@ func NewInviteRepositoryMock(t minimock.Tester) *InviteRepositoryMock { m.GetUserInvitesMock = mInviteRepositoryMockGetUserInvites{mock: m} m.GetUserInvitesMock.callArgs = []*InviteRepositoryMockGetUserInvitesParams{} - m.IncrementUsedCountMock = mInviteRepositoryMockIncrementUsedCount{mock: m} - m.IncrementUsedCountMock.callArgs = []*InviteRepositoryMockIncrementUsedCountParams{} - t.Cleanup(m.MinimockFinish) return m @@ -2543,348 +2533,6 @@ func (m *InviteRepositoryMock) MinimockGetUserInvitesInspect() { } } -type mInviteRepositoryMockIncrementUsedCount struct { - optional bool - mock *InviteRepositoryMock - defaultExpectation *InviteRepositoryMockIncrementUsedCountExpectation - expectations []*InviteRepositoryMockIncrementUsedCountExpectation - - callArgs []*InviteRepositoryMockIncrementUsedCountParams - mutex sync.RWMutex - - expectedInvocations uint64 - expectedInvocationsOrigin string -} - -// InviteRepositoryMockIncrementUsedCountExpectation specifies expectation struct of the InviteRepository.IncrementUsedCount -type InviteRepositoryMockIncrementUsedCountExpectation struct { - mock *InviteRepositoryMock - params *InviteRepositoryMockIncrementUsedCountParams - paramPtrs *InviteRepositoryMockIncrementUsedCountParamPtrs - expectationOrigins InviteRepositoryMockIncrementUsedCountExpectationOrigins - results *InviteRepositoryMockIncrementUsedCountResults - returnOrigin string - Counter uint64 -} - -// InviteRepositoryMockIncrementUsedCountParams contains parameters of the InviteRepository.IncrementUsedCount -type InviteRepositoryMockIncrementUsedCountParams struct { - ctx context.Context - code int64 -} - -// InviteRepositoryMockIncrementUsedCountParamPtrs contains pointers to parameters of the InviteRepository.IncrementUsedCount -type InviteRepositoryMockIncrementUsedCountParamPtrs struct { - ctx *context.Context - code *int64 -} - -// InviteRepositoryMockIncrementUsedCountResults contains results of the InviteRepository.IncrementUsedCount -type InviteRepositoryMockIncrementUsedCountResults struct { - err error -} - -// InviteRepositoryMockIncrementUsedCountOrigins contains origins of expectations of the InviteRepository.IncrementUsedCount -type InviteRepositoryMockIncrementUsedCountExpectationOrigins struct { - origin string - originCtx string - originCode string -} - -// Marks this method to be optional. The default behavior of any method with Return() is '1 or more', meaning -// the test will fail minimock's automatic final call check if the mocked method was not called at least once. -// Optional() makes method check to work in '0 or more' mode. -// It is NOT RECOMMENDED to use this option unless you really need it, as default behaviour helps to -// catch the problems when the expected method call is totally skipped during test run. -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) Optional() *mInviteRepositoryMockIncrementUsedCount { - mmIncrementUsedCount.optional = true - return mmIncrementUsedCount -} - -// Expect sets up expected params for InviteRepository.IncrementUsedCount -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) Expect(ctx context.Context, code int64) *mInviteRepositoryMockIncrementUsedCount { - if mmIncrementUsedCount.mock.funcIncrementUsedCount != nil { - mmIncrementUsedCount.mock.t.Fatalf("InviteRepositoryMock.IncrementUsedCount mock is already set by Set") - } - - if mmIncrementUsedCount.defaultExpectation == nil { - mmIncrementUsedCount.defaultExpectation = &InviteRepositoryMockIncrementUsedCountExpectation{} - } - - if mmIncrementUsedCount.defaultExpectation.paramPtrs != nil { - mmIncrementUsedCount.mock.t.Fatalf("InviteRepositoryMock.IncrementUsedCount mock is already set by ExpectParams functions") - } - - mmIncrementUsedCount.defaultExpectation.params = &InviteRepositoryMockIncrementUsedCountParams{ctx, code} - mmIncrementUsedCount.defaultExpectation.expectationOrigins.origin = minimock.CallerInfo(1) - for _, e := range mmIncrementUsedCount.expectations { - if minimock.Equal(e.params, mmIncrementUsedCount.defaultExpectation.params) { - mmIncrementUsedCount.mock.t.Fatalf("Expectation set by When has same params: %#v", *mmIncrementUsedCount.defaultExpectation.params) - } - } - - return mmIncrementUsedCount -} - -// ExpectCtxParam1 sets up expected param ctx for InviteRepository.IncrementUsedCount -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) ExpectCtxParam1(ctx context.Context) *mInviteRepositoryMockIncrementUsedCount { - if mmIncrementUsedCount.mock.funcIncrementUsedCount != nil { - mmIncrementUsedCount.mock.t.Fatalf("InviteRepositoryMock.IncrementUsedCount mock is already set by Set") - } - - if mmIncrementUsedCount.defaultExpectation == nil { - mmIncrementUsedCount.defaultExpectation = &InviteRepositoryMockIncrementUsedCountExpectation{} - } - - if mmIncrementUsedCount.defaultExpectation.params != nil { - mmIncrementUsedCount.mock.t.Fatalf("InviteRepositoryMock.IncrementUsedCount mock is already set by Expect") - } - - if mmIncrementUsedCount.defaultExpectation.paramPtrs == nil { - mmIncrementUsedCount.defaultExpectation.paramPtrs = &InviteRepositoryMockIncrementUsedCountParamPtrs{} - } - mmIncrementUsedCount.defaultExpectation.paramPtrs.ctx = &ctx - mmIncrementUsedCount.defaultExpectation.expectationOrigins.originCtx = minimock.CallerInfo(1) - - return mmIncrementUsedCount -} - -// ExpectCodeParam2 sets up expected param code for InviteRepository.IncrementUsedCount -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) ExpectCodeParam2(code int64) *mInviteRepositoryMockIncrementUsedCount { - if mmIncrementUsedCount.mock.funcIncrementUsedCount != nil { - mmIncrementUsedCount.mock.t.Fatalf("InviteRepositoryMock.IncrementUsedCount mock is already set by Set") - } - - if mmIncrementUsedCount.defaultExpectation == nil { - mmIncrementUsedCount.defaultExpectation = &InviteRepositoryMockIncrementUsedCountExpectation{} - } - - if mmIncrementUsedCount.defaultExpectation.params != nil { - mmIncrementUsedCount.mock.t.Fatalf("InviteRepositoryMock.IncrementUsedCount mock is already set by Expect") - } - - if mmIncrementUsedCount.defaultExpectation.paramPtrs == nil { - mmIncrementUsedCount.defaultExpectation.paramPtrs = &InviteRepositoryMockIncrementUsedCountParamPtrs{} - } - mmIncrementUsedCount.defaultExpectation.paramPtrs.code = &code - mmIncrementUsedCount.defaultExpectation.expectationOrigins.originCode = minimock.CallerInfo(1) - - return mmIncrementUsedCount -} - -// Inspect accepts an inspector function that has same arguments as the InviteRepository.IncrementUsedCount -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) Inspect(f func(ctx context.Context, code int64)) *mInviteRepositoryMockIncrementUsedCount { - if mmIncrementUsedCount.mock.inspectFuncIncrementUsedCount != nil { - mmIncrementUsedCount.mock.t.Fatalf("Inspect function is already set for InviteRepositoryMock.IncrementUsedCount") - } - - mmIncrementUsedCount.mock.inspectFuncIncrementUsedCount = f - - return mmIncrementUsedCount -} - -// Return sets up results that will be returned by InviteRepository.IncrementUsedCount -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) Return(err error) *InviteRepositoryMock { - if mmIncrementUsedCount.mock.funcIncrementUsedCount != nil { - mmIncrementUsedCount.mock.t.Fatalf("InviteRepositoryMock.IncrementUsedCount mock is already set by Set") - } - - if mmIncrementUsedCount.defaultExpectation == nil { - mmIncrementUsedCount.defaultExpectation = &InviteRepositoryMockIncrementUsedCountExpectation{mock: mmIncrementUsedCount.mock} - } - mmIncrementUsedCount.defaultExpectation.results = &InviteRepositoryMockIncrementUsedCountResults{err} - mmIncrementUsedCount.defaultExpectation.returnOrigin = minimock.CallerInfo(1) - return mmIncrementUsedCount.mock -} - -// Set uses given function f to mock the InviteRepository.IncrementUsedCount method -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) Set(f func(ctx context.Context, code int64) (err error)) *InviteRepositoryMock { - if mmIncrementUsedCount.defaultExpectation != nil { - mmIncrementUsedCount.mock.t.Fatalf("Default expectation is already set for the InviteRepository.IncrementUsedCount method") - } - - if len(mmIncrementUsedCount.expectations) > 0 { - mmIncrementUsedCount.mock.t.Fatalf("Some expectations are already set for the InviteRepository.IncrementUsedCount method") - } - - mmIncrementUsedCount.mock.funcIncrementUsedCount = f - mmIncrementUsedCount.mock.funcIncrementUsedCountOrigin = minimock.CallerInfo(1) - return mmIncrementUsedCount.mock -} - -// When sets expectation for the InviteRepository.IncrementUsedCount which will trigger the result defined by the following -// Then helper -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) When(ctx context.Context, code int64) *InviteRepositoryMockIncrementUsedCountExpectation { - if mmIncrementUsedCount.mock.funcIncrementUsedCount != nil { - mmIncrementUsedCount.mock.t.Fatalf("InviteRepositoryMock.IncrementUsedCount mock is already set by Set") - } - - expectation := &InviteRepositoryMockIncrementUsedCountExpectation{ - mock: mmIncrementUsedCount.mock, - params: &InviteRepositoryMockIncrementUsedCountParams{ctx, code}, - expectationOrigins: InviteRepositoryMockIncrementUsedCountExpectationOrigins{origin: minimock.CallerInfo(1)}, - } - mmIncrementUsedCount.expectations = append(mmIncrementUsedCount.expectations, expectation) - return expectation -} - -// Then sets up InviteRepository.IncrementUsedCount return parameters for the expectation previously defined by the When method -func (e *InviteRepositoryMockIncrementUsedCountExpectation) Then(err error) *InviteRepositoryMock { - e.results = &InviteRepositoryMockIncrementUsedCountResults{err} - return e.mock -} - -// Times sets number of times InviteRepository.IncrementUsedCount should be invoked -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) Times(n uint64) *mInviteRepositoryMockIncrementUsedCount { - if n == 0 { - mmIncrementUsedCount.mock.t.Fatalf("Times of InviteRepositoryMock.IncrementUsedCount mock can not be zero") - } - mm_atomic.StoreUint64(&mmIncrementUsedCount.expectedInvocations, n) - mmIncrementUsedCount.expectedInvocationsOrigin = minimock.CallerInfo(1) - return mmIncrementUsedCount -} - -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) invocationsDone() bool { - if len(mmIncrementUsedCount.expectations) == 0 && mmIncrementUsedCount.defaultExpectation == nil && mmIncrementUsedCount.mock.funcIncrementUsedCount == nil { - return true - } - - totalInvocations := mm_atomic.LoadUint64(&mmIncrementUsedCount.mock.afterIncrementUsedCountCounter) - expectedInvocations := mm_atomic.LoadUint64(&mmIncrementUsedCount.expectedInvocations) - - return totalInvocations > 0 && (expectedInvocations == 0 || expectedInvocations == totalInvocations) -} - -// IncrementUsedCount implements mm_repository.InviteRepository -func (mmIncrementUsedCount *InviteRepositoryMock) IncrementUsedCount(ctx context.Context, code int64) (err error) { - mm_atomic.AddUint64(&mmIncrementUsedCount.beforeIncrementUsedCountCounter, 1) - defer mm_atomic.AddUint64(&mmIncrementUsedCount.afterIncrementUsedCountCounter, 1) - - mmIncrementUsedCount.t.Helper() - - if mmIncrementUsedCount.inspectFuncIncrementUsedCount != nil { - mmIncrementUsedCount.inspectFuncIncrementUsedCount(ctx, code) - } - - mm_params := InviteRepositoryMockIncrementUsedCountParams{ctx, code} - - // Record call args - mmIncrementUsedCount.IncrementUsedCountMock.mutex.Lock() - mmIncrementUsedCount.IncrementUsedCountMock.callArgs = append(mmIncrementUsedCount.IncrementUsedCountMock.callArgs, &mm_params) - mmIncrementUsedCount.IncrementUsedCountMock.mutex.Unlock() - - for _, e := range mmIncrementUsedCount.IncrementUsedCountMock.expectations { - if minimock.Equal(*e.params, mm_params) { - mm_atomic.AddUint64(&e.Counter, 1) - return e.results.err - } - } - - if mmIncrementUsedCount.IncrementUsedCountMock.defaultExpectation != nil { - mm_atomic.AddUint64(&mmIncrementUsedCount.IncrementUsedCountMock.defaultExpectation.Counter, 1) - mm_want := mmIncrementUsedCount.IncrementUsedCountMock.defaultExpectation.params - mm_want_ptrs := mmIncrementUsedCount.IncrementUsedCountMock.defaultExpectation.paramPtrs - - mm_got := InviteRepositoryMockIncrementUsedCountParams{ctx, code} - - if mm_want_ptrs != nil { - - if mm_want_ptrs.ctx != nil && !minimock.Equal(*mm_want_ptrs.ctx, mm_got.ctx) { - mmIncrementUsedCount.t.Errorf("InviteRepositoryMock.IncrementUsedCount got unexpected parameter ctx, expected at\n%s:\nwant: %#v\n got: %#v%s\n", - mmIncrementUsedCount.IncrementUsedCountMock.defaultExpectation.expectationOrigins.originCtx, *mm_want_ptrs.ctx, mm_got.ctx, minimock.Diff(*mm_want_ptrs.ctx, mm_got.ctx)) - } - - if mm_want_ptrs.code != nil && !minimock.Equal(*mm_want_ptrs.code, mm_got.code) { - mmIncrementUsedCount.t.Errorf("InviteRepositoryMock.IncrementUsedCount got unexpected parameter code, expected at\n%s:\nwant: %#v\n got: %#v%s\n", - mmIncrementUsedCount.IncrementUsedCountMock.defaultExpectation.expectationOrigins.originCode, *mm_want_ptrs.code, mm_got.code, minimock.Diff(*mm_want_ptrs.code, mm_got.code)) - } - - } else if mm_want != nil && !minimock.Equal(*mm_want, mm_got) { - mmIncrementUsedCount.t.Errorf("InviteRepositoryMock.IncrementUsedCount got unexpected parameters, expected at\n%s:\nwant: %#v\n got: %#v%s\n", - mmIncrementUsedCount.IncrementUsedCountMock.defaultExpectation.expectationOrigins.origin, *mm_want, mm_got, minimock.Diff(*mm_want, mm_got)) - } - - mm_results := mmIncrementUsedCount.IncrementUsedCountMock.defaultExpectation.results - if mm_results == nil { - mmIncrementUsedCount.t.Fatal("No results are set for the InviteRepositoryMock.IncrementUsedCount") - } - return (*mm_results).err - } - if mmIncrementUsedCount.funcIncrementUsedCount != nil { - return mmIncrementUsedCount.funcIncrementUsedCount(ctx, code) - } - mmIncrementUsedCount.t.Fatalf("Unexpected call to InviteRepositoryMock.IncrementUsedCount. %v %v", ctx, code) - return -} - -// IncrementUsedCountAfterCounter returns a count of finished InviteRepositoryMock.IncrementUsedCount invocations -func (mmIncrementUsedCount *InviteRepositoryMock) IncrementUsedCountAfterCounter() uint64 { - return mm_atomic.LoadUint64(&mmIncrementUsedCount.afterIncrementUsedCountCounter) -} - -// IncrementUsedCountBeforeCounter returns a count of InviteRepositoryMock.IncrementUsedCount invocations -func (mmIncrementUsedCount *InviteRepositoryMock) IncrementUsedCountBeforeCounter() uint64 { - return mm_atomic.LoadUint64(&mmIncrementUsedCount.beforeIncrementUsedCountCounter) -} - -// Calls returns a list of arguments used in each call to InviteRepositoryMock.IncrementUsedCount. -// The list is in the same order as the calls were made (i.e. recent calls have a higher index) -func (mmIncrementUsedCount *mInviteRepositoryMockIncrementUsedCount) Calls() []*InviteRepositoryMockIncrementUsedCountParams { - mmIncrementUsedCount.mutex.RLock() - - argCopy := make([]*InviteRepositoryMockIncrementUsedCountParams, len(mmIncrementUsedCount.callArgs)) - copy(argCopy, mmIncrementUsedCount.callArgs) - - mmIncrementUsedCount.mutex.RUnlock() - - return argCopy -} - -// MinimockIncrementUsedCountDone returns true if the count of the IncrementUsedCount invocations corresponds -// the number of defined expectations -func (m *InviteRepositoryMock) MinimockIncrementUsedCountDone() bool { - if m.IncrementUsedCountMock.optional { - // Optional methods provide '0 or more' call count restriction. - return true - } - - for _, e := range m.IncrementUsedCountMock.expectations { - if mm_atomic.LoadUint64(&e.Counter) < 1 { - return false - } - } - - return m.IncrementUsedCountMock.invocationsDone() -} - -// MinimockIncrementUsedCountInspect logs each unmet expectation -func (m *InviteRepositoryMock) MinimockIncrementUsedCountInspect() { - for _, e := range m.IncrementUsedCountMock.expectations { - if mm_atomic.LoadUint64(&e.Counter) < 1 { - m.t.Errorf("Expected call to InviteRepositoryMock.IncrementUsedCount at\n%s with params: %#v", e.expectationOrigins.origin, *e.params) - } - } - - afterIncrementUsedCountCounter := mm_atomic.LoadUint64(&m.afterIncrementUsedCountCounter) - // if default expectation was set then invocations count should be greater than zero - if m.IncrementUsedCountMock.defaultExpectation != nil && afterIncrementUsedCountCounter < 1 { - if m.IncrementUsedCountMock.defaultExpectation.params == nil { - m.t.Errorf("Expected call to InviteRepositoryMock.IncrementUsedCount at\n%s", m.IncrementUsedCountMock.defaultExpectation.returnOrigin) - } else { - m.t.Errorf("Expected call to InviteRepositoryMock.IncrementUsedCount at\n%s with params: %#v", m.IncrementUsedCountMock.defaultExpectation.expectationOrigins.origin, *m.IncrementUsedCountMock.defaultExpectation.params) - } - } - // if func was set then invocations count should be greater than zero - if m.funcIncrementUsedCount != nil && afterIncrementUsedCountCounter < 1 { - m.t.Errorf("Expected call to InviteRepositoryMock.IncrementUsedCount at\n%s", m.funcIncrementUsedCountOrigin) - } - - if !m.IncrementUsedCountMock.invocationsDone() && afterIncrementUsedCountCounter > 0 { - m.t.Errorf("Expected %d calls to InviteRepositoryMock.IncrementUsedCount at\n%s but found %d calls", - mm_atomic.LoadUint64(&m.IncrementUsedCountMock.expectedInvocations), m.IncrementUsedCountMock.expectedInvocationsOrigin, afterIncrementUsedCountCounter) - } -} - // MinimockFinish checks that all mocked methods have been called the expected number of times func (m *InviteRepositoryMock) MinimockFinish() { m.finishOnce.Do(func() { @@ -2902,8 +2550,6 @@ func (m *InviteRepositoryMock) MinimockFinish() { m.MinimockFindByCodeInspect() m.MinimockGetUserInvitesInspect() - - m.MinimockIncrementUsedCountInspect() } }) } @@ -2933,6 +2579,5 @@ func (m *InviteRepositoryMock) minimockDone() bool { m.MinimockDecrementCanBeUsedCountTxDone() && m.MinimockFindActiveByCodeDone() && m.MinimockFindByCodeDone() && - m.MinimockGetUserInvitesDone() && - m.MinimockIncrementUsedCountDone() + m.MinimockGetUserInvitesDone() } diff --git a/internal/model/invite.go b/internal/model/invite.go index a15e84c..2d81f28 100644 --- a/internal/model/invite.go +++ b/internal/model/invite.go @@ -7,7 +7,6 @@ type InviteCode struct { UserID int Code int64 CanBeUsedCount int - UsedCount int IsActive bool CreatedAt time.Time ExpiresAt time.Time diff --git a/internal/repository/interfaces.go b/internal/repository/interfaces.go index 6392b40..785d63c 100644 --- a/internal/repository/interfaces.go +++ b/internal/repository/interfaces.go @@ -37,7 +37,6 @@ type InviteRepository interface { CreateTx(ctx context.Context, tx pgx.Tx, invite *model.InviteCode) error FindByCode(ctx context.Context, code int64) (*model.InviteCode, error) FindActiveByCode(ctx context.Context, code int64) (*model.InviteCode, error) - IncrementUsedCount(ctx context.Context, code int64) error DecrementCanBeUsedCountTx(ctx context.Context, tx pgx.Tx, code int64) error DeactivateExpired(ctx context.Context) (int, error) GetUserInvites(ctx context.Context, userID int) ([]*model.InviteCode, error) diff --git a/internal/repository/invite.go b/internal/repository/invite.go index f1453ab..ce275c9 100644 --- a/internal/repository/invite.go +++ b/internal/repository/invite.go @@ -53,7 +53,7 @@ func (r *inviteRepository) createWithExecutor(ctx context.Context, exec DBTX, in func (r *inviteRepository) FindByCode(ctx context.Context, code int64) (*model.InviteCode, error) { query := r.qb.Select( - "id", "user_id", "code", "can_be_used_count", "used_count", + "id", "user_id", "code", "can_be_used_count", "is_active", "created_at", "expires_at", ).From("invite_codes").Where(sq.Eq{"code": code}) @@ -65,7 +65,7 @@ func (r *inviteRepository) FindByCode(ctx context.Context, code int64) (*model.I invite := &model.InviteCode{} err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan( &invite.ID, &invite.UserID, &invite.Code, &invite.CanBeUsedCount, - &invite.UsedCount, &invite.IsActive, &invite.CreatedAt, &invite.ExpiresAt, + &invite.IsActive, &invite.CreatedAt, &invite.ExpiresAt, ) if errors.Is(err, pgx.ErrNoRows) { @@ -80,13 +80,13 @@ func (r *inviteRepository) FindByCode(ctx context.Context, code int64) (*model.I func (r *inviteRepository) FindActiveByCode(ctx context.Context, code int64) (*model.InviteCode, error) { query := r.qb.Select( - "id", "user_id", "code", "can_be_used_count", "used_count", + "id", "user_id", "code", "can_be_used_count", "is_active", "created_at", "expires_at", ).From("invite_codes").Where(sq.And{ sq.Eq{"code": code}, sq.Eq{"is_active": true}, sq.Expr("expires_at > now()"), - sq.Expr("can_be_used_count > used_count"), + sq.Expr("can_be_used_count > 0"), }) sqlQuery, args, err := query.ToSql() @@ -97,7 +97,7 @@ func (r *inviteRepository) FindActiveByCode(ctx context.Context, code int64) (*m invite := &model.InviteCode{} err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan( &invite.ID, &invite.UserID, &invite.Code, &invite.CanBeUsedCount, - &invite.UsedCount, &invite.IsActive, &invite.CreatedAt, &invite.ExpiresAt, + &invite.IsActive, &invite.CreatedAt, &invite.ExpiresAt, ) if errors.Is(err, pgx.ErrNoRows) { @@ -110,28 +110,10 @@ func (r *inviteRepository) FindActiveByCode(ctx context.Context, code int64) (*m return invite, nil } -func (r *inviteRepository) IncrementUsedCount(ctx context.Context, code int64) error { - query := r.qb.Update("invite_codes"). - Set("used_count", sq.Expr("used_count + 1")). - Where(sq.Eq{"code": code}) - - sqlQuery, args, err := query.ToSql() - if err != nil { - return errs.NewInternalError(errs.DatabaseError, "failed to build query", err) - } - - _, err = r.pool.Exec(ctx, sqlQuery, args...) - if err != nil { - return errs.NewInternalError(errs.DatabaseError, "failed to increment used count", err) - } - - return nil -} - func (r *inviteRepository) DecrementCanBeUsedCountTx(ctx context.Context, tx pgx.Tx, code int64) error { query := r.qb.Update("invite_codes"). - Set("used_count", sq.Expr("used_count + 1")). - Set("is_active", sq.Expr("CASE WHEN used_count + 1 >= can_be_used_count THEN false ELSE is_active END")). + Set("can_be_used_count", sq.Expr("can_be_used_count - 1")). + Set("is_active", sq.Expr("CASE WHEN can_be_used_count - 1 <= 0 THEN false ELSE is_active END")). Where(sq.Eq{"code": code}) sqlQuery, args, err := query.ToSql() @@ -170,7 +152,7 @@ func (r *inviteRepository) DeactivateExpired(ctx context.Context) (int, error) { func (r *inviteRepository) GetUserInvites(ctx context.Context, userID int) ([]*model.InviteCode, error) { query := r.qb.Select( - "id", "user_id", "code", "can_be_used_count", "used_count", + "id", "user_id", "code", "can_be_used_count", "is_active", "created_at", "expires_at", ).From("invite_codes"). Where(sq.Eq{"user_id": userID}). @@ -192,7 +174,7 @@ func (r *inviteRepository) GetUserInvites(ctx context.Context, userID int) ([]*m invite := &model.InviteCode{} err := rows.Scan( &invite.ID, &invite.UserID, &invite.Code, &invite.CanBeUsedCount, - &invite.UsedCount, &invite.IsActive, &invite.CreatedAt, &invite.ExpiresAt, + &invite.IsActive, &invite.CreatedAt, &invite.ExpiresAt, ) if err != nil { return nil, errs.NewInternalError(errs.DatabaseError, "failed to scan invite", err) diff --git a/migrations/00009_drop_used_count_column.sql b/migrations/00009_drop_used_count_column.sql new file mode 100644 index 0000000..3737653 --- /dev/null +++ b/migrations/00009_drop_used_count_column.sql @@ -0,0 +1,5 @@ +-- +goose Up +ALTER TABLE invite_codes DROP COLUMN IF EXISTS used_count; + +-- +goose Down +ALTER TABLE invite_codes ADD COLUMN used_count INT DEFAULT 0; diff --git a/pkg/pb/invite/invite.pb.go b/pkg/pb/invite/invite.pb.go index 6328374..7d7b705 100644 --- a/pkg/pb/invite/invite.pb.go +++ b/pkg/pb/invite/invite.pb.go @@ -191,10 +191,9 @@ type GetInfoResponse struct { Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` CanBeUsedCount int32 `protobuf:"varint,3,opt,name=can_be_used_count,json=canBeUsedCount,proto3" json:"can_be_used_count,omitempty"` - UsedCount int32 `protobuf:"varint,4,opt,name=used_count,json=usedCount,proto3" json:"used_count,omitempty"` - ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"` - IsActive bool `protobuf:"varint,6,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"` + IsActive bool `protobuf:"varint,5,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -250,13 +249,6 @@ func (x *GetInfoResponse) GetCanBeUsedCount() int32 { return 0 } -func (x *GetInfoResponse) GetUsedCount() int32 { - if x != nil { - return x.UsedCount - } - return 0 -} - func (x *GetInfoResponse) GetExpiresAt() *timestamppb.Timestamp { if x != nil { return x.ExpiresAt @@ -293,18 +285,16 @@ const file_invite_invite_proto_rawDesc = "" + "\n" + "expires_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\"$\n" + "\x0eGetInfoRequest\x12\x12\n" + - "\x04code\x18\x01 \x01(\tR\x04code\"\x9b\x02\n" + + "\x04code\x18\x01 \x01(\tR\x04code\"\xfc\x01\n" + "\x0fGetInfoResponse\x12\x12\n" + "\x04code\x18\x01 \x01(\tR\x04code\x12\x17\n" + "\auser_id\x18\x02 \x01(\x03R\x06userId\x12)\n" + - "\x11can_be_used_count\x18\x03 \x01(\x05R\x0ecanBeUsedCount\x12\x1d\n" + + "\x11can_be_used_count\x18\x03 \x01(\x05R\x0ecanBeUsedCount\x129\n" + "\n" + - "used_count\x18\x04 \x01(\x05R\tusedCount\x129\n" + + "expires_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\x12\x1b\n" + + "\tis_active\x18\x05 \x01(\bR\bisActive\x129\n" + "\n" + - "expires_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\x12\x1b\n" + - "\tis_active\x18\x06 \x01(\bR\bisActive\x129\n" + - "\n" + - "created_at\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt2\x8a\x01\n" + + "created_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt2\x8a\x01\n" + "\rInviteService\x12=\n" + "\bGenerate\x12\x17.invite.GenerateRequest\x1a\x18.invite.GenerateResponse\x12:\n" + "\aGetInfo\x12\x16.invite.GetInfoRequest\x1a\x17.invite.GetInfoResponseB>Z