Skip to content

Commit ea56df1

Browse files
committed
fix conflicts
2 parents 31bb83f + 140cf1f commit ea56df1

File tree

95 files changed

+1457
-701
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+1457
-701
lines changed

uncoder-core/app/translator/core/custom_types/functions.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,33 @@ class FunctionType(CustomEnum):
99
min = "min"
1010
sum = "sum"
1111

12-
divide = "divide"
12+
values = "values"
1313

1414
earliest = "earliest"
1515
latest = "latest"
1616

17+
divide = "divide"
18+
multiply = "multiply"
19+
1720
lower = "lower"
21+
split = "split"
1822
upper = "upper"
1923

20-
compare_boolean = "compare_boolean"
21-
24+
array_length = "array_length"
25+
extract_time = "extract_time"
2226
ipv4_is_in_range = "ipv4_is_in_range"
2327

2428
bin = "bin"
2529
eval = "eval"
2630
fields = "fields"
31+
iploc = "iploc"
32+
join = "join"
2733
rename = "rename"
2834
search = "search"
2935
sort_limit = "sort_limit"
3036
stats = "stats"
3137
table = "table"
3238
timeframe = "timeframe"
33-
values = "values"
39+
union = "union"
40+
41+
aggregation_data_function = "aggregation_data_function"

uncoder-core/app/translator/core/custom_types/predefined_fields.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ class IPLocationType(CustomEnum):
1010
lat_lon = "ip_loc_lat_lon"
1111
region = "ip_loc_region"
1212
timezone = "ip_loc_timezone"
13+
14+
15+
class TimeType(CustomEnum):
16+
timestamp = "timestamp"

uncoder-core/app/translator/core/exceptions/core.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
from typing import Optional
22

33

4-
class NotImplementedException(BaseException):
5-
...
6-
7-
84
class BasePlatformException(BaseException):
95
...
106

uncoder-core/app/translator/core/exceptions/render.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ class FunctionRenderException(BaseRenderException):
1414

1515
class UnsupportedRenderMethod(BaseRenderException):
1616
def __init__(self, platform_name: str, method: str):
17-
message = f"Cannot translate. {platform_name} backend does not support {method}."
17+
message = f'Cannot translate. {platform_name} backend does not support "{method}".'
1818
super().__init__(message)

uncoder-core/app/translator/core/functions.py

Lines changed: 76 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121
import re
2222
from abc import ABC, abstractmethod
2323
from dataclasses import dataclass
24-
from functools import cached_property
25-
from typing import TYPE_CHECKING, Any, Optional
24+
from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union
2625

27-
from app.translator.core.exceptions.functions import InvalidFunctionSignature, NotSupportedFunctionException
26+
from app.translator.core.exceptions.functions import NotSupportedFunctionException
2827
from app.translator.core.mapping import SourceMapping
29-
from app.translator.core.models.field import Field
3028
from app.translator.core.models.functions.base import Function, ParsedFunctions, RenderedFunctions
29+
from app.translator.core.models.query_tokens.field import Alias, Field, PredefinedField
30+
from app.translator.tools.utils import execute_module
3131
from settings import INIT_FUNCTIONS
3232

3333
if TYPE_CHECKING:
@@ -41,6 +41,14 @@ class FunctionMatchContainer:
4141

4242

4343
class BaseFunctionParser(ABC):
44+
function_names_map: ClassVar[dict[str, str]] = {}
45+
functions_group_name: str = None
46+
manager: PlatformFunctionsManager = None
47+
48+
def set_functions_manager(self, manager: PlatformFunctionsManager) -> BaseFunctionParser:
49+
self.manager = manager
50+
return self
51+
4452
@abstractmethod
4553
def parse(self, *args, **kwargs) -> Function:
4654
raise NotImplementedError
@@ -73,72 +81,81 @@ def parse(self, func_body: str, raw: str) -> Function:
7381

7482

7583
class FunctionRender(ABC):
84+
function_names_map: ClassVar[dict[str, str]] = {}
85+
order_to_render: int = 0
86+
render_to_prefix: bool = False
87+
manager: PlatformFunctionsManager = None
88+
89+
def set_functions_manager(self, manager: PlatformFunctionsManager) -> FunctionRender:
90+
self.manager = manager
91+
return self
92+
7693
@abstractmethod
7794
def render(self, function: Function, source_mapping: SourceMapping) -> str:
7895
raise NotImplementedError
7996

80-
@staticmethod
81-
def concat_kwargs(kwargs: dict[str, str]) -> str:
82-
result = ""
83-
for key, value in kwargs.items():
84-
if value:
85-
result = f"{result}, {key}={value}" if result else f"{key}={value}"
97+
def map_field(self, field: Union[Alias, Field], source_mapping: SourceMapping) -> str:
98+
if isinstance(field, Alias):
99+
return field.name
86100

87-
return result
101+
if isinstance(field, Field):
102+
mappings = self.manager.platform_functions.platform_query_render.mappings
103+
mapped_fields = mappings.map_field(field, source_mapping)
104+
return mapped_fields[0]
88105

