feat(all): 同步最新进度
This commit is contained in:
@@ -21,20 +21,24 @@ class CRUD:
|
||||
self.session = session
|
||||
self.model = model
|
||||
|
||||
async def get(self, filters: dict) -> Optional[Model]:
|
||||
async def get(self, filters: dict, model: Model = None) -> Optional[Model]:
|
||||
model = model or self.model
|
||||
async with self.session.begin():
|
||||
result = await self.session.execute(select(self.model).filter(
|
||||
*self.build_filter_conditions(filters))
|
||||
result = await self.session.execute(select(model).filter(
|
||||
*self.build_filter_conditions(filters, model))
|
||||
)
|
||||
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 def get_paginated(
|
||||
self, filters: dict, page: int = 1, page_size: int = 10, model: Model = None
|
||||
) -> Tuple[List[Model], int]:
|
||||
model = model or self.model
|
||||
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.created_at))
|
||||
query = select(model).filter(*filter_conditions).order_by(desc(model.created_at))
|
||||
|
||||
total_query = select(func.count()).select_from(self.model).filter(*filter_conditions)
|
||||
total_query = select(func.count()).select_from(model).filter(*filter_conditions)
|
||||
total_result = await self.session.execute(total_query)
|
||||
total = total_result.scalar()
|
||||
|
||||
@@ -44,9 +48,12 @@ class CRUD:
|
||||
|
||||
return records, total
|
||||
|
||||
async def get_grouped_count(self, group_by_field: str, filters: Dict[str, Any] = None) -> Dict[Any, int]:
|
||||
async def get_grouped_count(
|
||||
self, group_by_field: str, filters: Dict[str, Any] = None, model: Model = None
|
||||
) -> Dict[Any, int]:
|
||||
model = model or self.model
|
||||
filter_conditions = self.build_filter_conditions(filters) if filters else []
|
||||
group_by = getattr(self.model, group_by_field)
|
||||
group_by = getattr(model, group_by_field)
|
||||
query = select(group_by, func.count()).filter(*filter_conditions).group_by(group_by)
|
||||
|
||||
async with self.session.begin():
|
||||
@@ -55,32 +62,35 @@ class CRUD:
|
||||
|
||||
return {record[0]: record[1] for record in records}
|
||||
|
||||
async def create(self, data: dict, filters: dict) -> Union[Model, bool]:
|
||||
async def create(self, data: dict, filters: dict, model: Model = None) -> Union[Model, bool]:
|
||||
model = model or self.model
|
||||
async with self.session.begin():
|
||||
result = await self.session.execute(select(self.model).filter(
|
||||
*self.build_filter_conditions(filters))
|
||||
result = await self.session.execute(select(model).filter(
|
||||
*self.build_filter_conditions(filters, model))
|
||||
)
|
||||
if result.scalars().first() is not None:
|
||||
return False
|
||||
|
||||
record = self.model(**data)
|
||||
record = model(**data)
|
||||
self.session.add(record)
|
||||
await self.session.commit()
|
||||
return record
|
||||
|
||||
async def get_all(self, filters: dict = None) -> List[Model]:
|
||||
async def get_all(self, filters: dict = None, model: Model = None) -> List[Model]:
|
||||
model = model or self.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))
|
||||
select(model) if filters is None else select(model).filter(
|
||||
*self.build_filter_conditions(filters, model)).order_by(desc(model.insert_time))
|
||||
)
|
||||
records = result.scalars().all()
|
||||
return records
|
||||
|
||||
async def update(self, data: dict, filters: dict) -> Optional[Model]:
|
||||
async def update(self, data: dict, filters: dict, model: Model = None) -> Optional[Model]:
|
||||
model = model or self.model
|
||||
async with self.session.begin():
|
||||
result = await self.session.execute(select(self.model).filter(
|
||||
*self.build_filter_conditions(filters))
|
||||
result = await self.session.execute(select(model).filter(
|
||||
*self.build_filter_conditions(filters, model))
|
||||
)
|
||||
record = result.scalars().first()
|
||||
|
||||
@@ -101,10 +111,11 @@ class CRUD:
|
||||
await self.session.commit()
|
||||
return record
|
||||
|
||||
async def updates(self, data: dict, filters: dict) -> Optional[Model]:
|
||||
async def updates(self, data: dict, filters: dict, model: Model = None) -> Optional[Model]:
|
||||
model = model or self.model
|
||||
async with self.session.begin():
|
||||
result = await self.session.execute(select(self.model).filter(
|
||||
*self.build_filter_conditions(filters))
|
||||
result = await self.session.execute(select(model).filter(
|
||||
*self.build_filter_conditions(filters, model))
|
||||
)
|
||||
records = result.scalars().all()
|
||||
|
||||
@@ -125,10 +136,11 @@ class CRUD:
|
||||
await self.session.commit()
|
||||
return records
|
||||
|
||||
async def delete(self, filters: dict) -> bool:
|
||||
async def delete(self, filters: dict, model: Model = None) -> bool:
|
||||
model = model or self.model
|
||||
async with self.session.begin():
|
||||
result = await self.session.execute(select(self.model).filter(
|
||||
*self.build_filter_conditions(filters))
|
||||
result = await self.session.execute(select(model).filter(
|
||||
*self.build_filter_conditions(filters, model))
|
||||
)
|
||||
record = result.scalars().first()
|
||||
|
||||
@@ -139,7 +151,7 @@ class CRUD:
|
||||
await self.session.commit()
|
||||
return True
|
||||
|
||||
def build_filter_conditions(self, filters: Dict[str, Any]) -> tuple:
|
||||
def build_filter_conditions(self, filters: Dict[str, Any], model: Model) -> tuple:
|
||||
conditions = []
|
||||
|
||||
for key, value in filters.items():
|
||||
@@ -158,7 +170,7 @@ class CRUD:
|
||||
else:
|
||||
field_name = key
|
||||
|
||||
field = getattr(self.model, field_name)
|
||||
field = getattr(model, field_name)
|
||||
|
||||
if operator == 'like': # 模糊匹配
|
||||
conditions.append(field.like(f'%{value}%'))
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
# @Author : xingc
|
||||
# @Desc :
|
||||
import enum
|
||||
import random
|
||||
import uuid
|
||||
from datetime import datetime, date
|
||||
from typing import List
|
||||
|
||||
import ujson
|
||||
from sqlalchemy import (
|
||||
Column, Integer, String, Text, Date,
|
||||
ForeignKey, DECIMAL, CheckConstraint,
|
||||
UniqueConstraint, Index, Sequence, JSON, UUID, Enum, Boolean
|
||||
UniqueConstraint, Index, Sequence, JSON, Enum, Boolean, UUID, Table
|
||||
)
|
||||
from sqlalchemy.orm import (
|
||||
DeclarativeBase, Mapped, mapped_column, relationship
|
||||
@@ -57,10 +57,11 @@ class DateModel:
|
||||
class User(BaseModel, DateModel):
|
||||
__tablename__ = 'system_users'
|
||||
__table_args__ = (
|
||||
Index('wechat_openid', 'wechat_openid'),
|
||||
Index('idx_wechat_openid', 'wechat_openid'),
|
||||
UniqueConstraint('user_id', name='uniq_user_id'),
|
||||
{'comment': '用户表'}
|
||||
)
|
||||
|
||||
id = None
|
||||
user_id: Mapped[int] = mapped_column(
|
||||
Integer, Sequence('non_primary_id_seq', start=100000, increment=1), primary_key=True, autoincrement=True,
|
||||
@@ -75,22 +76,28 @@ class User(BaseModel, DateModel):
|
||||
vip_expire_date: Mapped[date] = mapped_column(Date, default=datetime.now().date, comment='会员到期时间')
|
||||
points: Mapped[int] = mapped_column(Integer, default=0, comment='会员积分')
|
||||
|
||||
collections: Mapped[list["UserCollection"]] = relationship(
|
||||
back_populates="user",
|
||||
cascade="all, delete-orphan"
|
||||
collections: Mapped[list['UserCollection']] = relationship(
|
||||
back_populates='user',
|
||||
cascade='all, delete-orphan'
|
||||
)
|
||||
# 关注者
|
||||
following: Mapped[list["UserFollows"]] = relationship(
|
||||
following: Mapped[list['UserFollows']] = relationship(
|
||||
'UserFollows',
|
||||
foreign_keys='UserFollows.follower_id',
|
||||
cascade="all, delete-orphan"
|
||||
cascade='all, delete-orphan'
|
||||
)
|
||||
# 定义被关注关系
|
||||
followers: Mapped[list["UserFollows"]] = relationship(
|
||||
followers: Mapped[list['UserFollows']] = relationship(
|
||||
'UserFollows',
|
||||
foreign_keys='UserFollows.followed_id',
|
||||
cascade="all, delete-orphan"
|
||||
cascade='all, delete-orphan'
|
||||
)
|
||||
chats: Mapped[List['Chat']] = relationship(secondary='chat_participant', back_populates='users')
|
||||
messages: Mapped[List['Message']] = relationship(back_populates='user')
|
||||
read_statuses: Mapped[List['ReadStatus']] = relationship(back_populates='user')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.user_id}'
|
||||
|
||||
|
||||
class UserFollows(BaseModel, DateModel):
|
||||
@@ -100,24 +107,23 @@ class UserFollows(BaseModel, DateModel):
|
||||
)
|
||||
|
||||
follower_id: Mapped[int] = mapped_column(
|
||||
Integer, ForeignKey('system_users.user_id', ondelete="CASCADE"), comment='关注者的用户id'
|
||||
Integer, ForeignKey('system_users.user_id', ondelete='CASCADE'), comment='关注者的用户id'
|
||||
)
|
||||
followed_id: Mapped[int] = mapped_column(
|
||||
Integer, ForeignKey('system_users.user_id', ondelete="CASCADE"), comment='被关注者的用户id'
|
||||
Integer, ForeignKey('system_users.user_id', ondelete='CASCADE'), comment='被关注者的用户id'
|
||||
)
|
||||
updated_at = None
|
||||
|
||||
follower = relationship('User', foreign_keys=[follower_id], back_populates='following')
|
||||
followed = relationship('User', foreign_keys=[followed_id], back_populates='followers')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<UserFollows(follower_id={self.follower_id}, followed_id={self.followed_id})>"
|
||||
return f'<UserFollows(follower_id={self.follower_id}, followed_id={self.followed_id})>'
|
||||
|
||||
|
||||
class Card(BaseModel, DateModel):
|
||||
__tablename__ = 'system_cards'
|
||||
__table_args__ = (
|
||||
Index('cert_number_category_source', 'cert_number', 'category', 'source'),
|
||||
Index('idx_cert_number_category_source', 'cert_number', 'category', 'source'),
|
||||
{'comment': '卡片表'}
|
||||
)
|
||||
|
||||
@@ -129,28 +135,28 @@ class Card(BaseModel, DateModel):
|
||||
card_name: Mapped[str] = mapped_column(String(225), nullable=True, comment='卡片名称')
|
||||
card_number: Mapped[str] = mapped_column(String(225), nullable=True, comment='卡片编号')
|
||||
card_type: Mapped[str] = mapped_column(String(20), nullable=True, comment='卡片类型')
|
||||
card_picture: Mapped[dict] = mapped_column(JSON, default=dict, comment='卡片正、反图片(本地)')
|
||||
card_spare_picture: Mapped[dict] = mapped_column(JSON, default=dict, comment='卡片正、反图片(远程)')
|
||||
card_picture: Mapped[dict] = mapped_column(JSON, default=lambda: dict(), comment='卡片正、反图片(本地)')
|
||||
card_spare_picture: Mapped[dict] = mapped_column(JSON, default=lambda: dict(), comment='卡片正、反图片(远程)')
|
||||
create_user_id: Mapped[int] = mapped_column(Integer, nullable=True, comment='创建者')
|
||||
perfect_user_id: Mapped[int] = mapped_column(Integer, nullable=True, comment='完善者')
|
||||
|
||||
category: Mapped[str] = mapped_column(
|
||||
Enum(base_schema.CardCategoryType, inherit_schema=True),
|
||||
nullable=True, default=base_schema.CardCategoryType.OTHER, comment='卡片分类'
|
||||
nullable=True, server_default=base_schema.CardCategoryType.OTHER.value, comment='卡片分类'
|
||||
)
|
||||
source: Mapped[str] = mapped_column(
|
||||
Enum(base_schema.PlatformSourceType, inherit_schema=True),
|
||||
comment='来源,PSA、BGS、CGC、GBTC、CCG、BCTC :采集 、OTHER:自定义'
|
||||
)
|
||||
|
||||
collections: Mapped[list["UserCollection"]] = relationship(
|
||||
back_populates="card",
|
||||
cascade="all, delete-orphan"
|
||||
collections: Mapped[list['UserCollection']] = relationship(
|
||||
back_populates='card',
|
||||
cascade='all, delete-orphan'
|
||||
)
|
||||
|
||||
|
||||
class UserCollection(BaseModel, DateModel):
|
||||
__tablename__ = "system_user_collections"
|
||||
__tablename__ = 'system_user_collections'
|
||||
__table_args__ = (
|
||||
UniqueConstraint('user_id', 'card_id', name='uniq_user_card'),
|
||||
CheckConstraint('purchase_price >= 0', name='check_purchase_price'),
|
||||
@@ -175,16 +181,15 @@ class UserCollection(BaseModel, DateModel):
|
||||
displayed: Mapped[bool] = mapped_column(
|
||||
Boolean, default=True
|
||||
)
|
||||
updated_at = None
|
||||
|
||||
user: Mapped["User"] = relationship(back_populates='collections')
|
||||
card: Mapped["Card"] = relationship(back_populates='collections')
|
||||
user: Mapped['User'] = relationship(back_populates='collections')
|
||||
card: Mapped['Card'] = relationship(back_populates='collections')
|
||||
|
||||
|
||||
class SearchCardCache(BaseModel, DateModel):
|
||||
__tablename__ = 'system_cache_cards'
|
||||
__table_args__ = (
|
||||
Index('cert_and_card_number_source', 'cert_number', 'source'),
|
||||
Index('idx_cert_and_card_number_source', 'cert_number', 'source'),
|
||||
{'comment': '搜索卡片信息缓存表'}
|
||||
)
|
||||
|
||||
@@ -196,38 +201,105 @@ class SearchCardCache(BaseModel, DateModel):
|
||||
comment='数据来源:PSA、BGS、CGC、GBTC、CCG、BCTC'
|
||||
)
|
||||
|
||||
# class Product(BaseModel, DateModel):
|
||||
# __tablename__ = 'system_products'
|
||||
# __table_args__ = {'comment': '产品信息表'}
|
||||
#
|
||||
# name: Mapped[str] = mapped_column(String(50), comment='产品名')
|
||||
# price: Mapped[float] = mapped_column(DECIMAL(10, 2), comment='价格')
|
||||
# action: Mapped[str] = mapped_column(String(10), comment='付款后的动作,会员续期:vip_renewal 积分:recharge_points')
|
||||
# number: Mapped[int] = mapped_column(Integer, comment='执行动作的增量值')
|
||||
# description: Mapped[str] = mapped_column(Text, comment='商品描述')
|
||||
#
|
||||
#
|
||||
# class Order(BaseModel, DateModel):
|
||||
# __tablename__ = 'system_orders'
|
||||
# __table_args__ = {'comment': '产品信息表'}
|
||||
#
|
||||
# order_id: Mapped[int] = mapped_column(String(20), comment='订单id')
|
||||
# user_id: Mapped[int] = mapped_column(Integer, comment='用户id')
|
||||
# product_id: Mapped[int] = mapped_column(Integer, comment='产品id')
|
||||
# price: Mapped[float] = mapped_column(DECIMAL(10, 2), comment='价格')
|
||||
# pay_url: Mapped[str] = mapped_column(String(255), comment='支付地址')
|
||||
# status: Mapped[int] = mapped_column(Integer, comment='订单状态,-1:初始化 0:失败 1:完成 2:待支付')
|
||||
|
||||
#
|
||||
# class Message(BaseModel, DateModel):
|
||||
# __tablename__ = 'system_messages'
|
||||
# __table_args__ = {'comment': '聊天消息表'}
|
||||
#
|
||||
# guid: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), default=uuid.uuid4)
|
||||
# message_type: Mapped[str] = mapped_column(
|
||||
# Enum(base_schema.MessageType, inherit_schema=True), default=base_schema.MessageType.TEXT
|
||||
# )
|
||||
# content: Mapped[str] = mapped_column(String(5000), comment='文本消息')
|
||||
# send_timestamp: Mapped[int] = mapped_column(Integer, comment='发送时间')
|
||||
#
|
||||
# user: Mapped["User"] = relationship(back_populates="system_messages")
|
||||
class Product(BaseModel, DateModel):
|
||||
__tablename__ = 'system_products'
|
||||
__table_args__ = {'comment': '产品信息表'}
|
||||
|
||||
name: Mapped[str] = mapped_column(String(20), comment='产品名')
|
||||
category: Mapped[str] = mapped_column(
|
||||
Enum(base_schema.ProductCategory, inherit_schema=True), comment='商品分类, vip-会员服务 points-积分服务'
|
||||
)
|
||||
price: Mapped[int] = mapped_column(Integer, comment='价格,不带小数点 单位为分')
|
||||
action: Mapped[str] = mapped_column(String(10), comment='付款后的动作,会员续期:vip_renewal 积分:recharge_points')
|
||||
number: Mapped[int] = mapped_column(Integer, comment='执行动作的增量值')
|
||||
description: Mapped[str] = mapped_column(Text, nullable=True, comment='商品描述')
|
||||
|
||||
|
||||
class Order(BaseModel, DateModel):
|
||||
__tablename__ = 'system_orders'
|
||||
__table_args__ = (
|
||||
Index('idx_order_on_order_id', 'order_id'),
|
||||
{'comment': '产品订单表'}
|
||||
)
|
||||
|
||||
order_id: Mapped[str] = mapped_column(String(32), comment='订单id')
|
||||
transaction_id: Mapped[str] = mapped_column(String(32), nullable=True, comment='微信订单id')
|
||||
user_id: Mapped[int] = mapped_column(Integer, comment='用户id')
|
||||
product_id: Mapped[int] = mapped_column(Integer, comment='产品id')
|
||||
total_fee: Mapped[int] = mapped_column(Integer, nullable=True, comment='发起的总金额,单位为分')
|
||||
notify_total_fee: Mapped[int] = mapped_column(Integer, nullable=True, comment='回调成功支付的总金额,单位为分')
|
||||
pay_url: Mapped[str] = mapped_column(String(255), nullable=True, comment='支付地址')
|
||||
status: Mapped[str] = mapped_column(
|
||||
Enum(base_schema.OrderStatusType, inherit_schema=True),
|
||||
server_default=base_schema.OrderStatusType.INIT.value,
|
||||
comment='订单状态,init:初始化 fail:失败 ok:完成 wait payment:待支付 cancel. 取消'
|
||||
)
|
||||
|
||||
|
||||
class Chat(BaseModel, DateModel):
|
||||
__tablename__ = 'system_chats'
|
||||
__table_args__ = (
|
||||
Index('idx_chat_on_guid', 'guid'),
|
||||
{'comment': '聊天表'}
|
||||
)
|
||||
|
||||
guid: Mapped[uuid.UUID] = mapped_column(String(36), nullable=True, default=lambda: str(uuid.uuid4()))
|
||||
|
||||
users: Mapped[List['User']] = relationship(secondary='chat_participant', back_populates='chats')
|
||||
messages: Mapped[List['Message']] = relationship(back_populates='chat', cascade='all,delete')
|
||||
is_deleted: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
read_statuses: Mapped[List['ReadStatus']] = relationship(back_populates='chat', cascade='all,delete')
|
||||
|
||||
|
||||
class Message(BaseModel, DateModel):
|
||||
__tablename__ = 'system_messages'
|
||||
__table_args__ = (
|
||||
Index('idx_message_on_user_id', 'user_id'),
|
||||
Index('idx_message_on_chat_id', 'chat_id'),
|
||||
Index('idx_message_on_user_id_chat_id', 'chat_id', 'user_id'),
|
||||
{'comment': '聊天消息表'}
|
||||
)
|
||||
|
||||
guid: Mapped[uuid.UUID] = mapped_column(String(36), nullable=True, default=lambda: str(uuid.uuid4()))
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey('system_users.user_id'))
|
||||
chat_id: Mapped[int] = mapped_column(ForeignKey('system_chats.id'))
|
||||
|
||||
message_type: Mapped[str] = mapped_column(
|
||||
Enum(base_schema.MessageType, inherit_schema=True), default=base_schema.MessageType.TEXT
|
||||
)
|
||||
content: Mapped[str] = mapped_column(String(5000), nullable=True, comment='文本消息')
|
||||
|
||||
chat: Mapped['Chat'] = relationship(back_populates='messages')
|
||||
user: Mapped['User'] = relationship(back_populates='messages')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.content}'
|
||||
|
||||
|
||||
class ReadStatus(BaseModel, DateModel):
|
||||
__tablename__ = 'system_read_status'
|
||||
__table_args__ = (
|
||||
Index('idx_read_status_on_chat_id', 'chat_id'),
|
||||
Index('idx_read_status_on_user_id', 'user_id'),
|
||||
{'comment': '聊天消息读取状态表'}
|
||||
)
|
||||
|
||||
last_read_message_id: Mapped[int] = mapped_column(nullable=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey('system_users.user_id'))
|
||||
chat_id: Mapped[int] = mapped_column(ForeignKey('system_chats.id'))
|
||||
|
||||
chat: Mapped['Chat'] = relationship(back_populates='read_statuses')
|
||||
user: Mapped['User'] = relationship(back_populates='read_statuses')
|
||||
|
||||
def __str__(self):
|
||||
return f'User: {self.user_id}, Message: {self.last_read_message_id}'
|
||||
|
||||
|
||||
chat_participant = Table(
|
||||
'chat_participant',
|
||||
BaseModel.metadata,
|
||||
Column('user_id', Integer, ForeignKey('system_users.user_id'), primary_key=True),
|
||||
Column('chat_id', Integer, ForeignKey('system_chats.id'), primary_key=True),
|
||||
comment='聊天参与者关联表'
|
||||
)
|
||||
Reference in New Issue
Block a user