pytrilogy 0.0.3.80__py3-none-any.whl → 0.0.3.81__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.3.80.dist-info → pytrilogy-0.0.3.81.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.3.80.dist-info → pytrilogy-0.0.3.81.dist-info}/RECORD +16 -16
- trilogy/__init__.py +1 -1
- trilogy/core/enums.py +3 -0
- trilogy/core/functions.py +28 -0
- trilogy/core/models/author.py +9 -4
- trilogy/core/processing/node_generators/basic_node.py +3 -0
- trilogy/core/processing/node_generators/node_merge_node.py +23 -8
- trilogy/dialect/base.py +5 -0
- trilogy/dialect/duckdb.py +14 -0
- trilogy/parsing/parse_engine.py +16 -2
- trilogy/parsing/trilogy.lark +8 -2
- {pytrilogy-0.0.3.80.dist-info → pytrilogy-0.0.3.81.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.3.80.dist-info → pytrilogy-0.0.3.81.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.3.80.dist-info → pytrilogy-0.0.3.81.dist-info}/licenses/LICENSE.md +0 -0
- {pytrilogy-0.0.3.80.dist-info → pytrilogy-0.0.3.81.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
pytrilogy-0.0.3.
|
|
2
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
pytrilogy-0.0.3.81.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
2
|
+
trilogy/__init__.py,sha256=TMYRdrnDsNt6dIWHpcXgKPBKzjBkbMC5oJTgTrClxz0,303
|
|
3
3
|
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
trilogy/constants.py,sha256=eKb_EJvSqjN9tGbdVEViwdtwwh8fZ3-jpOEDqL71y70,1691
|
|
5
5
|
trilogy/engine.py,sha256=OK2RuqCIUId6yZ5hfF8J1nxGP0AJqHRZiafcowmW0xc,1728
|
|
@@ -11,19 +11,19 @@ trilogy/utility.py,sha256=euQccZLKoYBz0LNg5tzLlvv2YHvXh9HArnYp1V3uXsM,763
|
|
|
11
11
|
trilogy/authoring/__init__.py,sha256=e74k-Jep4DLYPQU_2m0aVsYlw5HKTOucAKtdTbd6f2g,2595
|
|
12
12
|
trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
trilogy/core/constants.py,sha256=nizWYDCJQ1bigQMtkNIEMNTcN0NoEAXiIHLzpelxQ24,201
|
|
14
|
-
trilogy/core/enums.py,sha256=
|
|
14
|
+
trilogy/core/enums.py,sha256=kuwTeEur5TZ07DX8nO3fSiRQ32bLZ5jRK-vIjHbBUnc,8118
|
|
15
15
|
trilogy/core/env_processor.py,sha256=pFsxnluKIusGKx1z7tTnfsd_xZcPy9pZDungkjkyvI0,3170
|
|
16
16
|
trilogy/core/environment_helpers.py,sha256=VvPIiFemqaLLpIpLIqprfu63K7muZ1YzNg7UZIUph8w,8267
|
|
17
17
|
trilogy/core/ergonomics.py,sha256=e-7gE29vPLFdg0_A1smQ7eOrUwKl5VYdxRSTddHweRA,1631
|
|
18
18
|
trilogy/core/exceptions.py,sha256=jYEduuMehcMkmCpf-OC_taELPZm7qNfeSNzIWkDYScs,707
|
|
19
|
-
trilogy/core/functions.py,sha256=
|
|
19
|
+
trilogy/core/functions.py,sha256=9Q-c7UGxOR0SVwzcHt9mHX_aVroW9jEWwJr7BtHigw8,31766
|
|
20
20
|
trilogy/core/graph_models.py,sha256=BYhJzHKSgnZHVLJs1CfsgrxTPHqKqPNeA64RlozGY0A,3498
|
|
21
21
|
trilogy/core/internal.py,sha256=wFx4e1I0mtx159YFShSXeUBSQ82NINtAbOI-92RX4i8,2151
|
|
22
22
|
trilogy/core/optimization.py,sha256=ojpn-p79lr03SSVQbbw74iPCyoYpDYBmj1dbZ3oXCjI,8860
|
|
23
23
|
trilogy/core/query_processor.py,sha256=5aFgv-2LVM1Uku9cR_tFuTRDwyLnxc95bCMAHeFy2AY,20332
|
|
24
24
|
trilogy/core/utility.py,sha256=3VC13uSQWcZNghgt7Ot0ZTeEmNqs__cx122abVq9qhM,410
|
|
25
25
|
trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
-
trilogy/core/models/author.py,sha256=
|
|
26
|
+
trilogy/core/models/author.py,sha256=Xt_TRVl4xHF6fe-KTKPSt4Z8Srmplnv2KQe2grZXX3w,78411
|
|
27
27
|
trilogy/core/models/build.py,sha256=0TRcL__hvajLcpFwYeLjCV35cow5oVPbJHXA3oO09XA,65931
|
|
28
28
|
trilogy/core/models/build_environment.py,sha256=s_C9xAHuD3yZ26T15pWVBvoqvlp2LdZ8yjsv2_HdXLk,5363
|
|
29
29
|
trilogy/core/models/core.py,sha256=q-8ExAaSB3PoSDX2XOqfZ01HBBvT1pZFs7jGg1vZizc,11096
|
|
@@ -43,13 +43,13 @@ trilogy/core/processing/discovery_validation.py,sha256=fGWJmKpgEd1f4RkK-fYOBUT1c
|
|
|
43
43
|
trilogy/core/processing/graph_utils.py,sha256=8QUVrkE9j-9C1AyrCb1nQEh8daCe0u1HuXl-Te85lag,1205
|
|
44
44
|
trilogy/core/processing/utility.py,sha256=xsuVMRFi2nY2So0yohhweI2D92wZVsTpHezS0giM4ck,22583
|
|
45
45
|
trilogy/core/processing/node_generators/__init__.py,sha256=w8TQQgNhyAra6JQHdg1_Ags4BGyxjXYruu6UeC5yOkI,873
|
|
46
|
-
trilogy/core/processing/node_generators/basic_node.py,sha256=
|
|
46
|
+
trilogy/core/processing/node_generators/basic_node.py,sha256=TLZCv4WS196a-0g5xgKuJGthnGP8Ugm46iz85_3NIY4,5626
|
|
47
47
|
trilogy/core/processing/node_generators/common.py,sha256=PdysdroW9DUADP7f5Wv_GKPUyCTROZV1g3L45fawxi8,9443
|
|
48
48
|
trilogy/core/processing/node_generators/filter_node.py,sha256=oRRq2-T3ufgn4D23uQsc58f20eFk-djs4QI3WKA75K8,10908
|
|
49
49
|
trilogy/core/processing/node_generators/group_node.py,sha256=1QJhRxsTklJ5xq8wHlAURZaN9gL9FPpeCa1OJ7IwXnY,6769
|
|
50
50
|
trilogy/core/processing/node_generators/group_to_node.py,sha256=jKcNCDOY6fNblrdZwaRU0sbUSr9H0moQbAxrGgX6iGA,3832
|
|
51
51
|
trilogy/core/processing/node_generators/multiselect_node.py,sha256=GWV5yLmKTe1yyPhN60RG1Rnrn4ktfn9lYYXi_FVU4UI,7061
|
|
52
|
-
trilogy/core/processing/node_generators/node_merge_node.py,sha256=
|
|
52
|
+
trilogy/core/processing/node_generators/node_merge_node.py,sha256=bYhXGJqJDgT4JWlN4u761V3bkP96o6J25LFs6YBOiKQ,18304
|
|
53
53
|
trilogy/core/processing/node_generators/recursive_node.py,sha256=l5zdh0dURKwmAy8kK4OpMtZfyUEQRk6N-PwSWIyBpSM,2468
|
|
54
54
|
trilogy/core/processing/node_generators/rowset_node.py,sha256=5L5u6xz1In8EaHQdcYgR2si-tz9WB9YLXURo4AkUT9A,6630
|
|
55
55
|
trilogy/core/processing/node_generators/select_merge_node.py,sha256=Cv2GwNiYSmwewjuK8T3JB3pbgrLZFPsB75DCP153BMA,22818
|
|
@@ -76,12 +76,12 @@ trilogy/core/statements/build.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
|
|
|
76
76
|
trilogy/core/statements/common.py,sha256=KxEmz2ySySyZ6CTPzn0fJl5NX2KOk1RPyuUSwWhnK1g,759
|
|
77
77
|
trilogy/core/statements/execute.py,sha256=pfr1CZ_Cx1qQ-7LDyRI0JUfvtxBr_GGv-VeqiAjr43g,1406
|
|
78
78
|
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
|
-
trilogy/dialect/base.py,sha256=
|
|
79
|
+
trilogy/dialect/base.py,sha256=0nVDvsnDS8iMTIlCUsBs_ymoZMW6uh04U4MMZxOuHUw,47428
|
|
80
80
|
trilogy/dialect/bigquery.py,sha256=8xhEu0z_lKANjbvzvBbC7CeKrJf1iP8YyrHqNale-ug,4351
|
|
81
81
|
trilogy/dialect/common.py,sha256=tSthIZOXXRPQ4KeMKnDDsH7KlTmf2EVqigVtLyoc4zc,6071
|
|
82
82
|
trilogy/dialect/config.py,sha256=olnyeVU5W5T6b9-dMeNAnvxuPlyc2uefb7FRME094Ec,3834
|
|
83
83
|
trilogy/dialect/dataframe.py,sha256=RUbNgReEa9g3pL6H7fP9lPTrAij5pkqedpZ99D8_5AE,1522
|
|
84
|
-
trilogy/dialect/duckdb.py,sha256=
|
|
84
|
+
trilogy/dialect/duckdb.py,sha256=uqnZEd1IH4tO8FSbbUXe3Jl9EjoyrDde406k0VDuMXw,5544
|
|
85
85
|
trilogy/dialect/enums.py,sha256=FRNYQ5-w-B6-X0yXKNU5g9GowsMlERFogTC5u2nxL_s,4740
|
|
86
86
|
trilogy/dialect/postgres.py,sha256=el2PKwfyvWGk5EZtLudqAH5ewLitY1sFHJiocBSyxyM,3393
|
|
87
87
|
trilogy/dialect/presto.py,sha256=yzSF8SZ6o1dizj1UueAa7S3lR0qNYJdSXbF78EHyhY0,3668
|
|
@@ -97,9 +97,9 @@ trilogy/parsing/common.py,sha256=yV1AckK0h8u1OFeGQBTMu-wuW5m63c5CcZuPicsTH_w,306
|
|
|
97
97
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
98
98
|
trilogy/parsing/exceptions.py,sha256=Xwwsv2C9kSNv2q-HrrKC1f60JNHShXcCMzstTSEbiCw,154
|
|
99
99
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
100
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
100
|
+
trilogy/parsing/parse_engine.py,sha256=ll3uBwpJ2iAxT-KbbXy7OuCqUvKfLPzB1gHr8gApv_s,78591
|
|
101
101
|
trilogy/parsing/render.py,sha256=HSNntD82GiiwHT-TWPLXAaIMWLYVV5B5zQEsgwrHIBE,19605
|
|
102
|
-
trilogy/parsing/trilogy.lark,sha256=
|
|
102
|
+
trilogy/parsing/trilogy.lark,sha256=Uhy6A00-GsC-L8fRCN0JZC6fL87ujOOd9_4LbQWApY4,15248
|
|
103
103
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
104
104
|
trilogy/scripts/trilogy.py,sha256=1L0XrH4mVHRt1C9T1HnaDv2_kYEfbWTb5_-cBBke79w,3774
|
|
105
105
|
trilogy/std/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -110,8 +110,8 @@ trilogy/std/money.preql,sha256=XWwvAV3WxBsHX9zfptoYRnBigcfYwrYtBHXTME0xJuQ,2082
|
|
|
110
110
|
trilogy/std/net.preql,sha256=7l7MqIjs6TDCpO6dBAoNJU81Ex255jZRK36kBgE1GDs,158
|
|
111
111
|
trilogy/std/ranking.preql,sha256=LDoZrYyz4g3xsII9XwXfmstZD-_92i1Eox1UqkBIfi8,83
|
|
112
112
|
trilogy/std/report.preql,sha256=LbV-XlHdfw0jgnQ8pV7acG95xrd1-p65fVpiIc-S7W4,202
|
|
113
|
-
pytrilogy-0.0.3.
|
|
114
|
-
pytrilogy-0.0.3.
|
|
115
|
-
pytrilogy-0.0.3.
|
|
116
|
-
pytrilogy-0.0.3.
|
|
117
|
-
pytrilogy-0.0.3.
|
|
113
|
+
pytrilogy-0.0.3.81.dist-info/METADATA,sha256=0A4NkUsyAunmuRlrFbsAPi8sksv9Yf0l4jAFh6Q_NeU,9589
|
|
114
|
+
pytrilogy-0.0.3.81.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
115
|
+
pytrilogy-0.0.3.81.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
|
|
116
|
+
pytrilogy-0.0.3.81.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
117
|
+
pytrilogy-0.0.3.81.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/core/enums.py
CHANGED
|
@@ -171,6 +171,7 @@ class FunctionType(Enum):
|
|
|
171
171
|
RANDOM = "random"
|
|
172
172
|
FLOOR = "floor"
|
|
173
173
|
CEIL = "ceil"
|
|
174
|
+
LOG = "log"
|
|
174
175
|
|
|
175
176
|
# Aggregates
|
|
176
177
|
## group is not a real aggregate - it just means group by this + some other set of fields
|
|
@@ -193,6 +194,8 @@ class FunctionType(Enum):
|
|
|
193
194
|
SUBSTRING = "substring"
|
|
194
195
|
STRPOS = "strpos"
|
|
195
196
|
CONTAINS = "contains"
|
|
197
|
+
TRIM = "trim"
|
|
198
|
+
REPLACE = "replace"
|
|
196
199
|
|
|
197
200
|
# STRING REGEX
|
|
198
201
|
REGEXP_CONTAINS = "regexp_contains"
|
trilogy/core/functions.py
CHANGED
|
@@ -358,6 +358,16 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
358
358
|
output_type=DataType.INTEGER,
|
|
359
359
|
arg_count=2,
|
|
360
360
|
),
|
|
361
|
+
FunctionType.REPLACE: FunctionConfig(
|
|
362
|
+
valid_inputs=[
|
|
363
|
+
{DataType.STRING},
|
|
364
|
+
{DataType.STRING},
|
|
365
|
+
{DataType.STRING},
|
|
366
|
+
],
|
|
367
|
+
output_purpose=Purpose.PROPERTY,
|
|
368
|
+
output_type=DataType.STRING,
|
|
369
|
+
arg_count=3,
|
|
370
|
+
),
|
|
361
371
|
FunctionType.CONTAINS: FunctionConfig(
|
|
362
372
|
valid_inputs=[
|
|
363
373
|
{DataType.STRING},
|
|
@@ -367,6 +377,15 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
367
377
|
output_type=DataType.BOOL,
|
|
368
378
|
arg_count=2,
|
|
369
379
|
),
|
|
380
|
+
FunctionType.TRIM: FunctionConfig(
|
|
381
|
+
valid_inputs=[
|
|
382
|
+
{DataType.STRING},
|
|
383
|
+
{DataType.STRING},
|
|
384
|
+
],
|
|
385
|
+
output_purpose=Purpose.PROPERTY,
|
|
386
|
+
output_type=DataType.BOOL,
|
|
387
|
+
arg_count=2,
|
|
388
|
+
),
|
|
370
389
|
FunctionType.SUBSTRING: FunctionConfig(
|
|
371
390
|
valid_inputs=[{DataType.STRING}, {DataType.INTEGER}, {DataType.INTEGER}],
|
|
372
391
|
output_purpose=Purpose.PROPERTY,
|
|
@@ -688,6 +707,15 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
688
707
|
output_type=DataType.INTEGER,
|
|
689
708
|
arg_count=1,
|
|
690
709
|
),
|
|
710
|
+
FunctionType.LOG: FunctionConfig(
|
|
711
|
+
valid_inputs=[
|
|
712
|
+
{DataType.INTEGER, DataType.FLOAT, DataType.NUMBER, DataType.NUMERIC},
|
|
713
|
+
{DataType.INTEGER},
|
|
714
|
+
],
|
|
715
|
+
output_purpose=Purpose.PROPERTY,
|
|
716
|
+
output_type=DataType.FLOAT,
|
|
717
|
+
arg_count=2,
|
|
718
|
+
),
|
|
691
719
|
FunctionType.RANDOM: FunctionConfig(
|
|
692
720
|
valid_inputs=[],
|
|
693
721
|
output_purpose=Purpose.PROPERTY,
|
trilogy/core/models/author.py
CHANGED
|
@@ -1605,6 +1605,10 @@ def get_concept_arguments(expr) -> List["ConceptRef"]:
|
|
|
1605
1605
|
return output
|
|
1606
1606
|
|
|
1607
1607
|
|
|
1608
|
+
def args_to_pretty(input: set[DataType]) -> str:
|
|
1609
|
+
return ", ".join(sorted([f"'{x.value}'" for x in input if x != DataType.UNKNOWN]))
|
|
1610
|
+
|
|
1611
|
+
|
|
1608
1612
|
class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
1609
1613
|
operator: FunctionType
|
|
1610
1614
|
arg_count: int = Field(default=1)
|
|
@@ -1669,9 +1673,10 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1669
1673
|
and get_basic_type(arg.datatype.data_type) not in valid_inputs[idx]
|
|
1670
1674
|
):
|
|
1671
1675
|
if arg.datatype != DataType.UNKNOWN:
|
|
1676
|
+
|
|
1672
1677
|
raise TypeError(
|
|
1673
|
-
f"Invalid
|
|
1674
|
-
f"
|
|
1678
|
+
f"Invalid argument type '{arg.datatype.data_type.value}' passed into {operator_name} function in position {idx+1}"
|
|
1679
|
+
f" from concept: {arg.name}. Valid: {args_to_pretty(valid_inputs[idx])}."
|
|
1675
1680
|
)
|
|
1676
1681
|
if (
|
|
1677
1682
|
isinstance(arg, Function)
|
|
@@ -1679,8 +1684,8 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1679
1684
|
):
|
|
1680
1685
|
if arg.output_datatype != DataType.UNKNOWN:
|
|
1681
1686
|
raise TypeError(
|
|
1682
|
-
f"Invalid
|
|
1683
|
-
f" {operator_name} from function {arg.operator.name}
|
|
1687
|
+
f"Invalid argument type {arg.output_datatype}' passed into"
|
|
1688
|
+
f" {operator_name} function from function {arg.operator.name} in position {idx+1}. Valid: {args_to_pretty(valid_inputs[idx])}"
|
|
1684
1689
|
)
|
|
1685
1690
|
# check constants
|
|
1686
1691
|
comparisons: List[Tuple[Type, DataType]] = [
|
|
@@ -97,6 +97,9 @@ def gen_basic_node(
|
|
|
97
97
|
and not any(x.address in y.pseudonyms for y in equivalent_optional)
|
|
98
98
|
and x.address not in ignored_optional
|
|
99
99
|
]
|
|
100
|
+
logger.info(
|
|
101
|
+
f"{depth_prefix}{LOGGER_PREFIX} basic node for {concept} has non-equivalent optional {[x.address for x in non_equivalent_optional]}"
|
|
102
|
+
)
|
|
100
103
|
all_parents: list[BuildConcept] = unique(
|
|
101
104
|
parent_concepts + non_equivalent_optional, "address"
|
|
102
105
|
)
|
|
@@ -94,31 +94,45 @@ def determine_induced_minimal_nodes(
|
|
|
94
94
|
# inclusion of aggregates can create ambiguous node relation chains
|
|
95
95
|
# there may be a better way to handle this
|
|
96
96
|
# can be revisited if we need to connect a derived synonym based on an aggregate
|
|
97
|
-
if lookup.derivation in (
|
|
97
|
+
if lookup.derivation in (
|
|
98
|
+
Derivation.CONSTANT,
|
|
99
|
+
Derivation.AGGREGATE,
|
|
100
|
+
Derivation.FILTER,
|
|
101
|
+
):
|
|
98
102
|
nodes_to_remove.append(node)
|
|
99
103
|
# purge a node if we're already looking for all it's parents
|
|
100
104
|
if filter_downstream and lookup.derivation not in (Derivation.ROOT,):
|
|
101
105
|
nodes_to_remove.append(node)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
if nodes_to_remove:
|
|
107
|
+
logger.debug(f"Removing nodes {nodes_to_remove} from graph")
|
|
108
|
+
H.remove_nodes_from(nodes_to_remove)
|
|
109
|
+
isolates = list(nx.isolates(H))
|
|
110
|
+
if isolates:
|
|
111
|
+
logger.debug(f"Removing isolates {isolates} from graph")
|
|
112
|
+
H.remove_nodes_from(isolates)
|
|
106
113
|
|
|
107
114
|
zero_out = list(x for x in H.nodes if G.out_degree(x) == 0 and x not in nodelist)
|
|
108
115
|
while zero_out:
|
|
116
|
+
logger.debug(f"Removing zero out nodes {zero_out} from graph")
|
|
109
117
|
H.remove_nodes_from(zero_out)
|
|
110
118
|
zero_out = list(
|
|
111
119
|
x for x in H.nodes if G.out_degree(x) == 0 and x not in nodelist
|
|
112
120
|
)
|
|
113
|
-
|
|
114
121
|
try:
|
|
115
122
|
paths = nx.multi_source_dijkstra_path(H, nodelist)
|
|
116
123
|
# logger.debug(f"Paths found for {nodelist}")
|
|
117
124
|
except nx.exception.NodeNotFound:
|
|
118
125
|
# logger.debug(f"Unable to find paths for {nodelist}- {str(e)}")
|
|
119
126
|
return None
|
|
120
|
-
|
|
127
|
+
path_removals = list(x for x in H.nodes if x not in paths)
|
|
128
|
+
if path_removals:
|
|
129
|
+
logger.debug(f"Removing paths {path_removals} from graph")
|
|
130
|
+
H.remove_nodes_from(path_removals)
|
|
131
|
+
logger.debug(f"Graph after path removal {H.nodes}")
|
|
121
132
|
sG: nx.Graph = ax.steinertree.steiner_tree(H, nodelist).copy()
|
|
133
|
+
if not sG.nodes:
|
|
134
|
+
logger.debug(f"No Steiner tree found for nodes {nodelist}")
|
|
135
|
+
return None
|
|
122
136
|
# logger.debug(f"Steiner tree found for nodes {nodelist} {sG.nodes}")
|
|
123
137
|
final: nx.DiGraph = nx.subgraph(G, sG.nodes).copy()
|
|
124
138
|
|
|
@@ -293,7 +307,8 @@ def resolve_weak_components(
|
|
|
293
307
|
if not nx.is_weakly_connected(g):
|
|
294
308
|
break_flag = True
|
|
295
309
|
continue
|
|
296
|
-
|
|
310
|
+
# from trilogy.hooks.graph_hook import GraphHook
|
|
311
|
+
# GraphHook().query_graph_built(g, highlight_nodes=[concept_to_node(c.with_default_grain()) for c in all_concepts if "__preql_internal" not in c.address])
|
|
297
312
|
all_graph_concepts = [
|
|
298
313
|
extract_concept(extract_address(node), environment)
|
|
299
314
|
for node in g.nodes
|
trilogy/dialect/base.py
CHANGED
|
@@ -205,6 +205,9 @@ FUNCTION_MAP = {
|
|
|
205
205
|
FunctionType.MOD: lambda x: f"({x[0]} % {x[1]})",
|
|
206
206
|
FunctionType.SQRT: lambda x: f"sqrt({x[0]})",
|
|
207
207
|
FunctionType.RANDOM: lambda x: "random()",
|
|
208
|
+
FunctionType.LOG: lambda x: (
|
|
209
|
+
f"log({x[0]})" if x[1] == 10 else f"log({x[0]}, {x[1]})"
|
|
210
|
+
),
|
|
208
211
|
# aggregate types
|
|
209
212
|
FunctionType.COUNT_DISTINCT: lambda x: f"count(distinct {x[0]})",
|
|
210
213
|
FunctionType.COUNT: lambda x: f"count({x[0]})",
|
|
@@ -224,6 +227,8 @@ FUNCTION_MAP = {
|
|
|
224
227
|
FunctionType.REGEXP_CONTAINS: lambda x: f"REGEXP_CONTAINS({x[0]},{x[1]})",
|
|
225
228
|
FunctionType.REGEXP_EXTRACT: lambda x: f"REGEXP_EXTRACT({x[0]},{x[1]})",
|
|
226
229
|
FunctionType.REGEXP_REPLACE: lambda x: f"REGEXP_REPLACE({x[0]},{x[1]}, {x[2]})",
|
|
230
|
+
FunctionType.TRIM: lambda x: f"TRIM({x[0]})",
|
|
231
|
+
FunctionType.REPLACE: lambda x: f"REPLACE({x[0]},{x[1]},{x[2]})",
|
|
227
232
|
# FunctionType.NOT_LIKE: lambda x: f" CASE WHEN {x[0]} like {x[1]} THEN 0 ELSE 1 END",
|
|
228
233
|
# date types
|
|
229
234
|
FunctionType.DATE_TRUNCATE: lambda x: f"date_trunc({x[0]},{x[1]})",
|
trilogy/dialect/duckdb.py
CHANGED
|
@@ -33,11 +33,25 @@ def render_sort(args):
|
|
|
33
33
|
return f"list_sort({args[0]}, '{order[0]}', '{order[1]}')"
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def render_log(args):
|
|
37
|
+
if len(args) == 1:
|
|
38
|
+
return f"log({args[0]})"
|
|
39
|
+
elif len(args) == 2:
|
|
40
|
+
if int(args[1]) == 10:
|
|
41
|
+
return f"log({args[0]})"
|
|
42
|
+
else:
|
|
43
|
+
# change of base formula
|
|
44
|
+
return f"log({args[0]})/log({args[1]})"
|
|
45
|
+
else:
|
|
46
|
+
raise ValueError("log function requires 1 or 2 arguments")
|
|
47
|
+
|
|
48
|
+
|
|
36
49
|
FUNCTION_MAP = {
|
|
37
50
|
FunctionType.COUNT: lambda args: f"count({args[0]})",
|
|
38
51
|
FunctionType.SUM: lambda args: f"sum({args[0]})",
|
|
39
52
|
FunctionType.AVG: lambda args: f"avg({args[0]})",
|
|
40
53
|
FunctionType.LENGTH: lambda args: f"length({args[0]})",
|
|
54
|
+
FunctionType.LOG: lambda args: render_log(args),
|
|
41
55
|
FunctionType.LIKE: lambda args: (
|
|
42
56
|
f" CASE WHEN {args[0]} like {args[1]} THEN True ELSE False END"
|
|
43
57
|
),
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -1793,10 +1793,18 @@ class ParseToObjects(Transformer):
|
|
|
1793
1793
|
def fstrpos(self, meta, args):
|
|
1794
1794
|
return self.function_factory.create_function(args, FunctionType.STRPOS, meta)
|
|
1795
1795
|
|
|
1796
|
+
@v_args(meta=True)
|
|
1797
|
+
def freplace(self, meta, args):
|
|
1798
|
+
return self.function_factory.create_function(args, FunctionType.REPLACE, meta)
|
|
1799
|
+
|
|
1796
1800
|
@v_args(meta=True)
|
|
1797
1801
|
def fcontains(self, meta, args):
|
|
1798
1802
|
return self.function_factory.create_function(args, FunctionType.CONTAINS, meta)
|
|
1799
1803
|
|
|
1804
|
+
@v_args(meta=True)
|
|
1805
|
+
def ftrim(self, meta, args):
|
|
1806
|
+
return self.function_factory.create_function(args, FunctionType.TRIM, meta)
|
|
1807
|
+
|
|
1800
1808
|
@v_args(meta=True)
|
|
1801
1809
|
def fsubstring(self, meta, args):
|
|
1802
1810
|
return self.function_factory.create_function(args, FunctionType.SUBSTRING, meta)
|
|
@@ -1971,6 +1979,12 @@ class ParseToObjects(Transformer):
|
|
|
1971
1979
|
args.append(0)
|
|
1972
1980
|
return self.function_factory.create_function(args, FunctionType.ROUND, meta)
|
|
1973
1981
|
|
|
1982
|
+
@v_args(meta=True)
|
|
1983
|
+
def flog(self, meta, args) -> Function:
|
|
1984
|
+
if len(args) == 1:
|
|
1985
|
+
args.append(10)
|
|
1986
|
+
return self.function_factory.create_function(args, FunctionType.LOG, meta)
|
|
1987
|
+
|
|
1974
1988
|
@v_args(meta=True)
|
|
1975
1989
|
def ffloor(self, meta, args) -> Function:
|
|
1976
1990
|
return self.function_factory.create_function(args, FunctionType.FLOOR, meta)
|
|
@@ -2074,9 +2088,9 @@ def unpack_visit_error(e: VisitError, text: str | None = None):
|
|
|
2074
2088
|
extract = text[e.obj.meta.start_pos - 5 : e.obj.meta.end_pos + 5]
|
|
2075
2089
|
raise InvalidSyntaxException(
|
|
2076
2090
|
str(e.orig_exc)
|
|
2077
|
-
+ "
|
|
2091
|
+
+ " Raised when parsing rule: "
|
|
2078
2092
|
+ str(e.rule)
|
|
2079
|
-
+ f
|
|
2093
|
+
+ f' Line: {e.obj.meta.line} "...{extract}..."'
|
|
2080
2094
|
)
|
|
2081
2095
|
InvalidSyntaxException(
|
|
2082
2096
|
str(e.orig_exc) + " in " + str(e.rule) + f" Line: {e.obj.meta.line}"
|
trilogy/parsing/trilogy.lark
CHANGED
|
@@ -222,6 +222,8 @@
|
|
|
222
222
|
fmul: ("multiply"i "(" expr "," expr ")" )
|
|
223
223
|
fdiv: ( "divide"i "(" expr "," expr ")")
|
|
224
224
|
fmod: ( "mod"i "(" expr "," (int_lit | concept_lit ) ")")
|
|
225
|
+
_LOG.1: "log"i "("
|
|
226
|
+
flog: _LOG expr ("," expr)? ")"
|
|
225
227
|
_ROUND.1: "round"i "("
|
|
226
228
|
fround: _ROUND expr ("," expr)? ")"
|
|
227
229
|
_FLOOR.1: "floor"i "("
|
|
@@ -234,7 +236,7 @@
|
|
|
234
236
|
_RANDOM.1: "random("i
|
|
235
237
|
frandom: _RANDOM expr ")"
|
|
236
238
|
|
|
237
|
-
_math_functions: fmul | fdiv | fadd | fsub | fround | ffloor | fceil | fmod | fabs | fsqrt | frandom
|
|
239
|
+
_math_functions: fmul | fdiv | fadd | fsub | fround | ffloor | fceil | fmod | flog | fabs | fsqrt | frandom
|
|
238
240
|
|
|
239
241
|
//generic
|
|
240
242
|
_fcast_primary: "cast"i "(" expr "as"i data_type ")"
|
|
@@ -278,6 +280,10 @@
|
|
|
278
280
|
fstrpos: _STRPOS expr "," expr ")"
|
|
279
281
|
_CONTAINS.1: "contains("i
|
|
280
282
|
fcontains: _CONTAINS expr "," expr ")"
|
|
283
|
+
_TRIM.1: "trim("i
|
|
284
|
+
ftrim: _TRIM expr ")"
|
|
285
|
+
_REPLACE.1: "replace("i
|
|
286
|
+
freplace: _REPLACE expr "," expr "," expr ")"
|
|
281
287
|
_SUBSTRING.1: "substring("i
|
|
282
288
|
fsubstring: _SUBSTRING expr "," expr "," expr ")"
|
|
283
289
|
_REGEXP_EXTRACT.1: "regexp_extract("
|
|
@@ -287,7 +293,7 @@
|
|
|
287
293
|
_REGEXP_REPLACE.1: "regexp_replace("
|
|
288
294
|
fregexp_replace: _REGEXP_REPLACE expr "," expr "," expr ")"
|
|
289
295
|
|
|
290
|
-
_string_functions: like | ilike | upper | flower | fsplit | fstrpos | fsubstring | fcontains | fregexp_extract | fregexp_contains | fregexp_replace
|
|
296
|
+
_string_functions: like | ilike | upper | flower | fsplit | fstrpos | fsubstring | fcontains | ftrim | freplace | fregexp_extract | fregexp_contains | fregexp_replace
|
|
291
297
|
|
|
292
298
|
//array_functions
|
|
293
299
|
_ARRAY_SUM.1: "array_sum("i
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|