From d94ae83c2f52692b573ec38c5b5ce9650993ec33 Mon Sep 17 00:00:00 2001 From: SoXX Date: Tue, 25 Jun 2024 21:55:43 +0200 Subject: [PATCH] feat(errors): implemented custom errors Signed-off-by: SoXX --- error/validation.go | 7 - internal/postgres/post.go | 57 ++++--- internal/postgres/relationships.go | 87 +++++++++-- internal/postgres/source.go | 20 ++- internal/postgres/tag.go | 46 ++++-- internal/postgres/user.go | 230 ++++++++++++++++++----------- {error => pkg/errors}/database.go | 16 +- pkg/errors/validation.go | 11 ++ 8 files changed, 324 insertions(+), 150 deletions(-) delete mode 100644 error/validation.go rename {error => pkg/errors}/database.go (70%) create mode 100644 pkg/errors/validation.go diff --git a/error/validation.go b/error/validation.go deleted file mode 100644 index b6b4245..0000000 --- a/error/validation.go +++ /dev/null @@ -1,7 +0,0 @@ -package error - -type MissingAnthrovePostIDError struct{} - -func (e *MissingAnthrovePostIDError) Error() string { - return "AnthrovePostID is empty" -} diff --git a/internal/postgres/post.go b/internal/postgres/post.go index ffe74be..2206e00 100644 --- a/internal/postgres/post.go +++ b/internal/postgres/post.go @@ -3,24 +3,29 @@ package postgres import ( "context" "errors" + errors2 "git.dragse.it/anthrove/otter-space-sdk/pkg/errors" - error2 "git.dragse.it/anthrove/otter-space-sdk/error" "git.dragse.it/anthrove/otter-space-sdk/pkg/models" log "github.com/sirupsen/logrus" "gorm.io/gorm" ) func CreatePost(ctx context.Context, db *gorm.DB, anthrovePost *models.Post) error { - result := db.WithContext(ctx).Create(&anthrovePost) - if result.RowsAffected == 0 { - return &error2.NoDataWritten{} + if anthrovePost == nil { + return &errors2.EntityValidationFailed{Reason: "anthrovePost is nil"} } + result := db.WithContext(ctx).Create(&anthrovePost) if result.Error != nil { if errors.Is(result.Error, gorm.ErrDuplicatedKey) { - return &error2.EntityAlreadyExists{} + return &errors2.EntityAlreadyExists{} } + return result.Error + } + + if result.RowsAffected == 0 { + return &errors2.NoDataWritten{} } log.WithFields(log.Fields{ @@ -32,44 +37,58 @@ func CreatePost(ctx context.Context, db *gorm.DB, anthrovePost *models.Post) err } func GetPostByAnthroveID(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID) (*models.Post, error) { + if anthrovePostID == "" { - return nil, &error2.MissingAnthrovePostIDError{} + return nil, &errors2.EntityValidationFailed{Reason: "anthrovePostID is not set"} } + //TODO maybe check ofor id length too...? + var post models.Post result := db.WithContext(ctx).First(&post, "id = ?", anthrovePostID) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { - return nil, &error2.NoDataFound{} + return nil, &errors2.NoDataFound{} } + return nil, result.Error } return &post, nil } func GetPostByURL(ctx context.Context, db *gorm.DB, sourceURL string) (*models.Post, error) { - var post models.Post - err := db.WithContext(ctx).Raw(`SELECT p.id AS id, p.rating as rating FROM "Post" AS p INNER JOIN "PostReference" AS pr ON p.id = pr.post_id AND pr.url = $1 LIMIT 1`, sourceURL).First(&post).Error - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, nil + if sourceURL == "" { + return nil, &errors2.EntityValidationFailed{Reason: "sourceURL is not set"} + } + + var post models.Post + result := db.WithContext(ctx).Raw(`SELECT p.id AS id, p.rating as rating FROM "Post" AS p INNER JOIN "PostReference" AS pr ON p.id = pr.post_id AND pr.url = $1 LIMIT 1`, sourceURL).First(&post) + + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} } - return nil, err + return nil, result.Error } return &post, nil } func GetPostBySourceID(ctx context.Context, db *gorm.DB, sourceID models.AnthroveSourceID) (*models.Post, error) { - var post models.Post - err := db.WithContext(ctx).Raw(`SELECT p.id AS id, p.rating as rating FROM "Post" AS p INNER JOIN "PostReference" AS pr ON p.id = pr.post_id AND pr.source_id = $1 LIMIT 1`, sourceID).First(&post).Error - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, nil + if sourceID == "" { + return nil, &errors2.EntityValidationFailed{Reason: "sourceID is not set"} + } + + var post models.Post + result := db.WithContext(ctx).Raw(`SELECT p.id AS id, p.rating as rating FROM "Post" AS p INNER JOIN "PostReference" AS pr ON p.id = pr.post_id AND pr.source_id = $1 LIMIT 1`, sourceID).First(&post) + + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} } - return nil, err + return nil, result.Error } return &post, nil diff --git a/internal/postgres/relationships.go b/internal/postgres/relationships.go index b52f37e..c072241 100644 --- a/internal/postgres/relationships.go +++ b/internal/postgres/relationships.go @@ -2,6 +2,8 @@ package postgres import ( "context" + "errors" + errors2 "git.dragse.it/anthrove/otter-space-sdk/pkg/errors" "git.dragse.it/anthrove/otter-space-sdk/pkg/models" log "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -9,23 +11,44 @@ import ( func CreateReferenceBetweenPostAndSource(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID, sourceDomain models.AnthroveSourceDomain) error { var source models.Source - var err error + + if anthrovePostID == "" { + return &errors2.EntityValidationFailed{Reason: "anthrovePostID cannot be empty"} + } + + if len(anthrovePostID) != 25 { + return &errors2.EntityValidationFailed{Reason: "anthrovePostID needs to be 25 characters long"} + } + + if sourceDomain == "" { + return &errors2.EntityValidationFailed{Reason: "sourceDomain cannot be empty"} + } // Find the source - err = db.WithContext(ctx).Where("domain = ?", sourceDomain).First(&source).Error - if err != nil { - return err + result := db.WithContext(ctx).Where("domain = ?", sourceDomain).First(&source) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return &errors2.NoDataFound{} + } + return result.Error } // Establish the relationship - err = db.WithContext(ctx).Create(models.PostReference{ + result = db.WithContext(ctx).Create(models.PostReference{ PostID: string(anthrovePostID), SourceID: string(source.ID), URL: string(sourceDomain), - }).Error + }) - if err != nil { - return err + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + return &errors2.EntityAlreadyExists{} + } + return result.Error + } + + if result.RowsAffected == 0 { + return &errors2.NoDataWritten{} } log.WithFields(log.Fields{ @@ -37,14 +60,34 @@ func CreateReferenceBetweenPostAndSource(ctx context.Context, db *gorm.DB, anthr } func CreateReferenceBetweenUserAndPost(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) error { + + if anthrovePostID == "" { + return &errors2.EntityValidationFailed{Reason: "anthrovePostID cannot be empty"} + } + + if len(anthrovePostID) != 25 { + return &errors2.EntityValidationFailed{Reason: "anthrovePostID needs to be 25 characters long"} + } + + if anthroveUserID == "" { + return &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} + } + userFavorite := models.UserFavorites{ UserID: string(anthroveUserID), PostID: string(anthrovePostID), } - err := db.WithContext(ctx).Create(&userFavorite).Error - if err != nil { - return err + result := db.WithContext(ctx).Create(&userFavorite) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + return &errors2.EntityAlreadyExists{} + } + return result.Error + } + + if result.RowsAffected == 0 { + return &errors2.NoDataWritten{} } log.WithFields(log.Fields{ @@ -57,9 +100,25 @@ func CreateReferenceBetweenUserAndPost(ctx context.Context, db *gorm.DB, anthrov func CheckReferenceBetweenUserAndPost(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, anthrovePostID models.AnthrovePostID) (bool, error) { var count int64 - err := db.WithContext(ctx).Model(&models.UserFavorites{}).Where("user_id = ? AND post_id = ?", string(anthroveUserID), string(anthrovePostID)).Count(&count).Error - if err != nil { - return false, err + + if anthrovePostID == "" { + return false, &errors2.EntityValidationFailed{Reason: "anthrovePostID cannot be empty"} + } + + if len(anthrovePostID) != 25 { + return false, &errors2.EntityValidationFailed{Reason: "anthrovePostID needs to be 25 characters long"} + } + + if anthroveUserID == "" { + return false, &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} + } + + result := db.WithContext(ctx).Model(&models.UserFavorites{}).Where("user_id = ? AND post_id = ?", string(anthroveUserID), string(anthrovePostID)).Count(&count) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return false, &errors2.NoDataFound{} + } + return false, result.Error } exists := count > 0 diff --git a/internal/postgres/source.go b/internal/postgres/source.go index da13fc3..1238a87 100644 --- a/internal/postgres/source.go +++ b/internal/postgres/source.go @@ -2,7 +2,8 @@ package postgres import ( "context" - "fmt" + "errors" + errors2 "git.dragse.it/anthrove/otter-space-sdk/pkg/errors" "git.dragse.it/anthrove/otter-space-sdk/pkg/models" log "github.com/sirupsen/logrus" @@ -13,15 +14,22 @@ import ( func CreateSource(ctx context.Context, db *gorm.DB, anthroveSource *models.Source) error { if anthroveSource.Domain == "" { - return fmt.Errorf("anthroveSource domain is required") + return &errors2.EntityValidationFailed{Reason: "Domain is required"} } result := db.WithContext(ctx).Where(models.Source{Domain: anthroveSource.Domain}).FirstOrCreate(anthroveSource) if result.Error != nil { + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + return &errors2.EntityAlreadyExists{} + } return result.Error } + if result.RowsAffected == 0 { + return &errors2.NoDataWritten{} + } + log.WithFields(log.Fields{ "node_source_url": anthroveSource.Domain, "node_source_displayName": anthroveSource.DisplayName, @@ -38,6 +46,9 @@ func GetAllSource(ctx context.Context, db *gorm.DB) ([]models.Source, error) { result := db.WithContext(ctx).Find(&sources) if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } // TODO really...? i don't think this error handling should be here..? / not possible return nil, result.Error } @@ -53,12 +64,15 @@ func GetSourceByDomain(ctx context.Context, db *gorm.DB, sourceDomain models.Ant var sources models.Source if sourceDomain == "" { - return nil, fmt.Errorf("domain is required") + return nil, &errors2.EntityValidationFailed{Reason: "AnthroveSourceDomain is not set"} } result := db.WithContext(ctx).Where("domain = ?", sourceDomain).First(&sources) if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } return nil, result.Error } diff --git a/internal/postgres/tag.go b/internal/postgres/tag.go index d0aa2e0..248a6a7 100644 --- a/internal/postgres/tag.go +++ b/internal/postgres/tag.go @@ -2,7 +2,8 @@ package postgres import ( "context" - "fmt" + "errors" + errors2 "git.dragse.it/anthrove/otter-space-sdk/pkg/errors" "git.dragse.it/anthrove/otter-space-sdk/pkg/models" log "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -10,10 +11,20 @@ import ( func CreateTag(ctx context.Context, db *gorm.DB, tag *models.Tag) error { - resultTag := db.WithContext(ctx).Where(tag).Create(tag) + if tag == nil { + return &errors2.EntityValidationFailed{Reason: "Tag is nil"} + } - if resultTag.Error != nil { - return resultTag.Error + result := db.WithContext(ctx).Where(tag).Create(tag) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + return &errors2.EntityAlreadyExists{} + } + return result.Error + } + + if result.RowsAffected == 0 { + return &errors2.NoDataWritten{} } log.WithFields(log.Fields{ @@ -24,30 +35,36 @@ func CreateTag(ctx context.Context, db *gorm.DB, tag *models.Tag) error { return nil } -func CreateTagAndReferenceToPost(ctx context.Context, db *gorm.DB, PostID models.AnthrovePostID, tag *models.Tag) error { +func CreateTagAndReferenceToPost(ctx context.Context, db *gorm.DB, anthrovePostID models.AnthrovePostID, tag *models.Tag) error { - if PostID == "" { - return fmt.Errorf("PostID is empty") + if anthrovePostID == "" { + return &errors2.EntityValidationFailed{Reason: "anthrovePostID cannot be empty"} + } + + if len(anthrovePostID) != 25 { + return &errors2.EntityValidationFailed{Reason: "anthrovePostID needs to be 25 characters long"} } if tag == nil { - return fmt.Errorf("tag is nill") + return &errors2.EntityValidationFailed{Reason: "Tag is nil"} } pgPost := models.Post{ BaseModel: models.BaseModel[models.AnthrovePostID]{ - ID: PostID, + ID: anthrovePostID, }, } err := db.WithContext(ctx).Model(&pgPost).Association("Tags").Append(tag) - if err != nil { - return err + if errors.Is(err, gorm.ErrRecordNotFound) { + return &errors2.NoDataFound{} + } + return errors.Join(err, &errors2.NoRelationCreated{}) } log.WithFields(log.Fields{ - "anthrove_post_id": PostID, + "anthrove_post_id": anthrovePostID, "tag_name": tag.Name, "tag_type": tag.Type, }).Trace("database: created tag node") @@ -57,8 +74,13 @@ func CreateTagAndReferenceToPost(ctx context.Context, db *gorm.DB, PostID models func GetTags(ctx context.Context, db *gorm.DB) ([]models.Tag, error) { var tags []models.Tag + result := db.WithContext(ctx).Find(&tags) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { // TODO really...? i don't think this error handling should be here..? / not possible + return nil, &errors2.NoDataFound{} + } return nil, result.Error } diff --git a/internal/postgres/user.go b/internal/postgres/user.go index 359533f..0e4070b 100644 --- a/internal/postgres/user.go +++ b/internal/postgres/user.go @@ -2,7 +2,8 @@ package postgres import ( "context" - "fmt" + "errors" + errors2 "git.dragse.it/anthrove/otter-space-sdk/pkg/errors" "git.dragse.it/anthrove/otter-space-sdk/pkg/models" log "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -11,7 +12,11 @@ import ( func CreateUser(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) error { if anthroveUserID == "" { - return fmt.Errorf("anthroveUserID cannot be empty") + return &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} + } + + if len(anthroveUserID) != 25 { + return &errors2.EntityValidationFailed{Reason: "anthroveUserID needs to be 25 characters long"} } user := models.User{ @@ -20,12 +25,16 @@ func CreateUser(ctx context.Context, db *gorm.DB, anthroveUserID models.Anthrove }, } - err := db.WithContext(ctx).FirstOrCreate(&user).Error - if err != nil { - log.WithFields(log.Fields{ - "anthrove_user_id": anthroveUserID, - }).Error("database: failed to create user") - return err + result := db.WithContext(ctx).FirstOrCreate(&user) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + return &errors2.EntityAlreadyExists{} + } + return result.Error + } + + if result.RowsAffected == 0 { + return &errors2.NoDataWritten{} } return nil @@ -34,15 +43,19 @@ func CreateUser(ctx context.Context, db *gorm.DB, anthroveUserID models.Anthrove func CreateUserWithRelationToSource(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID, accountId string, accountUsername string) error { if anthroveUserID == "" { - return fmt.Errorf("anthroveUserID cannot be empty") + return &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} + } + + if len(anthroveUserID) != 25 { + return &errors2.EntityValidationFailed{Reason: "anthroveUserID needs to be 25 characters long"} } if accountId == "" { - return fmt.Errorf("account_id cannot be empty") + return &errors2.EntityValidationFailed{Reason: "accountID cannot be empty"} } if accountUsername == "" { - return fmt.Errorf("account_username cannot be empty") + return &errors2.EntityValidationFailed{Reason: "accountUsername cannot be empty"} } err := CreateUser(ctx, db, anthroveUserID) @@ -54,11 +67,12 @@ func CreateUserWithRelationToSource(ctx context.Context, db *gorm.DB, anthroveUs BaseModel: models.BaseModel[models.AnthroveSourceID]{ID: sourceID}, } - if err := db.WithContext(ctx).Where(&source).First(&source).Error; err != nil { - log.WithFields(log.Fields{ - "source_id": sourceID, - }).Error("database: failed to find source") - return err + result := db.WithContext(ctx).Where(&source).First(&source) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return &errors2.NoDataFound{} + } + return result.Error } userSource := models.UserSource{ @@ -69,14 +83,13 @@ func CreateUserWithRelationToSource(ctx context.Context, db *gorm.DB, anthroveUs UserID: string(anthroveUserID), } - if err := db.WithContext(ctx).FirstOrCreate(&userSource).Error; err != nil { - log.WithFields(log.Fields{ - "anthrove_user_id": anthroveUserID, - "source_id": sourceID, - "account_username": accountUsername, - "account_id": accountId, - }).Error("database: failed to create user-source relationship") - return err + result = db.WithContext(ctx).FirstOrCreate(&userSource) + if result.Error != nil { + return errors.Join(result.Error, &errors2.NoRelationCreated{}) + } + + if result.RowsAffected == 0 { + return &errors2.NoDataWritten{} } log.WithFields(log.Fields{ @@ -90,17 +103,22 @@ func CreateUserWithRelationToSource(ctx context.Context, db *gorm.DB, anthroveUs } func GetUserFavoritesCount(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) (int64, error) { + var count int64 + if anthroveUserID == "" { - return 0, fmt.Errorf("anthroveUserID cannot be empty") + return 0, &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} } - var count int64 - err := db.WithContext(ctx).Model(&models.UserFavorites{}).Where("user_id = ?", string(anthroveUserID)).Count(&count).Error - if err != nil { - log.WithFields(log.Fields{ - "anthrove_user_id": anthroveUserID, - }).Error("database: failed to get user favorites count") - return 0, err + if len(anthroveUserID) != 25 { + return 0, &errors2.EntityValidationFailed{Reason: "anthroveUserID needs to be 25 characters long"} + } + + result := db.WithContext(ctx).Model(&models.UserFavorites{}).Where("user_id = ?", string(anthroveUserID)).Count(&count) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return 0, &errors2.NoDataFound{} + } + return 0, result.Error } log.WithFields(log.Fields{ @@ -115,22 +133,30 @@ func GetUserSourceLinks(ctx context.Context, db *gorm.DB, anthroveUserID models. var userSources []models.UserSource userSourceMap := make(map[string]models.UserSource) - err := db.WithContext(ctx).Model(&models.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources).Error - if err != nil { - log.WithFields(log.Fields{ - "anthrove_user_id": anthroveUserID, - }).Error("database: failed to get user source link") - return nil, err + if anthroveUserID == "" { + return nil, &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} + } + + if len(anthroveUserID) != 25 { + return nil, &errors2.EntityValidationFailed{Reason: "anthroveUserID needs to be 25 characters long"} + } + + result := db.WithContext(ctx).Model(&models.UserSource{}).Where("user_id = ?", string(anthroveUserID)).Find(&userSources) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } + return nil, result.Error } for _, userSource := range userSources { var source models.Source - err = db.WithContext(ctx).Model(&models.Source{}).Where("id = ?", userSource.SourceID).First(&source).Error - if err != nil { - log.WithFields(log.Fields{ - "source_id": userSource.SourceID, - }).Error("database: failed to get source") - return nil, err + result = db.WithContext(ctx).Model(&models.Source{}).Where("id = ?", userSource.SourceID).First(&source) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } + return nil, result.Error } userSourceMap[source.DisplayName] = models.UserSource{ @@ -152,34 +178,41 @@ func GetUserSourceLinks(ctx context.Context, db *gorm.DB, anthroveUserID models. } func GetUserSourceBySourceID(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID, sourceID models.AnthroveSourceID) (map[string]models.UserSource, error) { - if anthroveUserID == "" { - return nil, fmt.Errorf("anthroveUserID cannot be empty") - } - - if sourceID == "" { - return nil, fmt.Errorf("sourceID cannot be empty") - } - var userSources []models.UserSource userSourceMap := make(map[string]models.UserSource) - err := db.WithContext(ctx).Model(&models.UserSource{}).InnerJoins("Source", db.Where("id = ?", sourceID)).Where("user_id = ?", string(anthroveUserID)).First(&userSources).Error - if err != nil { - log.WithFields(log.Fields{ - "anthrove_user_id": anthroveUserID, - "source_id": sourceID, - }).Error("database: failed to get specified user source link") - return nil, err + if anthroveUserID == "" { + return nil, &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} + } + + if len(anthroveUserID) != 25 { + return nil, &errors2.EntityValidationFailed{Reason: "anthroveUserID needs to be 25 characters long"} + } + + if sourceID == "" { + return nil, &errors2.EntityValidationFailed{Reason: "sourceID cannot be empty"} + } + + if len(sourceID) != 25 { + return nil, &errors2.EntityValidationFailed{Reason: "sourceID needs to be 25 characters long"} + } + + result := db.WithContext(ctx).Model(&models.UserSource{}).InnerJoins("Source", db.Where("id = ?", sourceID)).Where("user_id = ?", string(anthroveUserID)).First(&userSources) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } + return nil, result.Error } for _, userSource := range userSources { var source models.Source - err = db.WithContext(ctx).Model(&models.Source{}).Where("id = ?", userSource.SourceID).First(&source).Error - if err != nil { - log.WithFields(log.Fields{ - "source_id": userSource.SourceID, - }).Error("database: failed to get source") - return nil, err + result = db.WithContext(ctx).Model(&models.Source{}).Where("id = ?", userSource.SourceID).First(&source) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } + return nil, result.Error } userSourceMap[source.DisplayName] = models.UserSource{ @@ -205,14 +238,16 @@ func GetAllAnthroveUserIDs(ctx context.Context, db *gorm.DB) ([]models.AnthroveU var users []models.User var userIDs []models.AnthroveUserID - err := db.WithContext(ctx).Model(&models.User{}).Find(&users).Error - if err != nil { - log.Error("database: failed to get all anthrove user IDs") - return nil, err + result := db.WithContext(ctx).Model(&models.User{}).Find(&users) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } + return nil, result.Error } for _, user := range users { - userIDs = append(userIDs, models.AnthroveUserID(user.ID)) + userIDs = append(userIDs, user.ID) } log.WithFields(log.Fields{ @@ -226,13 +261,19 @@ func GetUserFavoriteWithPagination(ctx context.Context, db *gorm.DB, anthroveUse var userFavorites []models.UserFavorites var favoritePosts []models.Post + if anthroveUserID == "" { + return nil, &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} + } + + if len(anthroveUserID) != 25 { + return nil, &errors2.EntityValidationFailed{Reason: "anthroveUserID needs to be 25 characters long"} + } + err := db.WithContext(ctx).Model(&models.UserFavorites{}).Where("user_id = ?", string(anthroveUserID)).Offset(skip).Limit(limit).Find(&userFavorites).Error if err != nil { - log.WithFields(log.Fields{ - "anthrove_user_id": anthroveUserID, - "skip": skip, - "limit": limit, - }).Error("database: failed to get user favorites with pagination") + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } return nil, err } @@ -240,9 +281,9 @@ func GetUserFavoriteWithPagination(ctx context.Context, db *gorm.DB, anthroveUse var post models.Post err = db.WithContext(ctx).Model(&models.Post{}).Where("id = ?", userFavorite.PostID).First(&post).Error if err != nil { - log.WithFields(log.Fields{ - "post_id": userFavorite.PostID, - }).Error("database: failed to get post") + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } return nil, err } @@ -263,12 +304,21 @@ func GetUserFavoriteWithPagination(ctx context.Context, db *gorm.DB, anthroveUse func GetUserTagWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, anthroveUserID models.AnthroveUserID) ([]models.TagsWithFrequency, error) { var userFavorites []models.UserFavorites - err := db.WithContext(ctx).Where("user_id = ?", string(anthroveUserID)).Find(&userFavorites).Error - if err != nil { - log.WithFields(log.Fields{ - "anthrove_user_id": anthroveUserID, - }).Error("database: failed to get user favorites") - return nil, err + + if anthroveUserID == "" { + return nil, &errors2.EntityValidationFailed{Reason: "anthroveUserID cannot be empty"} + } + + if len(anthroveUserID) != 25 { + return nil, &errors2.EntityValidationFailed{Reason: "anthroveUserID needs to be 25 characters long"} + } + + result := db.WithContext(ctx).Where("user_id = ?", string(anthroveUserID)).Find(&userFavorites) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } + return nil, result.Error } tagFrequency := make(map[struct { @@ -278,12 +328,12 @@ func GetUserTagWitRelationToFavedPosts(ctx context.Context, db *gorm.DB, anthrov for _, userFavorite := range userFavorites { var post models.Post - err = db.WithContext(ctx).Preload("Tags").First(&post, "id = ?", userFavorite.PostID).Error - if err != nil { - log.WithFields(log.Fields{ - "post_id": userFavorite.PostID, - }).Error("database: failed to get post tags") - return nil, err + result = db.WithContext(ctx).Preload("Tags").First(&post, "id = ?", userFavorite.PostID) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, &errors2.NoDataFound{} + } + return nil, result.Error } for _, tag := range post.Tags { diff --git a/error/database.go b/pkg/errors/database.go similarity index 70% rename from error/database.go rename to pkg/errors/database.go index c842614..5559b95 100644 --- a/error/database.go +++ b/pkg/errors/database.go @@ -1,19 +1,25 @@ -package error +package errors type EntityAlreadyExists struct{} -type NoDataWritten struct{} - -type NoDataFound struct{} - func (e *EntityAlreadyExists) Error() string { return "EntityAlreadyExists error" } +type NoDataWritten struct{} + func (e *NoDataWritten) Error() string { return "NoDataWritten error" } +type NoDataFound struct{} + func (e *NoDataFound) Error() string { return "NoDataFound error" } + +type NoRelationCreated struct{} + +func (e *NoRelationCreated) Error() string { + return "relationship creation error" +} diff --git a/pkg/errors/validation.go b/pkg/errors/validation.go new file mode 100644 index 0000000..a04ac75 --- /dev/null +++ b/pkg/errors/validation.go @@ -0,0 +1,11 @@ +package errors + +import "fmt" + +type EntityValidationFailed struct { + Reason string +} + +func (e EntityValidationFailed) Error() string { + return fmt.Sprintf("Entity validation failed: %s", e.Reason) +}