1
1
import logging
2
2
import sqlite3
3
+ import os
3
4
4
5
logger = logging .getLogger (__name__ )
5
6
@@ -8,59 +9,124 @@ class DatabaseManager:
8
9
def __init__ (self , db_path = "data/bot_data.sqlite" ):
9
10
"""Initialize database connection and create tables if not exist"""
10
11
self .db_path = db_path
12
+ self ._ensure_db_directory ()
11
13
self ._create_tables ()
14
+ self ._migrate_schema ()
15
+
16
+ def _ensure_db_directory (self ):
17
+ """Ensure the database directory exists and has proper permissions"""
18
+ db_dir = os .path .dirname (self .db_path )
19
+ if not os .path .exists (db_dir ):
20
+ try :
21
+ os .makedirs (db_dir , mode = 0o755 )
22
+ except OSError as e :
23
+ logger .error (f"Failed to create database directory: { e } " )
24
+ raise
25
+ elif not os .access (db_dir , os .W_OK ):
26
+ logger .error (f"Database directory { db_dir } is not writable" )
27
+ raise PermissionError (f"Database directory { db_dir } is not writable" )
12
28
13
29
def _get_connection (self ):
14
- """Create and return a database connection"""
15
- return sqlite3 .connect (self .db_path )
30
+ """Create and return a database connection with proper error handling"""
31
+ try :
32
+ conn = sqlite3 .connect (self .db_path , timeout = 20 )
33
+ # Enable foreign keys and WAL mode for better concurrency
34
+ conn .execute ("PRAGMA foreign_keys = ON" )
35
+ conn .execute ("PRAGMA journal_mode = WAL" )
36
+ return conn
37
+ except sqlite3 .Error as e :
38
+ logger .error (f"Failed to connect to database: { e } " )
39
+ raise
16
40
17
41
def _create_tables (self ):
18
42
"""Create necessary tables if they don't exist"""
19
- with self ._get_connection () as conn :
20
- cursor = conn .cursor ()
21
- cursor .execute (
43
+ try :
44
+ with self ._get_connection () as conn :
45
+ cursor = conn .cursor ()
46
+ cursor .execute (
47
+ """
48
+ CREATE TABLE IF NOT EXISTS channels (
49
+ channel_id INTEGER PRIMARY KEY,
50
+ added_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
51
+ )
22
52
"""
23
- CREATE TABLE IF NOT EXISTS channels (
24
- channel_id INTEGER PRIMARY KEY,
25
- channel_title TEXT,
26
- added_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
27
53
)
28
- """
29
- )
30
- conn .commit ()
54
+ conn .commit ()
55
+ except sqlite3 .Error as e :
56
+ logger .error (f"Failed to create tables: { e } " )
57
+ raise
58
+
59
+ def _migrate_schema (self ):
60
+ """Migrate the database schema if needed"""
61
+ try :
62
+ with self ._get_connection () as conn :
63
+ cursor = conn .cursor ()
64
+
65
+ # Check if old schema exists (with channel_title column)
66
+ cursor .execute ("PRAGMA table_info(channels)" )
67
+ columns = [column [1 ] for column in cursor .fetchall ()]
68
+
69
+ if "channel_title" in columns :
70
+ logger .info ("Migrating database schema..." )
71
+ # Create temporary table with new schema
72
+ cursor .execute (
73
+ """
74
+ CREATE TABLE channels_new (
75
+ channel_id INTEGER PRIMARY KEY,
76
+ added_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
77
+ )
78
+ """
79
+ )
31
80
32
- def add_channel (self , channel_id , channel_title ):
81
+ # Copy data from old table to new table
82
+ cursor .execute (
83
+ "INSERT INTO channels_new (channel_id, added_timestamp) SELECT channel_id, added_timestamp FROM channels"
84
+ )
85
+
86
+ # Drop old table and rename new table
87
+ cursor .execute ("DROP TABLE channels" )
88
+ cursor .execute ("ALTER TABLE channels_new RENAME TO channels" )
89
+
90
+ conn .commit ()
91
+ logger .info ("Database schema migration completed successfully" )
92
+ except sqlite3 .Error as e :
93
+ logger .error (f"Error during schema migration: { e } " )
94
+ raise
95
+
96
+ def add_channel (self , channel_id ):
33
97
"""Add a channel to the database"""
34
- with self . _get_connection () as conn :
35
- cursor = conn . cursor ()
36
- try :
98
+ try :
99
+ with self . _get_connection () as conn :
100
+ cursor = conn . cursor ()
37
101
cursor .execute (
38
- "INSERT OR REPLACE INTO channels (channel_id, channel_title ) VALUES (?, ?)" ,
39
- (channel_id , channel_title ),
102
+ "INSERT OR REPLACE INTO channels (channel_id) VALUES (?)" ,
103
+ (channel_id ,),
40
104
)
41
105
conn .commit ()
42
- except sqlite3 .Error as e :
43
- logger .error (f"Error adding channel: { e } " )
106
+ except sqlite3 .Error as e :
107
+ logger .error (f"Error adding channel: { e } " )
108
+ raise
44
109
45
110
def remove_channel (self , channel_id ):
46
111
"""Remove a channel from the database"""
47
- with self . _get_connection () as conn :
48
- cursor = conn . cursor ()
49
- try :
112
+ try :
113
+ with self . _get_connection () as conn :
114
+ cursor = conn . cursor ()
50
115
cursor .execute (
51
116
"DELETE FROM channels WHERE channel_id = ?" , (channel_id ,)
52
117
)
53
118
conn .commit ()
54
- except sqlite3 .Error as e :
55
- logger .error (f"Error removing channel: { e } " )
119
+ except sqlite3 .Error as e :
120
+ logger .error (f"Error removing channel: { e } " )
121
+ raise
56
122
57
123
def get_all_channels (self ):
58
124
"""Retrieve all channels from the database"""
59
- with self . _get_connection () as conn :
60
- cursor = conn . cursor ()
61
- try :
62
- cursor .execute ("SELECT channel_id, channel_title FROM channels" )
125
+ try :
126
+ with self . _get_connection () as conn :
127
+ cursor = conn . cursor ()
128
+ cursor .execute ("SELECT channel_id FROM channels" )
63
129
return cursor .fetchall ()
64
- except sqlite3 .Error as e :
65
- logger .error (f"Error retrieving channels: { e } " )
66
- return []
130
+ except sqlite3 .Error as e :
131
+ logger .error (f"Error retrieving channels: { e } " )
132
+ raise
0 commit comments