-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdatabase.py
More file actions
149 lines (128 loc) · 4.34 KB
/
database.py
File metadata and controls
149 lines (128 loc) · 4.34 KB
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
143
144
145
146
147
148
149
import psycopg2
import psycopg2.extras
from psycopg2 import pool
import logging
from contextlib import contextmanager
from config import DATABASE_URL
logger = logging.getLogger(__name__)
# Connection pool
connection_pool = None
def init_connection_pool():
global connection_pool
try:
# Use connection pooling optimized for Fly.io
connection_pool = psycopg2.pool.ThreadedConnectionPool(
1, 5, # Smaller pool for Fly.io efficiency
dsn=DATABASE_URL,
sslmode='require'
)
logger.info("PostgreSQL connection pool initialized for Fly.io")
except Exception as e:
logger.error(f"Error initializing connection pool: {e}")
raise
@contextmanager
def get_db():
"""Get database connection from pool"""
if connection_pool is None:
init_connection_pool()
conn = None
try:
conn = connection_pool.getconn()
conn.autocommit = False
yield conn
conn.commit()
except Exception as e:
if conn:
conn.rollback()
logger.error(f"Database error: {e}")
raise
finally:
if conn:
connection_pool.putconn(conn)
def init_db():
"""Initialize database tables"""
with get_db() as conn:
cursor = conn.cursor()
# Users table
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
user_id BIGINT PRIMARY KEY,
username TEXT,
total_rep INTEGER DEFAULT 0,
level INTEGER DEFAULT 1,
profile_pic TEXT DEFAULT NULL,
join_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
badges TEXT DEFAULT '[]',
last_active TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
verification_status INTEGER DEFAULT 0
)""")
# Verification messages table
cursor.execute("""
CREATE TABLE IF NOT EXISTS verification_messages (
user_id BIGINT PRIMARY KEY,
chat_id BIGINT,
message_id INTEGER
)""")
# Admins table
cursor.execute("""
CREATE TABLE IF NOT EXISTS admins (
user_id BIGINT PRIMARY KEY
)""")
# Settings table
cursor.execute("""
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT
)""")
# Reputation transactions table
cursor.execute("""
CREATE TABLE IF NOT EXISTS reputation_transactions (
id SERIAL PRIMARY KEY,
from_user_id BIGINT,
to_user_id BIGINT NOT NULL,
chat_id BIGINT,
amount INTEGER DEFAULT 1,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
reason TEXT
)""")
# Loans table
cursor.execute("""
CREATE TABLE IF NOT EXISTS loans (
loan_id TEXT PRIMARY KEY,
user_id BIGINT NOT NULL,
username TEXT,
chat_id BIGINT,
amount DECIMAL(10,2) NOT NULL,
interest_rate DECIMAL(5,4) NOT NULL,
total_due DECIMAL(10,2) NOT NULL,
status TEXT DEFAULT 'pending',
request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
due_date TIMESTAMP,
approval_date TIMESTAMP,
repayment_date TIMESTAMP,
admin_id BIGINT,
level TEXT
)""")
# Create indexes for better performance
cursor.execute("""
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
""")
cursor.execute("""
CREATE INDEX IF NOT EXISTS idx_users_total_rep ON users(total_rep DESC);
""")
cursor.execute("""
CREATE INDEX IF NOT EXISTS idx_reputation_transactions_to_user ON reputation_transactions(to_user_id);
""")
cursor.execute("""
CREATE INDEX IF NOT EXISTS idx_loans_user_id ON loans(user_id);
""")
cursor.execute("""
CREATE INDEX IF NOT EXISTS idx_loans_status ON loans(status);
""")
logger.info("Database tables initialized successfully")
def close_connection_pool():
"""Close the connection pool"""
global connection_pool
if connection_pool:
connection_pool.closeall()
logger.info("Connection pool closed")