89-
@staticmethod
90-
def map_field(field: Field, source_mapping: SourceMapping) -> str:
91-
generic_field_name = field.get_generic_field_name(source_mapping.source_id)
92-
mapped_field = source_mapping.fields_mapping.get_platform_field_name(generic_field_name=generic_field_name)
93-
if isinstance(mapped_field, list):
94-
mapped_field = mapped_field[0]
106+
if isinstance(field, PredefinedField):
107+
return self.manager.platform_functions.platform_query_render.map_predefined_field(field)
95108

96-
return mapped_field if mapped_field else field.source_name
109+
raise NotSupportedFunctionException
97110

98111

99112
class PlatformFunctionsManager:
113+
platform_functions: PlatformFunctions = None
114+
100115
def __init__(self):
101-
self._parsers_map: dict[str, HigherOrderFunctionParser] = {}
102-
self._renders_map: dict[str, FunctionRender] = {}
103-
self._in_query_renders_map: dict[str, FunctionRender] = {}
104-
self._names_map: dict[str, str] = {}
105-
self._order_to_render: dict[str, int] = {}
106-
self._render_to_prefix_functions: list[str] = []
107-
108-
def post_init_configure(self, platform_render: PlatformQueryRender) -> None:
109-
raise NotImplementedError
116+
# {platform_func_name: HigherOrderFunctionParser}
117+
self._hof_parsers_map: dict[str, HigherOrderFunctionParser] = {}
118+
self._parsers_map: dict[str, FunctionParser] = {} # {platform_func_name: FunctionParser}
110119

111-
@cached_property
112-
def _inverted_names_map(self) -> dict[str, str]:
113-
return {value: key for key, value in self._names_map.items()}
120+
self._renders_map: dict[str, FunctionRender] = {} # {generic_func_name: FunctionRender}
121+
self._order_to_render: dict[str, int] = {} # {generic_func_name: int}
114122

115-
def get_parser(self, generic_func_name: str) -> HigherOrderFunctionParser:
116-
if INIT_FUNCTIONS and (parser := self._parsers_map.get(generic_func_name)):
117-
return parser
123+
def register_render(self, render_class: type[FunctionRender]) -> type[FunctionRender]:
124+
render = render_class()
125+
render.manager = self
126+
for generic_function_name in render.function_names_map:
127+
self._renders_map[generic_function_name] = render
128+
self._order_to_render[generic_function_name] = render.order_to_render
118129

119-
raise NotSupportedFunctionException
130+
return render_class
120131

121-
def get_render(self, generic_func_name: str) -> FunctionRender:
122-
if INIT_FUNCTIONS and (render := self._renders_map.get(generic_func_name)):
123-
return render
132+
def register_parser(self, parser_class: type[BaseFunctionParser]) -> type[BaseFunctionParser]:
133+
parser = parser_class()
134+
parser.manager = self
135+
parsers_map = self._hof_parsers_map if isinstance(parser, HigherOrderFunctionParser) else self._parsers_map
136+
for platform_function_name in parser.function_names_map:
137+
parsers_map[platform_function_name] = parser
124138

125-
raise NotSupportedFunctionException
139+
if parser.functions_group_name:
140+
parsers_map[parser.functions_group_name] = parser
126141

127-
def get_in_query_render(self, generic_func_name: str) -> FunctionRender:
128-
if INIT_FUNCTIONS and (render := self._in_query_renders_map.get(generic_func_name)):
129-
return render
142+
return parser_class
143+
144+
def get_hof_parser(self, platform_func_name: str) -> HigherOrderFunctionParser:
145+
if INIT_FUNCTIONS and (parser := self._hof_parsers_map.get(platform_func_name)):
146+
return parser
130147

131148
raise NotSupportedFunctionException
132149

133-
def get_generic_func_name(self, platform_func_name: str) -> Optional[str]:
134-
if INIT_FUNCTIONS and (generic_func_name := self._names_map.get(platform_func_name)):
135-
return generic_func_name
150+
def get_parser(self, platform_func_name: str) -> Optional[FunctionParser]:
151+
if INIT_FUNCTIONS and (parser := self._parsers_map.get(platform_func_name)):
152+
return parser
136153

137-
raise NotSupportedFunctionException
154+
def get_render(self, generic_func_name: str) -> FunctionRender:
155+
if INIT_FUNCTIONS and (render := self._renders_map.get(generic_func_name)):
156+
return render
138157

139-
def get_platform_func_name(self, generic_func_name: str) -> Optional[str]:
140-
if INIT_FUNCTIONS:
141-
return self._inverted_names_map.get(generic_func_name)
158+
raise NotSupportedFunctionException
142159

143160
@property
144161
def order_to_render(self) -> dict[str, int]:
@@ -147,39 +164,22 @@ def order_to_render(self) -> dict[str, int]:
147164

148165
return {}
149166

150-
@property
151-
def render_to_prefix_functions(self) -> list[str]:
152-
if INIT_FUNCTIONS:
153-
return self._render_to_prefix_functions
154-
155-
return []
156-
157167

