Add helper functions for Book

This commit is contained in:
Backend IM Bot 2025-03-28 10:29:43 +00:00
parent 20edf409f3
commit f8e0dfd22b

164
helpers/book_helpers.py Normal file
View File

@ -0,0 +1,164 @@
from typing import List, Dict, Optional, Union, Any
from datetime import datetime
import re
from sqlalchemy.orm import Session
from models.book import Book
from schemas.book import BookCreate, BookUpdate
def validate_isbn(isbn: str) -> bool:
"""
Validate ISBN format (supports both ISBN-10 and ISBN-13).
Args:
isbn: ISBN string to validate
Returns:
bool: True if valid ISBN format, False otherwise
"""
isbn = isbn.replace("-", "").replace(" ", "")
if len(isbn) == 10:
# ISBN-10 validation
if not isbn[:-1].isdigit() and isbn[-1].lower() != 'x':
return False
total = 0
for i in range(9):
total += int(isbn[i]) * (10 - i)
check = 11 - (total % 11)
return str(check) == isbn[-1] or (check == 10 and isbn[-1].lower() == 'x')
elif len(isbn) == 13:
# ISBN-13 validation
if not isbn.isdigit():
return False
total = 0
for i in range(12):
if i % 2 == 0:
total += int(isbn[i])
else:
total += int(isbn[i]) * 3
check = 10 - (total % 10)
if check == 10:
check = 0
return str(check) == isbn[-1]
return False
def search_books(
db: Session,
title: Optional[str] = None,
author: Optional[str] = None,
genre: Optional[str] = None,
publisher: Optional[str] = None,
available_only: bool = False
) -> List[Book]:
"""
Search books with multiple optional filters.
Args:
db: Database session
title: Optional title to search for
author: Optional author to search for
genre: Optional genre to filter by
publisher: Optional publisher to filter by
available_only: If True, return only available books
Returns:
List of books matching the search criteria
"""
query = db.query(Book)
if title:
query = query.filter(Book.title.ilike(f"%{title}%"))
if author:
query = query.filter(Book.author.ilike(f"%{author}%"))
if genre:
query = query.filter(Book.genre == genre)
if publisher:
query = query.filter(Book.publisher == publisher)
if available_only:
query = query.filter(Book.is_available == True)
return query.all()
def get_book_stats(db: Session) -> Dict[str, Any]:
"""
Get statistical information about books in the database.
Args:
db: Database session
Returns:
Dictionary containing various statistics about books
"""
total_books = db.query(Book).count()
available_books = db.query(Book).filter(Book.is_available == True).count()
genres = db.query(Book.genre).distinct().all()
languages = db.query(Book.language).distinct().all()
avg_pages = db.query(func.avg(Book.page_count)).scalar()
return {
"total_books": total_books,
"available_books": available_books,
"total_genres": len(genres),
"genres": [g[0] for g in genres],
"languages": [l[0] for l in languages],
"average_page_count": round(avg_pages if avg_pages else 0, 2)
}
def validate_book_data(book_data: Union[BookCreate, BookUpdate]) -> Dict[str, str]:
"""
Validate book data before creation or update.
Args:
book_data: Book data to validate
Returns:
Dictionary of validation errors, empty if validation passes
"""
errors = {}
if hasattr(book_data, 'isbn') and book_data.isbn:
if not validate_isbn(book_data.isbn):
errors['isbn'] = "Invalid ISBN format"
if hasattr(book_data, 'publication_year'):
current_year = datetime.now().year
if book_data.publication_year > current_year:
errors['publication_year'] = "Publication year cannot be in the future"
if hasattr(book_data, 'page_count'):
if book_data.page_count <= 0:
errors['page_count'] = "Page count must be positive"
return errors
def get_similar_books(db: Session, book_id: int, limit: int = 5) -> List[Book]:
"""
Find similar books based on genre and author.
Args:
db: Database session
book_id: ID of the reference book
limit: Maximum number of similar books to return
Returns:
List of similar books
"""
reference_book = db.query(Book).filter(Book.id == book_id).first()
if not reference_book:
return []
similar_books = db.query(Book).filter(
Book.id != book_id,
Book.genre == reference_book.genre,
Book.author == reference_book.author
).limit(limit).all()
if len(similar_books) < limit:
# If not enough books by same author, add books from same genre
additional_books = db.query(Book).filter(
Book.id != book_id,
Book.genre == reference_book.genre,
Book.author != reference_book.author
).limit(limit - len(similar_books)).all()
similar_books.extend(additional_books)
return similar_books