From 267099a1af29d0c462c5c2334ad70f2b502344cf Mon Sep 17 00:00:00 2001 From: Backend IM Bot Date: Fri, 28 Mar 2025 13:18:33 +0000 Subject: [PATCH] Add helper functions for Book --- helpers/book_helpers.py | 144 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 helpers/book_helpers.py diff --git a/helpers/book_helpers.py b/helpers/book_helpers.py new file mode 100644 index 0000000..9a7768e --- /dev/null +++ b/helpers/book_helpers.py @@ -0,0 +1,144 @@ +from typing import List, Dict, Optional, Union, Any +from datetime import datetime +from sqlalchemy.orm import Session +from sqlalchemy import desc, asc +from models.book import Book +from schemas.book import BookCreate, BookResponse + +def get_books_with_filters( + db: Session, + skip: int = 0, + limit: int = 100, + sort_by: str = "title", + sort_order: str = "asc", + title_search: Optional[str] = None, + min_price: Optional[float] = None, + max_price: Optional[float] = None +) -> List[Book]: + """ + Get books with various filter options. + + Args: + db: Database session + skip: Number of records to skip + limit: Maximum number of records to return + sort_by: Field to sort by + sort_order: Sort direction (asc/desc) + title_search: Search string for title + min_price: Minimum price filter + max_price: Maximum price filter + + Returns: + List of Book objects matching the criteria + """ + query = db.query(Book) + + if title_search: + query = query.filter(Book.title.ilike(f"%{title_search}%")) + + if min_price is not None: + query = query.filter(Book.price >= min_price) + + if max_price is not None: + query = query.filter(Book.price <= max_price) + + if sort_order == "desc": + query = query.order_by(desc(getattr(Book, sort_by))) + else: + query = query.order_by(asc(getattr(Book, sort_by))) + + return query.offset(skip).limit(limit).all() + +def get_book_by_id(db: Session, book_id: int) -> Optional[Book]: + """ + Get a single book by ID. + + Args: + db: Database session + book_id: ID of the book to retrieve + + Returns: + Book object if found, None otherwise + """ + return db.query(Book).filter(Book.id == book_id).first() + +def format_book_response(book: Book) -> BookResponse: + """ + Format a book object into API response format. + + Args: + book: Book object to format + + Returns: + Formatted book response + """ + return BookResponse( + id=book.id, + title=book.title, + author=book.author, + price=book.price, + isbn=book.isbn, + created_at=book.created_at, + updated_at=book.updated_at + ) + +def validate_isbn(isbn: str) -> bool: + """ + Validate ISBN format. + + Args: + isbn: ISBN string to validate + + Returns: + bool: True if valid ISBN format, False otherwise + """ + # Remove hyphens and spaces + isbn = isbn.replace('-', '').replace(' ', '') + + if len(isbn) == 13: # ISBN-13 + try: + total = sum( + (3 if i % 2 else 1) * int(d) + for i, d in enumerate(isbn[:-1]) + ) + check_digit = (10 - (total % 10)) % 10 + return check_digit == int(isbn[-1]) + except ValueError: + return False + return False + +def check_book_availability( + db: Session, + book_id: int, + quantity_requested: int = 1 +) -> Dict[str, Any]: + """ + Check if a book is available in requested quantity. + + Args: + db: Database session + book_id: ID of book to check + quantity_requested: Quantity being requested + + Returns: + Dict containing availability status and message + """ + book = get_book_by_id(db, book_id) + if not book: + return { + "available": False, + "message": "Book not found" + } + + if book.stock_quantity >= quantity_requested: + return { + "available": True, + "message": "Book available", + "stock_quantity": book.stock_quantity + } + + return { + "available": False, + "message": f"Only {book.stock_quantity} copies available", + "stock_quantity": book.stock_quantity + } \ No newline at end of file