File size: 7,049 Bytes
8d21059
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# database/schema.py
import logging
from database.connection import get_conn

logger = logging.getLogger(__name__)


def init_db() -> None:
    conn = get_conn()
    c    = conn.cursor()
    try:
        # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        # ุฌุฏูˆู„ ุงู„ู…ุณุชุฎุฏู…ูŠู†
        # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        c.execute("""
            CREATE TABLE IF NOT EXISTS users (
                user_id      INTEGER PRIMARY KEY,
                username     TEXT    DEFAULT '',
                first_name   TEXT    DEFAULT '',
                last_name    TEXT    DEFAULT '',
                joined_at    TEXT    DEFAULT (datetime('now','localtime')),
                search_count INTEGER DEFAULT 0,
                last_game    TEXT    DEFAULT '',
                referred_by  INTEGER DEFAULT NULL,
                is_banned    INTEGER DEFAULT 0
            )
        """)
        c.execute("CREATE INDEX IF NOT EXISTS idx_users_joined ON users(joined_at)")

        # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        # ุฌุฏูˆู„ ุงู„ู…ู†ุดูˆุฑุงุช ุงู„ู…ูู‡ุฑุณุฉ
        # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        c.execute("""
            CREATE TABLE IF NOT EXISTS posts (
                id                INTEGER PRIMARY KEY AUTOINCREMENT,
                message_id        INTEGER NOT NULL,
                channel_id        INTEGER NOT NULL,
                channel_username  TEXT    DEFAULT '',
                text_original     TEXT    DEFAULT '',
                text_normalized   TEXT    DEFAULT '',
                hashtags          TEXT    DEFAULT '',
                platform          TEXT    DEFAULT '',
                has_media         INTEGER DEFAULT 0,
                media_type        TEXT    DEFAULT '',
                posted_at         TEXT    NOT NULL,
                indexed_at        TEXT    DEFAULT (datetime('now','localtime')),
                UNIQUE(message_id, channel_id)
            )
        """)
        c.execute("CREATE INDEX IF NOT EXISTS idx_posts_platform ON posts(platform)")
        c.execute("CREATE INDEX IF NOT EXISTS idx_posts_indexed  ON posts(indexed_at)")

        # โ”€โ”€ FTS5 ู„ู„ุจุญุซ ุงู„ุณุฑูŠุน โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        c.execute("""
            CREATE VIRTUAL TABLE IF NOT EXISTS posts_fts
            USING fts5(
                text_original,
                text_normalized,
                hashtags,
                platform,
                content='posts',
                content_rowid='id',
                tokenize='unicode61'
            )
        """)

        # โ”€โ”€ Triggers ู…ุฒุงู…ู†ุฉ FTS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        c.executescript("""
            CREATE TRIGGER IF NOT EXISTS fts_ai
            AFTER INSERT ON posts BEGIN
                INSERT INTO posts_fts(rowid, text_original, text_normalized, hashtags, platform)
                VALUES (new.id, new.text_original, new.text_normalized, new.hashtags, new.platform);
            END;

            CREATE TRIGGER IF NOT EXISTS fts_ad
            AFTER DELETE ON posts BEGIN
                INSERT INTO posts_fts(posts_fts, rowid, text_original, text_normalized, hashtags, platform)
                VALUES ('delete', old.id, old.text_original, old.text_normalized, old.hashtags, old.platform);
            END;

            CREATE TRIGGER IF NOT EXISTS fts_au
            AFTER UPDATE ON posts BEGIN
                INSERT INTO posts_fts(posts_fts, rowid, text_original, text_normalized, hashtags, platform)
                VALUES ('delete', old.id, old.text_original, old.text_normalized, old.hashtags, old.platform);
                INSERT INTO posts_fts(rowid, text_original, text_normalized, hashtags, platform)
                VALUES (new.id, new.text_original, new.text_normalized, new.hashtags, new.platform);
            END;
        """)

        # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        # ุฌุฏูˆู„ ุงู„ู…ุดุชุฑูƒูŠู† ููŠ ุงู„ุฅุดุนุงุฑุงุช
        # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        c.execute("""
            CREATE TABLE IF NOT EXISTS subscribers (
                user_id              INTEGER PRIMARY KEY,
                wants_free_games     INTEGER DEFAULT 0,
                wants_dlcs           INTEGER DEFAULT 0,
                wants_translations   INTEGER DEFAULT 0,
                updated_at           TEXT    DEFAULT (datetime('now','localtime'))
            )
        """)

        # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        # ุฌุฏูˆู„ ุงู„ุฃู„ุนุงุจ ุงู„ู…ุฌุงู†ูŠุฉ ุงู„ู…ูุฑุณู„ุฉ (ู„ูƒู„ ู…ุณุชุฎุฏู…)
        # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        c.execute("""
            CREATE TABLE IF NOT EXISTS free_games_sent (
                id        INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id   INTEGER NOT NULL,
                game_id   TEXT    NOT NULL,
                platform  TEXT    DEFAULT '',
                sent_at   TEXT    DEFAULT (datetime('now','localtime')),
                UNIQUE(user_id, game_id)
            )
        """)
        c.execute("CREATE INDEX IF NOT EXISTS idx_fgs_user   ON free_games_sent(user_id)")
        c.execute("CREATE INDEX IF NOT EXISTS idx_fgs_gameid ON free_games_sent(game_id)")

        conn.commit()
        logger.info("โœ… ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช ุฌุงู‡ุฒุฉ ุจู†ุฌุงุญ")

    except Exception as e:
        conn.rollback()
        logger.critical(f"โŒ ูุดู„ ุชู‡ูŠุฆุฉ ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช: {e}", exc_info=True)
        raise
    finally:
        conn.close()


def rebuild_fts() -> bool:
    conn = get_conn()
    try:
        conn.execute("INSERT INTO posts_fts(posts_fts) VALUES('rebuild')")
        conn.commit()
        logger.info("โœ… FTS ุฃูุนูŠุฏ ุจู†ุงุคู‡")
        return True
    except Exception as e:
        logger.error(f"rebuild_fts: {e}", exc_info=True)
        return False
    finally:
        conn.close()