pytrilogy 0.0.1.117__py3-none-any.whl → 0.0.2.1__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.
Potentially problematic release.
This version of pytrilogy might be problematic. Click here for more details.
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/METADATA +1 -1
- pytrilogy-0.0.2.1.dist-info/RECORD +82 -0
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/WHEEL +1 -1
- trilogy/__init__.py +1 -1
- trilogy/constants.py +6 -0
- trilogy/core/enums.py +7 -2
- trilogy/core/env_processor.py +43 -19
- trilogy/core/functions.py +11 -0
- trilogy/core/models.py +737 -146
- trilogy/core/optimization.py +31 -28
- trilogy/core/optimizations/inline_constant.py +4 -1
- trilogy/core/optimizations/inline_datasource.py +25 -4
- trilogy/core/optimizations/predicate_pushdown.py +94 -54
- trilogy/core/processing/concept_strategies_v3.py +69 -39
- trilogy/core/processing/graph_utils.py +3 -3
- trilogy/core/processing/node_generators/__init__.py +0 -2
- trilogy/core/processing/node_generators/basic_node.py +30 -17
- trilogy/core/processing/node_generators/filter_node.py +3 -1
- trilogy/core/processing/node_generators/node_merge_node.py +345 -96
- trilogy/core/processing/node_generators/rowset_node.py +18 -16
- trilogy/core/processing/node_generators/select_node.py +44 -83
- trilogy/core/processing/nodes/__init__.py +2 -0
- trilogy/core/processing/nodes/base_node.py +22 -5
- trilogy/core/processing/nodes/filter_node.py +3 -0
- trilogy/core/processing/nodes/group_node.py +20 -2
- trilogy/core/processing/nodes/merge_node.py +32 -18
- trilogy/core/processing/nodes/select_node_v2.py +17 -3
- trilogy/core/processing/utility.py +100 -8
- trilogy/core/query_processor.py +77 -24
- trilogy/dialect/base.py +11 -46
- trilogy/dialect/bigquery.py +1 -1
- trilogy/dialect/common.py +11 -0
- trilogy/dialect/duckdb.py +1 -1
- trilogy/dialect/presto.py +1 -0
- trilogy/executor.py +29 -0
- trilogy/hooks/graph_hook.py +50 -5
- trilogy/hooks/query_debugger.py +1 -0
- trilogy/parsing/common.py +8 -5
- trilogy/parsing/parse_engine.py +48 -27
- trilogy/parsing/render.py +13 -6
- trilogy/parsing/trilogy.lark +12 -7
- pytrilogy-0.0.1.117.dist-info/RECORD +0 -83
- trilogy/core/processing/node_generators/concept_merge_node.py +0 -214
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.1.117.dist-info → pytrilogy-0.0.2.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
trilogy/__init__.py,sha256=f4K50J-SBruXMjFtcHLn_pB9eN7oCkbwqmtEjcxjSoM,290
|
|
2
|
+
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
trilogy/constants.py,sha256=KIvi-cgU4R9urNgDdGiCsRkCrzjAfM4xGHhZb1SVy2w,881
|
|
4
|
+
trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
|
|
5
|
+
trilogy/executor.py,sha256=5cRbU4Rj7p1pNV76rfp1pz704Hx_0q8_O8HFURjgXxQ,11016
|
|
6
|
+
trilogy/parser.py,sha256=UtuqSiGiCjpMAYgo1bvNq-b7NSzCA5hzbUW31RXaMII,281
|
|
7
|
+
trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
trilogy/utility.py,sha256=zM__8r29EsyDW7K9VOHz8yvZC2bXFzh7xKy3cL7GKsk,707
|
|
9
|
+
trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
trilogy/core/constants.py,sha256=LL8NLvxb3HRnAjvofyLRXqQJijLcYiXAQYQzGarVD-g,128
|
|
11
|
+
trilogy/core/enums.py,sha256=DWKPuShM_DbyAenjNFOAxcIH2l0QC9WgIwqZKPQqk_o,5850
|
|
12
|
+
trilogy/core/env_processor.py,sha256=Wpy-iiduBwHntTsQTYWBO1O0i3Ij9_VoL3d4IWDEoj4,2126
|
|
13
|
+
trilogy/core/environment_helpers.py,sha256=mzBDHhdF9ssZ_-LY8CcaM_ddfJavkpRYrFImUd3cjXI,5972
|
|
14
|
+
trilogy/core/ergonomics.py,sha256=w3gwXdgrxNHCuaRdyKg73t6F36tj-wIjQf47WZkHmJk,1465
|
|
15
|
+
trilogy/core/exceptions.py,sha256=NvV_4qLOgKXbpotgRf7c8BANDEvHxlqRPaA53IThQ2o,561
|
|
16
|
+
trilogy/core/functions.py,sha256=xISGHMiUR9hFyoZe2l3VLTMO6UEtyGHQcMuovzlVRqw,9492
|
|
17
|
+
trilogy/core/graph_models.py,sha256=oJUMSpmYhqXlavckHLpR07GJxuQ8dZ1VbB1fB0KaS8c,2036
|
|
18
|
+
trilogy/core/internal.py,sha256=jNGFHKENnbMiMCtAgsnLZYVSENDK4b5ALecXFZpTDzQ,1075
|
|
19
|
+
trilogy/core/models.py,sha256=432UOrJNzdY0_2vCbeBrNBDQOG_v-WaWqYSniM1CJpE,134387
|
|
20
|
+
trilogy/core/optimization.py,sha256=iX8BCh2BIEPJ6cYlcn7piDKFfig47azphhyqkwkYJM4,4291
|
|
21
|
+
trilogy/core/query_processor.py,sha256=PROehLEOMOuKy1EAUeIgdfGq1LrJsX0N7Z2qDED6S30,17580
|
|
22
|
+
trilogy/core/optimizations/__init__.py,sha256=pxRzNzd2g8oRMy4f_ub5va6bNS2pd4hnyp9JBzTKc1E,300
|
|
23
|
+
trilogy/core/optimizations/base_optimization.py,sha256=tWWT-xnTbnEU-mNi_isMNbywm8B9WTRsNFwGpeh3rqE,468
|
|
24
|
+
trilogy/core/optimizations/inline_constant.py,sha256=kHNyc2UoaPVdYfVAPAFwnWuk4sJ_IF5faRtVcDOrBtw,1110
|
|
25
|
+
trilogy/core/optimizations/inline_datasource.py,sha256=KiwZ4fnRnSOVK8zzdwMAkafszo3fNn5LY8xgb0X1CbI,3194
|
|
26
|
+
trilogy/core/optimizations/predicate_pushdown.py,sha256=mduJn4zzKmLVNUja60ZlY6LlNp389OwjEbq2Rj8K6co,5389
|
|
27
|
+
trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
+
trilogy/core/processing/concept_strategies_v3.py,sha256=hmbck3a23N61HfMwC2z3lxA6Yms9TP7Lm3Aw7GiDcMA,23765
|
|
29
|
+
trilogy/core/processing/graph_utils.py,sha256=aq-kqk4Iado2HywDxWEejWc-7PGO6Oa-ZQLAM6XWPHw,1199
|
|
30
|
+
trilogy/core/processing/utility.py,sha256=hgfPfz5FlghN8edIVGTQ21eDUof5EMvnl3Vu64hjfqY,13289
|
|
31
|
+
trilogy/core/processing/node_generators/__init__.py,sha256=-mzYkRsaRNa_dfTckYkKVFSR8h8a3ihEiPJDU_tAmDo,672
|
|
32
|
+
trilogy/core/processing/node_generators/basic_node.py,sha256=uD6noJOgrtmhjb-1aa-vD8sQ97s9Tya6wbso7V_AdyE,2819
|
|
33
|
+
trilogy/core/processing/node_generators/common.py,sha256=liZDth7mvhkF_sUFXK7JitJsiaKD132w3ySLbF7l-nE,8956
|
|
34
|
+
trilogy/core/processing/node_generators/filter_node.py,sha256=5B7UCK84A9lGgJ7EjCiC7YGWWM1xPyQGHkBwZgYypFM,4585
|
|
35
|
+
trilogy/core/processing/node_generators/group_node.py,sha256=xWI1xNIXEOj6jlRGD9hcv2_vVNvY6lpzJl6pQ8HuFBE,2988
|
|
36
|
+
trilogy/core/processing/node_generators/group_to_node.py,sha256=BzPdYwzoo8gRMH7BDffTTXq4z-mjfCEzvfB5I-P0_nw,2941
|
|
37
|
+
trilogy/core/processing/node_generators/multiselect_node.py,sha256=vP84dnLQy6dtypi6mUbt9sMAcmmrTgQ1Oz4GI6X1IEo,6421
|
|
38
|
+
trilogy/core/processing/node_generators/node_merge_node.py,sha256=YivTVrTEUJuQbQAHFVB2lUD4mJYQ-kTVVpwY4oT9A-Y,14664
|
|
39
|
+
trilogy/core/processing/node_generators/rowset_node.py,sha256=2ROd2c1_o4h5sbnDdaiL1o9UiiwyYw-B6OKyfHYNe0A,6188
|
|
40
|
+
trilogy/core/processing/node_generators/select_node.py,sha256=uk02lRvSJB1gWYRcSNfRZ8aYk3fME_tgg0I6EZyuxkI,19052
|
|
41
|
+
trilogy/core/processing/node_generators/unnest_node.py,sha256=6CH66eGwpadNX7TzUhWZ8aqIisOtQeHINbLV6X3QBUk,1779
|
|
42
|
+
trilogy/core/processing/node_generators/window_node.py,sha256=9nXUXUgQrNczU1gaOqhOZPNzCUxw-lkxt0R7HORI6ss,2582
|
|
43
|
+
trilogy/core/processing/nodes/__init__.py,sha256=-8ONG7Nqa6sNLpst5wNNyMigyaHRfUKGdE3xce8E3mM,3998
|
|
44
|
+
trilogy/core/processing/nodes/base_node.py,sha256=q1G4FO3Q4OuboWL8EaJgJ4jcnnqM9QsothMIcF2ot1g,11161
|
|
45
|
+
trilogy/core/processing/nodes/filter_node.py,sha256=ImUHYj5G5eHbOtki-ZMR31Op38wKOjR1xu_ETiE_D6I,1932
|
|
46
|
+
trilogy/core/processing/nodes/group_node.py,sha256=5dqGlonXG5Ou7HRSsTStbM1KyxeDSZROz9qKTjOUMEc,5166
|
|
47
|
+
trilogy/core/processing/nodes/merge_node.py,sha256=W7ryL9rceylCQGNgcuGY-dSiNoIz8qrbpJXKzg_Niwo,14056
|
|
48
|
+
trilogy/core/processing/nodes/select_node_v2.py,sha256=COu-WPuyabGAc3HTkJB-_7eNzR4OgxIL4YDuZIRrST0,7179
|
|
49
|
+
trilogy/core/processing/nodes/unnest_node.py,sha256=JFtm90IVM-46aCYkTNIaJah6v9ApAfonjVhcVM1HmDE,1903
|
|
50
|
+
trilogy/core/processing/nodes/window_node.py,sha256=X7qxLUKd3tekjUUsmH_4vz5b-U89gMnGd04VBxuu2Ns,1280
|
|
51
|
+
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
trilogy/dialect/base.py,sha256=EZCP3xU8-B4xpU1pFFew4CGtkNWignbyPll6OTENFLg,29832
|
|
53
|
+
trilogy/dialect/bigquery.py,sha256=BAN2o0SOuLvzLYLV7Sc11woapS5L7Cc36aMBeaphW5k,2905
|
|
54
|
+
trilogy/dialect/common.py,sha256=5jdOHWIj3Xv8F8y5mnyWHLjxD_we2fncM-ZnNetJP7U,2781
|
|
55
|
+
trilogy/dialect/config.py,sha256=tLVEMctaTDhUgARKXUNfHUcIolGaALkQ0RavUvXAY4w,2994
|
|
56
|
+
trilogy/dialect/duckdb.py,sha256=JQPnR5F39iDQXfTccKhbq7xWYGzYc0dPpn5vo0Qd_Vk,3076
|
|
57
|
+
trilogy/dialect/enums.py,sha256=4NdpsydBpDn6jnh0JzFz5VvQEtnShErWtWHVyT6TNpw,3948
|
|
58
|
+
trilogy/dialect/postgres.py,sha256=r47xbCA7nfEYENofiVfLZ-SnReNfDmUmW4OSHVkkP4E,3206
|
|
59
|
+
trilogy/dialect/presto.py,sha256=ouSVNbs7e3eEc20emLfxKyRjdINSibPGUFL4X9OwboA,3163
|
|
60
|
+
trilogy/dialect/snowflake.py,sha256=N3HknYgN-fjD7BLX1Ucj-ss_ku2Ox8DgLsF3BIHutHo,2941
|
|
61
|
+
trilogy/dialect/sql_server.py,sha256=HX68vNTrcDaTnOxe6Zbx_PBgrO42e2VuThxO6CYQ2cY,3026
|
|
62
|
+
trilogy/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
63
|
+
trilogy/hooks/base_hook.py,sha256=Xkb-A2qCHozYjum0A36zOy5PwTVwrP3NLDF0U2GpgHo,1100
|
|
64
|
+
trilogy/hooks/graph_hook.py,sha256=onHvMQPwj_KOS3HOTpRFiy7QLLKAiycq2MzJ_Q0Oh5Y,2467
|
|
65
|
+
trilogy/hooks/query_debugger.py,sha256=NDChfkPmmW-KINa4TaQmDe_adGiwsKFdGLDSYpbodeU,4282
|
|
66
|
+
trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
67
|
+
trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
|
+
trilogy/parsing/common.py,sha256=8MDRPccWymtVkHVQMzESjL5tOH79flWU5jo6Ys-C5UQ,5963
|
|
69
|
+
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
70
|
+
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
71
|
+
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
72
|
+
trilogy/parsing/parse_engine.py,sha256=hPvPZuO_ZBjoKRMh-bKzhnt6oo8R5l4gL9bJqZoMUfs,57619
|
|
73
|
+
trilogy/parsing/render.py,sha256=ym8DcgU-frNxd16ThWYGJFyChF-d0yd2gp9tEA6RFJU,12059
|
|
74
|
+
trilogy/parsing/trilogy.lark,sha256=4VXqLWOdxJsfZoJIp9Ug1G3p_LrXRDm5C2yAxaRgq98,10993
|
|
75
|
+
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
|
+
trilogy/scripts/trilogy.py,sha256=PHxvv6f2ODv0esyyhWxlARgra8dVhqQhYl0lTrSyVNo,3729
|
|
77
|
+
pytrilogy-0.0.2.1.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
78
|
+
pytrilogy-0.0.2.1.dist-info/METADATA,sha256=YN0xCd-8tn38c-px20-D1WgFDUjn-P6J6hNtsyhUFmE,7876
|
|
79
|
+
pytrilogy-0.0.2.1.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
|
|
80
|
+
pytrilogy-0.0.2.1.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
81
|
+
pytrilogy-0.0.2.1.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
82
|
+
pytrilogy-0.0.2.1.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/constants.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from logging import getLogger
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
from enum import Enum
|
|
4
|
+
import random
|
|
4
5
|
|
|
5
6
|
logger = getLogger("trilogy")
|
|
6
7
|
|
|
@@ -34,7 +35,12 @@ class Config:
|
|
|
34
35
|
validate_missing: bool = True
|
|
35
36
|
optimizations: Optimizations = field(default_factory=Optimizations)
|
|
36
37
|
|
|
38
|
+
def set_random_seed(self, seed: int):
|
|
39
|
+
random.seed(seed)
|
|
40
|
+
|
|
37
41
|
|
|
38
42
|
CONFIG = Config()
|
|
39
43
|
|
|
44
|
+
CONFIG.set_random_seed(42)
|
|
45
|
+
|
|
40
46
|
CONFIG.strict_mode = True
|
trilogy/core/enums.py
CHANGED
|
@@ -43,7 +43,6 @@ class PurposeLineage(Enum):
|
|
|
43
43
|
ROOT = "root"
|
|
44
44
|
ROWSET = "rowset"
|
|
45
45
|
MULTISELECT = "multiselect"
|
|
46
|
-
MERGE = "merge"
|
|
47
46
|
|
|
48
47
|
|
|
49
48
|
class Granularity(Enum):
|
|
@@ -263,7 +262,6 @@ class DatePart(Enum):
|
|
|
263
262
|
class SourceType(Enum):
|
|
264
263
|
FILTER = "filter"
|
|
265
264
|
SELECT = "select"
|
|
266
|
-
MERGE = "merge"
|
|
267
265
|
ABSTRACT = "abstract"
|
|
268
266
|
DIRECT_SELECT = "direct_select"
|
|
269
267
|
GROUP = "group"
|
|
@@ -271,8 +269,15 @@ class SourceType(Enum):
|
|
|
271
269
|
UNNEST = "unnest"
|
|
272
270
|
CONSTANT = "constant"
|
|
273
271
|
ROWSET = "rowset"
|
|
272
|
+
MERGE = "merge"
|
|
274
273
|
|
|
275
274
|
|
|
276
275
|
class ShowCategory(Enum):
|
|
277
276
|
MODELS = "models"
|
|
278
277
|
CONCEPTS = "concepts"
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class SelectFiltering(Enum):
|
|
281
|
+
NONE = "none"
|
|
282
|
+
EXPLICIT = "explicit" # the filtering contains only selected values
|
|
283
|
+
IMPLICIT = "implicit" # the filtering contains unselected values
|
trilogy/core/env_processor.py
CHANGED
|
@@ -3,37 +3,61 @@ from trilogy.core.graph_models import (
|
|
|
3
3
|
concept_to_node,
|
|
4
4
|
datasource_to_node,
|
|
5
5
|
)
|
|
6
|
-
from trilogy.core.models import Environment
|
|
7
|
-
from trilogy.core.enums import PurposeLineage
|
|
6
|
+
from trilogy.core.models import Environment, Concept, Datasource
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
def
|
|
11
|
-
|
|
9
|
+
def add_concept(concept: Concept, g: ReferenceGraph):
|
|
10
|
+
g.add_node(concept)
|
|
11
|
+
# if we have sources, recursively add them
|
|
12
|
+
node_name = concept_to_node(concept)
|
|
13
|
+
if concept.sources:
|
|
14
|
+
for source in concept.sources:
|
|
15
|
+
generic = source.with_default_grain()
|
|
16
|
+
g.add_edge(generic, node_name)
|
|
17
|
+
for _, pseudonym in concept.pseudonyms.items():
|
|
18
|
+
pseudonym = pseudonym.with_default_grain()
|
|
19
|
+
pseudonym_node = concept_to_node(pseudonym)
|
|
20
|
+
if pseudonym_node.split("@")[0] == node_name.split("@")[0]:
|
|
21
|
+
continue
|
|
22
|
+
g.add_edge(pseudonym_node, node_name, pseudonym=True)
|
|
23
|
+
g.add_edge(node_name, pseudonym_node, pseudonym=True)
|
|
24
|
+
add_concept(pseudonym, g)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def generate_adhoc_graph(
|
|
28
|
+
concepts: list[Concept],
|
|
29
|
+
datasources: list[Datasource],
|
|
30
|
+
restrict_to_listed: bool = False,
|
|
12
31
|
) -> ReferenceGraph:
|
|
13
32
|
g = ReferenceGraph()
|
|
14
33
|
|
|
15
34
|
# add all parsed concepts
|
|
16
|
-
for
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
node_name = concept_to_node(concept)
|
|
21
|
-
for source in concept.sources:
|
|
22
|
-
generic = source.with_default_grain()
|
|
23
|
-
g.add_edge(generic, node_name)
|
|
24
|
-
|
|
25
|
-
# link the concept to the generic source
|
|
26
|
-
if concept.derivation == PurposeLineage.MERGE:
|
|
27
|
-
g.add_edge(node_name, generic)
|
|
28
|
-
for _, dataset in environment.datasources.items():
|
|
35
|
+
for concept in concepts:
|
|
36
|
+
add_concept(concept, g)
|
|
37
|
+
|
|
38
|
+
for dataset in datasources:
|
|
29
39
|
node = datasource_to_node(dataset)
|
|
30
40
|
g.add_node(dataset, type="datasource", datasource=dataset)
|
|
31
41
|
for concept in dataset.concepts:
|
|
42
|
+
if restrict_to_listed:
|
|
43
|
+
if concept_to_node(concept) not in g.nodes:
|
|
44
|
+
continue
|
|
32
45
|
g.add_edge(node, concept)
|
|
33
46
|
g.add_edge(concept, node)
|
|
34
47
|
# if there is a key on a table at a different grain
|
|
35
48
|
# add an FK edge to the canonical source, if it exists
|
|
36
49
|
# for example, order ID on order product table
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
default = concept.with_default_grain()
|
|
51
|
+
if concept != default:
|
|
52
|
+
g.add_edge(concept, default)
|
|
53
|
+
g.add_edge(default, concept)
|
|
39
54
|
return g
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def generate_graph(
|
|
58
|
+
environment: Environment,
|
|
59
|
+
) -> ReferenceGraph:
|
|
60
|
+
|
|
61
|
+
return generate_adhoc_graph(
|
|
62
|
+
list(environment.concepts.values()), list(environment.datasources.values())
|
|
63
|
+
)
|
trilogy/core/functions.py
CHANGED
|
@@ -52,12 +52,22 @@ def argument_to_purpose(arg) -> Purpose:
|
|
|
52
52
|
if isinstance(arg, Function):
|
|
53
53
|
return arg.output_purpose
|
|
54
54
|
elif isinstance(arg, AggregateWrapper):
|
|
55
|
+
base = arg.function.output_purpose
|
|
56
|
+
if arg.by and base == Purpose.METRIC:
|
|
57
|
+
return Purpose.PROPERTY
|
|
55
58
|
return arg.function.output_purpose
|
|
56
59
|
elif isinstance(arg, Parenthetical):
|
|
57
60
|
return argument_to_purpose(arg.content)
|
|
58
61
|
elif isinstance(arg, WindowItem):
|
|
59
62
|
return Purpose.PROPERTY
|
|
60
63
|
elif isinstance(arg, Concept):
|
|
64
|
+
base = arg.purpose
|
|
65
|
+
if (
|
|
66
|
+
isinstance(arg.lineage, AggregateWrapper)
|
|
67
|
+
and arg.lineage.by
|
|
68
|
+
and base == Purpose.METRIC
|
|
69
|
+
):
|
|
70
|
+
return Purpose.PROPERTY
|
|
61
71
|
return arg.purpose
|
|
62
72
|
elif isinstance(arg, (int, float, str, bool, list, NumericType, DataType)):
|
|
63
73
|
return Purpose.CONSTANT
|
|
@@ -153,6 +163,7 @@ def Max(args: list[Concept]) -> Function:
|
|
|
153
163
|
DataType.DATE,
|
|
154
164
|
DataType.DATETIME,
|
|
155
165
|
DataType.TIMESTAMP,
|
|
166
|
+
DataType.BOOL,
|
|
156
167
|
},
|
|
157
168
|
arg_count=1,
|
|
158
169
|
# output_grain=Grain(components=arguments),
|