@@ -311,7 +311,7 @@ class AggregateDefinition(FunctionDefinition):
311311 An optional function that takes in the resolved argument and returns the attribute key to aggregate on.
312312 If not provided, assumes the aggregate is on the first argument.
313313 """
314- attribute_resolver : Callable [[ResolvedArguments ], AttributeKey ] | None = None
314+ attribute_resolver : Callable [[ResolvedArgument ], AttributeKey ] | None = None
315315
316316 def resolve (
317317 self ,
@@ -334,7 +334,72 @@ def resolve(
334334 raise InvalidSearchQuery ("Aggregates accept attribute keys only" )
335335 resolved_attribute = resolved_arguments [0 ]
336336 if self .attribute_resolver is not None :
337- resolved_attribute = self .attribute_resolver (resolved_arguments )
337+ resolved_attribute = self .attribute_resolver (resolved_attribute )
338+
339+ return ResolvedAggregate (
340+ public_alias = alias ,
341+ internal_name = self .internal_function ,
342+ search_type = search_type ,
343+ internal_type = self .internal_type ,
344+ processor = self .processor ,
345+ extrapolation = (
346+ self .extrapolation if not search_config .disable_aggregate_extrapolation else False
347+ ),
348+ argument = resolved_attribute ,
349+ )
350+
351+
352+ @dataclass (kw_only = True )
353+ class TraceMetricAggregateDefinition (AggregateDefinition ):
354+ internal_function : Function .ValueType
355+ attribute_resolver : Callable [[ResolvedArgument ], AttributeKey ] | None = None
356+
357+ def __post_init__ (self ) -> None :
358+ if len (self .arguments ) != 4 :
359+ raise InvalidSearchQuery (
360+ f"Trace metric aggregates expects exactly 4 arguments to be defined, got { len (self .arguments )} "
361+ )
362+
363+ if not isinstance (self .arguments [0 ], AttributeArgumentDefinition ):
364+ raise InvalidSearchQuery (
365+ "Trace metric aggregates expect argument 0 to be of type AttributeArgumentDefinition"
366+ )
367+
368+ for i in range (1 , 4 ):
369+ if not isinstance (self .arguments [i ], ValueArgumentDefinition ):
370+ raise InvalidSearchQuery (
371+ f"Trace metric aggregates expects argument { i } to be of type ValueArgumentDefinition"
372+ )
373+
374+ def resolve (
375+ self ,
376+ alias : str ,
377+ search_type : constants .SearchType ,
378+ resolved_arguments : ResolvedArguments ,
379+ snuba_params : SnubaParams ,
380+ query_result_cache : dict [str , EAPResponse ],
381+ search_config : SearchResolverConfig ,
382+ ) -> ResolvedAggregate :
383+ if not isinstance (resolved_arguments [0 ], AttributeKey ):
384+ raise InvalidSearchQuery (
385+ "Trace metric aggregates expect argument 0 to be of type AttributeArgumentDefinition"
386+ )
387+
388+ resolved_attribute = resolved_arguments [0 ]
389+ if self .attribute_resolver is not None :
390+ resolved_attribute = self .attribute_resolver (resolved_attribute )
391+
392+ if all (resolved_argument != "" for resolved_argument in resolved_arguments [1 :]):
393+ # a metric was passed
394+ # TODO: we need to put it into the top level query conditions
395+ pass
396+ elif all (resolved_argument == "" for resolved_argument in resolved_arguments [1 :]):
397+ # no metrics were specified, assume we query all metrics
398+ pass
399+ else :
400+ raise InvalidSearchQuery (
401+ f"Trace metric aggregates expect the full metric to be specified, got name:{ resolved_arguments [1 ]} type:{ resolved_arguments [2 ]} unit:{ resolved_arguments [3 ]} "
402+ )
338403
339404 return ResolvedAggregate (
340405 public_alias = alias ,
@@ -519,25 +584,18 @@ def attribute_key_to_tuple(attribute_key: AttributeKey) -> tuple[str, AttributeK
519584
520585def count_argument_resolver_optimized (
521586 always_present_attributes : list [AttributeKey ],
522- ) -> Callable [[ResolvedArguments ], AttributeKey ]:
587+ ) -> Callable [[ResolvedArgument ], AttributeKey ]:
523588 always_present_attributes_set = {
524589 attribute_key_to_tuple (attribute ) for attribute in always_present_attributes
525590 }
526591
527- def count_argument_resolver (resolved_arguments : ResolvedArguments ) -> AttributeKey :
528- if len (resolved_arguments ) != 1 :
529- raise InvalidSearchQuery (
530- f"Aggregates expects exactly 1 argument, got { len (resolved_arguments )} "
531- )
532-
533- if not isinstance (resolved_arguments [0 ], AttributeKey ):
592+ def count_argument_resolver (resolved_argument : ResolvedArgument ) -> AttributeKey :
593+ if not isinstance (resolved_argument , AttributeKey ):
534594 raise InvalidSearchQuery ("Aggregates accept attribute keys only" )
535595
536- resolved_attribute : AttributeKey = resolved_arguments [0 ]
537-
538- if attribute_key_to_tuple (resolved_attribute ) in always_present_attributes_set :
596+ if attribute_key_to_tuple (resolved_argument ) in always_present_attributes_set :
539597 return AttributeKey (name = "sentry.project_id" , type = AttributeKey .Type .TYPE_INT )
540598
541- return resolved_attribute
599+ return resolved_argument
542600
543601 return count_argument_resolver
0 commit comments