2121import re
2222from abc import ABC ,abstractmethod
2323from 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
2827from app .translator .core .mapping import SourceMapping
29- from app .translator .core .models .field import Field
28+ from app .translator .core .models .field import Alias , Field
3029from app .translator .core .models .functions .base import Function ,ParsedFunctions ,RenderedFunctions
30+ from app .translator .tools .utils import execute_module
3131from settings import INIT_FUNCTIONS
3232
3333if TYPE_CHECKING :
@@ -41,6 +41,14 @@ class FunctionMatchContainer:
4141
4242
4343class 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
4553def parse (self ,* args ,** kwargs )-> Function :
4654raise NotImplementedError
@@ -73,21 +81,25 @@ def parse(self, func_body: str, raw: str) -> Function:
7381
7482
7583class FunctionRender (ABC ):
84+ function_names_map :ClassVar [dict [str ,str ]]= {}
85+ order_to_render :int = 0
86+ in_query_render :bool = False
87+ render_to_prefix :bool = False
88+ manager :PlatformFunctionsManager = None
89+
90+ def set_functions_manager (self ,manager :PlatformFunctionsManager )-> FunctionRender :
91+ self .manager = manager
92+ return self
93+
7694@abstractmethod
7795def render (self ,function :Function ,source_mapping :SourceMapping )-> str :
7896raise NotImplementedError
7997
8098@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 } "
99+ def map_field (field :Union [Alias ,Field ],source_mapping :SourceMapping )-> str :
100+ if isinstance (field ,Alias ):
101+ return field .name
86102
87- return result
88-
89- @staticmethod
90- def map_field (field :Field ,source_mapping :SourceMapping )-> str :
91103generic_field_name = field .get_generic_field_name (source_mapping .source_id )
92104mapped_field = source_mapping .fields_mapping .get_platform_field_name (generic_field_name = generic_field_name )
93105if isinstance (mapped_field ,list ):
@@ -97,23 +109,48 @@ def map_field(field: Field, source_mapping: SourceMapping) -> str:
97109
98110
99111class PlatformFunctionsManager :
112+ platform_functions :PlatformFunctions = None
113+
100114def __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
115+ # {platform_func_name: HigherOrderFunctionParser}
116+ self ._hof_parsers_map :dict [str ,HigherOrderFunctionParser ]= {}
117+ self ._parsers_map :dict [str ,FunctionParser ]= {}# {platform_func_name: FunctionParser}
118+
119+ self ._renders_map :dict [str ,FunctionRender ]= {}# {generic_func_name: FunctionRender}
120+ self ._in_query_renders_map :dict [str ,FunctionRender ]= {}# {generic_func_name: FunctionRender}
121+ self ._order_to_render :dict [str ,int ]= {}# {generic_func_name: int}
122+
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
129+ if render .in_query_render :
130+ self ._in_query_renders_map [generic_function_name ]= render
131+
132+ return render_class
133+
134+ def register_parser (self ,parser_class :type [BaseFunctionParser ])-> type [BaseFunctionParser ]:
135+ parser = parser_class ()
136+ parser .manager = self
137+ parsers_map = self ._hof_parsers_map if isinstance (parser ,HigherOrderFunctionParser )else self ._parsers_map
138+ for platform_function_name in parser .function_names_map :
139+ parsers_map [platform_function_name ]= parser
140+
141+ if parser .functions_group_name :
142+ parsers_map [parser .functions_group_name ]= parser
143+
144+ return parser_class
145+
146+ def get_hof_parser (self ,platform_func_name :str )-> HigherOrderFunctionParser :
147+ if INIT_FUNCTIONS and (parser := self ._hof_parsers_map .get (platform_func_name )):
148+ return parser
110149
111- @cached_property
112- def _inverted_names_map (self )-> dict [str ,str ]:
113- return {value :key for key ,value in self ._names_map .items ()}
150+ raise NotSupportedFunctionException
114151
115- def get_parser (self ,generic_func_name :str )-> HigherOrderFunctionParser :
116- if INIT_FUNCTIONS and (parser := self ._parsers_map .get (generic_func_name )):
152+ def get_parser (self ,platform_func_name :str )-> FunctionParser :
153+ if INIT_FUNCTIONS and (parser := self ._parsers_map .get (platform_func_name )):
117154return parser
118155
119156raise NotSupportedFunctionException
@@ -130,56 +167,29 @@ def get_in_query_render(self, generic_func_name: str) -> FunctionRender:
130167
131168raise NotSupportedFunctionException
132169
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
136-
137- raise NotSupportedFunctionException
138-
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 )
142-
143170@property
144171def order_to_render (self )-> dict [str ,int ]:
145172if INIT_FUNCTIONS :
146173return self ._order_to_render
147174
148175return {}
149176
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-
157177
158178class PlatformFunctions :
179+ dir_path :str = None
180+ platform_query_render :PlatformQueryRender = None
159181manager :PlatformFunctionsManager = PlatformFunctionsManager ()
182+
160183function_delimiter = "|"
161184
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 )
185+ def __init__ (self ):
186+ self .manager .platform_functions = self
187+ if self .dir_path :
188+ execute_module (f"{ self .dir_path } /parsers/__init__.py" )
189+ execute_module (f"{ self .dir_path } /renders/__init__.py" )
177190
178- return ParsedFunctions (
179- functions = parsed ,
180- not_supported = [self .wrap_function_with_delimiter (func )for func in not_supported ],
181- invalid = invalid ,
182- )
191+ def parse (self ,query :str )-> ParsedFunctions :# noqa: ARG002
192+ return ParsedFunctions ()
183193
184194def _sort_functions_to_render (self ,functions :list [Function ])-> list [Function ]:
185195return sorted (functions ,key = lambda func :self .manager .order_to_render .get (func .name ,0 ))
@@ -193,7 +203,7 @@ def render(self, functions: list[Function], source_mapping: SourceMapping) -> Re
193203try :
194204func_render = self .manager .get_render (func .name )
195205_rendered = func_render .render (func ,source_mapping )
196- if func . name in self . manager . render_to_prefix_functions :
206+ if func_render . render_to_prefix :
197207rendered_prefix += _rendered
198208else :
199209rendered += self .wrap_function_with_delimiter (_rendered )