Coverage for app / models / book.py: 97%

32 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-06 04:49 +0000

1""" 

2This module defines the Book model, representing book records in the database. 

3 

4The Book class includes fields for storing details such as title, author, rating, 

5description, and relationships to other entities like reading statuses, feedbacks, 

6and lists. It supports converting an instance to a dictionary for easier 

7manipulation and provides a clean string representation. 

8""" 

9from sqlalchemy.orm import Mapped, mapped_column, relationship 

10 

11from app import db 

12from app.models.feedback import Feedback 

13from app.models.tags import TagBook 

14from app.models.reading_status import ReadingStatus 

15 

16 

17class Book(db.Model): 

18 """ 

19 Represents a book entity in the database. 

20 

21 This class is mapped to the `books` table in the database and is used to store 

22 and manage information about books such as title, author, description, and related attributes. 

23 The class provides methods to convert its instance to a dictionary and to return a string 

24 representation of the object. 

25 

26 :ivar id: Unique identifier for the book. 

27 :type id: int 

28 :ivar author: Name of the author of the book. 

29 :type author: str 

30 :ivar title: Title of the book. 

31 :type title: str 

32 :ivar asin: Amazon Standard Identification Number (ASIN) of the book, 

33 if available. 

34 :type asin: Optional[str] 

35 :ivar link: URL linking to the book's details, if available. 

36 :type link: Optional[str] 

37 :ivar image: URL linking to the book's image, if available. 

38 :type image: Optional[str] 

39 :ivar categories_flat: Flattened string representation of the 

40 book's categories, if available. 

41 :type categories_flat: Optional[str] 

42 :ivar book_description: Description of the book, if available. 

43 :type book_description: Optional[str] 

44 :ivar rating: Rating of the book, defaults to 0.0. 

45 :type rating: float 

46 :ivar isbn_13: International Standard Book Number (13-digit), 

47 if available. 

48 :type isbn_13: Optional[str] 

49 :ivar isbn_10: International Standard Book Number (10-digit), 

50 if available. 

51 :type isbn_10: Optional[str] 

52 :ivar hardcover: Indicates hardcover details of the book, if available. 

53 :type hardcover: Optional[str] 

54 :ivar bestsellers_rank_flat: Flattened string representation of the book's 

55 bestsellers rank, if available. 

56 :type bestsellers_rank_flat: Optional[str] 

57 :ivar specifications_flat: Flattened string representation of the book's 

58 specifications, if available. 

59 :type specifications_flat: Optional[str] 

60 """ 

61 __tablename__ = 'books' 

62 

63 id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) 

64 author: Mapped[str] = mapped_column(db.String(255), nullable=False, index=True) 

65 title: Mapped[str] = mapped_column(db.String(255), nullable=False, index=True) 

66 asin: Mapped[str | None] = mapped_column(db.String(20), index=True, nullable=True) 

67 link: Mapped[str | None] = mapped_column(db.Text, nullable=True) 

68 image: Mapped[str | None] = mapped_column(db.Text, nullable=True) 

69 categories_flat: Mapped[str | None] = mapped_column(db.String(255), index=True, nullable=True) 

70 book_description: Mapped[str | None] = mapped_column(db.Text, nullable=True) 

71 rating: Mapped[float] = mapped_column(db.Float, default=0.0, index=True, nullable=False) 

72 isbn_13: Mapped[str | None] = mapped_column(db.String(17), index=True, nullable=True) 

73 isbn_10: Mapped[str | None] = mapped_column(db.String(13), index=True, nullable=True) 

74 hardcover: Mapped[str | None] = mapped_column(db.String(64), nullable=True) 

75 bestsellers_rank_flat: Mapped[str | None] = mapped_column(db.Text, nullable=True) 

76 specifications_flat: Mapped[str | None] = mapped_column(db.Text, nullable=True) 

77 

78 reading_statuses: Mapped[list["ReadingStatus"]] = relationship(back_populates="book") 

79 feedbacks: Mapped[list["Feedback"]] = relationship(back_populates="book") 

80 

81 # Relationship to TagBook, connects with ListBook.book 

82 tags: Mapped[list['TagBook']] = relationship('TagBook', 

83 back_populates='book', 

84 cascade='all, delete-orphan') 

85 

86 def to_dict(self) -> dict: 

87 """Converts the model instance into a dictionary.""" 

88 result = {column.name: getattr(self, column.name) for column in self.__table__.columns} 

89 if result.get('book_description'): 

90 # some descriptions have   and these need to be rendered as just space 

91 result['book_description'] = result['book_description'].replace('\u00A0', '\u0020') 

92 return result 

93 

94 def __repr__(self) -> str: 

95 """Provides a clean string representation of the object.""" 

96 return f"<Book(id={self.id}, title='{self.title}', author='{self.author}')>" 

97 

98 

99__all__ = ["Book"]