feat(root):add mysql

This commit is contained in:
shahzeydyfah
2026-02-17 23:52:14 +03:30
parent abb1c01753
commit 189df529d9
4 changed files with 126 additions and 6 deletions
+27
View File
@@ -0,0 +1,27 @@
"""
مدل ORM برای جدول const در MySQL.
"""
from sqlalchemy import Column, Integer, String, Text
from core.service.mysql_orm import Base
class Const(Base):
"""مدل جدول const"""
__tablename__ = "const"
id = Column(Integer, primary_key=True, index=True)
key = Column(String(255), nullable=False, index=True)
title_fa = Column(String(255), nullable=True)
value = Column(Text, nullable=True)
def __repr__(self):
return f"<Const(id={self.id}, key='{self.key}', title_fa='{self.title_fa}')>"
def to_dict(self):
"""تبدیل به dict برای JSON response"""
return {
"id": self.id,
"key": self.key,
"title_fa": self.title_fa,
"value": self.value,
}
+34
View File
@@ -0,0 +1,34 @@
"""
Repository برای جدول const در MySQL - برای استفاده در خروجی اکسل.
"""
from typing import List, Dict, Optional
from sqlalchemy import select
from core.service.mysql_orm import get_mysql_session
from app.models.mysql_const import Const
class MySQLConstRepository:
"""Repository برای خواندن دیتا از جدول const"""
async def get_by_keys(self, keys: List[str]) -> Dict[int, str]:
"""
گرفتن const ها با لیست key ها و برگرداندن dict به صورت {id: title_fa}
مثال: get_by_keys(['nature', 'type']) -> {2: 'طبیعت 2', 9: 'نوع 9'}
"""
async with get_mysql_session() as session:
result = await session.execute(
select(Const).where(Const.key.in_(keys))
)
consts = result.scalars().all()
return {c.id: c.title_fa or c.value or str(c.id) for c in consts}
async def get_by_key(self, key: str) -> Dict[int, str]:
"""گرفتن const ها با یک key و برگرداندن dict به صورت {id: title_fa}"""
return await self.get_by_keys([key])
async def get_all_consts_dict(self) -> Dict[int, str]:
"""گرفتن همه const ها به صورت {id: title_fa} - برای کش کردن"""
async with get_mysql_session() as session:
result = await session.execute(select(Const))
consts = result.scalars().all()
return {c.id: c.title_fa or c.value or str(c.id) for c in consts}
+2 -2
View File
@@ -5,8 +5,8 @@ from core.service.mongo_db import use_collection
def get_auth_db():
return conf.server.is_prod and conf.database.get('mongo').production.db or conf.database.get(
'mongo').dev.db
return conf.server.is_prod and conf.database.get('mongo_auth').production.db or conf.database.get(
'mongo_auth').dev.db
def use_auth_collection(collection: str) -> Collection:
+63 -4
View File
@@ -17,6 +17,7 @@ from celery import shared_task
from .AbstractEngine import AbstractEngineClass
from ..utils.Models import FilterItem, FilterScope, OutPutType
from ..utils.excel_value_maps import EXCEL_VALUE_MAP_REGISTRY
from app.repositories.mysql_const_repo import MySQLConstRepository
# def zero_time_data(date, is_max=False):
@@ -39,6 +40,7 @@ class MongoEngine(AbstractEngineClass):
rows = []
stack = []
filters = {}
_const_cache: dict = None # کش const ها از MySQL
async def exe(self):
_f = self.filters = self.set_filters()
@@ -54,7 +56,7 @@ class MongoEngine(AbstractEngineClass):
if self.input.e and self.input.e.ot:
res = await tmp.to_list(None)
self.input.e.d = self.generate_output(res)
self.input.e.d = await self.generate_output(res)
return {'query': _f, 'sort': self.set_sort(), 'path': self.input.e.d}
self.rows = tmp.limit(self.input.get_limit()).skip(self.input.skip())
@@ -257,11 +259,11 @@ class MongoEngine(AbstractEngineClass):
def set_joins(self):
pass
def generate_output(self, _f):
async def generate_output(self, _f):
print(self.input.e.ot)
if self.input.e.ot == OutPutType.EXEL:
file_name = str(uuid.uuid4().hex) + '.xlsx'
return self.output_generator(_f, file_name=file_name, cols=self.input.e.c)
return await self.output_generator(_f, file_name=file_name, cols=self.input.e.c)
elif self.input.e.ot == OutPutType.JSON:
pass
elif self.input.e.ot == OutPutType.PDF:
@@ -275,7 +277,7 @@ class MongoEngine(AbstractEngineClass):
os.makedirs(temp_dir, exist_ok=True)
return temp_dir
def output_generator(self,query, file_name, cols):
async def output_generator(self, query, file_name, cols):
datas = query
file_dir = os.path.join(self._excel_temp_dir(), file_name)
head_cols = list(str(string.ascii_uppercase))
@@ -293,10 +295,15 @@ class MongoEngine(AbstractEngineClass):
# ساختن value_maps از vk (نام مپ) با استفاده از رجیستری
value_maps = self._build_value_maps()
# بارگذاری const ها برای فیلدهای خاص
const_maps = await self._load_const_maps(headers)
for row_index, item in enumerate(datas, start=1):
for col_index, col in enumerate(headers):
val = self.get_nested_value(item, col)
val = self._apply_value_map(col, val, value_maps)
val = await self._apply_const_map(col, val, const_maps)
worksheet.write(row_index, col_index, val)
workbook.close()
return file_name
@@ -328,6 +335,58 @@ class MongoEngine(AbstractEngineClass):
return mapping[str(key)]
return val
async def _load_const_maps(self, headers: List[str]) -> dict:
"""
شناسایی فیلدهای خاص (مثلاً nature_id, type_id, budget_id) و بارگذاری const ها از MySQL.
Returns: dict به صورت {col_key: {id: title_fa}} مثلاً {"design.nature_id": {2: "طبیعت 2", ...}}
"""
# لیست فیلدهای خاص که باید از const خوانده شوند
const_field_names = ['nature_id', 'type_id', 'budget_id'] # می‌تونی اضافه کنی
const_maps = {}
const_keys_to_load = set()
const_column_map = {} # {col_key: const_key} مثلاً {"design.nature_id": "nature"}
# شناسایی ستون‌هایی که باید const بخونن
for col_key in headers:
col_name = col_key.split('.')[-1] # آخرین بخش (nature_id)
if col_name in const_field_names:
const_key = col_name.replace('_id', '') # nature_id -> nature
const_keys_to_load.add(const_key)
const_column_map[col_key] = const_key
# بارگذاری const ها از MySQL
if const_keys_to_load:
repo = MySQLConstRepository()
for col_key, const_key in const_column_map.items():
consts_for_key = await repo.get_by_key(const_key)
if consts_for_key:
const_maps[col_key] = consts_for_key
return const_maps
async def _apply_const_map(self, col_key: str, val, const_maps: dict):
"""اگر این ستون در const_maps باشد، id را به title_fa تبدیل می‌کند."""
if not const_maps or col_key not in const_maps:
return val
mapping = const_maps[col_key]
if not isinstance(mapping, dict):
return val
if val is None:
return mapping.get(None, val)
# تبدیل val به int برای جستجو در mapping
key = val if isinstance(val, (int, float)) else (int(val) if isinstance(val, str) and str(val).strip().isdigit() else val)
if key in mapping:
return mapping[key]
if isinstance(key, int) and str(key) in mapping:
return mapping[str(key)]
return val
def get_nested_value(self, data, path, default='-'):
"""
دریافت مقدار از دیکشنری تو در تو با مسیر dot notation