migrate from supabase to postgres

This commit is contained in:
2025-09-09 16:01:58 +07:00
parent a836ebb2a6
commit aa62667d89
21 changed files with 327 additions and 902 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
from .home_debt import HomeDebtRepository
from .currency import CurrencyRepository
from .score import ScoreRepository
__all__ = ['HomeDebtRepository', 'CurrencyRepository']
__all__ = ['HomeDebtRepository', 'ScoreRepository']
-139
View File
@@ -1,139 +0,0 @@
from typing import List, Optional
from models.currency import DiscordCurrency
from infra.db import postgres
from datetime import datetime
class CurrencyRepository:
def __init__(self):
self.table = postgres.get_table('discord_currency')
async def get(self, user_id: int) -> Optional[DiscordCurrency]:
"""Lấy thông tin thành viên"""
try:
response = self.table.select('*').eq('user_id', user_id).execute()
if response.data:
data = response.data[0]
return DiscordCurrency(
id=data.get('id'),
user_id=data['user_id'],
balance=data['balance'],
updated_at=datetime.fromisoformat(data['updated_at'].replace('Z', '+00:00')) if data['updated_at'] else datetime.now()
)
return None
except Exception as e:
print(f"Error getting user: {e}")
return None
async def create(self, user_id: int, balance: int) -> Optional[DiscordCurrency]:
"""Tạo thông tin thành viên"""
try:
response = self.table.insert({'user_id': user_id, 'balance': balance}).execute()
if response.data:
data = response.data[0]
return DiscordCurrency(
id=data.get('id'),
user_id=data['user_id'],
balance=data['balance'],
updated_at=datetime.fromisoformat(data['updated_at'].replace('Z', '+00:00')) if data['updated_at'] else datetime.now()
)
return None
except Exception as e:
print(f"Error creating user: {e}")
return None
async def update(self, user_id: int, balance: int) -> Optional[DiscordCurrency]:
"""Cập nhật thông tin thành viên"""
try:
response = self.table.update({'balance': balance}).eq('user_id', user_id).execute()
if response.data:
data = response.data[0]
return DiscordCurrency(
id=data.get('id'),
user_id=data['user_id'],
balance=data['balance'],
updated_at=datetime.fromisoformat(data['updated_at'].replace('Z', '+00:00')) if data['updated_at'] else datetime.now()
)
return None
except Exception as e:
print(f"Error updating user: {e}")
return None
async def get_all(self) -> List[DiscordCurrency]:
"""Lấy tất cả thông tin thành viên"""
try:
response = self.table.select('*').order("balance", desc=True).execute()
currencies = []
for data in response.data:
currency = DiscordCurrency(
id=data.get('id'),
user_id=data['user_id'],
user_name=data['user_name'],
balance=data['balance'],
updated_at=datetime.now()
)
currencies.append(currency)
return currencies
except Exception as e:
print(f"Error getting all users: {e}")
return []
async def get_all_with_balance(self) -> List[DiscordCurrency]:
"""Lấy tất cả thông tin thành viên và số dư"""
try:
response = self.table.select('*').execute()
currencies = []
for data in response.data:
currencies.append(DiscordCurrency(
id=data.get('id'),
user_id=data['user_id'],
balance=data['balance'],
updated_at=datetime.fromisoformat(data['updated_at'].replace('Z', '+00:00')) if data['updated_at'] else datetime.now()
))
return currencies
except Exception as e:
print(f"Error getting all users with balance: {e}")
return []
# Get all with sort by balance
async def get_all_with_sort_by_balance(self) -> List[DiscordCurrency]:
"""Lấy tất cả thông tin thành viên và sắp xếp theo số dư"""
try:
response = self.table.select('*').order('balance', desc=True).execute()
currencies = []
for data in response.data:
currencies.append(DiscordCurrency(
id=data.get('id'),
user_id=data['user_id'],
balance=data['balance'],
updated_at=datetime.fromisoformat(data['updated_at'].replace('Z', '+00:00')) if data['updated_at'] else datetime.now()
))
return currencies
except Exception as e:
print(f"Error getting all users with sort by balance: {e}")
return []
async def upsert_or_increment_balance(self, user_id: str, user_name: str, amount: int) -> Optional[int]:
try:
response = self.table.select("*").eq("user_id", user_id).execute()
user_data = response.data[0] if response.data else None
now_str = datetime.utcnow().isoformat() + "Z"
if user_data:
new_balance = user_data["balance"] + amount
update_resp = self.table.update({
"balance": new_balance,
"updated_at": now_str
}).eq("user_id", user_id).execute()
return new_balance
else:
insert_resp = self.table.insert({
"user_id": user_id,
"user_name": user_name,
"balance": amount,
"updated_at": now_str
}).execute()
return amount
except Exception as e:
print(f"Error upserting balance for user {user_id}: {e}")
return None
+34 -22
View File
@@ -1,57 +1,69 @@
from typing import List, Optional
from models.home_debt import DiscordHomeDebt
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from models.home_debt import HomeDebt
from infra.db import postgres
class HomeDebtRepository:
def __init__(self):
self.table = postgres.get_table('discord_home_debt')
self.Session = postgres.get_sessionmaker()
async def get(self, discord_user_id: int) -> Optional[DiscordHomeDebt]:
async def get(self, discord_user_id: int) -> Optional[HomeDebt]:
"""Lấy thông tin thành viên"""
try:
response = self.table.select('*').eq('user_id', discord_user_id).execute()
if response.data:
return DiscordHomeDebt(**response.data[0])
return None
async with self.Session() as session:
stmt = select(HomeDebt).where(HomeDebt.user_id == discord_user_id)
result = await session.execute(stmt)
return result.scalar_one_or_none()
except Exception as e:
print(f"Error getting user: {e}")
return None
async def get_other(self, discord_user_id: int) -> Optional[DiscordHomeDebt]:
async def get_other(self, discord_user_id: int) -> Optional[HomeDebt]:
"""Lấy thông tin thành viên khác"""
try:
response = self.table.select('*').neq('user_id', discord_user_id).execute()
if response.data:
return DiscordHomeDebt(**response.data[0])
return None
async with self.Session() as session:
stmt = select(HomeDebt).where(HomeDebt.user_id != discord_user_id).limit(1)
result = await session.execute(stmt)
return result.scalar_one_or_none()
except Exception as e:
print(f"Error getting other member: {e}")
return None
async def create_home_debt(self, user_id: int, value: int) -> Optional[DiscordHomeDebt]:
async def create_home_debt(self, user_id: int, value: int) -> Optional[HomeDebt]:
"""Tạo mới khoản nợ"""
try:
home_debt = DiscordHomeDebt(user_id=user_id, value=value)
response = self.table.insert(home_debt.dict(exclude_none=True)).execute()
return DiscordHomeDebt(**response.data[0])
async with self.Session() as session:
home_debt = HomeDebt(user_id=user_id, value=value)
session.add(home_debt)
await session.commit()
await session.refresh(home_debt)
return home_debt
except Exception as e:
print(f"Error creating home debt: {e}")
return None
async def update_home_debt(self, home_debt: DiscordHomeDebt) -> Optional[DiscordHomeDebt]:
async def update_home_debt(self, home_debt: HomeDebt) -> Optional[HomeDebt]:
"""Cập nhật khoản nợ"""
try:
response = self.table.update(home_debt.to_dict()).eq('user_id', home_debt.user_id).execute()
return DiscordHomeDebt(**response.data[0])
async with self.Session() as session:
# Merge object vào session để cập nhật
merged_debt = await session.merge(home_debt)
await session.commit()
await session.refresh(merged_debt)
return merged_debt
except Exception as e:
print(f"Error updating home debt: {e}")
return None
async def get_all(self) -> List[DiscordHomeDebt]:
async def get_all(self) -> List[HomeDebt]:
"""Lấy tất cả khoản nợ"""
try:
response = self.table.select('*').execute()
return [DiscordHomeDebt(**home_debt) for home_debt in response.data]
async with self.Session() as session:
stmt = select(HomeDebt)
result = await session.execute(stmt)
return result.scalars().all()
except Exception as e:
print(f"Error getting all home debts: {e}")
return []
+33 -27
View File
@@ -1,31 +1,35 @@
from typing import List, Optional
from models.noi_tu import DiscordNoiTu
from infra.db import postgres
from datetime import datetime
import random
from sqlalchemy import select, delete
from models.noi_tu import DiscordNoiTu
from infra.db import postgres
class NoiTuRepository:
def __init__(self):
self.table = postgres.get_table('dictionary_vietnamese_two_words')
self.Session = postgres.get_sessionmaker()
async def is_exist(self, word: str) -> bool:
"""Kiểm tra xem từ có tồn tại trong bảng không"""
try:
word = word.strip()
response = self.table.select('*').eq('word', word).execute()
return len(response.data) > 0
async with self.Session() as session:
stmt = select(DiscordNoiTu).where(DiscordNoiTu.word == word).limit(1)
result = await session.execute(stmt)
return result.scalar_one_or_none() is not None
except Exception as e:
print(f"Error checking if word exists: {e}")
return False
async def add(self, word: str, meaning: Optional[str] = None) -> bool:
async def add(self, word: str) -> bool:
"""Thêm từ vào bảng"""
try:
response = self.table.insert({
'word': word,
'meaning': meaning
}).execute()
return response.data is not None
async with self.Session() as session:
noi_tu = DiscordNoiTu(word=word)
session.add(noi_tu)
await session.commit()
return True
except Exception as e:
print(f"Error adding word: {e}")
return False
@@ -33,8 +37,11 @@ class NoiTuRepository:
async def remove(self, word: str) -> bool:
"""Xóa từ khỏi bảng"""
try:
response = self.table.delete().eq('word', word).execute()
return response.data is not None
async with self.Session() as session:
stmt = delete(DiscordNoiTu).where(DiscordNoiTu.word == word)
await session.execute(stmt)
await session.commit()
return True
except Exception as e:
print(f"Error removing word: {e}")
return False
@@ -42,18 +49,18 @@ class NoiTuRepository:
async def get_random_word(self) -> Optional[str]:
"""Lấy một từ ngẫu nhiên từ bảng"""
try:
response = self.table.select('word').execute()
if response.data and len(response.data) > 0:
# Lọc từ có đúng 2 từ ghép, mỗi từ chỉ gồm chữ cái
words = []
for item in response.data:
word = item['word'].strip()
async with self.Session() as session:
stmt = select(DiscordNoiTu.word)
result = await session.execute(stmt)
words: List[str] = []
for row in result.scalars():
word = row.strip()
parts = word.split()
if len(parts) == 2 and all(part.isalpha() for part in parts):
words.append(word)
if words:
return random.choice(words)
return None
return None
except Exception as e:
print(f"Error getting random word: {e}")
return None
@@ -61,17 +68,16 @@ class NoiTuRepository:
async def get_all_words(self) -> List[str]:
"""Lấy tất cả từ trong bảng"""
try:
response = self.table.select('word').execute()
if response.data:
# Lọc từ có đúng 2 từ ghép, mỗi từ chỉ gồm chữ cái
words = []
for item in response.data:
word = item['word'].strip()
async with self.Session() as session:
stmt = select(DiscordNoiTu.word)
result = await session.execute(stmt)
words: List[str] = []
for row in result.scalars():
word = row.strip()
parts = word.split()
if len(parts) == 2 and all(part.isalpha() for part in parts):
words.append(word)
return words
return []
except Exception as e:
print(f"Error getting all words: {e}")
return []
+112
View File
@@ -0,0 +1,112 @@
from typing import List, Optional
from datetime import datetime
from sqlalchemy import select, update, insert
from sqlalchemy.dialects.postgresql import insert as pg_insert
from models.score import Score
from infra.db import postgres
class ScoreRepository:
def __init__(self):
self.Session = postgres.get_sessionmaker()
async def get(self, user_id: int) -> Optional[Score]:
"""Lấy thông tin thành viên"""
try:
async with self.Session() as session:
stmt = select(Score).where(Score.user_id == user_id)
result = await session.execute(stmt)
return result.scalar_one_or_none()
except Exception as e:
print(f"Error getting user: {e}")
return None
async def create(self, user_id: int, point: int) -> Optional[Score]:
"""Tạo thông tin thành viên"""
try:
async with self.Session() as session:
currency = Score(user_id=user_id, point=point)
session.add(currency)
await session.commit()
await session.refresh(currency)
return currency
except Exception as e:
print(f"Error creating user: {e}")
return None
async def update(self, user_id: int, point: int) -> Optional[Score]:
"""Cập nhật thông tin thành viên"""
try:
async with self.Session() as session:
stmt = (
update(Score)
.where(Score.user_id == user_id)
.values(point=point)
.returning(Score)
)
result = await session.execute(stmt)
await session.commit()
return result.scalar_one_or_none()
except Exception as e:
print(f"Error updating user: {e}")
return None
async def get_all(self) -> List[Score]:
"""Lấy tất cả thông tin thành viên"""
try:
async with self.Session() as session:
stmt = select(Score).order_by(Score.point.desc())
result = await session.execute(stmt)
return result.scalars().all()
except Exception as e:
print(f"Error getting all users: {e}")
return []
async def get_all_with_point(self) -> List[Score]:
"""Lấy tất cả thông tin thành viên và số dư"""
try:
async with self.Session() as session:
stmt = select(Score)
result = await session.execute(stmt)
return result.scalars().all()
except Exception as e:
print(f"Error getting all users with point: {e}")
return []
# Get all with sort by point
async def get_all_with_sort_by_point(self) -> List[Score]:
"""Lấy tất cả thông tin thành viên và sắp xếp theo số dư"""
try:
async with self.Session() as session:
stmt = select(Score).order_by(Score.point.desc())
result = await session.execute(stmt)
return result.scalars().all()
except Exception as e:
print(f"Error getting all users with sort by point: {e}")
return []
async def upsert_or_increment_point(self, user_id: str, user_name: str, amount: int) -> Optional[int]:
try:
async with self.Session() as session:
# Sử dụng PostgreSQL UPSERT (ON CONFLICT)
stmt = pg_insert(Score).values(
user_id=int(user_id),
user_name=user_name,
point=amount
)
stmt = stmt.on_conflict_do_update(
index_elements=['user_id'],
set_=dict(
point=Score.point + amount,
user_name=stmt.excluded.user_name
)
).returning(Score.point)
result = await session.execute(stmt)
await session.commit()
row = result.first()
return row[0] if row else None
except Exception as e:
print(f"Error upserting point for user {user_id}: {e}")
return None