|
2 | 2 |
|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | | -from typing import TYPE_CHECKING |
| 5 | +from typing import TYPE_CHECKING, Any |
6 | 6 |
|
7 | 7 | from advanced_alchemy.base import UUIDAuditBase |
8 | | -from sqlalchemy import BigInteger, ForeignKey |
9 | | -from sqlalchemy.ext.associationproxy import AssociationProxy, association_proxy |
| 8 | +from sqlalchemy import JSON, BigInteger, ForeignKey |
| 9 | +from sqlalchemy.dialects.postgresql import ARRAY |
10 | 10 | from sqlalchemy.orm import Mapped, mapped_column, relationship |
| 11 | +from sqlalchemy.types import TypeDecorator |
11 | 12 |
|
12 | 13 | if TYPE_CHECKING: |
| 14 | + from sqlalchemy.engine import Dialect |
| 15 | + |
13 | 16 | from byte_common.models.guild import Guild |
14 | 17 |
|
15 | | -__all__ = ("ForumConfig",) |
| 18 | +__all__ = ("ForumConfig", "IntegerArray") |
| 19 | + |
| 20 | + |
| 21 | +class IntegerArray(TypeDecorator): |
| 22 | + """Platform-independent integer array type. |
| 23 | +
|
| 24 | + Uses ARRAY on PostgreSQL and JSON on other databases. |
| 25 | + """ |
| 26 | + |
| 27 | + impl = JSON |
| 28 | + cache_ok = True |
| 29 | + |
| 30 | + def load_dialect_impl(self, dialect: Dialect) -> Any: |
| 31 | + """Load dialect-specific type implementation. |
| 32 | +
|
| 33 | + Args: |
| 34 | + dialect: Database dialect instance |
| 35 | +
|
| 36 | + Returns: |
| 37 | + Any: Type descriptor for the dialect (ARRAY or JSON) |
| 38 | + """ |
| 39 | + if dialect.name == "postgresql": |
| 40 | + return dialect.type_descriptor(ARRAY(BigInteger)) |
| 41 | + return dialect.type_descriptor(JSON()) |
| 42 | + |
| 43 | + def process_bind_param(self, value: list[int] | None, dialect: Dialect) -> list[int] | None: |
| 44 | + """Process value before binding to database. |
| 45 | +
|
| 46 | + Args: |
| 47 | + value: List of integers or None |
| 48 | + dialect: Database dialect instance |
| 49 | +
|
| 50 | + Returns: |
| 51 | + list[int] | None: Processed value |
| 52 | + """ |
| 53 | + if value is None: |
| 54 | + return value |
| 55 | + if dialect.name == "postgresql": |
| 56 | + return value |
| 57 | + # For JSON, ensure it's a list |
| 58 | + return value if isinstance(value, list) else [] |
| 59 | + |
| 60 | + def process_result_value(self, value: list[int] | None, _dialect: Dialect) -> list[int]: |
| 61 | + """Process value after fetching from database. |
| 62 | +
|
| 63 | + Args: |
| 64 | + value: List of integers or None |
| 65 | + _dialect: Database dialect instance (unused) |
| 66 | +
|
| 67 | + Returns: |
| 68 | + list[int]: Empty list if None, otherwise the value |
| 69 | + """ |
| 70 | + if value is None: |
| 71 | + return [] |
| 72 | + return value if isinstance(value, list) else [] |
16 | 73 |
|
17 | 74 |
|
18 | 75 | class ForumConfig(UUIDAuditBase): |
@@ -48,18 +105,16 @@ class ForumConfig(UUIDAuditBase): |
48 | 105 | # Help forum settings |
49 | 106 | help_forum: Mapped[bool] = mapped_column(default=False) |
50 | 107 | help_forum_category: Mapped[str | None] |
51 | | - help_channel_id: AssociationProxy[int | None] = association_proxy("guild", "help_channel_id") |
52 | 108 | help_thread_auto_close: Mapped[bool] = mapped_column(default=False) |
53 | 109 | help_thread_auto_close_days: Mapped[int | None] |
54 | 110 | help_thread_notify: Mapped[bool] = mapped_column(default=False) |
55 | | - help_thread_notify_roles: Mapped[str | None] |
| 111 | + help_thread_notify_roles: Mapped[list[int]] = mapped_column(IntegerArray, default=list) |
56 | 112 | help_thread_notify_days: Mapped[int | None] |
57 | | - help_thread_sync: AssociationProxy[bool] = association_proxy("guild", "github_config.discussion_sync") |
| 113 | + help_thread_sync: Mapped[bool] = mapped_column(default=False) |
58 | 114 |
|
59 | 115 | # Showcase forum settings |
60 | 116 | showcase_forum: Mapped[bool] = mapped_column(default=False) |
61 | 117 | showcase_forum_category: Mapped[str | None] |
62 | | - showcase_channel_id: AssociationProxy[int | None] = association_proxy("guild", "showcase_channel_id") |
63 | 118 | showcase_thread_auto_close: Mapped[bool] = mapped_column(default=False) |
64 | 119 | showcase_thread_auto_close_days: Mapped[int | None] |
65 | 120 |
|
|
0 commit comments