@@ -184,6 +184,7 @@ class QueryRender(ABC):
184184details :PlatformDetails = None
185185is_single_line_comment :bool = False
186186unsupported_functions_text = "Unsupported functions were excluded from the result query:"
187+ unmapped_fields_text = "Unmapped fields: "
187188
188189platform_functions :PlatformFunctions = None
189190
@@ -206,6 +207,11 @@ def wrap_with_not_supported_functions(self, query: str, not_supported_functions:
206207
207208return query
208209
210+ def wrap_with_unmapped_fields (self ,query :str ,fields :Optional [list [str ]])-> str :
211+ if fields :
212+ return query + "\n \n " + self .wrap_with_comment (f"{ self .unmapped_fields_text } { ', ' .join (fields )} " )
213+ return query
214+
209215def wrap_with_comment (self ,value :str )-> str :
210216return f"{ self .comment_symbol } { value } "
211217
@@ -216,7 +222,6 @@ def generate(self, query_container: Union[RawQueryContainer, TokenizedQueryConta
216222
217223class PlatformQueryRender (QueryRender ):
218224mappings :BasePlatformMappings = None
219- is_strict_mapping :bool = False
220225
221226or_token = "or"
222227and_token = "and"
@@ -247,22 +252,10 @@ def generate_prefix(self, log_source_signature: Optional[LogSourceSignature], fu
247252def generate_functions (self ,functions :list [Function ],source_mapping :SourceMapping )-> RenderedFunctions :
248253return self .platform_functions .render (functions ,source_mapping )
249254
250- def map_field (self ,field :Field ,source_mapping :SourceMapping )-> list [str ]:
251- generic_field_name = field .get_generic_field_name (source_mapping .source_id )
252- # field can be mapped to corresponding platform field name or list of platform field names
253- mapped_field = source_mapping .fields_mapping .get_platform_field_name (generic_field_name = generic_field_name )
254- if not mapped_field and self .is_strict_mapping :
255- raise StrictPlatformException (field_name = field .source_name ,platform_name = self .details .name )
256-
257- if isinstance (mapped_field ,str ):
258- mapped_field = [mapped_field ]
259-
260- return mapped_field if mapped_field else [generic_field_name ]if generic_field_name else [field .source_name ]
261-
262255def map_predefined_field (self ,predefined_field :PredefinedField )-> str :
263256if not (mapped_predefined_field_name := self .predefined_fields_map .get (predefined_field .name )):
264- if self .is_strict_mapping :
265- raise StrictPlatformException (field_name = predefined_field . name ,platform_name = self . details . name )
257+ if self .mappings . is_strict_mapping :
258+ raise StrictPlatformException (platform_name = self . details . name ,fields = [ predefined_field . name ] )
266259
267260return predefined_field .name
268261
@@ -275,7 +268,7 @@ def apply_token(self, token: QUERY_TOKEN_TYPE, source_mapping: SourceMapping) ->
275268elif token .predefined_field :
276269mapped_fields = [self .map_predefined_field (token .predefined_field )]
277270else :
278- mapped_fields = self .map_field (token .field ,source_mapping )
271+ mapped_fields = self .mappings . map_field (token .field ,source_mapping )
279272joined = self .logical_operators_map [LogicalOperatorType .OR ].join (
280273 [
281274self .field_value_render .apply_field_value (field = field ,operator = token .operator ,value = token .value )
@@ -285,9 +278,13 @@ def apply_token(self, token: QUERY_TOKEN_TYPE, source_mapping: SourceMapping) ->
285278return self .group_token % joined if len (mapped_fields )> 1 else joined
286279if isinstance (token ,FieldField ):
287280alias_left ,field_left = token .alias_left ,token .field_left
288- mapped_fields_left = [alias_left .name ]if alias_left else self .map_field (field_left ,source_mapping )
281+ mapped_fields_left = (
282+ [alias_left .name ]if alias_left else self .mappings .map_field (field_left ,source_mapping )
283+ )
289284alias_right ,field_right = token .alias_right ,token .field_right
290- mapped_fields_right = [alias_right .name ]if alias_right else self .map_field (field_right ,source_mapping )
285+ mapped_fields_right = (
286+ [alias_right .name ]if alias_right else self .mappings .map_field (field_right ,source_mapping )
287+ )
291288cross_paired_fields = list (itertools .product (mapped_fields_left ,mapped_fields_right ))
292289joined = self .logical_operators_map [LogicalOperatorType .OR ].join (
293290 [
@@ -311,14 +308,9 @@ def apply_token(self, token: QUERY_TOKEN_TYPE, source_mapping: SourceMapping) ->
311308
312309def generate_query (self ,tokens :list [QUERY_TOKEN_TYPE ],source_mapping :SourceMapping )-> str :
313310result_values = []
314- unmapped_fields = set ()
315311for token in tokens :
316- try :
317- result_values .append (self .apply_token (token = token ,source_mapping = source_mapping ))
318- except StrictPlatformException as err :
319- unmapped_fields .add (err .field_name )
320- if unmapped_fields :
321- raise StrictPlatformException (self .details .name ,"" ,source_mapping .source_id ,sorted (unmapped_fields ))
312+ result_values .append (self .apply_token (token = token ,source_mapping = source_mapping ))
313+
322314return "" .join (result_values )
323315
324316def wrap_with_meta_info (self ,query :str ,meta_info :Optional [MetaInfoContainer ])-> str :
@@ -351,11 +343,13 @@ def finalize_query(
351343meta_info :Optional [MetaInfoContainer ]= None ,
352344source_mapping :Optional [SourceMapping ]= None ,# noqa: ARG002
353345not_supported_functions :Optional [list ]= None ,
346+ unmapped_fields :Optional [list [str ]]= None ,
354347* args ,# noqa: ARG002
355348** kwargs ,# noqa: ARG002
356349 )-> str :
357350query = self ._join_query_parts (prefix ,query ,functions )
358351query = self .wrap_with_meta_info (query ,meta_info )
352+ query = self .wrap_with_unmapped_fields (query ,unmapped_fields )
359353return self .wrap_with_not_supported_functions (query ,not_supported_functions )
360354
361355@staticmethod
@@ -417,8 +411,10 @@ def generate_raw_log_fields(self, fields: list[Field], source_mapping: SourceMap
417411mapped_field = source_mapping .fields_mapping .get_platform_field_name (
418412generic_field_name = generic_field_name
419413 )
420- if not mapped_field and self .is_strict_mapping :
421- raise StrictPlatformException (field_name = field .source_name ,platform_name = self .details .name )
414+ if not mapped_field and self .mappings .is_strict_mapping :
415+ raise StrictPlatformException (
416+ platform_name = self .details .name ,fields = [field .source_name ],mapping = source_mapping .source_id
417+ )
422418if prefix_list := self .process_raw_log_field_prefix (field = mapped_field ,source_mapping = source_mapping ):
423419for prefix in prefix_list :
424420if prefix not in defined_raw_log_fields :
@@ -428,6 +424,9 @@ def generate_raw_log_fields(self, fields: list[Field], source_mapping: SourceMap
428424def _generate_from_tokenized_query_container_by_source_mapping (
429425self ,query_container :TokenizedQueryContainer ,source_mapping :SourceMapping
430426 )-> str :
427+ unmapped_fields = self .mappings .check_fields_mapping_existence (
428+ query_container .meta_info .query_fields ,source_mapping
429+ )
431430rendered_functions = self .generate_functions (query_container .functions .functions ,source_mapping )
432431prefix = self .generate_prefix (source_mapping .log_source_signature ,rendered_functions .rendered_prefix )
433432
@@ -443,6 +442,7 @@ def _generate_from_tokenized_query_container_by_source_mapping(
443442query = query ,
444443functions = rendered_functions .rendered ,
445444not_supported_functions = not_supported_functions ,
445+ unmapped_fields = unmapped_fields ,
446446meta_info = query_container .meta_info ,
447447source_mapping = source_mapping ,
448448 )