📝 继续完善数据库

This commit is contained in:
2025-04-29 18:11:09 +08:00
parent 6b99ec427c
commit 8243a1e1c8
12 changed files with 358 additions and 153 deletions
-3
View File
@@ -8,7 +8,6 @@ import aiosqlite
from zhenxun.services.log import logger
from ..config import g_sDBFilePath, g_sDBPath
from ..dbService import g_pDBService
class CSqlManager:
@@ -27,8 +26,6 @@ class CSqlManager:
cls.m_pDB = await aiosqlite.connect(g_sDBFilePath)
cls.m_pDB.row_factory = aiosqlite.Row
await g_pDBService.init()
return True
@classmethod
+48 -10
View File
@@ -1,10 +1,11 @@
import math
from datetime import date, datetime, timedelta
from typing import List, Union
from database import CSqlManager
from zhenxun.services.log import logger
from .database import CSqlManager
class CUserDB(CSqlManager):
@classmethod
@@ -65,6 +66,28 @@ class CUserDB(CSqlManager):
rows = await cursor.fetchall()
return [row[0] for row in rows]
@classmethod
async def isUserExist(cls, uid: str) -> bool:
"""判断用户是否存在
Args:
uid (str): 用户Uid
Returns:
bool: 如果用户存在返回True,否则返回False
"""
if not uid:
return False
try:
async with cls.m_pDB.execute(
"SELECT 1 FROM user WHERE uid = ?", (uid,)
) as cursor:
row = await cursor.fetchone()
return row is not None
except Exception as e:
logger.warning("isUserExist 查询失败!", e=e)
return False
@classmethod
async def getUserInfoByUid(cls, uid: str) -> dict:
"""获取指定用户完整信息
@@ -240,22 +263,37 @@ class CUserDB(CSqlManager):
uid (str): 用户Uid
Returns:
tuple[int, int, int]: (当前等级, 下级所需经验, 当前等级剩余经验),失败返回(-1, -1, -1)
tuple[int, int, int]: (当前等级, 升至下级还需经验, 当前等级已获经验),失败返回(-1, -1, -1)
"""
if not uid:
return -1, -1, -1
try:
async with cls.m_pDB.execute(
"SELECT exp FROM user WHERE uid = ?", (uid,)
) as cursor:
row = await cursor.fetchone()
if row and row[0] is not None:
expVal = int(row[0])
level = expVal // 200
nextLevelExp = 200 * (level + 1)
currentLevelExp = level * 200
remainingExp = expVal - currentLevelExp
return level, nextLevelExp, remainingExp
if not row or row[0] is None:
return -1, -1, -1
expVal = int(row[0])
levelStep = 200 # 每级经验增量
discriminant = 1 + 8 * expVal / levelStep
level = int((-1 + math.sqrt(discriminant)) // 2)
if level < 0:
level = 0
def cumExp(k: int) -> int:
return levelStep * k * (k + 1) // 2
totalExpCurrentLevel = cumExp(level)
totalExpNextLevel = cumExp(level + 1)
currentExp = expVal - totalExpCurrentLevel
return level, totalExpNextLevel, currentExp
return -1, -1, -1
except Exception as e:
logger.warning("getUserLevelByUid 查询失败!", e=e)
+7 -7
View File
@@ -1,9 +1,9 @@
from typing import Optional
from database import CSqlManager
from zhenxun.services.log import logger
from .database import CSqlManager
class CUserItemDB(CSqlManager):
@classmethod
@@ -41,7 +41,7 @@ class CUserItemDB(CSqlManager):
row = await cursor.fetchone()
return row[0] if row else None
except Exception as e:
logger.warning(f"真寻农场getUserItemByName查询失败!", e=e)
logger.warning(f"getUserItemByName查询失败!", e=e)
return None
@classmethod
@@ -64,7 +64,7 @@ class CUserItemDB(CSqlManager):
rows = await cursor.fetchall()
return {row["item"]: row["count"] for row in rows}
except Exception as e:
logger.warning(f"真寻农场getUserItemByUid查询失败!", e=e)
logger.warning(f"getUserItemByUid查询失败!", e=e)
return {}
@classmethod
@@ -88,7 +88,7 @@ class CUserItemDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场deleteUserItemByName失败!", e=e)
logger.warning(f"deleteUserItemByName失败!", e=e)
return False
@classmethod
@@ -119,7 +119,7 @@ class CUserItemDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场updateUserItemByName失败!", e=e)
logger.warning(f"updateUserItemByName失败!", e=e)
return False
@classmethod
@@ -164,5 +164,5 @@ class CUserItemDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场addUserItemByUid失败!", e=e)
logger.warning(f"addUserItemByUid失败!", e=e)
return False
+6 -6
View File
@@ -1,9 +1,9 @@
from typing import Dict, Optional
from database import CSqlManager
from zhenxun.services.log import logger
from .database import CSqlManager
class CUserPlantDB(CSqlManager):
@classmethod
@@ -56,7 +56,7 @@ class CUserPlantDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场addUserPlantByUid 失败!", e=e)
logger.warning(f"addUserPlantByUid 失败!", e=e)
return False
@classmethod
@@ -95,7 +95,7 @@ class CUserPlantDB(CSqlManager):
row = await cursor.fetchone()
return row[0] if row else None
except Exception as e:
logger.warning(f"真寻农场getUserPlantByName 查询失败!", e=e)
logger.warning(f"getUserPlantByName 查询失败!", e=e)
return None
@classmethod
@@ -121,7 +121,7 @@ class CUserPlantDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场updateUserPlantByName失败!", e=e)
logger.warning(f"updateUserPlantByName失败!", e=e)
return False
@classmethod
@@ -143,5 +143,5 @@ class CUserPlantDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场deleteUserPlantByName 失败!", e=e)
logger.warning(f"deleteUserPlantByName 失败!", e=e)
return False
+78 -11
View File
@@ -1,9 +1,9 @@
from typing import Optional
from database import CSqlManager
from zhenxun.services.log import logger
from .database import CSqlManager
class CUserSeedDB(CSqlManager):
@classmethod
@@ -22,7 +22,7 @@ class CUserSeedDB(CSqlManager):
@classmethod
async def addUserSeedByUid(cls, uid: str, seed: str, count: int = 1) -> bool:
"""根据用户uid添加种子信息
"""根据用户uid添加种子信息(事务版本)
Args:
uid (str): 用户uid
@@ -34,7 +34,6 @@ class CUserSeedDB(CSqlManager):
"""
try:
async with cls._transaction():
#检查是否已存在该种子
async with cls.m_pDB.execute(
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?",
(uid, seed)
@@ -42,21 +41,18 @@ class CUserSeedDB(CSqlManager):
row = await cursor.fetchone()
if row:
#如果种子已存在,则更新数量
newCount = row[0] + count
await cls.m_pDB.execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(newCount, uid, seed)
)
else:
#如果种子不存在,则插入新记录
newCount = count
await cls.m_pDB.execute(
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
(uid, seed, count)
)
#如果种子数量为 0,删除记录
if newCount <= 0:
await cls.m_pDB.execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?",
@@ -64,9 +60,33 @@ class CUserSeedDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场addUserSeedByUid 失败!", e=e)
logger.warning(f"addUserSeedByUid 失败!", e=e)
return False
@classmethod
async def _addUserSeedByUid(cls, uid: str, seed: str, count: int = 1) -> bool:
"""根据用户uid添加种子信息(非事务版,复用其他非事务接口)"""
try:
existing = await cls.getUserSeedByName(uid, seed)
newCount = (existing or 0) + count
if existing is not None:
await cls._updateUserSeedByName(uid, seed, newCount)
else:
await cls.m_pDB.execute(
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
(uid, seed, newCount)
)
if newCount <= 0:
await cls._deleteUserSeedByName(uid, seed)
return True
except Exception as e:
logger.warning(f"_addUserSeedByUid 失败!", e=e)
return False
@classmethod
async def getUserSeedByName(cls, uid: str, seed: str) -> Optional[int]:
"""根据种子名称获取种子数量
@@ -87,7 +107,7 @@ class CUserSeedDB(CSqlManager):
row = await cursor.fetchone()
return row[0] if row else None
except Exception as e:
logger.warning(f"真寻农场getUserSeedByName 查询失败!", e=e)
logger.warning(f"getUserSeedByName 查询失败!", e=e)
return None
@classmethod
@@ -131,7 +151,33 @@ class CUserSeedDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场updateUserSeedByName失败!", e=e)
logger.warning(f"updateUserSeedByName失败!", e=e)
return False
@classmethod
async def _updateUserSeedByName(cls, uid: str, seed: str, count: int) -> bool:
"""根据种子名称更新种子数量
Args:
uid (str): 用户uid
seed (str): 种子名称
count (int): 种子数量
Returns:
bool: 是否成功
"""
try:
if count <= 0:
return await cls.deleteUserSeedByName(uid, seed)
async with cls._transaction():
await cls.m_pDB.execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(count, uid, seed)
)
return True
except Exception as e:
logger.warning(f"updateUserSeedByName失败!", e=e)
return False
@classmethod
@@ -153,5 +199,26 @@ class CUserSeedDB(CSqlManager):
)
return True
except Exception as e:
logger.warning(f"真寻农场deleteUserSeedByName 删除失败!", e=e)
logger.warning(f"deleteUserSeedByName 删除失败!", e=e)
return False
@classmethod
async def _deleteUserSeedByName(cls, uid: str, seed: str) -> bool:
"""根据种子名称从种子仓库中删除种子
Args:
uid (str): 用户uid
seed (str): 种子名称
Returns:
bool: 是否成功
"""
try:
await cls.m_pDB.execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?",
(uid, seed)
)
return True
except Exception as e:
logger.warning(f"deleteUserSeedByName 删除失败!", e=e)
return False
+140 -71
View File
@@ -1,28 +1,27 @@
from datetime import date, datetime, timedelta
from typing import Optional
from database import CSqlManager
from zhenxun.services.log import logger
from ..config import g_pJsonManager
from ..dbService import g_pDBService
from .database import CSqlManager
class CUserSoilDB(CSqlManager):
@classmethod
async def initDB(cls):
#用户Uid
#地块索引从1开始
#作物名称
#播种时间
#成熟时间
#土地等级 0=普通地,1=红土地,2=黑土地,3=金土地
#枯萎状态 0=未枯萎,1=枯萎
#施肥状态 0=未施肥,1=施肥
#虫害状态 0=无虫害,1=有虫害
#杂草状态 0=无杂草,1=有杂草
#缺水状态 0=不缺水,1=缺水
# 用户Uid
# 地块索引从1开始
# 作物名称
# 播种时间
# 成熟时间
# 土地等级 0=普通地,1=红土地,2=黑土地,3=金土地
# 枯萎状态 0=未枯萎,1=枯萎
# 施肥状态 0=未施肥,1=施肥
# 虫害状态 0=无虫害,1=有虫害
# 杂草状态 0=无杂草,1=有杂草
# 缺水状态 0=不缺水,1=缺水
userSoil = {
"uid": "TEXT NOT NULL",
"soilIndex": "INTEGER NOT NULL",
@@ -35,7 +34,7 @@ class CUserSoilDB(CSqlManager):
"bugStatus": "INTEGER DEFAULT 0",
"weedStatus": "INTEGER DEFAULT 0",
"waterStatus": "INTEGER DEFAULT 0",
"PRIMARY KEY": "(uid, soilIndex)"
"PRIMARY KEY": "(uid, soilIndex)",
}
await cls.ensureTableSchema("userSoil", userSoil)
@@ -52,61 +51,50 @@ class CUserSoilDB(CSqlManager):
"""
cursor = await cls.m_pDB.execute("SELECT * FROM soil WHERE uid = ?", (uid,))
row = await cursor.fetchone()
if not row:
return {}
columns = [description[0] for description in cursor.description]
return dict(zip(columns, row))
@classmethod
async def migrateOldFarmData(cls):
async def migrateOldFarmData(cls) -> bool:
"""迁移旧土地数据到新表 userSoil 并删除旧表
Raises:
aiosqlite.Error: 数据库操作失败时抛出
Returns:
None
bool: 如果旧表不存在则返回 False,否则迁移并删除后返回 True
"""
# 检查旧表是否存在
cursor = await cls.m_pDB.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name='soil'"
)
if not await cursor.fetchone():
return False
async with cls._transaction():
users = await g_pDBService.user.getAllUsers()
for uid in users:
farmInfo = await cls.getUserFarmByUid(uid)
for i in range(1, 31):
soilName = f"soil{i}"
if soilName not in farmInfo:
key = f"soil{i}"
data = farmInfo.get(key)
if not data:
continue
soilData = farmInfo[soilName]
if not soilData:
parts = data.split(",")
if len(parts) < 3:
continue
name = parts[0]
pt = int(parts[1])
mt = int(parts[2])
fields = soilData.split(',')
if len(fields) < 6:
continue
await cls.m_pDB.execute(
"INSERT INTO userSoil (uid,soilIndex,plantName,plantTime,matureTime) VALUES (?,?,?,?,?)",
(uid, i, name, pt, mt),
)
plantName = fields[0]
plantTime = int(fields[1])
matureTime = int(fields[2])
soilLevel = int(fields[5])
# 构建新的土地数据
soilInfo = {
"uid": uid,
"soilIndex": i,
"plantName": plantName,
"plantTime": plantTime,
"matureTime": matureTime,
"soilLevel": soilLevel,
"wiltStatus":0,
"fertilizerStatus": 0,
"bugStatus": 0,
"weedStatus": 0,
"waterStatus": 0
}
await cls.insertUserSoil(soilInfo)
# 彻底清除旧表
await cls.m_pDB.execute("DROP TABLE soil")
return True
@classmethod
async def insertUserSoil(cls, soilInfo: dict):
@@ -131,10 +119,36 @@ class CUserSoilDB(CSqlManager):
soilInfo.get("fertilizerStatus", 0),
soilInfo.get("bugStatus", 0),
soilInfo.get("weedStatus", 0),
soilInfo.get("waterStatus", 0)
)
soilInfo.get("waterStatus", 0),
),
)
@classmethod
async def _insertUserSoil(cls, soilInfo: dict):
"""插入一条新的 userSoil 记录
Args:
soilInfo (dict): 新土地数据
Returns:
None
"""
await cls.m_pDB.execute(
"INSERT INTO userSoil (uid, soilIndex, plantName, plantTime, matureTime, soilLevel, fertilizerStatus, bugStatus, weedStatus, waterStatus) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(
soilInfo["uid"],
soilInfo["soilIndex"],
soilInfo.get("plantName", ""),
soilInfo.get("plantTime", 0),
soilInfo.get("matureTime", 0),
soilInfo.get("soilLevel", 0),
soilInfo.get("fertilizerStatus", 0),
soilInfo.get("bugStatus", 0),
soilInfo.get("weedStatus", 0),
soilInfo.get("waterStatus", 0),
),
)
@classmethod
async def getUserSoil(cls, uid: str, soilIndex: int) -> Optional[dict]:
"""获取指定用户某块土地的详细信息
@@ -149,7 +163,7 @@ class CUserSoilDB(CSqlManager):
async with cls._transaction():
cursor = await cls.m_pDB.execute(
"SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?",
(uid, soilIndex)
(uid, soilIndex),
)
row = await cursor.fetchone()
if not row:
@@ -157,6 +171,27 @@ class CUserSoilDB(CSqlManager):
columns = [description[0] for description in cursor.description]
return dict(zip(columns, row))
@classmethod
async def _getUserSoil(cls, uid: str, soilIndex: int) -> Optional[dict]:
"""获取指定用户某块土地的详细信息
Args:
uid (str): 用户ID
soilIndex (int): 土地索引
Returns:
Optional[dict]: 记录存在返回字段-值字典,否则返回 None
"""
cursor = await cls.m_pDB.execute(
"SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?",
(uid, soilIndex),
)
row = await cursor.fetchone()
if not row:
return None
columns = [description[0] for description in cursor.description]
return dict(zip(columns, row))
@classmethod
async def updateUserSoil(cls, uid: str, soilIndex: int, field: str, value):
"""更新指定用户土地的单个字段
@@ -173,9 +208,27 @@ class CUserSoilDB(CSqlManager):
async with cls._transaction():
await cls.m_pDB.execute(
f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?",
(value, uid, soilIndex)
(value, uid, soilIndex),
)
@classmethod
async def _updateUserSoil(cls, uid: str, soilIndex: int, field: str, value):
"""更新指定用户土地的单个字段
Args:
uid (str): 用户ID
soilIndex (int): 土地索引
field (str): 需更新的字段名
value: 新值
Returns:
None
"""
await cls.m_pDB.execute(
f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?",
(value, uid, soilIndex),
)
@classmethod
async def deleteUserSoil(cls, uid: str, soilIndex: int):
"""删除指定用户的土地记录
@@ -189,10 +242,24 @@ class CUserSoilDB(CSqlManager):
"""
async with cls._transaction():
await cls.m_pDB.execute(
"DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?",
(uid, soilIndex)
"DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex)
)
@classmethod
async def _deleteUserSoil(cls, uid: str, soilIndex: int):
"""删除指定用户的土地记录
Args:
uid (str): 用户ID
soilIndex (int): 土地索引
Returns:
None
"""
await cls.m_pDB.execute(
"DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex)
)
@classmethod
async def isSoilPlanted(cls, uid: str, soilIndex: int) -> bool:
"""判断指定用户的指定土地是否已种植
@@ -240,22 +307,24 @@ class CUserSoilDB(CSqlManager):
async with cls._transaction():
# 复用原有记录字段,保留土壤状态等信息
prev = soilRecord or {}
await cls.deleteUserSoil(uid, soilIndex)
await cls.insertUserSoil({
"uid": uid,
"soilIndex": soilIndex,
"plantName": plantName,
"plantTime": nowTs,
"matureTime": matureTs,
# 保留之前的土壤等级和状态字段,避免数据丢失
"soilLevel": prev.get("soilLevel", 0),
"wiltStatus": prev.get("wiltStatus", 0),
"fertilizerStatus": prev.get("fertilizerStatus", 0),
"bugStatus": prev.get("bugStatus", 0),
"weedStatus": prev.get("weedStatus", 0),
"waterStatus": prev.get("waterStatus", 0)
})
await cls._deleteUserSoil(uid, soilIndex)
await cls._insertUserSoil(
{
"uid": uid,
"soilIndex": soilIndex,
"plantName": plantName,
"plantTime": nowTs,
"matureTime": matureTs,
# 保留之前的土壤等级和状态字段,避免数据丢失
"soilLevel": prev.get("soilLevel", 0),
"wiltStatus": prev.get("wiltStatus", 0),
"fertilizerStatus": prev.get("fertilizerStatus", 0),
"bugStatus": prev.get("bugStatus", 0),
"weedStatus": prev.get("weedStatus", 0),
"waterStatus": prev.get("waterStatus", 0),
}
)
return True
except Exception as e:
logger.error(f"真寻农场播种失败!", e=e)
logger.error(f"播种失败!", e=e)
return False
+2 -2
View File
@@ -1,7 +1,7 @@
from database import CSqlManager
from zhenxun.services.log import logger
from .database import CSqlManager
class CUserStealDB(CSqlManager):
@classmethod