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,168 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from deepfos.core.logictable import MetaTable
|
|
6
|
+
from deepfos.lib.utils import unpack_expr
|
|
7
|
+
from deepfos.element.dimension import Dimension as EleDimension
|
|
8
|
+
from deepfos.element.datatable import DataTableClickHouse, DataTableMySQL
|
|
9
|
+
from ._base import DimensionBase, MemberBase, MemberContainer, NAME_DFLT
|
|
10
|
+
from .dimexpr import DimExprAnalysor
|
|
11
|
+
|
|
12
|
+
# -----------------------------------------------------------------------------
|
|
13
|
+
# typing
|
|
14
|
+
T_AbsDataTable = Union[DataTableMySQL, DataTableClickHouse]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# -----------------------------------------------------------------------------
|
|
18
|
+
# core
|
|
19
|
+
class AsMbrContainer:
|
|
20
|
+
def __init__(self, func, include_self=False):
|
|
21
|
+
self.func = func
|
|
22
|
+
self.include_self = include_self
|
|
23
|
+
|
|
24
|
+
def __get__(self, instance, owner=None):
|
|
25
|
+
with instance.tbl_dim.temporary_lock(name__in=instance.name_list):
|
|
26
|
+
with self.func(instance):
|
|
27
|
+
rslt = instance.data_tbl.data
|
|
28
|
+
if self.include_self:
|
|
29
|
+
# noinspection PyProtectedMember
|
|
30
|
+
rslt = rslt.append(instance._data)
|
|
31
|
+
return SysDimMemberContainer(rslt, *instance.split(), hierarchy=self.name)
|
|
32
|
+
|
|
33
|
+
def __set_name__(self, owner, name):
|
|
34
|
+
self.name = name
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class SysDimension(DimensionBase):
|
|
38
|
+
"""
|
|
39
|
+
系统维度
|
|
40
|
+
|
|
41
|
+
绕过维度元素,使用维度底层数据表创建的维度
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
dimname: 维度名称
|
|
45
|
+
tbl_closure: 维度绑定的closure表,记录维度层级关系
|
|
46
|
+
tbl_dim: 维度数据表
|
|
47
|
+
name_only: 是否仅需要维度名 (Cube用)
|
|
48
|
+
folder_id: 维度所在文件夹ID
|
|
49
|
+
path: 维度所在绝对路径
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
dimname: str,
|
|
55
|
+
tbl_closure: T_AbsDataTable = None,
|
|
56
|
+
tbl_dim: T_AbsDataTable = None,
|
|
57
|
+
name_only: bool = False,
|
|
58
|
+
folder_id: str = None,
|
|
59
|
+
path: str = None,
|
|
60
|
+
server_name: str = None,
|
|
61
|
+
):
|
|
62
|
+
super().__init__(dimname)
|
|
63
|
+
self._name_only = name_only
|
|
64
|
+
if tbl_closure is None or tbl_dim is None:
|
|
65
|
+
tbl_dim, tbl_closure = self._get_datatable(folder_id, path, server_name)
|
|
66
|
+
|
|
67
|
+
self._create_tree(tbl_closure, tbl_dim, name_only)
|
|
68
|
+
|
|
69
|
+
def _create_tree(self, tbl_closure, tbl_dim, name_only: bool):
|
|
70
|
+
# 组建table_dimension和table_closure的关联关系
|
|
71
|
+
# 父表为table_closure,以不同字段关联两张table_dimension
|
|
72
|
+
self.tbl_closure = MetaTable(tbl_closure.table_name, tuple(), {"datatable": tbl_closure})
|
|
73
|
+
self.tbl_dim = MetaTable(
|
|
74
|
+
tbl_dim.table_name, tuple(),
|
|
75
|
+
{"datatable": tbl_dim, "parent": {"cls": self.tbl_closure, 'on': ('id',), "alias": ('ancestor',)}}
|
|
76
|
+
)
|
|
77
|
+
self.data_tbl = MetaTable(
|
|
78
|
+
tbl_dim.table_name + '_data', tuple(),
|
|
79
|
+
{
|
|
80
|
+
"datatable": tbl_dim,
|
|
81
|
+
"parent": {"cls": self.tbl_closure, 'alias': ('descendants',), 'on': ('id',)}
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
if name_only:
|
|
85
|
+
self.data_tbl.fields = (NAME_DFLT,)
|
|
86
|
+
|
|
87
|
+
def _get_datatable(self, folder_id: str, path: str, server_name: str = None):
|
|
88
|
+
# 获取table_dimension和table_closure的真实表名
|
|
89
|
+
dim = EleDimension(self.name, folder_id=folder_id, path=path, server_name=server_name)
|
|
90
|
+
return dim.table_dimension, dim.table_closure
|
|
91
|
+
|
|
92
|
+
def __getitem__(self, item):
|
|
93
|
+
if self._name_only:
|
|
94
|
+
data = pd.DataFrame(data={NAME_DFLT: [item]})
|
|
95
|
+
return SysDimMember(item, self.tbl_closure, self.tbl_dim, self.data_tbl, data)
|
|
96
|
+
return SysDimMember(item, self.tbl_closure, self.tbl_dim, self.data_tbl)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
_base = lambda self: self.data_tbl.temporary_lock(is_base__eq=1)
|
|
100
|
+
_children = lambda self: self.tbl_closure.temporary_lock(distance__eq=1)
|
|
101
|
+
_descendant = lambda self: self.tbl_closure.temporary_lock(distance__ne=0)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class SysDimMember(MemberBase):
|
|
105
|
+
def __init__(self, name, tbl_closure, tbl_dim, data_tbl, data=None):
|
|
106
|
+
super().__init__(name)
|
|
107
|
+
self.tbl_closure = tbl_closure
|
|
108
|
+
self.tbl_dim = tbl_dim
|
|
109
|
+
self.data_tbl = data_tbl
|
|
110
|
+
self.name_list = (name, ) if isinstance(name, str) else name
|
|
111
|
+
if data is None:
|
|
112
|
+
self._data = self._fetch_data()
|
|
113
|
+
else:
|
|
114
|
+
self._data = data
|
|
115
|
+
if len(self.name_list) != len(self._data):
|
|
116
|
+
unknown = set(self.name_list) - set(self._data.name)
|
|
117
|
+
raise ValueError(f"Dimension {unknown!r} does not exist.")
|
|
118
|
+
|
|
119
|
+
def _fetch_data(self):
|
|
120
|
+
with self.tbl_dim.temporary_lock(name__in=self.name_list):
|
|
121
|
+
return self.tbl_dim.data
|
|
122
|
+
|
|
123
|
+
Base = AsMbrContainer(_base)
|
|
124
|
+
IBase = AsMbrContainer(_base, include_self=True)
|
|
125
|
+
Children = AsMbrContainer(_children)
|
|
126
|
+
IChildren = AsMbrContainer(_children, include_self=True)
|
|
127
|
+
Descendant = AsMbrContainer(_descendant)
|
|
128
|
+
IDescendant = AsMbrContainer(_descendant, include_self=True)
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def members(self):
|
|
132
|
+
return list(self._data.itertuples(index=False))
|
|
133
|
+
|
|
134
|
+
def __str__(self):
|
|
135
|
+
return ';'.join(self.name_list)
|
|
136
|
+
|
|
137
|
+
def where(self, method, **kwargs):
|
|
138
|
+
return SysDimMemberContainer(self._data, *self.split()).where(method, **kwargs)
|
|
139
|
+
|
|
140
|
+
def remove(self, *to_remove):
|
|
141
|
+
return SysDimMemberContainer(self._data, *self.split()).remove(*to_remove)
|
|
142
|
+
|
|
143
|
+
def split(self):
|
|
144
|
+
"""分解为仅行单个成员的SysDimMember"""
|
|
145
|
+
if len(self.name_list) == 1:
|
|
146
|
+
return [self]
|
|
147
|
+
|
|
148
|
+
rtn = []
|
|
149
|
+
for idx, name in enumerate(self.name_list):
|
|
150
|
+
rtn.append(self.__class__(
|
|
151
|
+
name, self.tbl_dim, self.tbl_closure, self.data_tbl,
|
|
152
|
+
data=self._data.iloc[idx:idx+1]))
|
|
153
|
+
return rtn
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class SysDimMemberContainer(MemberContainer):
|
|
157
|
+
def __init__(self, data, *anchor_mbr, hierarchy=None):
|
|
158
|
+
super().__init__(*anchor_mbr, hierarchy=hierarchy)
|
|
159
|
+
self.__data = data
|
|
160
|
+
|
|
161
|
+
def _get_all_member(self):
|
|
162
|
+
return list(self.__data.itertuples(index=False))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def read_expr(dim_expr):
|
|
166
|
+
dimname, expr = unpack_expr(dim_expr)
|
|
167
|
+
dim = SysDimension(dimname)
|
|
168
|
+
return DimExprAnalysor(dim, expr).solve()
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from typing import Iterable, Optional
|
|
2
|
+
from collections import UserDict, defaultdict
|
|
3
|
+
import itertools
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from loguru import logger
|
|
7
|
+
from .sqlcondition import SQLCondition
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Cache(UserDict):
|
|
11
|
+
def __init__(self, *args, **kwds):
|
|
12
|
+
super(Cache, self).__init__(*args, **kwds)
|
|
13
|
+
self.__ref_count = defaultdict(int)
|
|
14
|
+
self.__idx_map = {}
|
|
15
|
+
self._counter = itertools.count(1).__next__
|
|
16
|
+
|
|
17
|
+
def pop_by_score(self, score_func=None, highest=False):
|
|
18
|
+
if not self:
|
|
19
|
+
raise KeyError('dictionary is empty')
|
|
20
|
+
|
|
21
|
+
score_func = score_func or self._score_idx_plus_ref
|
|
22
|
+
|
|
23
|
+
sorted_keys = sorted(self.__idx_map.items(), key=score_func, reverse=highest)
|
|
24
|
+
pop_key = sorted_keys[0][0]
|
|
25
|
+
pop_val = self.pop(pop_key)
|
|
26
|
+
self.__idx_map.pop(pop_key)
|
|
27
|
+
return pop_key, pop_val
|
|
28
|
+
|
|
29
|
+
def _score_idx_plus_ref(self, key_with_idx, weight_idx=0.8, weight_ref=1):
|
|
30
|
+
key, idx = key_with_idx
|
|
31
|
+
ref_count = self.__ref_count[key]
|
|
32
|
+
return idx * weight_idx + ref_count * weight_ref
|
|
33
|
+
|
|
34
|
+
def __getitem__(self, item):
|
|
35
|
+
val = super(Cache, self).__getitem__(item)
|
|
36
|
+
self.__ref_count[item] += 1
|
|
37
|
+
return val
|
|
38
|
+
|
|
39
|
+
def __setitem__(self, key, value):
|
|
40
|
+
rslt = super(Cache, self).__setitem__(key, value)
|
|
41
|
+
self.__idx_map[key] = self._counter()
|
|
42
|
+
return rslt
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Fields:
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
fields: Optional[Iterable[str]],
|
|
49
|
+
extra_fields: Optional[Iterable[str]] = None
|
|
50
|
+
):
|
|
51
|
+
if fields is None:
|
|
52
|
+
self.flds = None
|
|
53
|
+
else:
|
|
54
|
+
extra_fields = extra_fields or []
|
|
55
|
+
all_flds = {*fields, *extra_fields}
|
|
56
|
+
if any(fld.strip() == '*' for fld in all_flds):
|
|
57
|
+
self.flds = None
|
|
58
|
+
else:
|
|
59
|
+
self.flds = all_flds
|
|
60
|
+
|
|
61
|
+
def __le__(self, other: 'Fields'):
|
|
62
|
+
if other.flds is None:
|
|
63
|
+
return True
|
|
64
|
+
elif self.flds is None:
|
|
65
|
+
return other.flds is None
|
|
66
|
+
else:
|
|
67
|
+
return self.flds <= other.flds
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class DataProxy:
|
|
71
|
+
def __init__(self, max_size=10):
|
|
72
|
+
self._data_cache = Cache()
|
|
73
|
+
self._cond_cache = dict()
|
|
74
|
+
self._fields_cache = {}
|
|
75
|
+
if not max_size >= 1:
|
|
76
|
+
raise ValueError("Max size must be positive.")
|
|
77
|
+
self._max_size = max_size
|
|
78
|
+
|
|
79
|
+
def make_cache(
|
|
80
|
+
self,
|
|
81
|
+
key: SQLCondition,
|
|
82
|
+
fields: Optional[Iterable[str]],
|
|
83
|
+
value: pd.DataFrame,
|
|
84
|
+
force_update: bool = False
|
|
85
|
+
):
|
|
86
|
+
series_code = key.serialized
|
|
87
|
+
|
|
88
|
+
if not force_update and series_code in self._cond_cache \
|
|
89
|
+
and Fields(fields) <= self._fields_cache[series_code]:
|
|
90
|
+
logger.debug("Found a better version in cache. Skip update.")
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
self._data_cache[series_code] = value
|
|
94
|
+
self._cond_cache[series_code] = key
|
|
95
|
+
self._fields_cache[series_code] = Fields(fields)
|
|
96
|
+
|
|
97
|
+
if len(self._data_cache) > self._max_size:
|
|
98
|
+
rm_key, _ = self._data_cache.pop_by_score()
|
|
99
|
+
logger.debug(f'Removed cache with lowest score:\n{_}')
|
|
100
|
+
self._cond_cache.pop(rm_key)
|
|
101
|
+
self._fields_cache.pop(rm_key)
|
|
102
|
+
|
|
103
|
+
def get_data(self, key: SQLCondition, fields: Optional[Iterable[str]]):
|
|
104
|
+
series_code = key.serialized
|
|
105
|
+
if series_code in self._data_cache:
|
|
106
|
+
fields_memo = Fields(fields)
|
|
107
|
+
if fields_memo <= self._fields_cache[series_code]:
|
|
108
|
+
logger.debug("Found perfect-match from cache.")
|
|
109
|
+
if fields_memo.flds is None:
|
|
110
|
+
return self._data_cache[series_code]
|
|
111
|
+
else:
|
|
112
|
+
return self._data_cache[series_code][list(fields)]
|
|
113
|
+
|
|
114
|
+
for sql_cnd in self._cond_cache.values():
|
|
115
|
+
# 不用小于号是为了避免重复调用__eq__
|
|
116
|
+
if key <= sql_cnd:
|
|
117
|
+
series_code = sql_cnd.serialized
|
|
118
|
+
fields_memo = Fields(fields, key.all_fields)
|
|
119
|
+
|
|
120
|
+
if fields_memo <= self._fields_cache[series_code]:
|
|
121
|
+
cache = self._data_cache[sql_cnd.serialized]
|
|
122
|
+
data = self.query_from_cache(cache, key)
|
|
123
|
+
if fields_memo.flds is None:
|
|
124
|
+
return data
|
|
125
|
+
else:
|
|
126
|
+
return data[list(fields)]
|
|
127
|
+
return None
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def query_from_cache(cache: pd.DataFrame, key: SQLCondition):
|
|
131
|
+
logger.debug(f"Query {key!r} from cache:\n{cache}")
|
|
132
|
+
query_str = key.to_pandasql()
|
|
133
|
+
if query_str is None:
|
|
134
|
+
data = cache
|
|
135
|
+
else:
|
|
136
|
+
data = cache.query(query_str)
|
|
137
|
+
fields = key.fields
|
|
138
|
+
if fields:
|
|
139
|
+
data = data.merge(key.val_list, on=fields, how='inner')
|
|
140
|
+
logger.debug(f"Got DATA from cache:\n{data}")
|
|
141
|
+
return data.reset_index(drop=True)
|