From 8f27794da6179f6b734cb3e4d586e9021c03d03a Mon Sep 17 00:00:00 2001 From: GinHa <15201596918@163.com> Date: Wed, 3 Jun 2026 14:15:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dscalar=5Fone=5For=5Fnone?= =?UTF-8?q?=E7=9B=B8=E5=85=B3limit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- video-gen-api/app/api/v1/admin.py | 38 ++++++++++--------- video-gen-api/app/api/v1/auth.py | 4 +- video-gen-api/app/api/v1/generation.py | 4 ++ video-gen-api/app/api/v1/generation_ai.py | 3 ++ video-gen-api/app/api/v1/menu_configs.py | 4 +- video-gen-api/app/api/v1/payments.py | 5 ++- video-gen-api/app/api/v1/projects.py | 1 + video-gen-api/app/api/v1/recharge_packages.py | 4 +- video-gen-api/app/dependencies.py | 2 +- video-gen-api/app/main.py | 14 ++++--- video-gen-api/app/services/auth.py | 4 +- video-gen-api/app/services/credits.py | 8 ++-- .../app/services/generation_ai_service.py | 4 +- .../services/generation_billing_service.py | 2 +- .../services/generation_provider_service.py | 4 +- video-gen-api/app/services/llm.py | 2 +- video-gen-api/app/services/notification.py | 3 +- video-gen-api/app/services/payment.py | 2 +- .../services/resource_accounting_service.py | 3 +- video-gen-api/app/services/video_queue.py | 1 + video-gen-api/app/services/video_url.py | 1 + .../app/tasks/generation_create_tasks.py | 4 +- .../app/tasks/generation_download_tasks.py | 4 +- .../app/tasks/generation_poll_tasks.py | 4 +- 24 files changed, 73 insertions(+), 52 deletions(-) diff --git a/video-gen-api/app/api/v1/admin.py b/video-gen-api/app/api/v1/admin.py index acf799f8..26ca72ae 100644 --- a/video-gen-api/app/api/v1/admin.py +++ b/video-gen-api/app/api/v1/admin.py @@ -97,18 +97,18 @@ async def create_user( if req.user_type == "frontend": if not req.phone: raise HTTPException(status_code=400, detail="前台用户必须填写手机号") - existing_phone = await db.execute(select(User).where(User.phone == req.phone)) + existing_phone = await db.execute(select(User).where(User.phone == req.phone).limit(1)) if existing_phone.scalar_one_or_none(): raise HTTPException(status_code=400, detail="该手机号已注册") username = f"用户{req.phone[-4:]}" - existing_name = await db.execute(select(User).where(User.username == username)) + existing_name = await db.execute(select(User).where(User.username == username).limit(1)) if existing_name.scalar_one_or_none(): username = f"用户{req.phone[-4:]}{random.randint(10, 99)}" else: if not req.username: raise HTTPException(status_code=400, detail="后台用户必须填写用户名") username = req.username - existing = await db.execute(select(User).where(User.username == username)) + existing = await db.execute(select(User).where(User.username == username).limit(1)) if existing.scalar_one_or_none(): raise HTTPException(status_code=400, detail="用户名已存在") @@ -137,7 +137,7 @@ async def update_user_menus( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): - result = await db.execute(select(User).where(User.id == user_id)) + result = await db.execute(select(User).where(User.id == user_id).limit(1)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="用户不存在") @@ -153,7 +153,7 @@ async def get_user( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): - result = await db.execute(select(User).where(User.id == user_id)) + result = await db.execute(select(User).where(User.id == user_id).limit(1)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="用户不存在") @@ -204,7 +204,7 @@ async def reset_user_password( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): - result = await db.execute(select(User).where(User.id == user_id)) + result = await db.execute(select(User).where(User.id == user_id).limit(1)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="用户不存在") @@ -356,7 +356,7 @@ async def delete_admin_notification( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(Notification).where(Notification.id == notification_id) + select(Notification).where(Notification.id == notification_id).limit(1) ) notif = result.scalar_one_or_none() if not notif: @@ -418,6 +418,7 @@ async def update_payment_config( SystemConfig.id == config_id, SystemConfig.key.like("payment_%"), ) + .limit(1) ) config = result.scalar_one_or_none() if not config: @@ -497,7 +498,7 @@ async def update_industry_config( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(IndustryConfig).where(IndustryConfig.id == config_id) + select(IndustryConfig).where(IndustryConfig.id == config_id).limit(1) ) config = result.scalar_one_or_none() if not config: @@ -520,7 +521,7 @@ async def delete_industry_config( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(IndustryConfig).where(IndustryConfig.id == config_id) + select(IndustryConfig).where(IndustryConfig.id == config_id).limit(1) ) config = result.scalar_one_or_none() if not config: @@ -563,7 +564,7 @@ async def update_video_engine( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(VideoEngine).where(VideoEngine.id == engine_id) + select(VideoEngine).where(VideoEngine.id == engine_id).limit(1) ) engine = result.scalar_one_or_none() if not engine: @@ -581,7 +582,7 @@ async def delete_video_engine( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(VideoEngine).where(VideoEngine.id == engine_id) + select(VideoEngine).where(VideoEngine.id == engine_id).limit(1) ) engine = result.scalar_one_or_none() if not engine: @@ -624,7 +625,7 @@ async def update_image_engine( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(ImageEngine).where(ImageEngine.id == engine_id) + select(ImageEngine).where(ImageEngine.id == engine_id).limit(1) ) engine = result.scalar_one_or_none() if not engine: @@ -642,7 +643,7 @@ async def delete_image_engine( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(ImageEngine).where(ImageEngine.id == engine_id) + select(ImageEngine).where(ImageEngine.id == engine_id).limit(1) ) engine = result.scalar_one_or_none() if not engine: @@ -711,7 +712,7 @@ async def update_credit_ratio( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(CreditRatio).where(CreditRatio.id == ratio_id) + select(CreditRatio).where(CreditRatio.id == ratio_id).limit(1) ) ratio = result.scalar_one_or_none() if not ratio: @@ -733,7 +734,7 @@ async def delete_credit_ratio( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(CreditRatio).where(CreditRatio.id == ratio_id) + select(CreditRatio).where(CreditRatio.id == ratio_id).limit(1) ) ratio = result.scalar_one_or_none() if not ratio: @@ -790,7 +791,7 @@ async def update_model_config( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): - result = await db.execute(select(ModelConfig).where(ModelConfig.id == config_id)) + result = await db.execute(select(ModelConfig).where(ModelConfig.id == config_id).limit(1)) config = result.scalar_one_or_none() if not config: raise HTTPException(status_code=404, detail="配置不存在") @@ -806,7 +807,7 @@ async def delete_model_config( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): - result = await db.execute(select(ModelConfig).where(ModelConfig.id == config_id)) + result = await db.execute(select(ModelConfig).where(ModelConfig.id == config_id).limit(1)) config = result.scalar_one_or_none() if not config: raise HTTPException(status_code=404, detail="配置不存在") @@ -833,7 +834,7 @@ async def update_system_config( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): - result = await db.execute(select(SystemConfig).where(SystemConfig.id == config_id)) + result = await db.execute(select(SystemConfig).where(SystemConfig.id == config_id).limit(1)) config = result.scalar_one_or_none() if not config: raise HTTPException(status_code=404, detail="配置不存在") @@ -1053,6 +1054,7 @@ async def admin_update_generation_status( GenerationRecord.id == record_id, GenerationRecord.deleted_at.is_(None), ) + .limit(1) ) record = result.scalar_one_or_none() if not record: diff --git a/video-gen-api/app/api/v1/auth.py b/video-gen-api/app/api/v1/auth.py index 1cf8ca40..1f309877 100644 --- a/video-gen-api/app/api/v1/auth.py +++ b/video-gen-api/app/api/v1/auth.py @@ -78,7 +78,7 @@ async def register(req: RegisterRequest, db: AsyncSession = Depends(get_db)): ) # Check if phone already registered - existing = await db.execute(select(User).where(User.phone == req.phone)) + existing = await db.execute(select(User).where(User.phone == req.phone).limit(1)) if existing.scalar_one_or_none(): from fastapi import HTTPException, status raise HTTPException( @@ -89,7 +89,7 @@ async def register(req: RegisterRequest, db: AsyncSession = Depends(get_db)): # Create user with default username: 用户 + last 4 digits of phone import random username = f"用户{req.phone[-4:]}" - existing_name = await db.execute(select(User).where(User.username == username)) + existing_name = await db.execute(select(User).where(User.username == username).limit(1)) if existing_name.scalar_one_or_none(): username = f"用户{req.phone[-4:]}{random.randint(10, 99)}" diff --git a/video-gen-api/app/api/v1/generation.py b/video-gen-api/app/api/v1/generation.py index c796d196..b157217a 100644 --- a/video-gen-api/app/api/v1/generation.py +++ b/video-gen-api/app/api/v1/generation.py @@ -228,6 +228,7 @@ async def optimize( Project.user_id == current_user.id, Project.deleted_at.is_(None), ) + .limit(1) ) project = proj_result.scalar_one_or_none() if not project: @@ -460,6 +461,7 @@ async def update_prompt( GenerationRecord.user_id == current_user.id, GenerationRecord.deleted_at.is_(None), ) + .limit(1) ) record = result.scalar_one_or_none() if not record: @@ -505,6 +507,7 @@ async def get_queue_status( GenerationRecord.user_id == current_user.id, GenerationRecord.deleted_at.is_(None), ) + .limit(1) ) record = result.scalar_one_or_none() if not record: @@ -548,6 +551,7 @@ async def seedance_callback(request: Request, db: AsyncSession = Depends(get_db) GenerationRecord.seedance_task_id == task_id, GenerationRecord.deleted_at.is_(None), ) + .limit(1) ) record = result.scalar_one_or_none() if not record: diff --git a/video-gen-api/app/api/v1/generation_ai.py b/video-gen-api/app/api/v1/generation_ai.py index 4ead2651..1aaebcca 100644 --- a/video-gen-api/app/api/v1/generation_ai.py +++ b/video-gen-api/app/api/v1/generation_ai.py @@ -416,6 +416,7 @@ async def get_task( ChatGenerationTask.generation_mode == "chatapi_async", ChatGenerationTask.deleted_at.is_(None), ) + .limit(1) ) task = result.scalar_one_or_none() if not task: @@ -464,6 +465,7 @@ async def delete_task( ChatGenerationTask.generation_mode == "chatapi_async", ChatGenerationTask.deleted_at.is_(None), ) + .limit(1) ) task = result.scalar_one_or_none() if not task: @@ -536,6 +538,7 @@ async def retry_task( ChatGenerationTask.generation_mode == "chatapi_async", ChatGenerationTask.deleted_at.is_(None), ) + .limit(1) ) task = result.scalar_one_or_none() if not task: diff --git a/video-gen-api/app/api/v1/menu_configs.py b/video-gen-api/app/api/v1/menu_configs.py index 0950ce1a..44794a57 100644 --- a/video-gen-api/app/api/v1/menu_configs.py +++ b/video-gen-api/app/api/v1/menu_configs.py @@ -65,7 +65,7 @@ async def update_menu_config( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): - result = await db.execute(select(MenuConfig).where(MenuConfig.id == menu_id)) + result = await db.execute(select(MenuConfig).where(MenuConfig.id == menu_id).limit(1)) menu = result.scalar_one_or_none() if not menu: from fastapi import HTTPException, status @@ -82,7 +82,7 @@ async def delete_menu_config( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): - result = await db.execute(select(MenuConfig).where(MenuConfig.id == menu_id)) + result = await db.execute(select(MenuConfig).where(MenuConfig.id == menu_id).limit(1)) menu = result.scalar_one_or_none() if not menu: from fastapi import HTTPException, status diff --git a/video-gen-api/app/api/v1/payments.py b/video-gen-api/app/api/v1/payments.py index bbb76a30..6b2d8ca4 100644 --- a/video-gen-api/app/api/v1/payments.py +++ b/video-gen-api/app/api/v1/payments.py @@ -23,6 +23,7 @@ async def recharge( RechargePackage.id == req.plan, RechargePackage.is_active == True, ) + .limit(1) ) pkg = result.scalar_one_or_none() if not pkg: @@ -45,7 +46,7 @@ async def wechat_callback(request: Request, db: AsyncSession = Depends(get_db)): raise HTTPException(status_code=400, detail="签名验证失败") order_no = data.get("out_trade_no") result = await db.execute( - select(PaymentOrder).where(PaymentOrder.order_no == order_no) + select(PaymentOrder).where(PaymentOrder.order_no == order_no).limit(1) ) order = result.scalar_one_or_none() if order: @@ -60,7 +61,7 @@ async def alipay_callback(request: Request, db: AsyncSession = Depends(get_db)): raise HTTPException(status_code=400, detail="签名验证失败") order_no = data.get("out_trade_no") result = await db.execute( - select(PaymentOrder).where(PaymentOrder.order_no == order_no) + select(PaymentOrder).where(PaymentOrder.order_no == order_no).limit(1) ) order = result.scalar_one_or_none() if order: diff --git a/video-gen-api/app/api/v1/projects.py b/video-gen-api/app/api/v1/projects.py index c0244d8f..56473f5e 100644 --- a/video-gen-api/app/api/v1/projects.py +++ b/video-gen-api/app/api/v1/projects.py @@ -60,6 +60,7 @@ async def delete_project( Project.user_id == current_user.id, Project.deleted_at.is_(None), ) + .limit(1) ) project = result.scalar_one_or_none() if not project: diff --git a/video-gen-api/app/api/v1/recharge_packages.py b/video-gen-api/app/api/v1/recharge_packages.py index ba737efa..acc82560 100644 --- a/video-gen-api/app/api/v1/recharge_packages.py +++ b/video-gen-api/app/api/v1/recharge_packages.py @@ -77,7 +77,7 @@ async def update_package( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(RechargePackage).where(RechargePackage.id == pkg_id) + select(RechargePackage).where(RechargePackage.id == pkg_id).limit(1) ) pkg = result.scalar_one_or_none() if not pkg: @@ -95,7 +95,7 @@ async def delete_package( db: AsyncSession = Depends(get_db), ): result = await db.execute( - select(RechargePackage).where(RechargePackage.id == pkg_id) + select(RechargePackage).where(RechargePackage.id == pkg_id).limit(1) ) pkg = result.scalar_one_or_none() if not pkg: diff --git a/video-gen-api/app/dependencies.py b/video-gen-api/app/dependencies.py index 54a28b84..00a8eb2f 100644 --- a/video-gen-api/app/dependencies.py +++ b/video-gen-api/app/dependencies.py @@ -46,7 +46,7 @@ async def get_current_user( detail="无效的凭证", ) - result = await db.execute(select(User).where(User.id == user_id)) + result = await db.execute(select(User).where(User.id == user_id).limit(1)) user = result.scalar_one_or_none() if not user or not user.is_active: raise HTTPException( diff --git a/video-gen-api/app/main.py b/video-gen-api/app/main.py index 198c14e0..1ceeb94a 100644 --- a/video-gen-api/app/main.py +++ b/video-gen-api/app/main.py @@ -77,7 +77,7 @@ async def _seed_data(): db.add(admin_user) # Seed demo user - result = await db.execute(select(User).where(User.username == "demo")) + result = await db.execute(select(User).where(User.username == "demo").limit(1)) demo = result.scalar_one_or_none() if not demo: demo_user = User( @@ -114,7 +114,7 @@ async def _seed_data(): ] for key, value, desc in configs: existing = await db.execute( - select(SystemConfig).where(SystemConfig.key == key) + select(SystemConfig).where(SystemConfig.key == key).limit(1) ) if not existing.scalar_one_or_none(): db.add( @@ -290,7 +290,7 @@ async def _seed_data(): ] for path, label, icon, order, target in default_menus: existing = await db.execute( - select(MenuConfig).where(MenuConfig.path == path) + select(MenuConfig).where(MenuConfig.path == path).limit(1) ) if not existing.scalar_one_or_none(): db.add( @@ -320,6 +320,7 @@ async def _seed_data(): MenuConfig.menu_type == "group", MenuConfig.menu_target == "admin", ) + .limit(1) ) group = existing.scalar_one_or_none() if not group: @@ -364,6 +365,7 @@ async def _seed_data(): MenuConfig.path == path, MenuConfig.menu_target == "admin", ) + .limit(1) ) if not existing.scalar_one_or_none(): db.add( @@ -391,7 +393,7 @@ async def _seed_data(): ] for name, credits, price, bonus, desc, ptype, order in default_packages: existing = await db.execute( - select(RechargePackage).where(RechargePackage.name == name) + select(RechargePackage).where(RechargePackage.name == name).limit(1) ) if not existing.scalar_one_or_none(): db.add( @@ -418,7 +420,7 @@ async def _seed_data(): ] for key, label, icon, desc, order in default_industries: existing = await db.execute( - select(IndustryConfig).where(IndustryConfig.key == key) + select(IndustryConfig).where(IndustryConfig.key == key).limit(1) ) if not existing.scalar_one_or_none(): db.add( @@ -571,7 +573,7 @@ def create_app() -> FastAPI: # Update system config async with async_session() as db: result = await db.execute( - select(SystemConfig).where(SystemConfig.key == config_key) + select(SystemConfig).where(SystemConfig.key == config_key).limit(1) ) config = result.scalar_one_or_none() if config: diff --git a/video-gen-api/app/services/auth.py b/video-gen-api/app/services/auth.py index 9407aeb8..9f7d0b0b 100644 --- a/video-gen-api/app/services/auth.py +++ b/video-gen-api/app/services/auth.py @@ -38,11 +38,11 @@ def decode_access_token(token: str) -> str | None: async def authenticate_user( db: AsyncSession, username: str, password: str ) -> User | None: - result = await db.execute(select(User).where(User.username == username)) + result = await db.execute(select(User).where(User.username == username).limit(1)) user = result.scalar_one_or_none() if not user: # Try phone number lookup for frontend users - result = await db.execute(select(User).where(User.phone == username)) + result = await db.execute(select(User).where(User.phone == username).limit(1)) user = result.scalar_one_or_none() if not user or not verify_password(password, user.hashed_password): return None diff --git a/video-gen-api/app/services/credits.py b/video-gen-api/app/services/credits.py index 99c8ee0a..eab2e46f 100644 --- a/video-gen-api/app/services/credits.py +++ b/video-gen-api/app/services/credits.py @@ -16,7 +16,7 @@ from app.utils.exceptions import InsufficientCreditsError async def calc_text_credits(db: AsyncSession, input_tokens: int, output_tokens: int) -> float: """Calculate text credits based on actual token usage and configurable rate.""" result = await db.execute( - select(SystemConfig).where(SystemConfig.key == "text_credits_per_1000_tokens") + select(SystemConfig).where(SystemConfig.key == "text_credits_per_1000_tokens").limit(1) ) config = result.scalar_one_or_none() rate = float(config.value) if config else 1.0 @@ -78,6 +78,7 @@ async def calc_video_credits( select(VideoEngine.id) .where(VideoEngine.is_active == True) .order_by(VideoEngine.priority.desc()) + .limit(1) ) engine_id = video_engines_result.scalar_one_or_none() ratio = await _get_credit_ratio( @@ -122,6 +123,7 @@ async def calc_image_credits( select(ImageEngine.id) .where(ImageEngine.is_active == True) .order_by(ImageEngine.priority.desc()) + .limit(1) ) engine_id = image_engines_result.scalar_one_or_none() ratio = await _get_credit_ratio( @@ -148,7 +150,7 @@ async def deduct_credits( ) -> User: """Atomically deduct credits from user. Raises InsufficientCreditsError.""" result = await db.execute( - select(User).where(User.id == user_id) + select(User).where(User.id == user_id).limit(1) ) user = result.scalar_one_or_none() if not user or user.credits < amount: @@ -178,7 +180,7 @@ async def add_credits( ) -> User: """Add credits to user.""" result = await db.execute( - select(User).where(User.id == user_id) + select(User).where(User.id == user_id).limit(1) ) user = result.scalar_one_or_none() if not user: diff --git a/video-gen-api/app/services/generation_ai_service.py b/video-gen-api/app/services/generation_ai_service.py index a4edcd8b..3ceaed5a 100644 --- a/video-gen-api/app/services/generation_ai_service.py +++ b/video-gen-api/app/services/generation_ai_service.py @@ -78,7 +78,9 @@ async def _get_video_engine(db: AsyncSession, engine_id: str | None) -> VideoEng if engine_id: query = query.where(VideoEngine.id == engine_id) else: - query = query.order_by(VideoEngine.priority.desc()).limit(1) + query = query.order_by(VideoEngine.priority.desc()) + + query = query.limit(1) result = await db.execute(query) engine = result.scalar_one_or_none() if not engine: diff --git a/video-gen-api/app/services/generation_billing_service.py b/video-gen-api/app/services/generation_billing_service.py index eb9865c3..30c33938 100644 --- a/video-gen-api/app/services/generation_billing_service.py +++ b/video-gen-api/app/services/generation_billing_service.py @@ -145,7 +145,7 @@ async def deduct_credits_locked_once( if amount <= 0: return BillingItem(charge_key=charge_key, amount=0.0, charged=False, skipped_reason="amount_lte_zero") - result = await db.execute(select(User).where(User.id == user_id).with_for_update()) + result = await db.execute(select(User).where(User.id == user_id).with_for_update().limit(1)) user = result.scalar_one_or_none() if not user: raise ValueError("User not found") diff --git a/video-gen-api/app/services/generation_provider_service.py b/video-gen-api/app/services/generation_provider_service.py index 9dd53fb1..e221c0ba 100644 --- a/video-gen-api/app/services/generation_provider_service.py +++ b/video-gen-api/app/services/generation_provider_service.py @@ -35,9 +35,9 @@ async def get_runtime_engine(db: AsyncSession, task: ChatGenerationTask) -> Any: if not task.engine_id: raise ValueError("缺少 engine_id") if task.gen_type == "image": - result = await db.execute(select(ImageEngine).where(ImageEngine.id == task.engine_id)) + result = await db.execute(select(ImageEngine).where(ImageEngine.id == task.engine_id).limit(1)) else: - result = await db.execute(select(VideoEngine).where(VideoEngine.id == task.engine_id)) + result = await db.execute(select(VideoEngine).where(VideoEngine.id == task.engine_id).limit(1)) engine = result.scalar_one_or_none() if not engine: raise ValueError("引擎不存在或已删除") diff --git a/video-gen-api/app/services/llm.py b/video-gen-api/app/services/llm.py index 0a2a67d6..79878493 100644 --- a/video-gen-api/app/services/llm.py +++ b/video-gen-api/app/services/llm.py @@ -180,7 +180,7 @@ async def _call_openai_compatible( if industry_key and db is not None: from app.models.industry_config import IndustryConfig result = await db.execute( - select(IndustryConfig).where(IndustryConfig.key == industry_key) + select(IndustryConfig).where(IndustryConfig.key == industry_key).limit(1) ) ind = result.scalar_one_or_none() if ind and ind.skills: diff --git a/video-gen-api/app/services/notification.py b/video-gen-api/app/services/notification.py index 8f786cb9..7dfb16d4 100644 --- a/video-gen-api/app/services/notification.py +++ b/video-gen-api/app/services/notification.py @@ -132,7 +132,7 @@ async def get_notifications( async def mark_read(db: AsyncSession, notification_id: str, user_id: str) -> None: """Mark a notification as read for a specific user.""" result = await db.execute( - select(Notification).where(Notification.id == notification_id) + select(Notification).where(Notification.id == notification_id).limit(1) ) notif = result.scalar_one_or_none() if not notif: @@ -150,6 +150,7 @@ async def mark_read(db: AsyncSession, notification_id: str, user_id: str) -> Non NotificationRead.notification_id == notification_id, NotificationRead.user_id == user_id, ) + .limit(1) ) if not existing.scalar_one_or_none(): db.add(NotificationRead( diff --git a/video-gen-api/app/services/payment.py b/video-gen-api/app/services/payment.py index fc989429..ed0e8946 100644 --- a/video-gen-api/app/services/payment.py +++ b/video-gen-api/app/services/payment.py @@ -104,7 +104,7 @@ async def process_payment_success(db: AsyncSession, order_id: str): from sqlalchemy import select result = await db.execute( - select(PaymentOrder).where(PaymentOrder.id == order_id) + select(PaymentOrder).where(PaymentOrder.id == order_id).limit(1) ) order = result.scalar_one_or_none() if not order or order.status != "pending": diff --git a/video-gen-api/app/services/resource_accounting_service.py b/video-gen-api/app/services/resource_accounting_service.py index 350dd4d4..b6bc20ac 100644 --- a/video-gen-api/app/services/resource_accounting_service.py +++ b/video-gen-api/app/services/resource_accounting_service.py @@ -84,6 +84,7 @@ async def _get_or_create_month_stat( UserResourceMonthStat.user_id == user_id, UserResourceMonthStat.stat_month == stat_month, ) + .limit(1) ) stat = result.scalar_one_or_none() if stat: @@ -104,7 +105,7 @@ async def _get_or_create_total_stat( user_id: str, ) -> UserResourceTotalStat: result = await db.execute( - select(UserResourceTotalStat).where(UserResourceTotalStat.user_id == user_id) + select(UserResourceTotalStat).where(UserResourceTotalStat.user_id == user_id).limit(1) ) stat = result.scalar_one_or_none() if stat: diff --git a/video-gen-api/app/services/video_queue.py b/video-gen-api/app/services/video_queue.py index 8d4dca26..2578564c 100644 --- a/video-gen-api/app/services/video_queue.py +++ b/video-gen-api/app/services/video_queue.py @@ -76,6 +76,7 @@ class TaskQueue: GenerationRecord.id == record_id, GenerationRecord.deleted_at.is_(None), ) + .limit(1) ) record = result.scalar_one_or_none() if not record or record.status != "generating": diff --git a/video-gen-api/app/services/video_url.py b/video-gen-api/app/services/video_url.py index a8358a51..fef91831 100644 --- a/video-gen-api/app/services/video_url.py +++ b/video-gen-api/app/services/video_url.py @@ -29,5 +29,6 @@ async def get_video_stream_url(db: AsyncSession, record_id: str) -> str | None: GenerationRecord.id == record_id, GenerationRecord.deleted_at.is_(None), ) + .limit(1) ) return result.scalar_one_or_none() diff --git a/video-gen-api/app/tasks/generation_create_tasks.py b/video-gen-api/app/tasks/generation_create_tasks.py index 93655896..dd5262b9 100644 --- a/video-gen-api/app/tasks/generation_create_tasks.py +++ b/video-gen-api/app/tasks/generation_create_tasks.py @@ -109,7 +109,7 @@ async def _run(task_id: str): result = await db.execute(select(ChatGenerationTask).where( ChatGenerationTask.id == task_id, ChatGenerationTask.deleted_at.is_(None), - )) + ).limit(1)) task = result.scalar_one_or_none() if not task or task.generation_mode != "chatapi_async": @@ -236,7 +236,7 @@ async def _run(task_id: str): result = await db.execute(select(ChatGenerationTask).where( ChatGenerationTask.id == task_id, ChatGenerationTask.deleted_at.is_(None), - )) + ).limit(1)) task = result.scalar_one_or_none() if task: diff --git a/video-gen-api/app/tasks/generation_download_tasks.py b/video-gen-api/app/tasks/generation_download_tasks.py index e459a966..993e22b2 100644 --- a/video-gen-api/app/tasks/generation_download_tasks.py +++ b/video-gen-api/app/tasks/generation_download_tasks.py @@ -61,7 +61,7 @@ async def _reload_task(db, task_id: str) -> ChatGenerationTask | None: select(ChatGenerationTask).where( ChatGenerationTask.id == task_id, ChatGenerationTask.deleted_at.is_(None), - ) + ).limit(1) ) return result.scalar_one_or_none() @@ -72,7 +72,7 @@ async def _run(task_id: str): select(ChatGenerationTask).where( ChatGenerationTask.id == task_id, ChatGenerationTask.deleted_at.is_(None), - ) + ).limit(1) ) task = result.scalar_one_or_none() if not task or task.generation_mode != "chatapi_async": diff --git a/video-gen-api/app/tasks/generation_poll_tasks.py b/video-gen-api/app/tasks/generation_poll_tasks.py index 7ba4cc0e..5bf04f36 100644 --- a/video-gen-api/app/tasks/generation_poll_tasks.py +++ b/video-gen-api/app/tasks/generation_poll_tasks.py @@ -41,7 +41,7 @@ async def _reload_task(db, task_id: str) -> ChatGenerationTask | None: select(ChatGenerationTask).where( ChatGenerationTask.id == task_id, ChatGenerationTask.deleted_at.is_(None), - ) + ).limit(1) ) return result.scalar_one_or_none() @@ -51,7 +51,7 @@ async def _run(task_id: str): result = await db.execute(select(ChatGenerationTask).where( ChatGenerationTask.id == task_id, ChatGenerationTask.deleted_at.is_(None), - )) + ).limit(1)) task = result.scalar_one_or_none() if not task or task.generation_mode != "chatapi_async": return