deepfos 1.1.60__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- deepfos/__init__.py +6 -0
- deepfos/_version.py +21 -0
- deepfos/algo/__init__.py +0 -0
- deepfos/algo/graph.py +171 -0
- deepfos/algo/segtree.py +31 -0
- deepfos/api/V1_1/__init__.py +0 -0
- deepfos/api/V1_1/business_model.py +119 -0
- deepfos/api/V1_1/dimension.py +599 -0
- deepfos/api/V1_1/models/__init__.py +0 -0
- deepfos/api/V1_1/models/business_model.py +1033 -0
- deepfos/api/V1_1/models/dimension.py +2768 -0
- deepfos/api/V1_2/__init__.py +0 -0
- deepfos/api/V1_2/dimension.py +285 -0
- deepfos/api/V1_2/models/__init__.py +0 -0
- deepfos/api/V1_2/models/dimension.py +2923 -0
- deepfos/api/__init__.py +0 -0
- deepfos/api/account.py +167 -0
- deepfos/api/accounting_engines.py +147 -0
- deepfos/api/app.py +626 -0
- deepfos/api/approval_process.py +198 -0
- deepfos/api/base.py +983 -0
- deepfos/api/business_model.py +160 -0
- deepfos/api/consolidation.py +129 -0
- deepfos/api/consolidation_process.py +106 -0
- deepfos/api/datatable.py +341 -0
- deepfos/api/deep_pipeline.py +61 -0
- deepfos/api/deepconnector.py +36 -0
- deepfos/api/deepfos_task.py +92 -0
- deepfos/api/deepmodel.py +188 -0
- deepfos/api/dimension.py +486 -0
- deepfos/api/financial_model.py +319 -0
- deepfos/api/journal_model.py +119 -0
- deepfos/api/journal_template.py +132 -0
- deepfos/api/memory_financial_model.py +98 -0
- deepfos/api/models/__init__.py +3 -0
- deepfos/api/models/account.py +483 -0
- deepfos/api/models/accounting_engines.py +756 -0
- deepfos/api/models/app.py +1338 -0
- deepfos/api/models/approval_process.py +1043 -0
- deepfos/api/models/base.py +234 -0
- deepfos/api/models/business_model.py +805 -0
- deepfos/api/models/consolidation.py +711 -0
- deepfos/api/models/consolidation_process.py +248 -0
- deepfos/api/models/datatable_mysql.py +427 -0
- deepfos/api/models/deep_pipeline.py +55 -0
- deepfos/api/models/deepconnector.py +28 -0
- deepfos/api/models/deepfos_task.py +386 -0
- deepfos/api/models/deepmodel.py +308 -0
- deepfos/api/models/dimension.py +1576 -0
- deepfos/api/models/financial_model.py +1796 -0
- deepfos/api/models/journal_model.py +341 -0
- deepfos/api/models/journal_template.py +854 -0
- deepfos/api/models/memory_financial_model.py +478 -0
- deepfos/api/models/platform.py +178 -0
- deepfos/api/models/python.py +221 -0
- deepfos/api/models/reconciliation_engine.py +411 -0
- deepfos/api/models/reconciliation_report.py +161 -0
- deepfos/api/models/role_strategy.py +884 -0
- deepfos/api/models/smartlist.py +237 -0
- deepfos/api/models/space.py +1137 -0
- deepfos/api/models/system.py +1065 -0
- deepfos/api/models/variable.py +463 -0
- deepfos/api/models/workflow.py +946 -0
- deepfos/api/platform.py +199 -0
- deepfos/api/python.py +90 -0
- deepfos/api/reconciliation_engine.py +181 -0
- deepfos/api/reconciliation_report.py +64 -0
- deepfos/api/role_strategy.py +234 -0
- deepfos/api/smartlist.py +69 -0
- deepfos/api/space.py +582 -0
- deepfos/api/system.py +372 -0
- deepfos/api/variable.py +154 -0
- deepfos/api/workflow.py +264 -0
- deepfos/boost/__init__.py +6 -0
- deepfos/boost/py_jstream.py +89 -0
- deepfos/boost/py_pandas.py +20 -0
- deepfos/cache.py +121 -0
- deepfos/config.py +6 -0
- deepfos/core/__init__.py +27 -0
- deepfos/core/cube/__init__.py +10 -0
- deepfos/core/cube/_base.py +462 -0
- deepfos/core/cube/constants.py +21 -0
- deepfos/core/cube/cube.py +408 -0
- deepfos/core/cube/formula.py +707 -0
- deepfos/core/cube/syscube.py +532 -0
- deepfos/core/cube/typing.py +7 -0
- deepfos/core/cube/utils.py +238 -0
- deepfos/core/dimension/__init__.py +11 -0
- deepfos/core/dimension/_base.py +506 -0
- deepfos/core/dimension/dimcreator.py +184 -0
- deepfos/core/dimension/dimension.py +472 -0
- deepfos/core/dimension/dimexpr.py +271 -0
- deepfos/core/dimension/dimmember.py +155 -0
- deepfos/core/dimension/eledimension.py +22 -0
- deepfos/core/dimension/filters.py +99 -0
- deepfos/core/dimension/sysdimension.py +168 -0
- deepfos/core/logictable/__init__.py +5 -0
- deepfos/core/logictable/_cache.py +141 -0
- deepfos/core/logictable/_operator.py +663 -0
- deepfos/core/logictable/nodemixin.py +673 -0
- deepfos/core/logictable/sqlcondition.py +609 -0
- deepfos/core/logictable/tablemodel.py +497 -0
- deepfos/db/__init__.py +36 -0
- deepfos/db/cipher.py +660 -0
- deepfos/db/clickhouse.py +191 -0
- deepfos/db/connector.py +195 -0
- deepfos/db/daclickhouse.py +171 -0
- deepfos/db/dameng.py +101 -0
- deepfos/db/damysql.py +189 -0
- deepfos/db/dbkits.py +358 -0
- deepfos/db/deepengine.py +99 -0
- deepfos/db/deepmodel.py +82 -0
- deepfos/db/deepmodel_kingbase.py +83 -0
- deepfos/db/edb.py +214 -0
- deepfos/db/gauss.py +83 -0
- deepfos/db/kingbase.py +83 -0
- deepfos/db/mysql.py +184 -0
- deepfos/db/oracle.py +131 -0
- deepfos/db/postgresql.py +192 -0
- deepfos/db/sqlserver.py +99 -0
- deepfos/db/utils.py +135 -0
- deepfos/element/__init__.py +89 -0
- deepfos/element/accounting.py +348 -0
- deepfos/element/apvlprocess.py +215 -0
- deepfos/element/base.py +398 -0
- deepfos/element/bizmodel.py +1269 -0
- deepfos/element/datatable.py +2467 -0
- deepfos/element/deep_pipeline.py +186 -0
- deepfos/element/deepconnector.py +59 -0
- deepfos/element/deepmodel.py +1806 -0
- deepfos/element/dimension.py +1254 -0
- deepfos/element/fact_table.py +427 -0
- deepfos/element/finmodel.py +1485 -0
- deepfos/element/journal.py +840 -0
- deepfos/element/journal_template.py +943 -0
- deepfos/element/pyscript.py +412 -0
- deepfos/element/reconciliation.py +553 -0
- deepfos/element/rolestrategy.py +243 -0
- deepfos/element/smartlist.py +457 -0
- deepfos/element/variable.py +756 -0
- deepfos/element/workflow.py +560 -0
- deepfos/exceptions/__init__.py +239 -0
- deepfos/exceptions/hook.py +86 -0
- deepfos/lazy.py +104 -0
- deepfos/lazy_import.py +84 -0
- deepfos/lib/__init__.py +0 -0
- deepfos/lib/_javaobj.py +366 -0
- deepfos/lib/asynchronous.py +879 -0
- deepfos/lib/concurrency.py +107 -0
- deepfos/lib/constant.py +39 -0
- deepfos/lib/decorator.py +310 -0
- deepfos/lib/deepchart.py +778 -0
- deepfos/lib/deepux.py +477 -0
- deepfos/lib/discovery.py +273 -0
- deepfos/lib/edb_lexer.py +789 -0
- deepfos/lib/eureka.py +156 -0
- deepfos/lib/filterparser.py +751 -0
- deepfos/lib/httpcli.py +106 -0
- deepfos/lib/jsonstreamer.py +80 -0
- deepfos/lib/msg.py +394 -0
- deepfos/lib/nacos.py +225 -0
- deepfos/lib/patch.py +92 -0
- deepfos/lib/redis.py +241 -0
- deepfos/lib/serutils.py +181 -0
- deepfos/lib/stopwatch.py +99 -0
- deepfos/lib/subtask.py +572 -0
- deepfos/lib/sysutils.py +703 -0
- deepfos/lib/utils.py +1003 -0
- deepfos/local.py +160 -0
- deepfos/options.py +670 -0
- deepfos/translation.py +237 -0
- deepfos-1.1.60.dist-info/METADATA +33 -0
- deepfos-1.1.60.dist-info/RECORD +175 -0
- deepfos-1.1.60.dist-info/WHEEL +5 -0
- deepfos-1.1.60.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
from contextlib import asynccontextmanager
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Union, Iterable, Dict, Any, Sequence, List, TYPE_CHECKING, Optional
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from pypika import ClickHouseQuery, Order
|
|
7
|
+
from pypika.queries import QueryBuilder, Table
|
|
8
|
+
from pypika.terms import Term, EmptyCriterion, Field, CustomFunction, ValueWrapper
|
|
9
|
+
|
|
10
|
+
from deepfos.api.datatable import ClickHouseAPI
|
|
11
|
+
from deepfos.api.models.datatable_mysql import CustomSqlRespDTO
|
|
12
|
+
from deepfos.element.datatable import AsyncDataTableClickHouse, T_DictLike, AsyncDirectAccessDataTableClickHouse # noqa
|
|
13
|
+
from deepfos.lib.constant import DECIMAL_COL, STRING_COL
|
|
14
|
+
from deepfos.element.base import SyncMeta
|
|
15
|
+
from deepfos.lib.utils import FrozenClass
|
|
16
|
+
from deepfos.lib.decorator import cached_property
|
|
17
|
+
|
|
18
|
+
__all__ = ['AsyncFactTable', 'FactTable']
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AsyncFactTable(AsyncDataTableClickHouse):
|
|
22
|
+
"""事实表"""
|
|
23
|
+
api_class = ClickHouseAPI
|
|
24
|
+
api: ClickHouseAPI
|
|
25
|
+
query = ClickHouseQuery
|
|
26
|
+
|
|
27
|
+
@cached_property
|
|
28
|
+
def dim_cols(self):
|
|
29
|
+
return sorted([col.name for col in self.meta.datatableColumn if col.whetherPrimary])
|
|
30
|
+
|
|
31
|
+
async def insert_null(self, where: Union[Term, EmptyCriterion] = None):
|
|
32
|
+
"""
|
|
33
|
+
删除事实表的数据
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
where: 删除条件。列名-> 要删除的值
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
Hint:
|
|
40
|
+
实际通过insert除createdate、createtime外,皆为NULL的数据实现
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
main_query = self._build_query_with_valid_data(sub_query_col=self.dim_cols, where=where)
|
|
45
|
+
|
|
46
|
+
main_table = Table("main_table")
|
|
47
|
+
|
|
48
|
+
createtime = _timestamp()
|
|
49
|
+
createdate = _format_dt()
|
|
50
|
+
insert_null = self.query.into(self.table) \
|
|
51
|
+
.columns(*self.dim_cols, DECIMAL_COL, STRING_COL, 'createtime', 'createdate') \
|
|
52
|
+
.from_(main_query.as_("main_table")) \
|
|
53
|
+
.select(*[main_table.field(dim) for dim in self.dim_cols], None, None,
|
|
54
|
+
ValueWrapper(createtime), ValueWrapper(createdate))
|
|
55
|
+
|
|
56
|
+
sql = insert_null.get_sql(quote_char='`')
|
|
57
|
+
|
|
58
|
+
return await self.run_sql(sql)
|
|
59
|
+
|
|
60
|
+
delete = insert_null
|
|
61
|
+
|
|
62
|
+
def _build_select_sql(
|
|
63
|
+
self,
|
|
64
|
+
columns: Iterable[Union[str, Term]] = None,
|
|
65
|
+
where: Union[Term, EmptyCriterion] = None,
|
|
66
|
+
distinct: bool = False,
|
|
67
|
+
groupby: Iterable[Union[str, int, Term]] = None,
|
|
68
|
+
having: Iterable[Union[Term, EmptyCriterion]] = None,
|
|
69
|
+
orderby: Iterable[Union[str, Field]] = None,
|
|
70
|
+
order: Union[Order, str] = Order.asc,
|
|
71
|
+
limit: int = None,
|
|
72
|
+
offset: int = None,
|
|
73
|
+
) -> str:
|
|
74
|
+
col = []
|
|
75
|
+
if columns is None:
|
|
76
|
+
col = [*self.dim_cols]
|
|
77
|
+
else:
|
|
78
|
+
for c in columns:
|
|
79
|
+
col.append(self._gen_col(c))
|
|
80
|
+
col = sorted(list(set(col).union(self.dim_cols)))
|
|
81
|
+
|
|
82
|
+
if DECIMAL_COL in col:
|
|
83
|
+
col.remove(DECIMAL_COL)
|
|
84
|
+
if STRING_COL in col:
|
|
85
|
+
col.remove(STRING_COL)
|
|
86
|
+
main_query = self._build_query_with_valid_data(col, columns, where, distinct, groupby, having, orderby, order,
|
|
87
|
+
limit, offset)
|
|
88
|
+
sql = main_query.get_sql(quote_char='`')
|
|
89
|
+
return sql
|
|
90
|
+
|
|
91
|
+
async def insert(
|
|
92
|
+
self,
|
|
93
|
+
value_map: Dict[str, Any] = None,
|
|
94
|
+
value_list: Iterable[Sequence[Any]] = None,
|
|
95
|
+
columns: Iterable[Union[str, Term]] = None,
|
|
96
|
+
):
|
|
97
|
+
"""
|
|
98
|
+
插入数据,数据量极少时推荐使用
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
value_map: 以键值对(列名 -> 插入值)提供的入库数据
|
|
102
|
+
value_list: 入库数据(不包含列数据)
|
|
103
|
+
columns: 入库数据对应的列,不提供则默认使用全部列
|
|
104
|
+
|
|
105
|
+
"""
|
|
106
|
+
if value_map is not None:
|
|
107
|
+
for v in value_map:
|
|
108
|
+
if not isinstance(value_map[v], List):
|
|
109
|
+
value_map[v] = [value_map[v]]
|
|
110
|
+
df = pd.DataFrame(value_map)
|
|
111
|
+
elif value_list is None:
|
|
112
|
+
raise ValueError('None of argumnet [value_map, value_list] is set.')
|
|
113
|
+
else:
|
|
114
|
+
if columns:
|
|
115
|
+
df = pd.DataFrame(value_list, columns=list(columns))
|
|
116
|
+
else:
|
|
117
|
+
df = pd.DataFrame(value_list, columns=self.structure.columns.keys())
|
|
118
|
+
|
|
119
|
+
return await self.insert_df(df)
|
|
120
|
+
|
|
121
|
+
async def insert_df(
|
|
122
|
+
self,
|
|
123
|
+
dataframe: pd.DataFrame,
|
|
124
|
+
updatecol: Iterable = None,
|
|
125
|
+
chunksize: int = 5000,
|
|
126
|
+
auto_fit: bool = True,
|
|
127
|
+
) -> Union[CustomSqlRespDTO, Dict, List, None]:
|
|
128
|
+
"""将 ``DataFrame`` 的数据插入当前事实表
|
|
129
|
+
|
|
130
|
+
入库前会对DataFrame的数据作以下处理:
|
|
131
|
+
|
|
132
|
+
#. (强制)所有空值变更为 null,确保能正常入库
|
|
133
|
+
#. (强制)以当前时间信息覆盖createdate和createtime列
|
|
134
|
+
#. (非强制)对于 **不可为空** 的字符串类型数据列,会填充 ``'null'`` 字符串(未来可能会修改,不要依赖这个逻辑)
|
|
135
|
+
#. (非强制)对于decimal类型,自动 ``round`` 至规定小数位
|
|
136
|
+
|
|
137
|
+
上述 **(非强制)** 逻辑,可以通过指定 ``auto_fit=False`` 关闭。
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
dataframe: 待插入数据
|
|
141
|
+
updatecol: 更新的列 (用于INSERT INTO ON DUPLICATE)
|
|
142
|
+
chunksize: 单次插库的数据行数
|
|
143
|
+
auto_fit: 是否自动进行数据调整
|
|
144
|
+
|
|
145
|
+
Hint:
|
|
146
|
+
如果单次入库数据过多,导致超出数据库的单条sql语句的上限,可以降低
|
|
147
|
+
chuncksize,此方法将把一条较大的sql拆分成多条执行。
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
执行的操作记录
|
|
151
|
+
|
|
152
|
+
"""
|
|
153
|
+
dataframe = dataframe.copy()
|
|
154
|
+
dataframe['createtime'] = _timestamp()
|
|
155
|
+
dataframe['createdate'] = pd.to_datetime(_format_dt())
|
|
156
|
+
|
|
157
|
+
return await super().insert_df(dataframe, updatecol, chunksize, auto_fit)
|
|
158
|
+
|
|
159
|
+
async def update(
|
|
160
|
+
self,
|
|
161
|
+
assignment_list: T_DictLike,
|
|
162
|
+
where: Union[None, Term, EmptyCriterion]
|
|
163
|
+
):
|
|
164
|
+
"""
|
|
165
|
+
更新事实表的数据
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
assignment_list: 更新的字段与对应的更新值
|
|
169
|
+
where: 更新行满足的条件
|
|
170
|
+
|
|
171
|
+
Important:
|
|
172
|
+
实现上使用了insert createtime和createdate 为当前时间,且数据为原最新数据更新了update内容的数据的方式
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
if not isinstance(assignment_list, Dict):
|
|
176
|
+
assignment_list = dict(assignment_list)
|
|
177
|
+
|
|
178
|
+
main_query = self._build_query_with_valid_data(sub_query_col=self.dim_cols, where=where)
|
|
179
|
+
|
|
180
|
+
update_col = {e: e for e in [*self.dim_cols, DECIMAL_COL, STRING_COL]}
|
|
181
|
+
|
|
182
|
+
main_table = Table('main_table')
|
|
183
|
+
|
|
184
|
+
for k, value in assignment_list.items():
|
|
185
|
+
# for constant str, use ValueWrapper to differ with field
|
|
186
|
+
if isinstance(value, str) and value not in [*self.dim_cols, DECIMAL_COL, STRING_COL]:
|
|
187
|
+
value = ValueWrapper(value)
|
|
188
|
+
if isinstance(value, Term):
|
|
189
|
+
value = value.replace_table(self.table, main_table)
|
|
190
|
+
update_col[self._gen_col(k)] = value
|
|
191
|
+
|
|
192
|
+
insert = self.query.into(self.table) \
|
|
193
|
+
.columns(*update_col.keys(), 'createtime', 'createdate') \
|
|
194
|
+
.from_(main_query.as_("main_table")) \
|
|
195
|
+
.select(*update_col.values(),
|
|
196
|
+
ValueWrapper(_timestamp()), ValueWrapper(_format_dt()))
|
|
197
|
+
|
|
198
|
+
sql = insert.get_sql(quote_char='`')
|
|
199
|
+
|
|
200
|
+
return await self.run_sql(sql)
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
@asynccontextmanager
|
|
204
|
+
async def start_transaction(cls, flatten: bool = False):
|
|
205
|
+
"""不可用
|
|
206
|
+
|
|
207
|
+
FactTable不支持事务
|
|
208
|
+
"""
|
|
209
|
+
try:
|
|
210
|
+
yield
|
|
211
|
+
finally:
|
|
212
|
+
raise NotImplementedError('事实表不支持事务.')
|
|
213
|
+
|
|
214
|
+
async def count(
|
|
215
|
+
self,
|
|
216
|
+
where: Union[str, Term, EmptyCriterion],
|
|
217
|
+
) -> int:
|
|
218
|
+
raise NotImplementedError('事实表未实现方法:count.')
|
|
219
|
+
|
|
220
|
+
async def copy_rows(
|
|
221
|
+
self,
|
|
222
|
+
where: Union[str, Term, EmptyCriterion],
|
|
223
|
+
field_map: Dict[str, Union[str, int, FrozenClass, Term]] = None,
|
|
224
|
+
distinct: bool = False,
|
|
225
|
+
) -> CustomSqlRespDTO:
|
|
226
|
+
raise NotImplementedError('事实表未实现方法:copy_rows.')
|
|
227
|
+
|
|
228
|
+
async def update_from_dataframe(
|
|
229
|
+
self,
|
|
230
|
+
source: pd.DataFrame,
|
|
231
|
+
chucksize: Optional[int] = None
|
|
232
|
+
):
|
|
233
|
+
raise NotImplementedError('事实表未实现方法:update_from_dataframe.')
|
|
234
|
+
|
|
235
|
+
_arg_max = CustomFunction('argMax', ['arg', 'val'])
|
|
236
|
+
_ck_if = CustomFunction('if', ['condition', 'if', 'else'])
|
|
237
|
+
_if_null = CustomFunction('ifNull', ['condition', 'val'])
|
|
238
|
+
_to_string = CustomFunction('toString', ['val'])
|
|
239
|
+
|
|
240
|
+
def get_latest_val(self, table, colname):
|
|
241
|
+
return self._ck_if(self._arg_max(self._if_null(self._to_string(table.field(colname)), 'isnull'),
|
|
242
|
+
table.createtime) == 'isnull',
|
|
243
|
+
None,
|
|
244
|
+
self._arg_max(table.field(colname), table.createtime))
|
|
245
|
+
|
|
246
|
+
@staticmethod
|
|
247
|
+
def _gen_col(col):
|
|
248
|
+
if isinstance(col, Term):
|
|
249
|
+
field = col.fields_().copy().pop()
|
|
250
|
+
return field.name
|
|
251
|
+
else:
|
|
252
|
+
return col
|
|
253
|
+
|
|
254
|
+
def _build_query_with_valid_data(
|
|
255
|
+
self,
|
|
256
|
+
sub_query_col: Iterable[Union[str, Term]] = None,
|
|
257
|
+
columns: Iterable[Union[str, Term]] = None,
|
|
258
|
+
where: Union[Term, EmptyCriterion] = None,
|
|
259
|
+
distinct: bool = False,
|
|
260
|
+
groupby: Iterable[Union[str, int, Term]] = None,
|
|
261
|
+
having: Iterable[Union[Term, EmptyCriterion]] = None,
|
|
262
|
+
orderby: Iterable[Union[str, Field]] = None,
|
|
263
|
+
order: Union[Order, str] = Order.asc,
|
|
264
|
+
limit: int = None,
|
|
265
|
+
offset: int = None) -> QueryBuilder:
|
|
266
|
+
if where is not None and not isinstance(where, (Term, EmptyCriterion)):
|
|
267
|
+
raise TypeError('事实表只支持使用Pypika Term或EmptyCriterion作为where条件入参')
|
|
268
|
+
# generate sub query from original table , result is the latest data
|
|
269
|
+
ori_table = Table("ori_table")
|
|
270
|
+
sub_query = self.query.from_(self.table.as_("ori_table")) \
|
|
271
|
+
.select(*sub_query_col,
|
|
272
|
+
self.get_latest_val(ori_table, DECIMAL_COL).as_(DECIMAL_COL),
|
|
273
|
+
self.get_latest_val(ori_table, STRING_COL).as_(STRING_COL))
|
|
274
|
+
|
|
275
|
+
if where is not None:
|
|
276
|
+
sub_query = sub_query.where(where.replace_table(self.table, ori_table))
|
|
277
|
+
|
|
278
|
+
sub_query = sub_query.groupby(*sub_query_col)
|
|
279
|
+
sub_table = Table('sub_table')
|
|
280
|
+
|
|
281
|
+
# generate main query from sub query , result is the notnull data
|
|
282
|
+
main_query = self.query.from_(sub_query.as_("sub_table"))
|
|
283
|
+
|
|
284
|
+
if distinct:
|
|
285
|
+
main_query = main_query.distinct()
|
|
286
|
+
|
|
287
|
+
if columns is None:
|
|
288
|
+
columns = [*self.dim_cols, DECIMAL_COL, STRING_COL]
|
|
289
|
+
|
|
290
|
+
main_query = main_query.select(*columns)
|
|
291
|
+
|
|
292
|
+
main_query = main_query.where(
|
|
293
|
+
(sub_table.field(DECIMAL_COL).isnotnull() | sub_table.field(STRING_COL).isnotnull())
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
if groupby is not None:
|
|
297
|
+
main_query = main_query.groupby(*groupby)
|
|
298
|
+
if having is not None:
|
|
299
|
+
main_query = main_query.having(*having)
|
|
300
|
+
if orderby is not None:
|
|
301
|
+
if isinstance(order, str):
|
|
302
|
+
order = Order[order.lower()]
|
|
303
|
+
main_query = main_query.orderby(*orderby, order=order)
|
|
304
|
+
if limit is not None:
|
|
305
|
+
main_query = main_query.limit(limit)
|
|
306
|
+
if offset is not None:
|
|
307
|
+
main_query = main_query.offset(offset)
|
|
308
|
+
|
|
309
|
+
return main_query.replace_table(self.table, sub_table)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _timestamp(): # pragma: no cover
|
|
313
|
+
return int(datetime.now().timestamp() * 1000)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _format_dt(): # pragma: no cover
|
|
317
|
+
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class FactTable(AsyncFactTable, metaclass=SyncMeta):
|
|
321
|
+
synchronize = (
|
|
322
|
+
'count',
|
|
323
|
+
'select',
|
|
324
|
+
'select_raw',
|
|
325
|
+
'insert',
|
|
326
|
+
'insert_df',
|
|
327
|
+
'delete',
|
|
328
|
+
'update',
|
|
329
|
+
'update_from_dataframe',
|
|
330
|
+
'copy_rows',
|
|
331
|
+
'run_sql',
|
|
332
|
+
'insert_null'
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
@classmethod
|
|
336
|
+
def start_transaction(cls, flatten: bool = False):
|
|
337
|
+
"""不可用
|
|
338
|
+
|
|
339
|
+
FactTable不支持事务
|
|
340
|
+
"""
|
|
341
|
+
raise NotImplementedError('FactTable does not support transaction.')
|
|
342
|
+
|
|
343
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
344
|
+
def count(
|
|
345
|
+
self,
|
|
346
|
+
where: Union[str, Term, EmptyCriterion],
|
|
347
|
+
) -> int:
|
|
348
|
+
...
|
|
349
|
+
|
|
350
|
+
def select(
|
|
351
|
+
self,
|
|
352
|
+
columns: Iterable[Union[str, Term]] = None,
|
|
353
|
+
where: Union[str, Term, EmptyCriterion] = None,
|
|
354
|
+
distinct: bool = False,
|
|
355
|
+
groupby: Iterable[Union[str, int, Term]] = None,
|
|
356
|
+
having: Iterable[Union[Term, EmptyCriterion]] = None,
|
|
357
|
+
orderby: Iterable[Union[str, Field]] = None,
|
|
358
|
+
order: Union[Order, str] = Order.asc,
|
|
359
|
+
limit: int = None,
|
|
360
|
+
offset: int = None,
|
|
361
|
+
) -> pd.DataFrame:
|
|
362
|
+
...
|
|
363
|
+
|
|
364
|
+
def select_raw(
|
|
365
|
+
self,
|
|
366
|
+
columns: Iterable[Union[str, Term]] = None,
|
|
367
|
+
where: Union[str, Term, EmptyCriterion] = None,
|
|
368
|
+
distinct: bool = False,
|
|
369
|
+
groupby: Iterable[Union[str, int, Term]] = None,
|
|
370
|
+
having: Iterable[Union[Term, EmptyCriterion]] = None,
|
|
371
|
+
orderby: Iterable[Union[str, Field]] = None,
|
|
372
|
+
order: Union[Order, str] = Order.asc,
|
|
373
|
+
limit: int = None,
|
|
374
|
+
offset: int = None,
|
|
375
|
+
) -> List[dict]:
|
|
376
|
+
...
|
|
377
|
+
|
|
378
|
+
def insert(
|
|
379
|
+
self,
|
|
380
|
+
value_map: Dict[str, Any] = None,
|
|
381
|
+
value_list: Iterable[Sequence[Any]] = None,
|
|
382
|
+
columns: Iterable[Union[str, Term]] = None,
|
|
383
|
+
):
|
|
384
|
+
...
|
|
385
|
+
|
|
386
|
+
def insert_df(
|
|
387
|
+
self,
|
|
388
|
+
dataframe: pd.DataFrame,
|
|
389
|
+
updatecol: Iterable = None,
|
|
390
|
+
chunksize: int = 5000,
|
|
391
|
+
auto_fit: bool = True,
|
|
392
|
+
) -> Union[CustomSqlRespDTO, Dict, None]:
|
|
393
|
+
...
|
|
394
|
+
|
|
395
|
+
def delete(
|
|
396
|
+
self,
|
|
397
|
+
where: Union[str, Term, EmptyCriterion],
|
|
398
|
+
) -> CustomSqlRespDTO:
|
|
399
|
+
...
|
|
400
|
+
|
|
401
|
+
def update(
|
|
402
|
+
self,
|
|
403
|
+
assignment_list: T_DictLike,
|
|
404
|
+
where: Union[None, Term, EmptyCriterion]
|
|
405
|
+
):
|
|
406
|
+
...
|
|
407
|
+
|
|
408
|
+
def copy_rows(
|
|
409
|
+
self,
|
|
410
|
+
where: Union[str, Term, EmptyCriterion],
|
|
411
|
+
field_map: Dict[str, Union[str, int, FrozenClass, Term]] = None,
|
|
412
|
+
distinct: bool = False,
|
|
413
|
+
) -> CustomSqlRespDTO:
|
|
414
|
+
...
|
|
415
|
+
|
|
416
|
+
def run_sql(self, sql: str) -> Optional[CustomSqlRespDTO]:
|
|
417
|
+
...
|
|
418
|
+
|
|
419
|
+
def update_from_dataframe(
|
|
420
|
+
self,
|
|
421
|
+
source: pd.DataFrame,
|
|
422
|
+
chucksize: Optional[int] = None
|
|
423
|
+
):
|
|
424
|
+
...
|
|
425
|
+
|
|
426
|
+
def insert_null(self, where: Union[str, Term, EmptyCriterion] = None):
|
|
427
|
+
...
|