158168
class PlatformFunctions:
169+
dir_path: str = None
170+
platform_query_render: PlatformQueryRender = None
159171
manager: PlatformFunctionsManager = PlatformFunctionsManager()
172+
160173
function_delimiter = "|"
161174

162-
def parse(self, query: str) -> ParsedFunctions:
163-
parsed = []
164-
not_supported = []
165-
invalid = []
166-
functions = query.split(self.function_delimiter)
167-
for func in functions:
168-
split_func = func.strip().split(" ")
169-
func_name, func_body = split_func[0], " ".join(split_func[1:])
170-
try:
171-
func_parser = self.manager.get_parser(self.manager.get_generic_func_name(func_name))
172-
parsed.append(func_parser.parse(func_body, func))
173-
except NotSupportedFunctionException:
174-
not_supported.append(func)
175-
except InvalidFunctionSignature:
176-
invalid.append(func)
175+
def __init__(self):
176+
self.manager.platform_functions = self
177+
if self.dir_path:
178+
execute_module(f"{self.dir_path}/parsers/__init__.py")
179+
execute_module(f"{self.dir_path}/renders/__init__.py")
177180

178-
return ParsedFunctions(
179-
functions=parsed,
180-
not_supported=[self.wrap_function_with_delimiter(func) for func in not_supported],
181-
invalid=invalid,
182-
)
181+
def parse(self, query: str) -> ParsedFunctions: # noqa: ARG002
182+
return ParsedFunctions()
183183

184184
def _sort_functions_to_render(self, functions: list[Function]) -> list[Function]:
185185
return sorted(functions, key=lambda func: self.manager.order_to_render.get(func.name, 0))
@@ -193,7 +193,7 @@ def render(self, functions: list[Function], source_mapping: SourceMapping) -> Re
193193
try:
194194
func_render = self.manager.get_render(func.name)
195195
_rendered = func_render.render(func, source_mapping)
196-
if func.name in self.manager.render_to_prefix_functions:
196+
if func_render.render_to_prefix:
197197
rendered_prefix += _rendered
198198
else:
199199
rendered += self.wrap_function_with_delimiter(_rendered)

uncoder-core/app/translator/core/mapping.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from abc import ABC, abstractmethod
4-
from typing import TYPE_CHECKING, Optional, TypeVar
4+
from typing import TYPE_CHECKING, Optional, TypeVar, Union
55

66
from app.translator.core.exceptions.core import StrictPlatformException
77
from app.translator.core.models.platform_details import PlatformDetails
@@ -19,9 +19,14 @@ class LogSourceSignature(ABC):
1919
wildcard_symbol = "*"
2020

2121
@abstractmethod
22-
def is_suitable(self, *args, **kwargs) -> bool:
22+
def is_suitable(self, **kwargs) -> bool:
2323
raise NotImplementedError("Abstract method")
2424

25+
@staticmethod
26+
def _check_conditions(conditions: list[Union[bool, None]]) -> bool:
27+
conditions = [condition for condition in conditions if condition is not None]
28+
return bool(conditions) and all(conditions)
29+
2530
@abstractmethod
2631
def __str__(self) -> str:
2732
raise NotImplementedError("Abstract method")
@@ -70,7 +75,7 @@ def update(self, fields_mapping: FieldsMapping) -> None:
7075
self.__render_mapping.update(fields_mapping.__render_mapping)
7176

7277
def is_suitable(self, field_names: list[str]) -> bool:
73-
return set(field_names).issubset(set(self.__parser_mapping.keys()))
78+
return bool(field_names) and set(field_names).issubset(set(self.__parser_mapping.keys()))
7479

7580

7681
_LogSourceSignatureType = TypeVar("_LogSourceSignatureType", bound=LogSourceSignature)
@@ -147,9 +152,23 @@ def prepare_fields_mapping(field_mapping: dict) -> FieldsMapping:
147152
def prepare_log_source_signature(self, mapping: dict) -> LogSourceSignature:
148153
raise NotImplementedError("Abstract method")
149154

150-
@abstractmethod
151-
def get_suitable_source_mappings(self, *args, **kwargs) -> list[SourceMapping]:
152-
raise NotImplementedError("Abstract method")
155+
def get_suitable_source_mappings(
156+
self, field_names: list[str], log_sources: dict[str, list[Union[int, str]]]
157+
) -> list[SourceMapping]:
158+
by_log_sources_and_fields = []
159+
by_fields = []
160+
for source_mapping in self._source_mappings.values():
161+
if source_mapping.source_id == DEFAULT_MAPPING_NAME:
162+
continue
163+
164+
if source_mapping.fields_mapping.is_suitable(field_names):
165+
by_fields.append(source_mapping)
166+
167+
log_source_signature: LogSourceSignature = source_mapping.log_source_signature
168+
if log_source_signature and log_source_signature.is_suitable(**log_sources):
169+
by_log_sources_and_fields.append(source_mapping)
170+
171+
return by_log_sources_and_fields or by_fields or [self._source_mappings[DEFAULT_MAPPING_NAME]]
153172

154173
def get_source_mapping(self, source_id: str) -> Optional[SourceMapping]:
155174
return self._source_mappings.get(source_id)

0 commit comments

Comments
 (0)