first init

This commit is contained in:
xingc
2025-02-18 14:26:47 +08:00
commit 48a02974fc
41 changed files with 2297 additions and 0 deletions

185
core/db/crud.py Normal file
View File

@@ -0,0 +1,185 @@
# -*- coding = utf-8 -*-
# @Time : 2025/2/13 下午12:18
# @File : crud.py
# @Software : PyCharm
# @Author : xingc
# @Desc :
from datetime import datetime
from typing import List, Optional, Union, NewType, Dict, Any, Tuple
from sqlalchemy import func, desc
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from .models import User, Card, SearchCardCache
Model = NewType('Model', Union[User, Card, SearchCardCache])
class CRUD:
def __init__(self, session: AsyncSession, model: Model):
self.session = session
self.model = model
async def get(self, filters: dict) -> Optional[Model]:
async with self.session.begin():
result = await self.session.execute(select(self.model).filter(
*self.build_filter_conditions(filters))
)
record = result.scalar_one_or_none()
return record
async def get_paginated(self, filters: dict, page: int = 1, page_size: int = 10) -> Tuple[List[Model], int]:
async with self.session.begin():
filter_conditions = self.build_filter_conditions(filters) if filters else []
query = select(self.model).filter(*filter_conditions).order_by(desc(self.model.insert_time))
total_query = select(func.count()).select_from(self.model).filter(*filter_conditions)
total_result = await self.session.execute(total_query)
total = total_result.scalar()
query = query.limit(page_size).offset((page - 1) * page_size)
result = await self.session.execute(query)
records = result.scalars().all()
return records, total
async def get_grouped_count(self, group_by_field: str, filters: Dict[str, Any] = None) -> Dict[Any, int]:
# 构建过滤条件
filter_conditions = self.build_filter_conditions(filters) if filters else []
# 确定分组字段
group_by = getattr(self.model, group_by_field)
# 构建查询
query = select(group_by, func.count()).filter(*filter_conditions).group_by(group_by)
# 执行查询并获取结果
async with self.session.begin():
result = await self.session.execute(query)
records = result.all()
return {record[0]: record[1] for record in records}
async def create(self, data: dict, filters: dict) -> Union[Model, bool]:
async with self.session.begin():
result = await self.session.execute(select(self.model).filter(
*self.build_filter_conditions(filters))
)
if result.scalars().first() is not None:
return False
record = self.model(**data)
self.session.add(record)
await self.session.commit()
return record
async def get_all(self, filters: dict = None) -> List[Model]:
async with self.session.begin():
result = await self.session.execute(
select(self.model) if filters is None else select(self.model).filter(
*self.build_filter_conditions(filters)).order_by(desc(self.model.insert_time))
)
records = result.scalars().all()
return records
async def update(self, data: dict, filters: dict) -> Optional[Model]:
async with self.session.begin():
result = await self.session.execute(select(self.model).filter(
*self.build_filter_conditions(filters))
)
record = result.scalars().first()
if not record:
return None
count = 0
for key, value in data.items():
if any([
value is None,
value == getattr(record, key),
key in ['insert_time', 'update_time']
]):
continue
setattr(record, key, value)
count += 1
if count > 0:
await self.session.commit()
return record
async def updates(self, data: dict, filters: dict) -> Optional[Model]:
async with self.session.begin():
result = await self.session.execute(select(self.model).filter(
*self.build_filter_conditions(filters))
)
records = result.scalars().all()
if len(records) == 0:
return None
count = 0
for record in records:
for key, value in data.items():
if any([
value is None,
value == getattr(record, key),
key in ['insert_time', 'update_time']
]):
continue
setattr(record, key, value)
count += 1
if count > 0:
await self.session.commit()
return records
async def delete(self, filters: dict) -> bool:
async with self.session.begin():
result = await self.session.execute(select(self.model).filter(
*self.build_filter_conditions(filters))
)
record = result.scalars().first()
if not record:
return False
await self.session.delete(record)
await self.session.commit()
return True
def build_filter_conditions(self, filters: Dict[str, Any]) -> tuple:
conditions = []
for key, value in filters.items():
if any([
value is None,
value == '',
]):
continue
if isinstance(value, datetime) and value.tzinfo is not None:
value = value.astimezone()
# 解析字段名和操作符
field_name, operator = key, None
if '__' in key:
field_name, operator = key.split('__', 1)
else:
field_name = key
field = getattr(self.model, field_name)
if operator == 'like': # 模糊匹配
conditions.append(field.like(f'%{value}%'))
elif operator == 'gt': # 大于
conditions.append(field > value)
elif operator == 'lt': # 小于
conditions.append(field < value)
elif operator == 'eq': # 等于
conditions.append(field == value)
elif operator == 'ne': # 不等于
conditions.append(field != value)
elif operator == 'in': # 在集合中
conditions.append(field.in_(value))
else:
# 如果没有匹配的操作符,默认为等于
conditions.append(field == value)
return tuple(conditions)