feat(root):add mysql
This commit is contained in:
@@ -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,
|
||||||
|
}
|
||||||
@@ -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
@@ -5,8 +5,8 @@ from core.service.mongo_db import use_collection
|
|||||||
|
|
||||||
|
|
||||||
def get_auth_db():
|
def get_auth_db():
|
||||||
return conf.server.is_prod and conf.database.get('mongo').production.db or conf.database.get(
|
return conf.server.is_prod and conf.database.get('mongo_auth').production.db or conf.database.get(
|
||||||
'mongo').dev.db
|
'mongo_auth').dev.db
|
||||||
|
|
||||||
|
|
||||||
def use_auth_collection(collection: str) -> Collection:
|
def use_auth_collection(collection: str) -> Collection:
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from celery import shared_task
|
|||||||
from .AbstractEngine import AbstractEngineClass
|
from .AbstractEngine import AbstractEngineClass
|
||||||
from ..utils.Models import FilterItem, FilterScope, OutPutType
|
from ..utils.Models import FilterItem, FilterScope, OutPutType
|
||||||
from ..utils.excel_value_maps import EXCEL_VALUE_MAP_REGISTRY
|
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):
|
# def zero_time_data(date, is_max=False):
|
||||||
@@ -39,6 +40,7 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
rows = []
|
rows = []
|
||||||
stack = []
|
stack = []
|
||||||
filters = {}
|
filters = {}
|
||||||
|
_const_cache: dict = None # کش const ها از MySQL
|
||||||
|
|
||||||
async def exe(self):
|
async def exe(self):
|
||||||
_f = self.filters = self.set_filters()
|
_f = self.filters = self.set_filters()
|
||||||
@@ -54,7 +56,7 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
|
|
||||||
if self.input.e and self.input.e.ot:
|
if self.input.e and self.input.e.ot:
|
||||||
res = await tmp.to_list(None)
|
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}
|
return {'query': _f, 'sort': self.set_sort(), 'path': self.input.e.d}
|
||||||
|
|
||||||
self.rows = tmp.limit(self.input.get_limit()).skip(self.input.skip())
|
self.rows = tmp.limit(self.input.get_limit()).skip(self.input.skip())
|
||||||
@@ -257,11 +259,11 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
def set_joins(self):
|
def set_joins(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def generate_output(self, _f):
|
async def generate_output(self, _f):
|
||||||
print(self.input.e.ot)
|
print(self.input.e.ot)
|
||||||
if self.input.e.ot == OutPutType.EXEL:
|
if self.input.e.ot == OutPutType.EXEL:
|
||||||
file_name = str(uuid.uuid4().hex) + '.xlsx'
|
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:
|
elif self.input.e.ot == OutPutType.JSON:
|
||||||
pass
|
pass
|
||||||
elif self.input.e.ot == OutPutType.PDF:
|
elif self.input.e.ot == OutPutType.PDF:
|
||||||
@@ -275,7 +277,7 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
os.makedirs(temp_dir, exist_ok=True)
|
os.makedirs(temp_dir, exist_ok=True)
|
||||||
return temp_dir
|
return temp_dir
|
||||||
|
|
||||||
def output_generator(self,query, file_name, cols):
|
async def output_generator(self, query, file_name, cols):
|
||||||
datas = query
|
datas = query
|
||||||
file_dir = os.path.join(self._excel_temp_dir(), file_name)
|
file_dir = os.path.join(self._excel_temp_dir(), file_name)
|
||||||
head_cols = list(str(string.ascii_uppercase))
|
head_cols = list(str(string.ascii_uppercase))
|
||||||
@@ -293,10 +295,15 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
|
|
||||||
# ساختن value_maps از vk (نام مپ) با استفاده از رجیستری
|
# ساختن value_maps از vk (نام مپ) با استفاده از رجیستری
|
||||||
value_maps = self._build_value_maps()
|
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 row_index, item in enumerate(datas, start=1):
|
||||||
for col_index, col in enumerate(headers):
|
for col_index, col in enumerate(headers):
|
||||||
val = self.get_nested_value(item, col)
|
val = self.get_nested_value(item, col)
|
||||||
val = self._apply_value_map(col, val, value_maps)
|
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)
|
worksheet.write(row_index, col_index, val)
|
||||||
workbook.close()
|
workbook.close()
|
||||||
return file_name
|
return file_name
|
||||||
@@ -328,6 +335,58 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
return mapping[str(key)]
|
return mapping[str(key)]
|
||||||
return val
|
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='-'):
|
def get_nested_value(self, data, path, default='-'):
|
||||||
"""
|
"""
|
||||||
دریافت مقدار از دیکشنری تو در تو با مسیر dot notation
|
دریافت مقدار از دیکشنری تو در تو با مسیر dot notation
|
||||||
|
|||||||
Reference in New Issue
Block a user