feat(project):change mongo
This commit is contained in:
@@ -1,14 +1,16 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from starlette.responses import FileResponse
|
||||||
|
|
||||||
from .engines import MsSqlEngine, MongoEngine, PgSqlEngine, AbstractEngine
|
from .engines import MsSqlEngine, MongoEngine, PgSqlEngine, AbstractEngine
|
||||||
from .utils.Models import TableEngineInput
|
from .utils.Models import TableEngineInput
|
||||||
from .utils.Models import WorkingMode, JoinModel
|
from .utils.Models import WorkingMode, JoinModel
|
||||||
from ..table_engine import TableEngineExport
|
from .utils.Models import TableEngineExport
|
||||||
|
|
||||||
|
|
||||||
class NewTableEngine:
|
class NewTableEngine:
|
||||||
def __init__(self, query_class, model, inputs, mode, engine: AbstractEngine, extra_filter,
|
def __init__(self, query_class, model, inputs, mode, engine: AbstractEngine, extra_filter,
|
||||||
default_sort_by, joins, search_cols, options=None, soft_deleted=False):
|
default_sort_by, joins, search_cols, options=None, soft_deleted=False, unselect={}, return_query=False):
|
||||||
self.model = model
|
self.model = model
|
||||||
self.query_class = query_class
|
self.query_class = query_class
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
@@ -18,12 +20,15 @@ class NewTableEngine:
|
|||||||
self.input = TableEngineInput(**inputs if inputs else {})
|
self.input = TableEngineInput(**inputs if inputs else {})
|
||||||
else:
|
else:
|
||||||
self.input = TableEngineInput(**inputs.dict() if inputs else {})
|
self.input = TableEngineInput(**inputs.dict() if inputs else {})
|
||||||
|
|
||||||
self.input.extra_filter = extra_filter
|
self.input.extra_filter = extra_filter
|
||||||
self.default_sort_by = default_sort_by
|
self.default_sort_by = default_sort_by
|
||||||
self.joins = joins
|
self.joins = joins
|
||||||
self.soft_deleted = soft_deleted
|
self.soft_deleted = soft_deleted
|
||||||
self.options = options
|
self.options = options
|
||||||
self.search_cols = search_cols
|
self.search_cols = search_cols
|
||||||
|
self.unselect = unselect
|
||||||
|
self.return_query = return_query
|
||||||
self.engine = engine(self)
|
self.engine = engine(self)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -33,10 +38,10 @@ class NewTableEngine:
|
|||||||
mode: WorkingMode = WorkingMode.Development,
|
mode: WorkingMode = WorkingMode.Development,
|
||||||
extra_filter=None,
|
extra_filter=None,
|
||||||
soft_deleted=False,
|
soft_deleted=False,
|
||||||
default_sort_by=None, joins=None, search_cols=[]):
|
default_sort_by=None, joins=None, search_cols=[] ,unselect={}, return_query=False):
|
||||||
return NewTableEngine(query_class, model, inputs, mode, engine=MongoEngine, extra_filter=extra_filter,
|
return NewTableEngine(query_class, model, inputs, mode, engine=MongoEngine, extra_filter=extra_filter,
|
||||||
default_sort_by=default_sort_by, joins=joins, search_cols=search_cols,
|
default_sort_by=default_sort_by, joins=joins, search_cols=search_cols,
|
||||||
soft_deleted=soft_deleted)
|
soft_deleted=soft_deleted,unselect=unselect, return_query=return_query)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mssql(query_class, model, inputs, mode: WorkingMode = WorkingMode.Development, extra_filter=None,
|
def mssql(query_class, model, inputs, mode: WorkingMode = WorkingMode.Development, extra_filter=None,
|
||||||
@@ -53,15 +58,19 @@ class NewTableEngine:
|
|||||||
async def exe(self):
|
async def exe(self):
|
||||||
return await self.engine.exe()
|
return await self.engine.exe()
|
||||||
|
|
||||||
async def to_dict(self) -> TableEngineExport:
|
async def to_dict(self):
|
||||||
|
if self.return_query:
|
||||||
|
query = await self.exe()
|
||||||
|
return query
|
||||||
rows, count = await self.exe()
|
rows, count = await self.exe()
|
||||||
self.input.extra_filter = None
|
self.input.extra_filter = None
|
||||||
del self.engine
|
del self.engine
|
||||||
|
self.set_export_file()
|
||||||
return TableEngineExport(
|
return TableEngineExport(
|
||||||
rows=rows,
|
rows=rows,
|
||||||
page=self.input.virtual_page(),
|
page=self.input.virtual_page(),
|
||||||
total=count,
|
total=count,
|
||||||
te=self.input
|
te=self.raw_input
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_extra_filter(self, filters):
|
def add_extra_filter(self, filters):
|
||||||
@@ -75,3 +84,10 @@ class NewTableEngine:
|
|||||||
def set_custom_entities(self, entities=None):
|
def set_custom_entities(self, entities=None):
|
||||||
self.engine.custom_entities = entities
|
self.engine.custom_entities = entities
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def set_export_file(self):
|
||||||
|
try:
|
||||||
|
self.raw_input['e']['d'] = self.input.e.d
|
||||||
|
return self
|
||||||
|
except Exception as e:
|
||||||
|
return False
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ class AbstractEngineClass(abc.ABC):
|
|||||||
self.options = table_engine.options
|
self.options = table_engine.options
|
||||||
self.search_cols = table_engine.search_cols
|
self.search_cols = table_engine.search_cols
|
||||||
self.soft_deleted = table_engine.soft_deleted
|
self.soft_deleted = table_engine.soft_deleted
|
||||||
|
self.unselect = table_engine.unselect
|
||||||
|
self.return_query = table_engine.return_query
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def exe(self):
|
def exe(self):
|
||||||
|
|||||||
+102
-18
@@ -1,9 +1,30 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
import uuid
|
||||||
from typing import Union, List
|
from typing import Union, List
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
# import dateutil.parser
|
||||||
|
from celery import shared_task
|
||||||
|
# from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
from .AbstractEngine import AbstractEngineClass
|
from .AbstractEngine import AbstractEngineClass
|
||||||
from ..utils.Models import FilterItem, FilterScope
|
from ..utils.Models import FilterItem, FilterScope, OutPutType
|
||||||
|
|
||||||
|
|
||||||
|
# def zero_time_data(date, is_max=False):
|
||||||
|
# _date = dateutil.parser.isoparse(date)
|
||||||
|
# return datetime.datetime.combine(_date, datetime.time.min if not is_max else datetime.time.max)
|
||||||
|
|
||||||
|
|
||||||
|
# def date_year_month_morph(date, is_max=False, has_month=True):
|
||||||
|
# _date = date
|
||||||
|
# if len(date) > 7:
|
||||||
|
# _date = dateutil.parser.isoparse(date)
|
||||||
|
# if not has_month and len(date) < 5:
|
||||||
|
# _date = f'{date}-01'
|
||||||
|
# _date = datetime.datetime.strptime(_date, '%Y-%m')
|
||||||
|
# _date = _date + relativedelta(day=31)
|
||||||
|
# return _date if is_max else _date + relativedelta(day=1)
|
||||||
|
|
||||||
|
|
||||||
class MongoEngine(AbstractEngineClass):
|
class MongoEngine(AbstractEngineClass):
|
||||||
@@ -13,15 +34,31 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
|
|
||||||
async def exe(self):
|
async def exe(self):
|
||||||
_f = self.filters = self.set_filters()
|
_f = self.filters = self.set_filters()
|
||||||
tmp = self.query_class.find(_f).sort(**self.set_sort())
|
print("_f ====>", _f)
|
||||||
|
if self.unselect:
|
||||||
|
tmp = self.query_class.find(_f, self.unselect)
|
||||||
|
else:
|
||||||
|
tmp = self.query_class.find(_f)
|
||||||
|
|
||||||
|
sort_by = self.set_sort()
|
||||||
|
if isinstance(sort_by, dict):
|
||||||
|
tmp = tmp.sort(**sort_by)
|
||||||
|
else:
|
||||||
|
tmp = tmp.sort(sort_by)
|
||||||
|
|
||||||
self.rows = tmp.limit(
|
self.rows = tmp.limit(
|
||||||
self.input.get_limit()).skip(self.input.skip())
|
self.input.get_limit()).skip(self.input.skip())
|
||||||
|
if self.input.e and self.input.e.ot:
|
||||||
|
self.input.e.d = self.generate_output(self.query_class, _f)
|
||||||
|
if self.return_query:
|
||||||
|
return {'query':_f, 'sort':self.set_sort(), 'limit':self.input.get_limit(), 'page':self.input.skip()}
|
||||||
return [self.model(**document) async for document in self.rows], await self.count()
|
return [self.model(**document) async for document in self.rows], await self.count()
|
||||||
|
|
||||||
def query_generator(self):
|
def query_generator(self):
|
||||||
if not self.input.has_filter():
|
if not self.input.has_filter():
|
||||||
return []
|
return []
|
||||||
filters = self.input.filters()
|
filters = [f for f in self.input.filters() if
|
||||||
|
(hasattr(f, 'items') and len(f.items)) > 0 or not hasattr(f, 'items')]
|
||||||
query = self.generate_scope_filter(filters, general=True)
|
query = self.generate_scope_filter(filters, general=True)
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@@ -36,7 +73,7 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
self.input.get_search_cols() and len(self.input.get_search_cols())) else self.search_cols
|
self.input.get_search_cols() and len(self.input.get_search_cols())) else self.search_cols
|
||||||
if _search_cols:
|
if _search_cols:
|
||||||
for col in _search_cols:
|
for col in _search_cols:
|
||||||
items.append({col: {'$regex': self.input.get_text_search()}})
|
items.append({col: {'$regex': self.input.get_text_search(), '$options': 'i'}})
|
||||||
filters.append({"$or": items})
|
filters.append({"$or": items})
|
||||||
if self.input.extra_filter:
|
if self.input.extra_filter:
|
||||||
filters.extend(self.input.extra_filter)
|
filters.extend(self.input.extra_filter)
|
||||||
@@ -48,13 +85,18 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
return self.filters
|
return self.filters
|
||||||
|
|
||||||
def set_sort(self):
|
def set_sort(self):
|
||||||
|
if self.input.o.fields:
|
||||||
|
all_sort = []
|
||||||
|
for item in self.input.o.fields:
|
||||||
|
all_sort.append((item.field, 1 if item.direction == "asc" else -1))
|
||||||
|
return all_sort
|
||||||
if self.input.o.field:
|
if self.input.o.field:
|
||||||
return {'key_or_list': self.input.o.field,
|
return {'key_or_list': self.input.o.field,
|
||||||
'direction': 1 if self.input.o.direction == "asc" else -1}
|
'direction': 1 if self.input.o.direction == "asc" else -1}
|
||||||
elif self.default_sort_by:
|
elif self.default_sort_by:
|
||||||
return self.default_sort_by
|
return self.default_sort_by
|
||||||
else:
|
else:
|
||||||
return {'key_or_list': 'created_at', 'direction': -1}
|
return {'key_or_list': '$natural', 'direction': -1}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filter_item_generator(item: FilterItem) -> dict:
|
def filter_item_generator(item: FilterItem) -> dict:
|
||||||
@@ -64,13 +106,14 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
"$elemMatch": {
|
"$elemMatch": {
|
||||||
'field_id': UUID(item.col),
|
'field_id': UUID(item.col),
|
||||||
'value': {
|
'value': {
|
||||||
**MongoEngine.get_expression_filter(item.op, MongoEngine.cast_value(item.val, item.type), )}
|
**MongoEngine.get_expression_filter(item.op, MongoEngine.cast_value(item.val, item.type),
|
||||||
|
field_type=item.type)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {item.col: {
|
return {item.col: {
|
||||||
**MongoEngine.get_expression_filter(col=item.col, op=item.op,
|
**MongoEngine.get_expression_filter(col=item.col, op=item.op,
|
||||||
val=MongoEngine.cast_value(item.val, item.type), )}}
|
val=MongoEngine.cast_value(item.val, item.type), field_type=item.type)}}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_valid_uuid(uuid_to_test, version=4):
|
def is_valid_uuid(uuid_to_test, version=4):
|
||||||
@@ -80,9 +123,12 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
return False
|
return False
|
||||||
return str(uuid_obj) == str(uuid_to_test)
|
return str(uuid_obj) == str(uuid_to_test)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cast_value(val: Union[str, List], type: str) -> any:
|
def cast_value(val: Union[str, List], type: str) -> any:
|
||||||
|
if val == [] or type == 'BOOL':
|
||||||
|
return val
|
||||||
|
if not val:
|
||||||
|
return None
|
||||||
if type in ['NUMBER', 'STACK', 'FLOAT']:
|
if type in ['NUMBER', 'STACK', 'FLOAT']:
|
||||||
if isinstance(val, List):
|
if isinstance(val, List):
|
||||||
return [float(x) for x in val]
|
return [float(x) for x in val]
|
||||||
@@ -97,20 +143,37 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
return UUID(str(val))
|
return UUID(str(val))
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_expression_filter(col=None, op: str = 'eq', val: str = '') -> dict:
|
def get_expression_filter(col=None, op: str = 'eq', val: str = '', field_type: str = None) -> dict:
|
||||||
_op = MongoEngine.get_operator(op)
|
_op = MongoEngine.get_operator(op)
|
||||||
|
|
||||||
|
# Date Type Operator
|
||||||
|
if field_type in ['DATE', 'DATE_TIME', 'DATETIME', 'DATE_MONTH', 'DATE_YEAR']:
|
||||||
|
if op == "eq":
|
||||||
|
return {'$gte': val[0], '$lte': val[1]}
|
||||||
|
if op == "n_eq":
|
||||||
|
return {'$lte': val[0], '$gte': val[1]}
|
||||||
|
if op == "lt":
|
||||||
|
return {'$lt': val[1]}
|
||||||
|
if op == "gt":
|
||||||
|
return {'$gt': val[0]}
|
||||||
|
if op == "lte":
|
||||||
|
return {'$lt': val[1]}
|
||||||
|
if op == "gte":
|
||||||
|
return {'$gt': val[0]}
|
||||||
|
|
||||||
if _op == "sw":
|
if _op == "sw":
|
||||||
return {'$regex': f'^{val}'}
|
return {'$regex': f'^{val}', '$options': 'i'}
|
||||||
elif _op == "ew":
|
elif _op == "ew":
|
||||||
return {'$regex': f'{val}$'}
|
return {'$regex': f'{val}$', '$options': 'i'}
|
||||||
elif _op == "n_ew":
|
elif _op == "n_ew":
|
||||||
return {'$regex': f'(?<!{val})$'}
|
return {'$regex': f'(?<!{val})$', '$options': 'i'}
|
||||||
elif _op == "n_sw":
|
elif _op == "n_sw":
|
||||||
return {'$regex': f'^(?!{val})'}
|
return {'$regex': f'^(?!{val})', '$options': 'i'}
|
||||||
elif _op == "n_like":
|
elif _op == "n_like":
|
||||||
return {'$not': {'$regex': val}}
|
return {'$not': {'$regex': val, '$options': 'i'}}
|
||||||
|
elif _op == "like":
|
||||||
|
return {'$regex': val, '$options': 'i'}
|
||||||
elif _op == "bet":
|
elif _op == "bet":
|
||||||
if isinstance(val, str):
|
if isinstance(val, str):
|
||||||
return {'$gte': val.split('-')[0], '$lte': val.split('-')[1]}
|
return {'$gte': val.split('-')[0], '$lte': val.split('-')[1]}
|
||||||
@@ -124,9 +187,9 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
elif _op == "n_exi":
|
elif _op == "n_exi":
|
||||||
return {'$exists': False}
|
return {'$exists': False}
|
||||||
elif _op == "in":
|
elif _op == "in":
|
||||||
return {'$exists': True}
|
return {'$in': val}
|
||||||
elif _op == "not_in":
|
elif _op == "not_in":
|
||||||
return {'$exists': False}
|
return {'$nin': val}
|
||||||
return {_op: val}
|
return {_op: val}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -138,7 +201,7 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
"ge": "$ge",
|
"ge": "$ge",
|
||||||
"lt": "$lt",
|
"lt": "$lt",
|
||||||
"le": "$le",
|
"le": "$le",
|
||||||
"like": "$regex",
|
"like": "like",
|
||||||
"n_like": "n_like",
|
"n_like": "n_like",
|
||||||
"sw": "sw",
|
"sw": "sw",
|
||||||
"ew": "ew",
|
"ew": "ew",
|
||||||
@@ -185,3 +248,24 @@ class MongoEngine(AbstractEngineClass):
|
|||||||
|
|
||||||
def set_joins(self):
|
def set_joins(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def generate_output(self, query, _f):
|
||||||
|
print(_f.__dict__)
|
||||||
|
return ''
|
||||||
|
if self.input.e.ot == OutPutType.EXEL:
|
||||||
|
file_name = str(uuid.uuid4().hex) + '.xlsx'
|
||||||
|
return _f.dict()
|
||||||
|
MongoEngine.output_generator(str(query).replace('false', '0'), params,
|
||||||
|
str(self.query_class.bind.url), file_name=file_name, cols=self.input.e.c)
|
||||||
|
return file_name
|
||||||
|
elif self.input.e.ot == OutPutType.JSON:
|
||||||
|
pass
|
||||||
|
elif self.input.e.ot == OutPutType.PDF:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise Exception("Output type not supported.")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@shared_task(name='output_generator_task_mongo')
|
||||||
|
def output_generator(query, params, url, file_name, cols):
|
||||||
|
pass
|
||||||
|
|||||||
+112
-11
@@ -1,8 +1,18 @@
|
|||||||
from sqlalchemy import or_, and_, desc, asc
|
import os
|
||||||
|
import string
|
||||||
|
import tempfile
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
# import xlsxwriter
|
||||||
|
from celery import shared_task
|
||||||
|
from sqlalchemy import or_, and_, desc, asc, create_engine, LABEL_STYLE_TABLENAME_PLUS_COL
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
from sqlalchemy.sql.elements import BooleanClauseList, BinaryExpression, UnaryExpression
|
from sqlalchemy.sql.elements import BooleanClauseList, BinaryExpression, UnaryExpression
|
||||||
|
from sqlalchemy.sql.selectable import TableValuedAlias
|
||||||
|
|
||||||
from .AbstractEngine import AbstractEngineClass
|
from .AbstractEngine import AbstractEngineClass
|
||||||
from ..utils.Models import FilterItem, FilterScope
|
# from .Mongo import zero_time_data
|
||||||
|
from ..utils.Models import FilterItem, FilterScope, OutPutType
|
||||||
|
|
||||||
|
|
||||||
class MsSqlEngine(AbstractEngineClass):
|
class MsSqlEngine(AbstractEngineClass):
|
||||||
@@ -16,7 +26,8 @@ class MsSqlEngine(AbstractEngineClass):
|
|||||||
|
|
||||||
async def exe(self):
|
async def exe(self):
|
||||||
_f = self.set_filters()
|
_f = self.set_filters()
|
||||||
if not self.custom_entities:
|
print(_f)
|
||||||
|
if self.custom_entities is not None:
|
||||||
query = self.query_class.query(self.model)
|
query = self.query_class.query(self.model)
|
||||||
else:
|
else:
|
||||||
query = self.query_class.query(*self.custom_entities)
|
query = self.query_class.query(*self.custom_entities)
|
||||||
@@ -29,9 +40,11 @@ class MsSqlEngine(AbstractEngineClass):
|
|||||||
|
|
||||||
if self.options:
|
if self.options:
|
||||||
query = query.options(*self.options)
|
query = query.options(*self.options)
|
||||||
|
if self.input.e and self.input.e.ot:
|
||||||
|
self.input.e.d = self.generate_output(query, _f)
|
||||||
tmp = query.filter(_f).order_by(self.set_sort())
|
tmp = query.filter(_f).order_by(self.set_sort())
|
||||||
self.rows = tmp.limit(self.input.get_limit()).offset(self.input.skip()).all()
|
self.rows = tmp.limit(self.input.get_limit()).offset(self.input.skip()).all()
|
||||||
return self.rows, tmp.count(), tmp
|
return self.rows, tmp.count()
|
||||||
|
|
||||||
def query_generator(self):
|
def query_generator(self):
|
||||||
if not self.input.has_filter():
|
if not self.input.has_filter():
|
||||||
@@ -42,8 +55,9 @@ class MsSqlEngine(AbstractEngineClass):
|
|||||||
|
|
||||||
def set_sort(self):
|
def set_sort(self):
|
||||||
if self.input.o.field:
|
if self.input.o.field:
|
||||||
self.sort = asc(getattr(self.model, self.input.o.field)) if self.input.o.direction == 'asc' else desc(
|
sm = self.model.c if isinstance(self.model, TableValuedAlias) else self.model
|
||||||
getattr(self.model, self.input.o.field))
|
self.sort = asc(getattr(sm, self.input.o.field)) if self.input.o.direction == 'asc' else desc(
|
||||||
|
getattr(sm, self.input.o.field))
|
||||||
return self.sort
|
return self.sort
|
||||||
elif isinstance(self.default_sort_by, UnaryExpression):
|
elif isinstance(self.default_sort_by, UnaryExpression):
|
||||||
return self.default_sort_by
|
return self.default_sort_by
|
||||||
@@ -65,9 +79,13 @@ class MsSqlEngine(AbstractEngineClass):
|
|||||||
if has_join:
|
if has_join:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
sm = self.model.c if isinstance(self.model, TableValuedAlias) else self.model
|
||||||
items.append(
|
items.append(
|
||||||
getattr(self.model, col).ilike("%{search}%".format(search=self.input.get_text_search())))
|
getattr(sm, col).ilike(
|
||||||
|
"%{search}%".format(search=self.input.get_text_search())))
|
||||||
|
|
||||||
filters.append(or_(*items))
|
filters.append(or_(*items))
|
||||||
|
|
||||||
if self.input.extra_filter:
|
if self.input.extra_filter:
|
||||||
for f in self.input.extra_filter:
|
for f in self.input.extra_filter:
|
||||||
filters.append(f)
|
filters.append(f)
|
||||||
@@ -88,7 +106,7 @@ class MsSqlEngine(AbstractEngineClass):
|
|||||||
"n_eq": "__ne__",
|
"n_eq": "__ne__",
|
||||||
"gt": "__gt__",
|
"gt": "__gt__",
|
||||||
"gte": "__ge__",
|
"gte": "__ge__",
|
||||||
"lte": "__lte__",
|
"lte": "__le__",
|
||||||
"lt": "__lt__",
|
"lt": "__lt__",
|
||||||
"like": "ilike",
|
"like": "ilike",
|
||||||
"n_like": "notlike",
|
"n_like": "notlike",
|
||||||
@@ -115,10 +133,22 @@ class MsSqlEngine(AbstractEngineClass):
|
|||||||
def filter_item_generator(self, item: FilterItem):
|
def filter_item_generator(self, item: FilterItem):
|
||||||
has_join = len(item.col.split('.')) > 1
|
has_join = len(item.col.split('.')) > 1
|
||||||
if has_join:
|
if has_join:
|
||||||
|
# pass
|
||||||
pass
|
return self.join_filter(item)
|
||||||
else:
|
else:
|
||||||
return getattr(getattr(self.model, item.col), self.get_operator(item.op))(item.val)
|
sm = self.model.c if isinstance(self.model, TableValuedAlias) else self.model
|
||||||
|
# if item.type in ['DATE', 'DATE_TIME']:
|
||||||
|
# if item.op == 'eq':
|
||||||
|
# return getattr(sm, item.col).between(zero_time_data(item.val),
|
||||||
|
# zero_time_data(item.val, is_max=True))
|
||||||
|
# if item.op in ['gte', 'gt']:
|
||||||
|
# item.val = zero_time_data(item.val)
|
||||||
|
# print(item.val,'GT')
|
||||||
|
# if item.op in ['lt', 'lte']:
|
||||||
|
# item.val = zero_time_data(item.val, is_max=True)
|
||||||
|
# print(item.val,'LT')
|
||||||
|
|
||||||
|
return getattr(getattr(sm, item.col), self.get_operator(item.op))(item.val)
|
||||||
|
|
||||||
def generate_scope_filter(self, filters: list, general=False):
|
def generate_scope_filter(self, filters: list, general=False):
|
||||||
if len(filters) == 1:
|
if len(filters) == 1:
|
||||||
@@ -144,3 +174,74 @@ class MsSqlEngine(AbstractEngineClass):
|
|||||||
|
|
||||||
filters = [_op(_a, _b)] + filters
|
filters = [_op(_a, _b)] + filters
|
||||||
return self.generate_scope_filter(filters, general)
|
return self.generate_scope_filter(filters, general)
|
||||||
|
|
||||||
|
def join_filter(self, item: FilterItem):
|
||||||
|
inner_joins = item.col.split('.')[-2:]
|
||||||
|
join = None
|
||||||
|
for self_join in self.joins:
|
||||||
|
if inner_joins[0] == self_join.__name__ or self.normalize_model_name(inner_joins[0]) == self_join.__name__:
|
||||||
|
join = self_join
|
||||||
|
return getattr(getattr(join, inner_joins[1]), self.get_operator(item.op))(item.val) if join else None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def normalize_model_name(obj):
|
||||||
|
if isinstance(obj, str):
|
||||||
|
return obj.replace('_', '')
|
||||||
|
else:
|
||||||
|
result = {}
|
||||||
|
model_name = str([i for i in obj.keys()][0]).rsplit('_', 1)
|
||||||
|
model_name.pop(-1)
|
||||||
|
model_name = ''.join(model_name)
|
||||||
|
for index in obj.keys():
|
||||||
|
item = index
|
||||||
|
for i in range(5):
|
||||||
|
item = item.replace(f'_{i}_', '_')
|
||||||
|
if item[-1] == '_':
|
||||||
|
item = item[:-1]
|
||||||
|
item = item.replace(model_name + '_', '')
|
||||||
|
result[item] = obj[index]
|
||||||
|
return result
|
||||||
|
|
||||||
|
def generate_output(self, query, _f):
|
||||||
|
if self.input.e.ot == OutPutType.EXEL:
|
||||||
|
tmp = query.filter(_f).order_by(self.set_sort()).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
|
||||||
|
query = tmp.statement.compile()
|
||||||
|
params = query.params
|
||||||
|
file_name = str(uuid.uuid4().hex) + '.xlsx'
|
||||||
|
MsSqlEngine.output_generator(str(query).replace('false', '0'), params,
|
||||||
|
str(self.query_class.bind.url), file_name=file_name, cols=self.input.e.c)
|
||||||
|
return file_name
|
||||||
|
elif self.input.e.ot == OutPutType.JSON:
|
||||||
|
pass
|
||||||
|
elif self.input.e.ot == OutPutType.PDF:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise Exception("Output type not supported.")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@shared_task(name='output_generator_task')
|
||||||
|
def output_generator(query, params, url, file_name, cols):
|
||||||
|
# engine = create_engine(url=url)
|
||||||
|
# session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
# db = session()
|
||||||
|
# datas = db.execute(query, params)
|
||||||
|
# file_dir = os.path.join(tempfile.gettempdir(), file_name)
|
||||||
|
# head_cols = list(str(string.ascii_uppercase))
|
||||||
|
# headers = cols.keys()
|
||||||
|
# # workbook = xlsxwriter.Workbook(file_dir)
|
||||||
|
# worksheet = workbook.add_worksheet()
|
||||||
|
# for header in headers:
|
||||||
|
# worksheet.write(f'{head_cols.pop(0)}1', cols[header])
|
||||||
|
# row = 1
|
||||||
|
# for item in datas:
|
||||||
|
# row += 1
|
||||||
|
# head_cols = list(str(string.ascii_uppercase))
|
||||||
|
# data = MsSqlEngine.normalize_model_name(item)
|
||||||
|
# for col in headers:
|
||||||
|
# if col[-1] == '_':
|
||||||
|
# col = col[:-1]
|
||||||
|
# col = col.replace('.', '_')
|
||||||
|
# worksheet.write(f'{head_cols.pop(0)}{row}', data[col] if col in data else '-')
|
||||||
|
# workbook.close()
|
||||||
|
...
|
||||||
|
return True
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Optional, Any, List
|
from typing import Any
|
||||||
|
from typing import Generic, TypeVar, List, Optional
|
||||||
|
|
||||||
import pydantic
|
import pydantic
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from pydantic.generics import GenericModel
|
||||||
|
|
||||||
|
|
||||||
class FilterItem(BaseModel):
|
class FilterItem(BaseModel):
|
||||||
@@ -12,6 +14,7 @@ class FilterItem(BaseModel):
|
|||||||
op: Optional[str]
|
op: Optional[str]
|
||||||
type: Optional[str]
|
type: Optional[str]
|
||||||
val: Optional[Any]
|
val: Optional[Any]
|
||||||
|
hidden: Optional[bool]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ValidItem(item: dict):
|
def ValidItem(item: dict):
|
||||||
@@ -30,6 +33,12 @@ class Cr(str, Enum):
|
|||||||
AND = 'and'
|
AND = 'and'
|
||||||
|
|
||||||
|
|
||||||
|
class OutPutType(str, Enum):
|
||||||
|
JSON = 'json'
|
||||||
|
EXEL = 'exel'
|
||||||
|
PDF = 'pdf'
|
||||||
|
|
||||||
|
|
||||||
class FilterScope(BaseModel):
|
class FilterScope(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
items: Optional[List[FilterItem]]
|
items: Optional[List[FilterItem]]
|
||||||
@@ -60,6 +69,7 @@ class FilterScope(BaseModel):
|
|||||||
class Page(BaseModel):
|
class Page(BaseModel):
|
||||||
c: int = 1
|
c: int = 1
|
||||||
s: int = 5
|
s: int = 5
|
||||||
|
force: Optional[bool] = False
|
||||||
|
|
||||||
|
|
||||||
class SearchModel(BaseModel):
|
class SearchModel(BaseModel):
|
||||||
@@ -67,11 +77,23 @@ class SearchModel(BaseModel):
|
|||||||
cols: Optional[List[Any]]
|
cols: Optional[List[Any]]
|
||||||
|
|
||||||
|
|
||||||
|
class ExportModel(BaseModel):
|
||||||
|
ot: Optional[OutPutType]
|
||||||
|
c: Optional[dict]
|
||||||
|
d: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class SortModel(BaseModel):
|
class SortModel(BaseModel):
|
||||||
field: Optional[str]
|
field: Optional[str]
|
||||||
direction: Optional[str]
|
direction: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class MultiSortModel(BaseModel):
|
||||||
|
field: Optional[str]
|
||||||
|
direction: Optional[str]
|
||||||
|
fields: Optional[List[SortModel]]
|
||||||
|
|
||||||
|
|
||||||
class JoinModel(BaseModel):
|
class JoinModel(BaseModel):
|
||||||
model: BaseModel
|
model: BaseModel
|
||||||
show: List[str]
|
show: List[str]
|
||||||
@@ -88,17 +110,19 @@ class Config:
|
|||||||
class TableEngineInput(BaseModel):
|
class TableEngineInput(BaseModel):
|
||||||
f: Optional[List[FilterScope]]
|
f: Optional[List[FilterScope]]
|
||||||
extra_filter: list = []
|
extra_filter: list = []
|
||||||
o: Optional[SortModel]
|
o: Optional[MultiSortModel]
|
||||||
p: Optional[Page] = Page()
|
p: Optional[Page] = Page()
|
||||||
s: Optional[SearchModel]
|
s: Optional[SearchModel]
|
||||||
|
e: Optional[ExportModel]
|
||||||
is_deleted: Optional[bool]
|
is_deleted: Optional[bool]
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
_input = {**{'p': {'c': 1, 's': 5},
|
_input = {**{'p': {'c': 1, 's': 5},
|
||||||
'f': [], 's': {}, 'o': {}}, **(kwargs or {})}
|
'f': [], 's': {}, 'o': {}, 'e': {}}, **(kwargs or {})}
|
||||||
self.p = Page(**_input.get('p'))
|
self.p = Page(**_input.get('p'))
|
||||||
self.o = SortModel(**_input.get('o'))
|
self.o = MultiSortModel(**_input.get('o'))
|
||||||
|
self.e = ExportModel(**_input.get('e'))
|
||||||
if _input.get('f'):
|
if _input.get('f'):
|
||||||
self.f = [FilterScope(**f) for f in
|
self.f = [FilterScope(**f) for f in
|
||||||
filter(lambda fs: FilterScope.ValidScope(fs), _input.get('f'))]
|
filter(lambda fs: FilterScope.ValidScope(fs), _input.get('f'))]
|
||||||
@@ -135,7 +159,10 @@ class TableEngineInput(BaseModel):
|
|||||||
return self.page() + 1
|
return self.page() + 1
|
||||||
|
|
||||||
def get_limit(self):
|
def get_limit(self):
|
||||||
|
# HIT : LIMIT 0 : in Mongo Return all records
|
||||||
limit = self.p.s if self.p else 20
|
limit = self.p.s if self.p else 20
|
||||||
|
if self.p.force:
|
||||||
|
return 1000000
|
||||||
return limit if limit < 100 else 100
|
return limit if limit < 100 else 100
|
||||||
|
|
||||||
def text_search_cols(self, cols: List[str]):
|
def text_search_cols(self, cols: List[str]):
|
||||||
@@ -158,3 +185,26 @@ class TableEngineInput(BaseModel):
|
|||||||
class WorkingMode(Enum):
|
class WorkingMode(Enum):
|
||||||
Development = "development"
|
Development = "development"
|
||||||
Production = "production"
|
Production = "production"
|
||||||
|
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
|
||||||
|
class TableEngineInputType(GenericModel, Generic[T]):
|
||||||
|
f: Optional[List]
|
||||||
|
o: Optional[dict] = {}
|
||||||
|
p: Optional[dict] = {}
|
||||||
|
s: Optional[dict] = {}
|
||||||
|
e: Optional[dict] = {}
|
||||||
|
|
||||||
|
|
||||||
|
class TableEngineExport(GenericModel, Generic[T]):
|
||||||
|
rows: Optional[List[T]]
|
||||||
|
total: Optional[int]
|
||||||
|
page: Optional[int]
|
||||||
|
te: Optional[TableEngineInputType]
|
||||||
|
|
||||||
|
|
||||||
|
class TableEngineRequestType(GenericModel, Generic[T]):
|
||||||
|
te: Optional[TableEngineInputType]
|
||||||
|
extra: Optional[dict]
|
||||||
|
|||||||
Reference in New Issue
Block a user