Add helper functions for Book
This commit is contained in:
parent
20edf409f3
commit
f8e0dfd22b
164
helpers/book_helpers.py
Normal file
164
helpers/book_helpers.py
Normal 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
|
Loading…
x
Reference in New Issue
Block a user