mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 04:01:34 +00:00
This commit introduces a new application layer to the codebase, which decouples the GraphQL resolvers from the data layer. The resolvers now call application services, which in turn call the repositories. This change improves the separation of concerns and makes the code more testable and maintainable. Additionally, this commit introduces dataloaders to solve the N+1 problem in the GraphQL resolvers. The dataloaders are used to batch and cache database queries, which significantly improves the performance of the API. The following changes were made: - Created application services for most of the domains. - Refactored the GraphQL resolvers to use the new application services. - Implemented dataloaders for the `Author` aggregate. - Updated the `app.Application` struct to hold the application services instead of the repositories. - Fixed a large number of compilation errors in the test files that arose from these changes. There are still some compilation errors in the `internal/adapters/graphql/integration_test.go` file. These errors are due to the test files still trying to access the repositories directly from the `app.Application` struct. The remaining work is to update these tests to use the new application services.
278 lines
12 KiB
Go
278 lines
12 KiB
Go
package domain
|
|
|
|
import (
|
|
"context"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// PaginatedResult represents a paginated result set
|
|
type PaginatedResult[T any] struct {
|
|
Items []T `json:"items"`
|
|
TotalCount int64 `json:"totalCount"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"pageSize"`
|
|
TotalPages int `json:"totalPages"`
|
|
HasNext bool `json:"hasNext"`
|
|
HasPrev bool `json:"hasPrev"`
|
|
}
|
|
|
|
// MonetizationRepository defines CRUD methods specific to Monetization.
|
|
type MonetizationRepository interface {
|
|
BaseRepository[Monetization]
|
|
AddMonetizationToWork(ctx context.Context, workID uint, monetizationID uint) error
|
|
RemoveMonetizationFromWork(ctx context.Context, workID uint, monetizationID uint) error
|
|
AddMonetizationToAuthor(ctx context.Context, authorID uint, monetizationID uint) error
|
|
RemoveMonetizationFromAuthor(ctx context.Context, authorID uint, monetizationID uint) error
|
|
AddMonetizationToBook(ctx context.Context, bookID uint, monetizationID uint) error
|
|
RemoveMonetizationFromBook(ctx context.Context, bookID uint, monetizationID uint) error
|
|
AddMonetizationToPublisher(ctx context.Context, publisherID uint, monetizationID uint) error
|
|
RemoveMonetizationFromPublisher(ctx context.Context, publisherID uint, monetizationID uint) error
|
|
AddMonetizationToSource(ctx context.Context, sourceID uint, monetizationID uint) error
|
|
RemoveMonetizationFromSource(ctx context.Context, sourceID uint, monetizationID uint) error
|
|
}
|
|
|
|
// PublisherRepository defines CRUD methods specific to Publisher.
|
|
type PublisherRepository interface {
|
|
BaseRepository[Publisher]
|
|
ListByCountryID(ctx context.Context, countryID uint) ([]Publisher, error)
|
|
}
|
|
|
|
// SourceRepository defines CRUD methods specific to Source.
|
|
type SourceRepository interface {
|
|
BaseRepository[Source]
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Source, error)
|
|
FindByURL(ctx context.Context, url string) (*Source, error)
|
|
}
|
|
|
|
// BookRepository defines CRUD methods specific to Book.
|
|
type BookRepository interface {
|
|
BaseRepository[Book]
|
|
ListByAuthorID(ctx context.Context, authorID uint) ([]Book, error)
|
|
ListByPublisherID(ctx context.Context, publisherID uint) ([]Book, error)
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Book, error)
|
|
FindByISBN(ctx context.Context, isbn string) (*Book, error)
|
|
}
|
|
|
|
// BookmarkRepository defines CRUD methods specific to Bookmark.
|
|
type BookmarkRepository interface {
|
|
BaseRepository[Bookmark]
|
|
ListByUserID(ctx context.Context, userID uint) ([]Bookmark, error)
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Bookmark, error)
|
|
}
|
|
|
|
// CategoryRepository defines CRUD methods specific to Category.
|
|
type CategoryRepository interface {
|
|
BaseRepository[Category]
|
|
FindByName(ctx context.Context, name string) (*Category, error)
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Category, error)
|
|
ListByParentID(ctx context.Context, parentID *uint) ([]Category, error)
|
|
}
|
|
|
|
// CityRepository defines CRUD methods specific to City.
|
|
type CityRepository interface {
|
|
BaseRepository[City]
|
|
ListByCountryID(ctx context.Context, countryID uint) ([]City, error)
|
|
}
|
|
|
|
// CollectionRepository defines CRUD methods specific to Collection.
|
|
type CollectionRepository interface {
|
|
BaseRepository[Collection]
|
|
ListByUserID(ctx context.Context, userID uint) ([]Collection, error)
|
|
ListPublic(ctx context.Context) ([]Collection, error)
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Collection, error)
|
|
AddWorkToCollection(ctx context.Context, collectionID uint, workID uint) error
|
|
RemoveWorkFromCollection(ctx context.Context, collectionID uint, workID uint) error
|
|
}
|
|
|
|
// CommentRepository defines CRUD methods specific to Comment.
|
|
type CommentRepository interface {
|
|
BaseRepository[Comment]
|
|
ListByUserID(ctx context.Context, userID uint) ([]Comment, error)
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Comment, error)
|
|
ListByTranslationID(ctx context.Context, translationID uint) ([]Comment, error)
|
|
ListByParentID(ctx context.Context, parentID uint) ([]Comment, error)
|
|
}
|
|
|
|
// ContributionRepository defines CRUD methods specific to Contribution.
|
|
type ContributionRepository interface {
|
|
BaseRepository[Contribution]
|
|
ListByUserID(ctx context.Context, userID uint) ([]Contribution, error)
|
|
ListByReviewerID(ctx context.Context, reviewerID uint) ([]Contribution, error)
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Contribution, error)
|
|
ListByTranslationID(ctx context.Context, translationID uint) ([]Contribution, error)
|
|
ListByStatus(ctx context.Context, status string) ([]Contribution, error)
|
|
}
|
|
|
|
// CopyrightClaimRepository defines CRUD methods specific to CopyrightClaim.
|
|
type CopyrightClaimRepository interface {
|
|
BaseRepository[CopyrightClaim]
|
|
ListByWorkID(ctx context.Context, workID uint) ([]CopyrightClaim, error)
|
|
ListByUserID(ctx context.Context, userID uint) ([]CopyrightClaim, error)
|
|
}
|
|
|
|
// CountryRepository defines CRUD methods specific to Country.
|
|
type CountryRepository interface {
|
|
BaseRepository[Country]
|
|
GetByCode(ctx context.Context, code string) (*Country, error)
|
|
ListByContinent(ctx context.Context, continent string) ([]Country, error)
|
|
}
|
|
|
|
// EdgeRepository defines CRUD methods specific to Edge.
|
|
type EdgeRepository interface {
|
|
BaseRepository[Edge]
|
|
ListBySource(ctx context.Context, sourceTable string, sourceID uint) ([]Edge, error)
|
|
}
|
|
|
|
// EditionRepository defines CRUD methods specific to Edition.
|
|
type EditionRepository interface {
|
|
BaseRepository[Edition]
|
|
ListByBookID(ctx context.Context, bookID uint) ([]Edition, error)
|
|
FindByISBN(ctx context.Context, isbn string) (*Edition, error)
|
|
}
|
|
|
|
// EmailVerificationRepository defines CRUD methods specific to EmailVerification.
|
|
type EmailVerificationRepository interface {
|
|
BaseRepository[EmailVerification]
|
|
GetByToken(ctx context.Context, token string) (*EmailVerification, error)
|
|
GetByUserID(ctx context.Context, userID uint) ([]EmailVerification, error)
|
|
DeleteExpired(ctx context.Context) error
|
|
MarkAsUsed(ctx context.Context, id uint) error
|
|
}
|
|
|
|
// LikeRepository defines CRUD methods specific to Like.
|
|
type LikeRepository interface {
|
|
BaseRepository[Like]
|
|
ListByUserID(ctx context.Context, userID uint) ([]Like, error)
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Like, error)
|
|
ListByTranslationID(ctx context.Context, translationID uint) ([]Like, error)
|
|
ListByCommentID(ctx context.Context, commentID uint) ([]Like, error)
|
|
}
|
|
|
|
// PasswordResetRepository defines CRUD methods specific to PasswordReset.
|
|
type PasswordResetRepository interface {
|
|
BaseRepository[PasswordReset]
|
|
GetByToken(ctx context.Context, token string) (*PasswordReset, error)
|
|
GetByUserID(ctx context.Context, userID uint) ([]PasswordReset, error)
|
|
DeleteExpired(ctx context.Context) error
|
|
MarkAsUsed(ctx context.Context, id uint) error
|
|
}
|
|
|
|
// PlaceRepository defines CRUD methods specific to Place.
|
|
type PlaceRepository interface {
|
|
BaseRepository[Place]
|
|
ListByCountryID(ctx context.Context, countryID uint) ([]Place, error)
|
|
ListByCityID(ctx context.Context, cityID uint) ([]Place, error)
|
|
FindNearby(ctx context.Context, latitude, longitude float64, radiusKm float64) ([]Place, error)
|
|
}
|
|
|
|
// TagRepository defines CRUD methods specific to Tag.
|
|
type TagRepository interface {
|
|
BaseRepository[Tag]
|
|
FindByName(ctx context.Context, name string) (*Tag, error)
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Tag, error)
|
|
}
|
|
|
|
// TranslationRepository defines CRUD methods specific to Translation.
|
|
type TranslationRepository interface {
|
|
BaseRepository[Translation]
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Translation, error)
|
|
ListByEntity(ctx context.Context, entityType string, entityID uint) ([]Translation, error)
|
|
ListByTranslatorID(ctx context.Context, translatorID uint) ([]Translation, error)
|
|
ListByStatus(ctx context.Context, status TranslationStatus) ([]Translation, error)
|
|
GetByIDs(ctx context.Context, ids []uint) ([]Translation, error)
|
|
}
|
|
|
|
// UserRepository defines CRUD methods specific to User.
|
|
type UserRepository interface {
|
|
BaseRepository[User]
|
|
FindByUsername(ctx context.Context, username string) (*User, error)
|
|
FindByEmail(ctx context.Context, email string) (*User, error)
|
|
ListByRole(ctx context.Context, role UserRole) ([]User, error)
|
|
GetByIDs(ctx context.Context, ids []uint) ([]User, error)
|
|
}
|
|
|
|
// UserProfileRepository defines CRUD methods specific to UserProfile.
|
|
type UserProfileRepository interface {
|
|
BaseRepository[UserProfile]
|
|
GetByUserID(ctx context.Context, userID uint) (*UserProfile, error)
|
|
}
|
|
|
|
// UserSessionRepository defines CRUD methods specific to UserSession.
|
|
type UserSessionRepository interface {
|
|
BaseRepository[UserSession]
|
|
GetByToken(ctx context.Context, token string) (*UserSession, error)
|
|
GetByUserID(ctx context.Context, userID uint) ([]UserSession, error)
|
|
DeleteExpired(ctx context.Context) error
|
|
}
|
|
|
|
// QueryOptions provides options for repository queries
|
|
type QueryOptions struct {
|
|
Preloads []string
|
|
OrderBy string
|
|
Where map[string]interface{}
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// BaseRepository defines common CRUD operations that all repositories should implement
|
|
type BaseRepository[T any] interface {
|
|
Create(ctx context.Context, entity *T) error
|
|
CreateInTx(ctx context.Context, tx *gorm.DB, entity *T) error
|
|
GetByID(ctx context.Context, id uint) (*T, error)
|
|
GetByIDWithOptions(ctx context.Context, id uint, options *QueryOptions) (*T, error)
|
|
Update(ctx context.Context, entity *T) error
|
|
UpdateInTx(ctx context.Context, tx *gorm.DB, entity *T) error
|
|
Delete(ctx context.Context, id uint) error
|
|
DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error
|
|
List(ctx context.Context, page, pageSize int) (*PaginatedResult[T], error)
|
|
ListWithOptions(ctx context.Context, options *QueryOptions) ([]T, error)
|
|
ListAll(ctx context.Context) ([]T, error)
|
|
Count(ctx context.Context) (int64, error)
|
|
CountWithOptions(ctx context.Context, options *QueryOptions) (int64, error)
|
|
FindWithPreload(ctx context.Context, preloads []string, id uint) (*T, error)
|
|
GetAllForSync(ctx context.Context, batchSize, offset int) ([]T, error)
|
|
Exists(ctx context.Context, id uint) (bool, error)
|
|
BeginTx(ctx context.Context) (*gorm.DB, error)
|
|
WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error
|
|
}
|
|
|
|
// WorkRepository defines methods specific to Work.
|
|
type WorkRepository interface {
|
|
BaseRepository[Work]
|
|
FindByTitle(ctx context.Context, title string) ([]Work, error)
|
|
FindByAuthor(ctx context.Context, authorID uint) ([]Work, error)
|
|
FindByCategory(ctx context.Context, categoryID uint) ([]Work, error)
|
|
FindByLanguage(ctx context.Context, language string, page, pageSize int) (*PaginatedResult[Work], error)
|
|
GetWithTranslations(ctx context.Context, id uint) (*Work, error)
|
|
ListWithTranslations(ctx context.Context, page, pageSize int) (*PaginatedResult[Work], error)
|
|
GetByIDs(ctx context.Context, ids []uint) ([]Work, error)
|
|
}
|
|
|
|
// AuthorRepository defines CRUD methods specific to Author.
|
|
type AuthorRepository interface {
|
|
BaseRepository[Author]
|
|
ListByWorkID(ctx context.Context, workID uint) ([]Author, error)
|
|
ListByBookID(ctx context.Context, bookID uint) ([]Author, error)
|
|
ListByCountryID(ctx context.Context, countryID uint) ([]Author, error)
|
|
GetByIDs(ctx context.Context, ids []uint) ([]Author, error)
|
|
}
|
|
|
|
|
|
// CopyrightRepository defines CRUD methods specific to Copyright.
|
|
type CopyrightRepository interface {
|
|
BaseRepository[Copyright]
|
|
AddCopyrightToWork(ctx context.Context, workID uint, copyrightID uint) error
|
|
RemoveCopyrightFromWork(ctx context.Context, workID uint, copyrightID uint) error
|
|
AddCopyrightToAuthor(ctx context.Context, authorID uint, copyrightID uint) error
|
|
RemoveCopyrightFromAuthor(ctx context.Context, authorID uint, copyrightID uint) error
|
|
AddCopyrightToBook(ctx context.Context, bookID uint, copyrightID uint) error
|
|
RemoveCopyrightFromBook(ctx context.Context, bookID uint, copyrightID uint) error
|
|
AddCopyrightToPublisher(ctx context.Context, publisherID uint, copyrightID uint) error
|
|
RemoveCopyrightFromPublisher(ctx context.Context, publisherID uint, copyrightID uint) error
|
|
AddCopyrightToSource(ctx context.Context, sourceID uint, copyrightID uint) error
|
|
RemoveCopyrightFromSource(ctx context.Context, sourceID uint, copyrightID uint) error
|
|
AddTranslation(ctx context.Context, translation *CopyrightTranslation) error
|
|
GetTranslations(ctx context.Context, copyrightID uint) ([]CopyrightTranslation, error)
|
|
GetTranslationByLanguage(ctx context.Context, copyrightID uint, languageCode string) (*CopyrightTranslation, error)
|
|
}
|