Add helper functions for Book
This commit is contained in:
parent
b0eb4cc121
commit
d0beabc78c
156
helpers/book_helpers.py
Normal file
156
helpers/book_helpers.py
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
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 (both ISBN-10 and ISBN-13).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
isbn: ISBN string to validate
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if ISBN format is valid, False otherwise
|
||||||
|
"""
|
||||||
|
# Remove hyphens and spaces
|
||||||
|
isbn = isbn.replace('-', '').replace(' ', '')
|
||||||
|
|
||||||
|
if len(isbn) == 10:
|
||||||
|
# ISBN-10 validation
|
||||||
|
if not isbn[:-1].isdigit():
|
||||||
|
return False
|
||||||
|
check = sum((10 - i) * int(x) for i, x in enumerate(isbn[:9]))
|
||||||
|
check = (11 - (check % 11)) % 11
|
||||||
|
return str(check) == isbn[-1] or (check == 10 and isbn[-1].upper() == 'X')
|
||||||
|
|
||||||
|
elif len(isbn) == 13:
|
||||||
|
# ISBN-13 validation
|
||||||
|
if not isbn.isdigit():
|
||||||
|
return False
|
||||||
|
check = sum((3 if i % 2 else 1) * int(x) for i, x in enumerate(isbn[:12]))
|
||||||
|
check = (10 - (check % 10)) % 10
|
||||||
|
return int(isbn[-1]) == check
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_book_by_isbn(db: Session, isbn: str) -> Optional[Book]:
|
||||||
|
"""
|
||||||
|
Retrieve a book by its ISBN.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
db: Database session
|
||||||
|
isbn: ISBN to search for
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Book object if found, None otherwise
|
||||||
|
"""
|
||||||
|
return db.query(Book).filter(Book.isbn == isbn).first()
|
||||||
|
|
||||||
|
def search_books(
|
||||||
|
db: Session,
|
||||||
|
title: Optional[str] = None,
|
||||||
|
author: Optional[str] = None,
|
||||||
|
publisher: Optional[str] = None,
|
||||||
|
year_from: Optional[int] = None,
|
||||||
|
year_to: Optional[int] = None,
|
||||||
|
available_only: bool = False
|
||||||
|
) -> List[Book]:
|
||||||
|
"""
|
||||||
|
Search books with multiple optional filters.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
db: Database session
|
||||||
|
title: Optional title search string
|
||||||
|
author: Optional author search string
|
||||||
|
publisher: Optional publisher search string
|
||||||
|
year_from: Optional start year for publication
|
||||||
|
year_to: Optional end year for publication
|
||||||
|
available_only: If True, return only available books
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of Book objects 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 publisher:
|
||||||
|
query = query.filter(Book.publisher.ilike(f"%{publisher}%"))
|
||||||
|
if year_from:
|
||||||
|
query = query.filter(Book.publication_year >= year_from)
|
||||||
|
if year_to:
|
||||||
|
query = query.filter(Book.publication_year <= year_to)
|
||||||
|
if available_only:
|
||||||
|
query = query.filter(Book.is_available == True)
|
||||||
|
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
def create_book_safely(db: Session, book_data: BookCreate) -> Union[Book, Dict[str, str]]:
|
||||||
|
"""
|
||||||
|
Create a new book with validation and error handling.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
db: Database session
|
||||||
|
book_data: Book data for creation
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Book object if created successfully, error dict otherwise
|
||||||
|
"""
|
||||||
|
# Validate ISBN
|
||||||
|
if not validate_isbn(book_data.isbn):
|
||||||
|
return {"error": "Invalid ISBN format"}
|
||||||
|
|
||||||
|
# Check if book already exists
|
||||||
|
existing_book = get_book_by_isbn(db, book_data.isbn)
|
||||||
|
if existing_book:
|
||||||
|
return {"error": "ISBN already exists"}
|
||||||
|
|
||||||
|
# Validate publication year
|
||||||
|
current_year = datetime.now().year
|
||||||
|
if book_data.publication_year > current_year:
|
||||||
|
return {"error": "Publication year cannot be in the future"}
|
||||||
|
|
||||||
|
# Create the book
|
||||||
|
db_book = Book(
|
||||||
|
title=book_data.title,
|
||||||
|
author=book_data.author,
|
||||||
|
isbn=book_data.isbn,
|
||||||
|
description=book_data.description,
|
||||||
|
publication_year=book_data.publication_year,
|
||||||
|
pages=book_data.pages,
|
||||||
|
publisher=book_data.publisher,
|
||||||
|
is_available=book_data.is_available
|
||||||
|
)
|
||||||
|
|
||||||
|
db.add(db_book)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_book)
|
||||||
|
|
||||||
|
return db_book
|
||||||
|
|
||||||
|
def update_book_availability(db: Session, isbn: str, is_available: bool) -> Union[Book, Dict[str, str]]:
|
||||||
|
"""
|
||||||
|
Update the availability status of a book.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
db: Database session
|
||||||
|
isbn: ISBN of the book to update
|
||||||
|
is_available: New availability status
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Updated Book object if successful, error dict otherwise
|
||||||
|
"""
|
||||||
|
book = get_book_by_isbn(db, isbn)
|
||||||
|
if not book:
|
||||||
|
return {"error": "Book not found"}
|
||||||
|
|
||||||
|
book.is_available = is_available
|
||||||
|
db.commit()
|
||||||
|
db.refresh(book)
|
||||||
|
|
||||||
|
return book
|
Loading…
x
Reference in New Issue
Block a user