package query import ( "regexp" "strings" "git.artlef.fr/bibliomane/internal/dto" "git.artlef.fr/bibliomane/internal/fileutils" "git.artlef.fr/bibliomane/internal/model" "gorm.io/gorm" ) func FetchBookGet(db *gorm.DB, userId uint, bookId uint64) (dto.FullBookGet, error) { var book dto.FullBookGet query := db.Model(&model.Book{}) selectQueryString := "books.title, authors.name as author, authors.id as author_id, books.isbn, books.inventaire_id, books.open_library_id, books.short_description, books.summary, " + "user_books.review, user_books.rating, user_books.read, user_books.want_read, " + "DATE(user_books.start_read_date) as start_read_date, " + "DATE(user_books.end_read_date) AS end_read_date, " + selectStaticFilesPath() query = query.Select(selectQueryString) query = joinAuthors(query) query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", userId) query = joinStaticFiles(query) query = query.Where("books.id = ?", bookId) res := query.First(&book) return book, res.Error } func FetchReadUserBook(db *gorm.DB, userId uint, limit int, offset int) ([]dto.BookItemGet, error) { var books []dto.BookItemGet query := fetchReadUserBookQuery(db, userId) query = query.Limit(limit) query = query.Offset(offset) res := query.Find(&books) return books, res.Error } func FetchReadUserBookCount(db *gorm.DB, userId uint) (int64, error) { query := fetchReadUserBookQuery(db, userId) var count int64 res := query.Count(&count) return count, res.Error } func FetchReadingUserBook(db *gorm.DB, userId uint, limit int, offset int) ([]dto.BookItemGet, error) { var books []dto.BookItemGet query := fetchReadingUserBookQuery(db, userId) query = query.Limit(limit) query = query.Offset(offset) res := query.Find(&books) return books, res.Error } func FetchReadingUserBookCount(db *gorm.DB, userId uint) (int64, error) { query := fetchReadingUserBookQuery(db, userId) var count int64 res := query.Count(&count) return count, res.Error } func fetchReadUserBookQuery(db *gorm.DB, userId uint) *gorm.DB { query := fetchUserBookGet(db, userId) query = query.Where("user_books.read IS TRUE") return query } func fetchReadingUserBookQuery(db *gorm.DB, userId uint) *gorm.DB { query := fetchUserBookGet(db, userId) query = query.Where("user_books.start_read_date IS NOT NULL AND (user_books.read IS NULL OR user_books.read IS FALSE)") return query } func FetchWantReadUserBook(db *gorm.DB, userId uint, limit int, offset int) ([]dto.BookItemGet, error) { var books []dto.BookItemGet query := fetchWantReadUserBookQuery(db, userId) query = query.Limit(limit) query = query.Offset(offset) res := query.Find(&books) return books, res.Error } func FetchWantReadUserBookCount(db *gorm.DB, userId uint) (int64, error) { query := fetchWantReadUserBookQuery(db, userId) var count int64 res := query.Count(&count) return count, res.Error } func fetchWantReadUserBookQuery(db *gorm.DB, userId uint) *gorm.DB { query := fetchUserBookGet(db, userId) query = query.Where("user_books.want_read IS TRUE") return query } // fetch only books where userbook exists func fetchUserBookGet(db *gorm.DB, userId uint) *gorm.DB { query := db.Model(&model.UserBook{}) query = query.Select(selectBookItem()) query = query.Joins("left join books on (books.id = user_books.book_id)") query = joinAuthors(query) query = joinStaticFiles(query) query = query.Where("user_id = ?", userId) return query } func FetchAllBooks(db *gorm.DB, userId uint, limit int, offset int) ([]dto.BookItemGet, error) { var books []dto.BookItemGet query := fetchBookQueryBuilder(db, userId) query = query.Limit(limit) query = query.Offset(offset) query = query.Order("books.id DESC") res := query.Find(&books) return books, res.Error } func FetchAllBooksCount(db *gorm.DB, userId uint) (int64, error) { var count int64 query := fetchBookQueryBuilder(db, userId) res := query.Count(&count) return count, res.Error } func FetchBookSearchByAuthorGet(db *gorm.DB, userId uint, authorId uint64, limit int, offset int) ([]dto.BookItemGet, error) { var books []dto.BookItemGet query := fetchBookSearchByAuthorQuery(db, userId, authorId) query = query.Limit(limit) query = query.Offset(offset) res := query.Find(&books) return books, res.Error } func FetchBookSearchByAuthorGetCount(db *gorm.DB, userId uint, authorId uint64) (int64, error) { var count int64 query := fetchBookSearchByAuthorQuery(db, userId, authorId) res := query.Count(&count) return count, res.Error } func fetchBookSearchByAuthorQuery(db *gorm.DB, userId uint, authorId uint64) *gorm.DB { query := fetchBookQueryBuilder(db, userId) return query.Where("authors.id = ?", authorId) } func FetchBookSearchGet(db *gorm.DB, userId uint, searchterm string, limit int, offset int) ([]dto.BookItemGet, error) { var books []dto.BookItemGet query := fetchBookSearchQuery(db, userId, searchterm) query = query.Limit(limit) query = query.Offset(offset) res := query.Find(&books) return books, res.Error } func FetchBookSearchGetCount(db *gorm.DB, userId uint, searchterm string) (int64, error) { query := fetchBookSearchQuery(db, userId, searchterm) var count int64 res := query.Count(&count) return count, res.Error } func fetchBookSearchQuery(db *gorm.DB, userId uint, searchterm string) *gorm.DB { query := fetchBookQueryBuilder(db, userId) isIsbn, _ := regexp.Match(`\d{10,13}`, []byte(searchterm)) if isIsbn { query = query.Where("books.isbn = ?", searchterm) } else { query = query.Where("LOWER(books.title) LIKE ?", "%"+strings.ToLower(searchterm)+"%") } return query } // fetch all books even whithout user books func fetchBookQueryBuilder(db *gorm.DB, userId uint) *gorm.DB { query := db.Model(&model.Book{}) query = query.Select(selectBookItem()) query = joinAuthors(query) query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", userId) query = joinStaticFiles(query) return query } func selectBookItem() string { return "books.id, books.title, authors.name as author, books.short_description as description, books.inventaire_id, user_books.rating, user_books.read, DATE(user_books.start_read_date) as start_read_date, user_books.want_read, " + selectStaticFilesPath() } type CollectionsQueryResult struct { ID uint UserID uint Name string BookId uint BookTitle string CoverPath string } type collectionId struct { ID uint } func FetchAllCollections(db *gorm.DB, userId uint, limit int, offset int) ([]CollectionsQueryResult, error) { var collections []CollectionsQueryResult var collectionIds []collectionId res := fetchCollections(db, userId).Limit(limit).Offset(offset).Order("collections.id DESC").Find(&collectionIds) if res.Error != nil { return collections, res.Error } for _, collectionId := range collectionIds { //only takes first 5 books queryResults, err := FetchCollectionBooks(db, collectionId.ID, 5, 0) if err != nil { return collections, res.Error } collections = append(collections, queryResults...) } return collections, res.Error } func FetchCollectionBooks(db *gorm.DB, collectionId uint, limit int, offset int) ([]CollectionsQueryResult, error) { var collections []CollectionsQueryResult query := fetchCollectionBooksQuery(db, collectionId) query = query.Limit(limit) query = query.Offset(offset) res := query.Find(&collections) return collections, res.Error } func FetchCollectionBooksCount(db *gorm.DB, collectionId uint) (int64, error) { var count int64 res := fetchCollectionBooksQuery(db, collectionId).Where("book_id IS NOT NULL").Count(&count) return count, res.Error } func fetchCollectionBooksQuery(db *gorm.DB, collectionId uint) *gorm.DB { query := db.Model(&model.Collection{}) query = query.Select("collections.id, collections.user_id, collections.name, books.id as book_id, books.title as book_title, " + selectStaticFilesPath()) query = query.Joins("left join collection_books on (collection_books.collection_id = collections.id)") query = query.Joins("left join books on (books.id = collection_books.book_id)") query = joinStaticFiles(query) query = query.Where("collections.id = ?", collectionId) return query } func FetchAllCollectionsCount(db *gorm.DB, userId uint) (int64, error) { var count int64 res := fetchCollections(db, userId).Count(&count) return count, res.Error } func fetchCollections(db *gorm.DB, userId uint) *gorm.DB { return db.Model(&model.Collection{}).Where("collections.user_id = ?", userId) } func selectStaticFilesPath() string { return "(CASE COALESCE(static_files.path, '') WHEN '' THEN '' ELSE concat('" + fileutils.GetWsLinkPrefix() + "', static_files.path) END) as CoverPath" } func joinAuthors(query *gorm.DB) *gorm.DB { return query.Joins("left join authors on (authors.id = books.author_id)") } func joinStaticFiles(query *gorm.DB) *gorm.DB { return query.Joins("left join static_files on (static_files.id = books.cover_id)") }