pytrilogy 0.3.148__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.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.
- LICENSE.md +19 -0
- _preql_import_resolver/__init__.py +5 -0
- _preql_import_resolver/_preql_import_resolver.cpython-312-aarch64-linux-gnu.so +0 -0
- pytrilogy-0.3.148.dist-info/METADATA +555 -0
- pytrilogy-0.3.148.dist-info/RECORD +206 -0
- pytrilogy-0.3.148.dist-info/WHEEL +5 -0
- pytrilogy-0.3.148.dist-info/entry_points.txt +2 -0
- pytrilogy-0.3.148.dist-info/licenses/LICENSE.md +19 -0
- trilogy/__init__.py +27 -0
- trilogy/ai/README.md +10 -0
- trilogy/ai/__init__.py +19 -0
- trilogy/ai/constants.py +92 -0
- trilogy/ai/conversation.py +107 -0
- trilogy/ai/enums.py +7 -0
- trilogy/ai/execute.py +50 -0
- trilogy/ai/models.py +34 -0
- trilogy/ai/prompts.py +100 -0
- trilogy/ai/providers/__init__.py +0 -0
- trilogy/ai/providers/anthropic.py +106 -0
- trilogy/ai/providers/base.py +24 -0
- trilogy/ai/providers/google.py +146 -0
- trilogy/ai/providers/openai.py +89 -0
- trilogy/ai/providers/utils.py +68 -0
- trilogy/authoring/README.md +3 -0
- trilogy/authoring/__init__.py +148 -0
- trilogy/constants.py +119 -0
- trilogy/core/README.md +52 -0
- trilogy/core/__init__.py +0 -0
- trilogy/core/constants.py +6 -0
- trilogy/core/enums.py +454 -0
- trilogy/core/env_processor.py +239 -0
- trilogy/core/environment_helpers.py +320 -0
- trilogy/core/ergonomics.py +193 -0
- trilogy/core/exceptions.py +123 -0
- trilogy/core/functions.py +1240 -0
- trilogy/core/graph_models.py +142 -0
- trilogy/core/internal.py +85 -0
- trilogy/core/models/__init__.py +0 -0
- trilogy/core/models/author.py +2662 -0
- trilogy/core/models/build.py +2603 -0
- trilogy/core/models/build_environment.py +165 -0
- trilogy/core/models/core.py +506 -0
- trilogy/core/models/datasource.py +434 -0
- trilogy/core/models/environment.py +756 -0
- trilogy/core/models/execute.py +1213 -0
- trilogy/core/optimization.py +251 -0
- trilogy/core/optimizations/__init__.py +12 -0
- trilogy/core/optimizations/base_optimization.py +17 -0
- trilogy/core/optimizations/hide_unused_concept.py +47 -0
- trilogy/core/optimizations/inline_datasource.py +102 -0
- trilogy/core/optimizations/predicate_pushdown.py +245 -0
- trilogy/core/processing/README.md +94 -0
- trilogy/core/processing/READMEv2.md +121 -0
- trilogy/core/processing/VIRTUAL_UNNEST.md +30 -0
- trilogy/core/processing/__init__.py +0 -0
- trilogy/core/processing/concept_strategies_v3.py +508 -0
- trilogy/core/processing/constants.py +15 -0
- trilogy/core/processing/discovery_node_factory.py +451 -0
- trilogy/core/processing/discovery_utility.py +548 -0
- trilogy/core/processing/discovery_validation.py +167 -0
- trilogy/core/processing/graph_utils.py +43 -0
- trilogy/core/processing/node_generators/README.md +9 -0
- trilogy/core/processing/node_generators/__init__.py +31 -0
- trilogy/core/processing/node_generators/basic_node.py +160 -0
- trilogy/core/processing/node_generators/common.py +270 -0
- trilogy/core/processing/node_generators/constant_node.py +38 -0
- trilogy/core/processing/node_generators/filter_node.py +315 -0
- trilogy/core/processing/node_generators/group_node.py +213 -0
- trilogy/core/processing/node_generators/group_to_node.py +117 -0
- trilogy/core/processing/node_generators/multiselect_node.py +207 -0
- trilogy/core/processing/node_generators/node_merge_node.py +695 -0
- trilogy/core/processing/node_generators/recursive_node.py +88 -0
- trilogy/core/processing/node_generators/rowset_node.py +165 -0
- trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +261 -0
- trilogy/core/processing/node_generators/select_merge_node.py +786 -0
- trilogy/core/processing/node_generators/select_node.py +95 -0
- trilogy/core/processing/node_generators/synonym_node.py +98 -0
- trilogy/core/processing/node_generators/union_node.py +91 -0
- trilogy/core/processing/node_generators/unnest_node.py +182 -0
- trilogy/core/processing/node_generators/window_node.py +201 -0
- trilogy/core/processing/nodes/README.md +28 -0
- trilogy/core/processing/nodes/__init__.py +179 -0
- trilogy/core/processing/nodes/base_node.py +522 -0
- trilogy/core/processing/nodes/filter_node.py +75 -0
- trilogy/core/processing/nodes/group_node.py +194 -0
- trilogy/core/processing/nodes/merge_node.py +420 -0
- trilogy/core/processing/nodes/recursive_node.py +46 -0
- trilogy/core/processing/nodes/select_node_v2.py +242 -0
- trilogy/core/processing/nodes/union_node.py +53 -0
- trilogy/core/processing/nodes/unnest_node.py +62 -0
- trilogy/core/processing/nodes/window_node.py +56 -0
- trilogy/core/processing/utility.py +823 -0
- trilogy/core/query_processor.py +604 -0
- trilogy/core/statements/README.md +35 -0
- trilogy/core/statements/__init__.py +0 -0
- trilogy/core/statements/author.py +536 -0
- trilogy/core/statements/build.py +0 -0
- trilogy/core/statements/common.py +20 -0
- trilogy/core/statements/execute.py +155 -0
- trilogy/core/table_processor.py +66 -0
- trilogy/core/utility.py +8 -0
- trilogy/core/validation/README.md +46 -0
- trilogy/core/validation/__init__.py +0 -0
- trilogy/core/validation/common.py +161 -0
- trilogy/core/validation/concept.py +146 -0
- trilogy/core/validation/datasource.py +227 -0
- trilogy/core/validation/environment.py +73 -0
- trilogy/core/validation/fix.py +256 -0
- trilogy/dialect/__init__.py +32 -0
- trilogy/dialect/base.py +1431 -0
- trilogy/dialect/bigquery.py +314 -0
- trilogy/dialect/common.py +147 -0
- trilogy/dialect/config.py +159 -0
- trilogy/dialect/dataframe.py +50 -0
- trilogy/dialect/duckdb.py +376 -0
- trilogy/dialect/enums.py +149 -0
- trilogy/dialect/metadata.py +173 -0
- trilogy/dialect/mock.py +190 -0
- trilogy/dialect/postgres.py +117 -0
- trilogy/dialect/presto.py +110 -0
- trilogy/dialect/results.py +89 -0
- trilogy/dialect/snowflake.py +129 -0
- trilogy/dialect/sql_server.py +137 -0
- trilogy/engine.py +48 -0
- trilogy/execution/__init__.py +17 -0
- trilogy/execution/config.py +119 -0
- trilogy/execution/state/__init__.py +0 -0
- trilogy/execution/state/file_state_store.py +0 -0
- trilogy/execution/state/sqllite_state_store.py +0 -0
- trilogy/execution/state/state_store.py +301 -0
- trilogy/executor.py +656 -0
- trilogy/hooks/__init__.py +4 -0
- trilogy/hooks/base_hook.py +40 -0
- trilogy/hooks/graph_hook.py +135 -0
- trilogy/hooks/query_debugger.py +166 -0
- trilogy/metadata/__init__.py +0 -0
- trilogy/parser.py +10 -0
- trilogy/parsing/README.md +21 -0
- trilogy/parsing/__init__.py +0 -0
- trilogy/parsing/common.py +1069 -0
- trilogy/parsing/config.py +5 -0
- trilogy/parsing/exceptions.py +8 -0
- trilogy/parsing/helpers.py +1 -0
- trilogy/parsing/parse_engine.py +2863 -0
- trilogy/parsing/render.py +773 -0
- trilogy/parsing/trilogy.lark +544 -0
- trilogy/py.typed +0 -0
- trilogy/render.py +45 -0
- trilogy/scripts/README.md +9 -0
- trilogy/scripts/__init__.py +0 -0
- trilogy/scripts/agent.py +41 -0
- trilogy/scripts/agent_info.py +306 -0
- trilogy/scripts/common.py +430 -0
- trilogy/scripts/dependency/Cargo.lock +617 -0
- trilogy/scripts/dependency/Cargo.toml +39 -0
- trilogy/scripts/dependency/README.md +131 -0
- trilogy/scripts/dependency/build.sh +25 -0
- trilogy/scripts/dependency/src/directory_resolver.rs +387 -0
- trilogy/scripts/dependency/src/lib.rs +16 -0
- trilogy/scripts/dependency/src/main.rs +770 -0
- trilogy/scripts/dependency/src/parser.rs +435 -0
- trilogy/scripts/dependency/src/preql.pest +208 -0
- trilogy/scripts/dependency/src/python_bindings.rs +311 -0
- trilogy/scripts/dependency/src/resolver.rs +716 -0
- trilogy/scripts/dependency/tests/base.preql +3 -0
- trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
- trilogy/scripts/dependency/tests/customer.preql +6 -0
- trilogy/scripts/dependency/tests/main.preql +9 -0
- trilogy/scripts/dependency/tests/orders.preql +7 -0
- trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
- trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
- trilogy/scripts/dependency.py +323 -0
- trilogy/scripts/display.py +555 -0
- trilogy/scripts/environment.py +59 -0
- trilogy/scripts/fmt.py +32 -0
- trilogy/scripts/ingest.py +472 -0
- trilogy/scripts/ingest_helpers/__init__.py +1 -0
- trilogy/scripts/ingest_helpers/foreign_keys.py +123 -0
- trilogy/scripts/ingest_helpers/formatting.py +93 -0
- trilogy/scripts/ingest_helpers/typing.py +161 -0
- trilogy/scripts/init.py +105 -0
- trilogy/scripts/parallel_execution.py +748 -0
- trilogy/scripts/plan.py +189 -0
- trilogy/scripts/refresh.py +106 -0
- trilogy/scripts/run.py +79 -0
- trilogy/scripts/serve.py +202 -0
- trilogy/scripts/serve_helpers/__init__.py +41 -0
- trilogy/scripts/serve_helpers/file_discovery.py +142 -0
- trilogy/scripts/serve_helpers/index_generation.py +206 -0
- trilogy/scripts/serve_helpers/models.py +38 -0
- trilogy/scripts/single_execution.py +131 -0
- trilogy/scripts/testing.py +129 -0
- trilogy/scripts/trilogy.py +75 -0
- trilogy/std/__init__.py +0 -0
- trilogy/std/color.preql +3 -0
- trilogy/std/date.preql +13 -0
- trilogy/std/display.preql +18 -0
- trilogy/std/geography.preql +22 -0
- trilogy/std/metric.preql +15 -0
- trilogy/std/money.preql +67 -0
- trilogy/std/net.preql +14 -0
- trilogy/std/ranking.preql +7 -0
- trilogy/std/report.preql +5 -0
- trilogy/std/semantic.preql +6 -0
- trilogy/utility.py +34 -0
trilogy/constants.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import random
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from logging import getLogger
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
logger = getLogger("trilogy")
|
|
9
|
+
|
|
10
|
+
DEFAULT_NAMESPACE = "local"
|
|
11
|
+
|
|
12
|
+
RECURSIVE_GATING_CONCEPT = "_terminal"
|
|
13
|
+
|
|
14
|
+
VIRTUAL_CONCEPT_PREFIX = "_virt"
|
|
15
|
+
|
|
16
|
+
ENV_CACHE_NAME = ".preql_cache.json"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MagicConstants(Enum):
|
|
20
|
+
NULL = "null"
|
|
21
|
+
LINE_SEPARATOR = "\n"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
NULL_VALUE = MagicConstants.NULL
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class Optimizations:
|
|
29
|
+
predicate_pushdown: bool = True
|
|
30
|
+
datasource_inlining: bool = True
|
|
31
|
+
constant_inlining: bool = True
|
|
32
|
+
constant_inline_cutoff: int = 10
|
|
33
|
+
direct_return: bool = True
|
|
34
|
+
hide_unused_concepts: bool = True
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class Generation:
|
|
39
|
+
datasource_build_cache: bool = True
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class Comments:
|
|
44
|
+
"""Control what is placed in CTE comments"""
|
|
45
|
+
|
|
46
|
+
show: bool = False
|
|
47
|
+
basic: bool = True
|
|
48
|
+
joins: bool = False
|
|
49
|
+
nullable: bool = False
|
|
50
|
+
partial: bool = False
|
|
51
|
+
source_map: bool = False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class Rendering:
|
|
56
|
+
"""Control how the SQL is rendered"""
|
|
57
|
+
|
|
58
|
+
parameters: bool = True
|
|
59
|
+
concise: bool = False
|
|
60
|
+
|
|
61
|
+
@contextmanager
|
|
62
|
+
def temporary(self, **kwargs: Any):
|
|
63
|
+
"""
|
|
64
|
+
Context manager to temporarily set attributes and revert them afterwards.
|
|
65
|
+
|
|
66
|
+
Usage:
|
|
67
|
+
r = Rendering()
|
|
68
|
+
with r.temporary(parameters=False, concise=True):
|
|
69
|
+
# parameters is False, concise is True here
|
|
70
|
+
do_something()
|
|
71
|
+
# parameters and concise are back to their original values
|
|
72
|
+
"""
|
|
73
|
+
# Store original values
|
|
74
|
+
original_values = {key: getattr(self, key) for key in kwargs}
|
|
75
|
+
|
|
76
|
+
# Set new values
|
|
77
|
+
for key, value in kwargs.items():
|
|
78
|
+
setattr(self, key, value)
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
yield self
|
|
82
|
+
finally:
|
|
83
|
+
# Restore original values
|
|
84
|
+
for key, value in original_values.items():
|
|
85
|
+
setattr(self, key, value)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class Parsing:
|
|
90
|
+
"""Control Parsing"""
|
|
91
|
+
|
|
92
|
+
strict_name_shadow_enforcement: bool = False
|
|
93
|
+
select_as_definition: bool = True
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# TODO: support loading from environments
|
|
97
|
+
@dataclass
|
|
98
|
+
class Config:
|
|
99
|
+
strict_mode: bool = True
|
|
100
|
+
human_identifiers: bool = True
|
|
101
|
+
randomize_cte_names: bool = False
|
|
102
|
+
validate_missing: bool = True
|
|
103
|
+
comments: Comments = field(default_factory=Comments)
|
|
104
|
+
optimizations: Optimizations = field(default_factory=Optimizations)
|
|
105
|
+
rendering: Rendering = field(default_factory=Rendering)
|
|
106
|
+
parsing: Parsing = field(default_factory=Parsing)
|
|
107
|
+
generation: Generation = field(default_factory=Generation)
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def show_comments(self) -> bool:
|
|
111
|
+
return self.comments.show
|
|
112
|
+
|
|
113
|
+
def set_random_seed(self, seed: int):
|
|
114
|
+
random.seed(seed)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
CONFIG = Config()
|
|
118
|
+
|
|
119
|
+
CONFIG.set_random_seed(42)
|
trilogy/core/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Implicit Filtering Design
|
|
5
|
+
|
|
6
|
+
An implicit filter is any case where the where clause of a statement references more fields than are in the output of a select.
|
|
7
|
+
|
|
8
|
+
In those cases, those concepts are "promoted" up into a virtual CTE before the final output is returned.
|
|
9
|
+
|
|
10
|
+
THe `wrinkle` is aggregates - aggregates must have the implicit filter pushed "inside" the aggregate via the select_context
|
|
11
|
+
to ensure that they aggregate appropriately. Applying the condition after creating the aggregate would result in an incorrect
|
|
12
|
+
aggregation result.
|
|
13
|
+
|
|
14
|
+
### Case 1 - Basic Scalar Filtering
|
|
15
|
+
|
|
16
|
+
SELECT
|
|
17
|
+
abc,
|
|
18
|
+
def
|
|
19
|
+
where
|
|
20
|
+
gde = 1
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
We should source
|
|
24
|
+
ABC,
|
|
25
|
+
DEF,
|
|
26
|
+
GDE
|
|
27
|
+
|
|
28
|
+
filter on GDE = 1;
|
|
29
|
+
|
|
30
|
+
return results with optional grouping.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Case 2 - Aggregate Filtering
|
|
34
|
+
|
|
35
|
+
SELECT
|
|
36
|
+
sum(abc)
|
|
37
|
+
WHERE
|
|
38
|
+
gde = 1
|
|
39
|
+
|
|
40
|
+
We should source
|
|
41
|
+
|
|
42
|
+
abc | gde =1
|
|
43
|
+
|
|
44
|
+
;
|
|
45
|
+
|
|
46
|
+
### Case 3 - Mixed filter
|
|
47
|
+
|
|
48
|
+
SELECT
|
|
49
|
+
sum(abc) by def,
|
|
50
|
+
def,
|
|
51
|
+
gde
|
|
52
|
+
|
trilogy/core/__init__.py
ADDED
|
File without changes
|
trilogy/core/enums.py
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
InfiniteFunctionArgs = -1
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DatasourceState(Enum):
|
|
7
|
+
PUBLISHED = "published"
|
|
8
|
+
UNPUBLISHED = "unpublished"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CreateMode(Enum):
|
|
12
|
+
CREATE = "create"
|
|
13
|
+
CREATE_IF_NOT_EXISTS = "create_if_not_exists"
|
|
14
|
+
CREATE_OR_REPLACE = "create_or_replace"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UnnestMode(Enum):
|
|
18
|
+
DIRECT = "direct"
|
|
19
|
+
CROSS_APPLY = "cross_apply"
|
|
20
|
+
CROSS_JOIN = "cross_join"
|
|
21
|
+
CROSS_JOIN_UNNEST = "cross_join_unnest"
|
|
22
|
+
CROSS_JOIN_ALIAS = "cross_join_alias"
|
|
23
|
+
PRESTO = "presto"
|
|
24
|
+
SNOWFLAKE = "snowflake"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class GroupMode(Enum):
|
|
28
|
+
AUTO = "auto"
|
|
29
|
+
BY_INDEX = "by_index"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ConceptSource(Enum):
|
|
33
|
+
MANUAL = "manual"
|
|
34
|
+
CTE = "cte"
|
|
35
|
+
SELECT = "select"
|
|
36
|
+
PERSIST_STATEMENT = "persist_statement"
|
|
37
|
+
AUTO_DERIVED = "auto_derived"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class StatementType(Enum):
|
|
41
|
+
QUERY = "query"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Purpose(Enum):
|
|
45
|
+
CONSTANT = "const"
|
|
46
|
+
KEY = "key"
|
|
47
|
+
PROPERTY = "property"
|
|
48
|
+
UNIQUE_PROPERTY = "unique_property"
|
|
49
|
+
METRIC = "metric"
|
|
50
|
+
ROWSET = "rowset"
|
|
51
|
+
AUTO = "auto"
|
|
52
|
+
PARAMETER = "parameter"
|
|
53
|
+
UNKNOWN = "unknown"
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def _missing_(cls, value):
|
|
57
|
+
if value.lower() == "constant":
|
|
58
|
+
return Purpose.CONSTANT
|
|
59
|
+
if value.lower() == "param":
|
|
60
|
+
return Purpose.PARAMETER
|
|
61
|
+
return super()._missing_(value)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Derivation(Enum):
|
|
65
|
+
BASIC = "basic"
|
|
66
|
+
GROUP_TO = "group_to"
|
|
67
|
+
WINDOW = "window"
|
|
68
|
+
AGGREGATE = "aggregate"
|
|
69
|
+
FILTER = "filter"
|
|
70
|
+
CONSTANT = "constant"
|
|
71
|
+
UNNEST = "unnest"
|
|
72
|
+
UNION = "union"
|
|
73
|
+
ROOT = "root"
|
|
74
|
+
ROWSET = "rowset"
|
|
75
|
+
MULTISELECT = "multiselect"
|
|
76
|
+
RECURSIVE = "recursive"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class Granularity(Enum):
|
|
80
|
+
SINGLE_ROW = "single_row"
|
|
81
|
+
MULTI_ROW = "multi_row"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class PersistMode(Enum):
|
|
85
|
+
OVERWRITE = "overwrite"
|
|
86
|
+
APPEND = "append"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class PublishAction(Enum):
|
|
90
|
+
PUBLISH = "publish"
|
|
91
|
+
UNPUBLISH = "unpublish"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class AddressType(Enum):
|
|
95
|
+
TABLE = "table"
|
|
96
|
+
QUERY = "query"
|
|
97
|
+
PYTHON_SCRIPT = "python_script"
|
|
98
|
+
CSV = "csv"
|
|
99
|
+
TSV = "tsv"
|
|
100
|
+
PARQUET = "parquet"
|
|
101
|
+
SQL = "sql"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class Modifier(Enum):
|
|
105
|
+
PARTIAL = "Partial"
|
|
106
|
+
OPTIONAL = "Optional"
|
|
107
|
+
HIDDEN = "Hidden"
|
|
108
|
+
NULLABLE = "Nullable"
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def _missing_(cls, value):
|
|
112
|
+
strval = str(value)
|
|
113
|
+
if strval == "~":
|
|
114
|
+
return Modifier.PARTIAL
|
|
115
|
+
elif strval == "?":
|
|
116
|
+
return Modifier.NULLABLE
|
|
117
|
+
return super()._missing_(value=strval.capitalize())
|
|
118
|
+
|
|
119
|
+
def __lt__(self, other):
|
|
120
|
+
order = [
|
|
121
|
+
Modifier.HIDDEN,
|
|
122
|
+
Modifier.PARTIAL,
|
|
123
|
+
Modifier.NULLABLE,
|
|
124
|
+
Modifier.OPTIONAL,
|
|
125
|
+
]
|
|
126
|
+
return order.index(self) < order.index(other)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class JoinType(Enum):
|
|
130
|
+
INNER = "inner"
|
|
131
|
+
LEFT_OUTER = "left outer"
|
|
132
|
+
FULL = "full"
|
|
133
|
+
RIGHT_OUTER = "right outer"
|
|
134
|
+
CROSS = "cross"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class Ordering(Enum):
|
|
138
|
+
ASCENDING = "asc"
|
|
139
|
+
DESCENDING = "desc"
|
|
140
|
+
ASC_NULLS_AUTO = "asc nulls auto"
|
|
141
|
+
ASC_NULLS_FIRST = "asc nulls first"
|
|
142
|
+
ASC_NULLS_LAST = "asc nulls last"
|
|
143
|
+
DESC_NULLS_FIRST = "desc nulls first"
|
|
144
|
+
DESC_NULLS_LAST = "desc nulls last"
|
|
145
|
+
DESC_NULLS_AUTO = "desc nulls auto"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class WindowType(Enum):
|
|
149
|
+
ROW_NUMBER = "row_number"
|
|
150
|
+
RANK = "rank"
|
|
151
|
+
LAG = "lag"
|
|
152
|
+
LEAD = "lead"
|
|
153
|
+
SUM = "sum"
|
|
154
|
+
MAX = "max"
|
|
155
|
+
MIN = "min"
|
|
156
|
+
AVG = "avg"
|
|
157
|
+
COUNT = "count"
|
|
158
|
+
COUNT_DISTINCT = "count_distinct"
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class WindowOrder(Enum):
|
|
162
|
+
ASCENDING = "top"
|
|
163
|
+
DESCENDING = "bottom"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class FunctionType(Enum):
|
|
167
|
+
# custom
|
|
168
|
+
CUSTOM = "custom"
|
|
169
|
+
|
|
170
|
+
# structural
|
|
171
|
+
UNNEST = "unnest"
|
|
172
|
+
RECURSE_EDGE = "recurse_edge"
|
|
173
|
+
|
|
174
|
+
UNION = "union"
|
|
175
|
+
|
|
176
|
+
ALIAS = "alias"
|
|
177
|
+
|
|
178
|
+
PARENTHETICAL = "parenthetical"
|
|
179
|
+
|
|
180
|
+
# Generic
|
|
181
|
+
CASE = "case"
|
|
182
|
+
CAST = "cast"
|
|
183
|
+
CONCAT = "concat"
|
|
184
|
+
CONSTANT = "constant"
|
|
185
|
+
TYPED_CONSTANT = "typed_constant"
|
|
186
|
+
COALESCE = "coalesce"
|
|
187
|
+
IS_NULL = "isnull"
|
|
188
|
+
NULLIF = "nullif"
|
|
189
|
+
BOOL = "bool"
|
|
190
|
+
|
|
191
|
+
# COMPLEX
|
|
192
|
+
INDEX_ACCESS = "index_access"
|
|
193
|
+
MAP_ACCESS = "map_access"
|
|
194
|
+
ATTR_ACCESS = "attr_access"
|
|
195
|
+
STRUCT = "struct"
|
|
196
|
+
ARRAY = "array"
|
|
197
|
+
DATE_LITERAL = "date_literal"
|
|
198
|
+
DATETIME_LITERAL = "datetime_literal"
|
|
199
|
+
|
|
200
|
+
# ARRAY
|
|
201
|
+
ARRAY_DISTINCT = "array_distinct"
|
|
202
|
+
ARRAY_SUM = "array_sum"
|
|
203
|
+
ARRAY_SORT = "array_sort"
|
|
204
|
+
ARRAY_TRANSFORM = "array_transform"
|
|
205
|
+
ARRAY_TO_STRING = "array_to_string"
|
|
206
|
+
ARRAY_FILTER = "array_filter"
|
|
207
|
+
GENERATE_ARRAY = "generate_array"
|
|
208
|
+
|
|
209
|
+
# MAP
|
|
210
|
+
MAP_KEYS = "map_keys"
|
|
211
|
+
MAP_VALUES = "map_values"
|
|
212
|
+
|
|
213
|
+
# TEXT AND MAYBE MORE
|
|
214
|
+
SPLIT = "split"
|
|
215
|
+
LENGTH = "len"
|
|
216
|
+
|
|
217
|
+
# Maths
|
|
218
|
+
DIVIDE = "divide"
|
|
219
|
+
MULTIPLY = "multiply"
|
|
220
|
+
ADD = "add"
|
|
221
|
+
SUBTRACT = "subtract"
|
|
222
|
+
MOD = "mod"
|
|
223
|
+
ROUND = "round"
|
|
224
|
+
ABS = "abs"
|
|
225
|
+
SQRT = "sqrt"
|
|
226
|
+
RANDOM = "random"
|
|
227
|
+
FLOOR = "floor"
|
|
228
|
+
CEIL = "ceil"
|
|
229
|
+
LOG = "log"
|
|
230
|
+
POWER = "power"
|
|
231
|
+
|
|
232
|
+
# Aggregates
|
|
233
|
+
## group is not a real aggregate - it just means group by this + some other set of fields
|
|
234
|
+
## but is here as syntax is identical
|
|
235
|
+
GROUP = "group"
|
|
236
|
+
|
|
237
|
+
COUNT = "count"
|
|
238
|
+
COUNT_DISTINCT = "count_distinct"
|
|
239
|
+
SUM = "sum"
|
|
240
|
+
MAX = "max"
|
|
241
|
+
MIN = "min"
|
|
242
|
+
AVG = "avg"
|
|
243
|
+
ARRAY_AGG = "array_agg"
|
|
244
|
+
BOOL_OR = "bool_or"
|
|
245
|
+
BOOL_AND = "bool_and"
|
|
246
|
+
ANY = "any"
|
|
247
|
+
|
|
248
|
+
# String
|
|
249
|
+
LIKE = "like"
|
|
250
|
+
ILIKE = "ilike"
|
|
251
|
+
LOWER = "lower"
|
|
252
|
+
UPPER = "upper"
|
|
253
|
+
SUBSTRING = "substring"
|
|
254
|
+
STRPOS = "strpos"
|
|
255
|
+
CONTAINS = "contains"
|
|
256
|
+
TRIM = "trim"
|
|
257
|
+
REPLACE = "replace"
|
|
258
|
+
HASH = "hash"
|
|
259
|
+
|
|
260
|
+
# STRING REGEX
|
|
261
|
+
REGEXP_CONTAINS = "regexp_contains"
|
|
262
|
+
REGEXP_EXTRACT = "regexp_extract"
|
|
263
|
+
REGEXP_REPLACE = "regexp_replace"
|
|
264
|
+
|
|
265
|
+
# Dates
|
|
266
|
+
DATE = "date"
|
|
267
|
+
DATETIME = "datetime"
|
|
268
|
+
TIMESTAMP = "timestamp"
|
|
269
|
+
|
|
270
|
+
# time
|
|
271
|
+
SECOND = "second"
|
|
272
|
+
MINUTE = "minute"
|
|
273
|
+
HOUR = "hour"
|
|
274
|
+
DAY = "day"
|
|
275
|
+
DAY_OF_WEEK = "day_of_week"
|
|
276
|
+
WEEK = "week"
|
|
277
|
+
MONTH = "month"
|
|
278
|
+
QUARTER = "quarter"
|
|
279
|
+
YEAR = "year"
|
|
280
|
+
MONTH_NAME = "month_name"
|
|
281
|
+
DAY_NAME = "day_name"
|
|
282
|
+
|
|
283
|
+
DATE_PART = "date_part"
|
|
284
|
+
DATE_TRUNCATE = "date_truncate"
|
|
285
|
+
DATE_ADD = "date_add"
|
|
286
|
+
DATE_SUB = "date_sub"
|
|
287
|
+
DATE_DIFF = "date_diff"
|
|
288
|
+
DATE_SPINE = "date_spine"
|
|
289
|
+
|
|
290
|
+
# Geography
|
|
291
|
+
GEO_POINT = "geo_point"
|
|
292
|
+
GEO_DISTANCE = "geo_distance"
|
|
293
|
+
|
|
294
|
+
# UNIX
|
|
295
|
+
UNIX_TO_TIMESTAMP = "unix_to_timestamp"
|
|
296
|
+
|
|
297
|
+
# CONSTANTS
|
|
298
|
+
CURRENT_DATE = "current_date"
|
|
299
|
+
CURRENT_DATETIME = "current_datetime"
|
|
300
|
+
CURRENT_TIMESTAMP = "current_timestamp"
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class FunctionClass(Enum):
|
|
304
|
+
AGGREGATE_FUNCTIONS = [
|
|
305
|
+
FunctionType.MAX,
|
|
306
|
+
FunctionType.MIN,
|
|
307
|
+
FunctionType.SUM,
|
|
308
|
+
FunctionType.AVG,
|
|
309
|
+
FunctionType.ARRAY_AGG,
|
|
310
|
+
FunctionType.COUNT,
|
|
311
|
+
FunctionType.COUNT_DISTINCT,
|
|
312
|
+
FunctionType.ANY,
|
|
313
|
+
FunctionType.BOOL_OR,
|
|
314
|
+
FunctionType.BOOL_AND,
|
|
315
|
+
]
|
|
316
|
+
SINGLE_ROW = [
|
|
317
|
+
FunctionType.CONSTANT,
|
|
318
|
+
FunctionType.CURRENT_DATE,
|
|
319
|
+
FunctionType.CURRENT_DATETIME,
|
|
320
|
+
]
|
|
321
|
+
|
|
322
|
+
ONE_TO_MANY = [FunctionType.UNNEST, FunctionType.DATE_SPINE]
|
|
323
|
+
|
|
324
|
+
RECURSIVE = [FunctionType.RECURSE_EDGE]
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class Boolean(Enum):
|
|
328
|
+
TRUE = "true"
|
|
329
|
+
FALSE = "false"
|
|
330
|
+
|
|
331
|
+
@classmethod
|
|
332
|
+
def _missing_(cls, value):
|
|
333
|
+
if value is True:
|
|
334
|
+
return Boolean.TRUE
|
|
335
|
+
elif value is False:
|
|
336
|
+
return Boolean.FALSE
|
|
337
|
+
strval = str(value)
|
|
338
|
+
if strval.lower() != strval:
|
|
339
|
+
return Boolean(strval.lower())
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
class BooleanOperator(Enum):
|
|
343
|
+
AND = "and"
|
|
344
|
+
OR = "or"
|
|
345
|
+
|
|
346
|
+
@classmethod
|
|
347
|
+
def _missing_(cls, value):
|
|
348
|
+
strval = str(value)
|
|
349
|
+
if strval.lower() != strval:
|
|
350
|
+
return BooleanOperator(strval.lower())
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class ComparisonOperator(Enum):
|
|
355
|
+
LT = "<"
|
|
356
|
+
GT = ">"
|
|
357
|
+
EQ = "="
|
|
358
|
+
IS = "is"
|
|
359
|
+
IS_NOT = "is not"
|
|
360
|
+
GTE = ">="
|
|
361
|
+
LTE = "<="
|
|
362
|
+
NE = "!="
|
|
363
|
+
IN = "in"
|
|
364
|
+
NOT_IN = "not in"
|
|
365
|
+
# TODO: deprecate for contains?
|
|
366
|
+
LIKE = "like"
|
|
367
|
+
ILIKE = "ilike"
|
|
368
|
+
CONTAINS = "contains"
|
|
369
|
+
ELSE = "else"
|
|
370
|
+
|
|
371
|
+
def __eq__(self, other):
|
|
372
|
+
if isinstance(other, str):
|
|
373
|
+
return self.value == other
|
|
374
|
+
if not isinstance(other, ComparisonOperator):
|
|
375
|
+
return False
|
|
376
|
+
return self.value == other.value
|
|
377
|
+
|
|
378
|
+
@classmethod
|
|
379
|
+
def _missing_(cls, value):
|
|
380
|
+
if not isinstance(value, list) and " " in str(value):
|
|
381
|
+
value = str(value).split()
|
|
382
|
+
if isinstance(value, list):
|
|
383
|
+
processed = [str(v).lower() for v in value]
|
|
384
|
+
if processed == ["not", "in"]:
|
|
385
|
+
return ComparisonOperator.NOT_IN
|
|
386
|
+
if processed == ["is", "not"]:
|
|
387
|
+
return ComparisonOperator.IS_NOT
|
|
388
|
+
if value == ["in"]:
|
|
389
|
+
return ComparisonOperator.IN
|
|
390
|
+
if str(value).lower() != str(value):
|
|
391
|
+
return ComparisonOperator(str(value).lower())
|
|
392
|
+
return super()._missing_(str(value).lower())
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
class DatePart(Enum):
|
|
396
|
+
MONTH = "month"
|
|
397
|
+
YEAR = "year"
|
|
398
|
+
WEEK = "week"
|
|
399
|
+
DAY = "day"
|
|
400
|
+
QUARTER = "quarter"
|
|
401
|
+
HOUR = "hour"
|
|
402
|
+
MINUTE = "minute"
|
|
403
|
+
SECOND = "second"
|
|
404
|
+
DAY_OF_WEEK = "day_of_week"
|
|
405
|
+
|
|
406
|
+
@classmethod
|
|
407
|
+
def _missing_(cls, value):
|
|
408
|
+
if isinstance(value, str) and value.lower() != value:
|
|
409
|
+
return DatePart(value.lower())
|
|
410
|
+
return super()._missing_(value)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
class SourceType(Enum):
|
|
414
|
+
FILTER = "filter"
|
|
415
|
+
SELECT = "select"
|
|
416
|
+
ABSTRACT = "abstract"
|
|
417
|
+
DIRECT_SELECT = "direct_select"
|
|
418
|
+
GROUP = "group"
|
|
419
|
+
WINDOW = "window"
|
|
420
|
+
UNNEST = "unnest"
|
|
421
|
+
CONSTANT = "constant"
|
|
422
|
+
ROWSET = "rowset"
|
|
423
|
+
MERGE = "merge"
|
|
424
|
+
BASIC = "basic"
|
|
425
|
+
UNION = "union"
|
|
426
|
+
RECURSIVE = "recursive"
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
class ShowCategory(Enum):
|
|
430
|
+
DATASOURCES = "datasources"
|
|
431
|
+
CONCEPTS = "concepts"
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
class IOType(Enum):
|
|
435
|
+
CSV = "csv"
|
|
436
|
+
PARQUET = "parquet"
|
|
437
|
+
|
|
438
|
+
@classmethod
|
|
439
|
+
def _missing_(cls, value):
|
|
440
|
+
if isinstance(value, str) and value.lower() != value:
|
|
441
|
+
return IOType(value.lower())
|
|
442
|
+
return super()._missing_(value)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
class ValidationScope(Enum):
|
|
446
|
+
ALL = "all"
|
|
447
|
+
CONCEPTS = "concepts"
|
|
448
|
+
DATASOURCES = "datasources"
|
|
449
|
+
|
|
450
|
+
@classmethod
|
|
451
|
+
def _missing_(cls, value):
|
|
452
|
+
if isinstance(value, str) and value.lower() != value:
|
|
453
|
+
return ValidationScope(value.lower())
|
|
454
|
+
return super()._missing_(value)
|