Removed sync store for token/service/user/service-acc (#139)

This commit is contained in:
Marko Gaćeša 2022-12-29 11:52:50 +01:00 committed by GitHub
parent e4ae2b269b
commit ae6e864f57
11 changed files with 151 additions and 438 deletions

View File

@ -6,10 +6,10 @@ package database
import (
"context"
"database/sql"
"fmt"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
@ -43,10 +43,13 @@ type ServiceStore struct {
// Find finds the service by id.
func (s *ServiceStore) Find(ctx context.Context, id int64) (*types.Service, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := new(service)
if err := s.db.GetContext(ctx, dst, serviceSelectID, id); err != nil {
if err := db.GetContext(ctx, dst, serviceSelectID, id); err != nil {
return nil, processSQLErrorf(err, "Select by id query failed")
}
return s.mapDBService(dst), nil
}
@ -60,10 +63,13 @@ func (s *ServiceStore) FindUID(ctx context.Context, uid string) (*types.Service,
return nil, store.ErrResourceNotFound
}
db := dbtx.GetAccessor(ctx, s.db)
dst := new(service)
if err = s.db.GetContext(ctx, dst, serviceSelectUIDUnique, uidUnique); err != nil {
if err = db.GetContext(ctx, dst, serviceSelectUIDUnique, uidUnique); err != nil {
return nil, processSQLErrorf(err, "Select by uid query failed")
}
return s.mapDBService(dst), nil
}
@ -74,12 +80,14 @@ func (s *ServiceStore) Create(ctx context.Context, svc *types.Service) error {
return fmt.Errorf("failed to map db service: %w", err)
}
query, arg, err := s.db.BindNamed(serviceInsert, dbSVC)
db := dbtx.GetAccessor(ctx, s.db)
query, arg, err := db.BindNamed(serviceInsert, dbSVC)
if err != nil {
return processSQLErrorf(err, "Failed to bind service object")
}
if err = s.db.QueryRowContext(ctx, query, arg...).Scan(&svc.ID); err != nil {
if err = db.QueryRowContext(ctx, query, arg...).Scan(&svc.ID); err != nil {
return processSQLErrorf(err, "Insert query failed")
}
@ -93,12 +101,14 @@ func (s *ServiceStore) Update(ctx context.Context, svc *types.Service) error {
return fmt.Errorf("failed to map db service: %w", err)
}
query, arg, err := s.db.BindNamed(serviceUpdate, dbSVC)
db := dbtx.GetAccessor(ctx, s.db)
query, arg, err := db.BindNamed(serviceUpdate, dbSVC)
if err != nil {
return processSQLErrorf(err, "Failed to bind service object")
}
if _, err = s.db.ExecContext(ctx, query, arg...); err != nil {
if _, err = db.ExecContext(ctx, query, arg...); err != nil {
return processSQLErrorf(err, "Update query failed")
}
@ -107,38 +117,40 @@ func (s *ServiceStore) Update(ctx context.Context, svc *types.Service) error {
// Delete deletes the service.
func (s *ServiceStore) Delete(ctx context.Context, id int64) error {
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return processSQLErrorf(err, "Failed to start a new transaction")
}
defer func(tx *sql.Tx) {
_ = tx.Rollback()
}(tx)
db := dbtx.GetAccessor(ctx, s.db)
// delete the service
if _, err = tx.ExecContext(ctx, serviceDelete, id); err != nil {
if _, err := db.ExecContext(ctx, serviceDelete, id); err != nil {
return processSQLErrorf(err, "The delete query failed")
}
return tx.Commit()
return nil
}
// List returns a list of service for a specific parent.
func (s *ServiceStore) List(ctx context.Context) ([]*types.Service, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := []*service{}
err := s.db.SelectContext(ctx, &dst, serviceSelect)
err := db.SelectContext(ctx, &dst, serviceSelect)
if err != nil {
return nil, processSQLErrorf(err, "Failed executing default list query")
}
return s.mapDBServices(dst), nil
}
// Count returns a count of service for a specific parent.
func (s *ServiceStore) Count(ctx context.Context) (int64, error) {
db := dbtx.GetAccessor(ctx, s.db)
var count int64
err := s.db.QueryRowContext(ctx, serviceCount).Scan(&count)
err := db.QueryRowContext(ctx, serviceCount).Scan(&count)
if err != nil {
return 0, processSQLErrorf(err, "Failed executing count query")
}
return count, nil
}

View File

@ -6,10 +6,10 @@ package database
import (
"context"
"database/sql"
"fmt"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
@ -43,8 +43,10 @@ type ServiceAccountStore struct {
// Find finds the service account by id.
func (s *ServiceAccountStore) Find(ctx context.Context, id int64) (*types.ServiceAccount, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := new(serviceAccount)
if err := s.db.GetContext(ctx, dst, serviceAccountSelectID, id); err != nil {
if err := db.GetContext(ctx, dst, serviceAccountSelectID, id); err != nil {
return nil, processSQLErrorf(err, "Select by id query failed")
}
return s.mapDBServiceAccount(dst), nil
@ -60,10 +62,13 @@ func (s *ServiceAccountStore) FindUID(ctx context.Context, uid string) (*types.S
return nil, store.ErrResourceNotFound
}
db := dbtx.GetAccessor(ctx, s.db)
dst := new(serviceAccount)
if err = s.db.GetContext(ctx, dst, serviceAccountSelectUIDUnique, uidUnique); err != nil {
if err = db.GetContext(ctx, dst, serviceAccountSelectUIDUnique, uidUnique); err != nil {
return nil, processSQLErrorf(err, "Select by uid query failed")
}
return s.mapDBServiceAccount(dst), nil
}
@ -74,12 +79,14 @@ func (s *ServiceAccountStore) Create(ctx context.Context, sa *types.ServiceAccou
return fmt.Errorf("failed to map db service account: %w", err)
}
query, arg, err := s.db.BindNamed(serviceAccountInsert, dbSA)
db := dbtx.GetAccessor(ctx, s.db)
query, arg, err := db.BindNamed(serviceAccountInsert, dbSA)
if err != nil {
return processSQLErrorf(err, "Failed to bind service account object")
}
if err = s.db.QueryRowContext(ctx, query, arg...).Scan(&sa.ID); err != nil {
if err = db.QueryRowContext(ctx, query, arg...).Scan(&sa.ID); err != nil {
return processSQLErrorf(err, "Insert query failed")
}
@ -93,12 +100,14 @@ func (s *ServiceAccountStore) Update(ctx context.Context, sa *types.ServiceAccou
return fmt.Errorf("failed to map db service account: %w", err)
}
query, arg, err := s.db.BindNamed(serviceAccountUpdate, dbSA)
db := dbtx.GetAccessor(ctx, s.db)
query, arg, err := db.BindNamed(serviceAccountUpdate, dbSA)
if err != nil {
return processSQLErrorf(err, "Failed to bind service account object")
}
if _, err = s.db.ExecContext(ctx, query, arg...); err != nil {
if _, err = db.ExecContext(ctx, query, arg...); err != nil {
return processSQLErrorf(err, "Update query failed")
}
@ -107,40 +116,40 @@ func (s *ServiceAccountStore) Update(ctx context.Context, sa *types.ServiceAccou
// Delete deletes the service account.
func (s *ServiceAccountStore) Delete(ctx context.Context, id int64) error {
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return processSQLErrorf(err, "Failed to start a new transaction")
}
defer func(tx *sql.Tx) {
_ = tx.Rollback()
}(tx)
// delete the service account
if _, err = tx.ExecContext(ctx, serviceAccountDelete, id); err != nil {
db := dbtx.GetAccessor(ctx, s.db)
if _, err := db.ExecContext(ctx, serviceAccountDelete, id); err != nil {
return processSQLErrorf(err, "The delete query failed")
}
return tx.Commit()
return nil
}
// List returns a list of service accounts for a specific parent.
func (s *ServiceAccountStore) List(ctx context.Context, parentType enum.ParentResourceType,
parentID int64) ([]*types.ServiceAccount, error) {
dst := []*serviceAccount{}
db := dbtx.GetAccessor(ctx, s.db)
err := s.db.SelectContext(ctx, &dst, serviceAccountSelectByParentTypeAndID, parentType, parentID)
dst := []*serviceAccount{}
err := db.SelectContext(ctx, &dst, serviceAccountSelectByParentTypeAndID, parentType, parentID)
if err != nil {
return nil, processSQLErrorf(err, "Failed executing default list query")
}
return s.mapDBServiceAccounts(dst), nil
}
// Count returns a count of service accounts for a specific parent.
func (s *ServiceAccountStore) Count(ctx context.Context,
parentType enum.ParentResourceType, parentID int64) (int64, error) {
db := dbtx.GetAccessor(ctx, s.db)
var count int64
err := s.db.QueryRowContext(ctx, serviceAccountCountByParentTypeAndID, parentType, parentID).Scan(&count)
err := db.QueryRowContext(ctx, serviceAccountCountByParentTypeAndID, parentType, parentID).Scan(&count)
if err != nil {
return 0, processSQLErrorf(err, "Failed executing count query")
}
return count, nil
}

View File

@ -1,79 +0,0 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package database
import (
"context"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/mutex"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
var _ store.ServiceAccountStore = (*ServiceAccountStoreSync)(nil)
// NewServiceAccountStoreSync returns a new ServiceAccountStoreSync.
func NewServiceAccountStoreSync(base *ServiceAccountStore) *ServiceAccountStoreSync {
return &ServiceAccountStoreSync{base}
}
// ServiceAccountStoreSync synchronizes read and write access to the
// service account store. This prevents race conditions when the database
// type is sqlite3.
type ServiceAccountStoreSync struct {
base *ServiceAccountStore
}
// Find finds the service account by id.
func (s *ServiceAccountStoreSync) Find(ctx context.Context, id int64) (*types.ServiceAccount, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Find(ctx, id)
}
// FindUID finds the service account by uid.
func (s *ServiceAccountStoreSync) FindUID(ctx context.Context, uid string) (*types.ServiceAccount, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.FindUID(ctx, uid)
}
// Create saves the service account.
func (s *ServiceAccountStoreSync) Create(ctx context.Context, sa *types.ServiceAccount) error {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Create(ctx, sa)
}
// Update updates the service account details.
func (s *ServiceAccountStoreSync) Update(ctx context.Context, sa *types.ServiceAccount) error {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Update(ctx, sa)
}
// Delete deletes the service account.
func (s *ServiceAccountStoreSync) Delete(ctx context.Context, id int64) error {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Delete(ctx, id)
}
// List returns a list of service accounts for a specific parent.
func (s *ServiceAccountStoreSync) List(ctx context.Context, parentType enum.ParentResourceType,
parentID int64) ([]*types.ServiceAccount, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.List(ctx, parentType, parentID)
}
// Count returns a count of service accounts for a specific parent.
func (s *ServiceAccountStoreSync) Count(ctx context.Context, parentType enum.ParentResourceType,
parentID int64) (int64, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Count(ctx, parentType, parentID)
}

View File

@ -1,76 +0,0 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package database
import (
"context"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/mutex"
"github.com/harness/gitness/types"
)
var _ store.ServiceStore = (*ServiceStoreSync)(nil)
// NewServiceStoreSync returns a new ServiceStoreSync.
func NewServiceStoreSync(base *ServiceStore) *ServiceStoreSync {
return &ServiceStoreSync{base}
}
// ServiceStoreSync synchronizes read and write access to the
// service store. This prevents race conditions when the database
// type is sqlite3.
type ServiceStoreSync struct {
base *ServiceStore
}
// Find finds the service by id.
func (s *ServiceStoreSync) Find(ctx context.Context, id int64) (*types.Service, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Find(ctx, id)
}
// FindUID finds the service by uid.
func (s *ServiceStoreSync) FindUID(ctx context.Context, uid string) (*types.Service, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.FindUID(ctx, uid)
}
// Create saves the service.
func (s *ServiceStoreSync) Create(ctx context.Context, sa *types.Service) error {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Create(ctx, sa)
}
// Update updates the service.
func (s *ServiceStoreSync) Update(ctx context.Context, sa *types.Service) error {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Update(ctx, sa)
}
// Delete deletes the service.
func (s *ServiceStoreSync) Delete(ctx context.Context, id int64) error {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Delete(ctx, id)
}
// List returns a list of service for a specific parent.
func (s *ServiceStoreSync) List(ctx context.Context) ([]*types.Service, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.List(ctx)
}
// Count returns a count of service for a specific parent.
func (s *ServiceStoreSync) Count(ctx context.Context) (int64, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Count(ctx)
}

View File

@ -30,6 +30,7 @@ func connect() (*sqlx.DB, error) {
// seed seed the database state.
func seed(db *sqlx.DB) error {
/*
_, err := db.Exec("DELETE FROM executions")
if err != nil {
return err
@ -52,6 +53,8 @@ func seed(db *sqlx.DB) error {
}
_, err = db.Exec("ALTER SEQUENCE executions_execution_id_seq RESTART WITH 1")
return err
*/
return nil
}
// unmarshal a testdata file.

View File

@ -8,6 +8,7 @@ import (
"context"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
@ -28,30 +29,38 @@ type TokenStore struct {
// Find finds the token by id.
func (s *TokenStore) Find(ctx context.Context, id int64) (*types.Token, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := new(types.Token)
if err := s.db.GetContext(ctx, dst, TokenSelectByID, id); err != nil {
if err := db.GetContext(ctx, dst, TokenSelectByID, id); err != nil {
return nil, processSQLErrorf(err, "Select query failed")
}
return dst, nil
}
// Find finds the token by principalId and tokenUID.
func (s *TokenStore) FindByUID(ctx context.Context, principalID int64, tokenUID string) (*types.Token, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := new(types.Token)
if err := s.db.GetContext(ctx, dst, TokenSelectByPrincipalIDAndUID, principalID, tokenUID); err != nil {
if err := db.GetContext(ctx, dst, TokenSelectByPrincipalIDAndUID, principalID, tokenUID); err != nil {
return nil, processSQLErrorf(err, "Select query failed")
}
return dst, nil
}
// Create saves the token details.
func (s *TokenStore) Create(ctx context.Context, token *types.Token) error {
query, arg, err := s.db.BindNamed(tokenInsert, token)
db := dbtx.GetAccessor(ctx, s.db)
query, arg, err := db.BindNamed(tokenInsert, token)
if err != nil {
return processSQLErrorf(err, "Failed to bind token object")
}
if err = s.db.QueryRowContext(ctx, query, arg...).Scan(&token.ID); err != nil {
if err = db.QueryRowContext(ctx, query, arg...).Scan(&token.ID); err != nil {
return processSQLErrorf(err, "Insert query failed")
}
@ -60,7 +69,9 @@ func (s *TokenStore) Create(ctx context.Context, token *types.Token) error {
// Delete deletes the token with the given id.
func (s *TokenStore) Delete(ctx context.Context, id int64) error {
if _, err := s.db.ExecContext(ctx, tokenDelete, id); err != nil {
db := dbtx.GetAccessor(ctx, s.db)
if _, err := db.ExecContext(ctx, tokenDelete, id); err != nil {
return processSQLErrorf(err, "The delete query failed")
}
@ -69,7 +80,9 @@ func (s *TokenStore) Delete(ctx context.Context, id int64) error {
// DeleteForPrincipal deletes all tokens for a specific principal.
func (s *TokenStore) DeleteForPrincipal(ctx context.Context, principalID int64) error {
if _, err := s.db.ExecContext(ctx, tokenDeleteForPrincipal, principalID); err != nil {
db := dbtx.GetAccessor(ctx, s.db)
if _, err := db.ExecContext(ctx, tokenDeleteForPrincipal, principalID); err != nil {
return processSQLErrorf(err, "The delete query failed")
}
@ -79,22 +92,27 @@ func (s *TokenStore) DeleteForPrincipal(ctx context.Context, principalID int64)
// Count returns a count of tokens of a specifc type for a specific principal.
func (s *TokenStore) Count(ctx context.Context,
principalID int64, tokenType enum.TokenType) (int64, error) {
db := dbtx.GetAccessor(ctx, s.db)
var count int64
err := s.db.QueryRowContext(ctx, tokenCountForPrincipalIDOfType, principalID, tokenType).Scan(&count)
err := db.QueryRowContext(ctx, tokenCountForPrincipalIDOfType, principalID, tokenType).Scan(&count)
if err != nil {
return 0, processSQLErrorf(err, "Failed executing count query")
}
return count, nil
}
// List returns a list of tokens of a specific type for a specific principal.
func (s *TokenStore) List(ctx context.Context,
principalID int64, tokenType enum.TokenType) ([]*types.Token, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := []*types.Token{}
// TODO: custom filters / sorting for tokens.
err := s.db.SelectContext(ctx, &dst, tokenSelectForPrincipalIDOfType, principalID, tokenType)
err := db.SelectContext(ctx, &dst, tokenSelectForPrincipalIDOfType, principalID, tokenType)
if err != nil {
return nil, processSQLErrorf(err, "Failed executing token list query")
}

View File

@ -1,77 +0,0 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package database
import (
"context"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/mutex"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
var _ store.TokenStore = (*TokenStoreSync)(nil)
// NewTokenStoreSync returns a new TokenStoreSync.
func NewTokenStoreSync(store *TokenStore) *TokenStoreSync {
return &TokenStoreSync{base: store}
}
// TokenStoreSync synronizes read and write access to the
// token store. This prevents race conditions when the database
// type is sqlite3.
type TokenStoreSync struct{ base *TokenStore }
// Find finds the token by id.
func (s *TokenStoreSync) Find(ctx context.Context, id int64) (*types.Token, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Find(ctx, id)
}
// Find finds the token by principalId and tokenUID.
func (s *TokenStoreSync) FindByUID(ctx context.Context, principalID int64, tokenUID string) (*types.Token, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.FindByUID(ctx, principalID, tokenUID)
}
// Create saves the token details.
func (s *TokenStoreSync) Create(ctx context.Context, token *types.Token) error {
mutex.Lock()
defer mutex.Unlock()
return s.base.Create(ctx, token)
}
// Delete deletes the token with the given id.
func (s *TokenStoreSync) Delete(ctx context.Context, id int64) error {
mutex.Lock()
defer mutex.Unlock()
return s.base.Delete(ctx, id)
}
// DeleteForPrincipal deletes all tokens for a specific principal.
func (s *TokenStoreSync) DeleteForPrincipal(ctx context.Context, principalID int64) error {
mutex.Lock()
defer mutex.Unlock()
return s.base.DeleteForPrincipal(ctx, principalID)
}
// Count returns a count of tokens of a specifc type for a specific principal.
func (s *TokenStoreSync) Count(ctx context.Context, principalID int64,
tokenType enum.TokenType) (int64, error) {
mutex.Lock()
defer mutex.Unlock()
return s.base.Count(ctx, principalID, tokenType)
}
// List returns a list of tokens of a specific type for a specific principal.
func (s *TokenStoreSync) List(ctx context.Context, principalID int64,
tokenType enum.TokenType) ([]*types.Token, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.List(ctx, principalID, tokenType)
}

View File

@ -6,10 +6,10 @@ package database
import (
"context"
"database/sql"
"fmt"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
@ -35,8 +35,7 @@ func NewUserStore(db *sqlx.DB, uidTransformation store.PrincipalUIDTransformatio
}
}
// UserStore implements a UserStore backed by a relational
// database.
// UserStore implements a UserStore backed by a relational database.
type UserStore struct {
db *sqlx.DB
uidTransformation store.PrincipalUIDTransformation
@ -44,10 +43,13 @@ type UserStore struct {
// Find finds the user by id.
func (s *UserStore) Find(ctx context.Context, id int64) (*types.User, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := new(user)
if err := s.db.GetContext(ctx, dst, userSelectID, id); err != nil {
if err := db.GetContext(ctx, dst, userSelectID, id); err != nil {
return nil, processSQLErrorf(err, "Select by id query failed")
}
return s.mapDBUser(dst), nil
}
@ -61,19 +63,25 @@ func (s *UserStore) FindUID(ctx context.Context, uid string) (*types.User, error
return nil, store.ErrResourceNotFound
}
db := dbtx.GetAccessor(ctx, s.db)
dst := new(user)
if err = s.db.GetContext(ctx, dst, userSelectUIDUnique, uidUnique); err != nil {
if err = db.GetContext(ctx, dst, userSelectUIDUnique, uidUnique); err != nil {
return nil, processSQLErrorf(err, "Select by uid query failed")
}
return s.mapDBUser(dst), nil
}
// FindEmail finds the user by email.
func (s *UserStore) FindEmail(ctx context.Context, email string) (*types.User, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := new(user)
if err := s.db.GetContext(ctx, dst, userSelectEmail, email); err != nil {
if err := db.GetContext(ctx, dst, userSelectEmail, email); err != nil {
return nil, processSQLErrorf(err, "Select by email query failed")
}
return s.mapDBUser(dst), nil
}
@ -84,12 +92,14 @@ func (s *UserStore) Create(ctx context.Context, user *types.User) error {
return fmt.Errorf("failed to map db user: %w", err)
}
query, arg, err := s.db.BindNamed(userInsert, dbUser)
db := dbtx.GetAccessor(ctx, s.db)
query, arg, err := db.BindNamed(userInsert, dbUser)
if err != nil {
return processSQLErrorf(err, "Failed to bind user object")
}
if err = s.db.QueryRowContext(ctx, query, arg...).Scan(&user.ID); err != nil {
if err = db.QueryRowContext(ctx, query, arg...).Scan(&user.ID); err != nil {
return processSQLErrorf(err, "Insert query failed")
}
@ -103,12 +113,14 @@ func (s *UserStore) Update(ctx context.Context, user *types.User) error {
return fmt.Errorf("failed to map db user: %w", err)
}
query, arg, err := s.db.BindNamed(userUpdate, dbUser)
db := dbtx.GetAccessor(ctx, s.db)
query, arg, err := db.BindNamed(userUpdate, dbUser)
if err != nil {
return processSQLErrorf(err, "Failed to bind user object")
}
if _, err = s.db.ExecContext(ctx, query, arg...); err != nil {
if _, err = db.ExecContext(ctx, query, arg...); err != nil {
return processSQLErrorf(err, "Update query failed")
}
@ -117,28 +129,25 @@ func (s *UserStore) Update(ctx context.Context, user *types.User) error {
// Delete deletes the user.
func (s *UserStore) Delete(ctx context.Context, id int64) error {
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return processSQLErrorf(err, "Failed to start a new transaction")
}
defer func(tx *sql.Tx) {
_ = tx.Rollback()
}(tx)
// delete the user
if _, err = tx.ExecContext(ctx, userDelete, id); err != nil {
db := dbtx.GetAccessor(ctx, s.db)
if _, err := db.ExecContext(ctx, userDelete, id); err != nil {
return processSQLErrorf(err, "The delete query failed")
}
return tx.Commit()
return nil
}
// List returns a list of users.
func (s *UserStore) List(ctx context.Context, opts *types.UserFilter) ([]*types.User, error) {
db := dbtx.GetAccessor(ctx, s.db)
dst := []*user{}
// if the user does not provide any customer filter
// or sorting we use the default select statement.
if opts.Sort == enum.UserAttrNone {
err := s.db.SelectContext(ctx, &dst, userSelect, limit(opts.Size), offset(opts.Page, opts.Size))
err := db.SelectContext(ctx, &dst, userSelect, limit(opts.Size), offset(opts.Page, opts.Size))
if err != nil {
return nil, processSQLErrorf(err, "Failed executing default list query")
}
@ -173,7 +182,7 @@ func (s *UserStore) List(ctx context.Context, opts *types.UserFilter) ([]*types.
return nil, errors.Wrap(err, "Failed to convert query to sql")
}
if err = s.db.SelectContext(ctx, &dst, sql); err != nil {
if err = db.SelectContext(ctx, &dst, sql); err != nil {
return nil, processSQLErrorf(err, "Failed executing custom list query")
}
@ -182,11 +191,14 @@ func (s *UserStore) List(ctx context.Context, opts *types.UserFilter) ([]*types.
// Count returns a count of users.
func (s *UserStore) Count(ctx context.Context) (int64, error) {
db := dbtx.GetAccessor(ctx, s.db)
var count int64
err := s.db.QueryRowContext(ctx, userCount).Scan(&count)
err := db.QueryRowContext(ctx, userCount).Scan(&count)
if err != nil {
return 0, processSQLErrorf(err, "Failed executing count query")
}
return count, nil
}

View File

@ -1,81 +0,0 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package database
import (
"context"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/database/mutex"
"github.com/harness/gitness/types"
)
var _ store.UserStore = (*UserStoreSync)(nil)
// NewUserStoreSync returns a new UserStoreSync.
func NewUserStoreSync(store *UserStore) *UserStoreSync {
return &UserStoreSync{base: store}
}
// UserStoreSync synronizes read and write access to the
// user store. This prevents race conditions when the database
// type is sqlite3.
type UserStoreSync struct{ base *UserStore }
// Find finds the user by id.
func (s *UserStoreSync) Find(ctx context.Context, id int64) (*types.User, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.Find(ctx, id)
}
// FindUID finds the user by uid.
func (s *UserStoreSync) FindUID(ctx context.Context, uid string) (*types.User, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.FindUID(ctx, uid)
}
// FindEmail finds the user by email.
func (s *UserStoreSync) FindEmail(ctx context.Context, email string) (*types.User, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.FindEmail(ctx, email)
}
// List returns a list of users.
func (s *UserStoreSync) List(ctx context.Context, opts *types.UserFilter) ([]*types.User, error) {
mutex.RLock()
defer mutex.RUnlock()
return s.base.List(ctx, opts)
}
// Create saves the user details.
func (s *UserStoreSync) Create(ctx context.Context, user *types.User) error {
mutex.Lock()
defer mutex.Unlock()
return s.base.Create(ctx, user)
}
// Update updates the user details.
func (s *UserStoreSync) Update(ctx context.Context, user *types.User) error {
mutex.Lock()
defer mutex.Unlock()
return s.base.Update(ctx, user)
}
// Delete deletes the user.
func (s *UserStoreSync) Delete(ctx context.Context, id int64) error {
mutex.Lock()
defer mutex.Unlock()
return s.base.Delete(ctx, id)
}
// Count returns a count of users.
func (s *UserStoreSync) Count(ctx context.Context) (int64, error) {
mutex.Lock()
defer mutex.Unlock()
return s.base.Count(ctx)
}

View File

@ -38,7 +38,7 @@ func TestUser(t *testing.T) {
return
}
userStoreSync := NewUserStoreSync(NewUserStore(db, store.ToLowerPrincipalUIDTransformation))
userStoreSync := NewUserStore(db, store.ToLowerPrincipalUIDTransformation)
t.Run("create", testUserCreate(userStoreSync))
t.Run("duplicate", testUserDuplicate(userStoreSync))
t.Run("count", testUserCount(userStoreSync))
@ -244,8 +244,8 @@ func testUserDelete(s store.UserStore) func(t *testing.T) {
t.Error(err)
return
}
if _, err = s.Find(ctx, 1); errors.Is(err, store.ErrResourceNotFound) {
t.Errorf("Expected sql.ErrNoRows got %s", err)
if _, err = s.Find(ctx, 1); !errors.Is(err, store.ErrResourceNotFound) {
t.Errorf("Expected store.ErrResourceNotFound got %s", err)
}
}
}

View File

@ -44,39 +44,18 @@ func ProvideDatabase(ctx context.Context, config *types.Config) (*sqlx.DB, error
// ProvideUserStore provides a user store.
func ProvideUserStore(db *sqlx.DB, uidTransformation store.PrincipalUIDTransformation) store.UserStore {
switch db.DriverName() {
case postgres:
return NewUserStore(db, uidTransformation)
default:
return NewUserStoreSync(
NewUserStore(db, uidTransformation),
)
}
}
// ProvideServiceAccountStore provides a service account store.
func ProvideServiceAccountStore(db *sqlx.DB,
uidTransformation store.PrincipalUIDTransformation) store.ServiceAccountStore {
switch db.DriverName() {
case postgres:
return NewServiceAccountStore(db, uidTransformation)
default:
return NewServiceAccountStoreSync(
NewServiceAccountStore(db, uidTransformation),
)
}
}
// ProvideServiceStore provides a service store.
func ProvideServiceStore(db *sqlx.DB, uidTransformation store.PrincipalUIDTransformation) store.ServiceStore {
switch db.DriverName() {
case postgres:
return NewServiceStore(db, uidTransformation)
default:
return NewServiceStoreSync(
NewServiceStore(db, uidTransformation),
)
}
}
// ProvideSpaceStore provides a space store.
@ -105,14 +84,7 @@ func ProvideRepoStore(db *sqlx.DB, pathTransformation store.PathTransformation)
// ProvideTokenStore provides a token store.
func ProvideTokenStore(db *sqlx.DB) store.TokenStore {
switch db.DriverName() {
case postgres:
return NewTokenStore(db)
default:
return NewTokenStoreSync(
NewTokenStore(db),
)
}
}
// ProvidePullReqStore provides a pull request store.