Coverage for polar/models/downloadable.py: 100%

30 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-07 12:42 +0000

1from datetime import datetime 

2from enum import StrEnum 

3from uuid import UUID 

4 

5from sqlalchemy import ( 

6 TIMESTAMP, 

7 ForeignKey, 

8 Integer, 

9 String, 

10 UniqueConstraint, 

11 Uuid, 

12) 

13from sqlalchemy.orm import Mapped, declared_attr, mapped_column, relationship 

14 

15from polar.kit.db.models import RecordModel 

16 

17from .benefit import Benefit 

18from .customer import Customer 

19from .file import File 

20 

21 

22class DownloadableStatus(StrEnum): 

23 granted = "granted" 

24 revoked = "revoked" 

25 

26 

27class Downloadable(RecordModel): 

28 __tablename__ = "downloadables" 

29 __table_args__ = (UniqueConstraint("customer_id", "file_id", "benefit_id"),) 

30 

31 file_id: Mapped[UUID] = mapped_column( 

32 Uuid, ForeignKey("files.id"), nullable=False, index=True 

33 ) 

34 

35 @declared_attr 

36 def file(cls) -> Mapped[File]: 

37 return relationship(File, lazy="raise") 

38 

39 status: Mapped[DownloadableStatus] = mapped_column(String, nullable=False) 

40 

41 customer_id: Mapped[UUID] = mapped_column( 

42 Uuid, 

43 ForeignKey("customers.id", ondelete="cascade"), 

44 nullable=False, 

45 # Don't create an index for customer_id 

46 # as it's covered by the unique constraint, being the leading column of it 

47 index=False, 

48 ) 

49 

50 @declared_attr 

51 def customer(cls) -> Mapped[Customer]: 

52 return relationship("Customer", lazy="raise") 

53 

54 benefit_id: Mapped[UUID] = mapped_column( 

55 Uuid, 

56 ForeignKey("benefits.id", ondelete="cascade"), 

57 nullable=False, 

58 index=True, 

59 ) 

60 

61 @declared_attr 

62 def benefit(cls) -> Mapped[Benefit]: 

63 return relationship("Benefit", lazy="raise") 

64 

65 downloaded: Mapped[int] = mapped_column(Integer, nullable=False, default=0) 

66 

67 last_downloaded_at: Mapped[datetime | None] = mapped_column( 

68 TIMESTAMP(timezone=True), 

69 nullable=True, 

70 )