newMetricsSQL creates a resolver for evaluating metrics SQL. It wraps the regular SQL resolver and compiles the metrics SQL to a regular SQL query first. The compiler preserves templating in the SQL, allowing the regular SQL resolver to handle SQL templating rules.
(ctx context.Context, opts *runtime.ResolverOptions)
| 41 | // It wraps the regular SQL resolver and compiles the metrics SQL to a regular SQL query first. |
| 42 | // The compiler preserves templating in the SQL, allowing the regular SQL resolver to handle SQL templating rules. |
| 43 | func newMetricsSQL(ctx context.Context, opts *runtime.ResolverOptions) (runtime.Resolver, error) { |
| 44 | props := &metricsSQLProps{} |
| 45 | if err := mapstructureutil.WeakDecode(opts.Properties, props); err != nil { |
| 46 | return nil, err |
| 47 | } |
| 48 | if props.SQL == "" { |
| 49 | return nil, errors.New(`metrics SQL: missing required property "sql"`) |
| 50 | } |
| 51 | |
| 52 | span := trace.SpanFromContext(ctx) |
| 53 | if span.SpanContext().IsValid() { |
| 54 | span.SetAttributes( |
| 55 | attribute.String("metrics_sql", props.SQL), |
| 56 | attribute.String("time_zone", props.TimeZone), |
| 57 | attribute.Bool("has_additional_where", props.AdditionalWhere != nil || len(props.AdditionalWhereByMetricsView) > 0), |
| 58 | attribute.Bool("has_additional_time_range", props.AdditionalTimeRange != nil), |
| 59 | ) |
| 60 | } |
| 61 | |
| 62 | instance, err := opts.Runtime.Instance(ctx, opts.InstanceID) |
| 63 | if err != nil { |
| 64 | return nil, err |
| 65 | } |
| 66 | |
| 67 | props.SQL, _, err = resolveTemplate(props.SQL, opts.Args, instance, opts.Claims.UserAttributes, opts.ForExport) |
| 68 | if err != nil { |
| 69 | return nil, err |
| 70 | } |
| 71 | |
| 72 | ctrl, err := opts.Runtime.Controller(ctx, opts.InstanceID) |
| 73 | if err != nil { |
| 74 | return nil, err |
| 75 | } |
| 76 | |
| 77 | sqlArgs := &metricsSQLArgs{} |
| 78 | if err := mapstructure.Decode(opts.Args, sqlArgs); err != nil { |
| 79 | return nil, err |
| 80 | } |
| 81 | |
| 82 | // Create a metrics SQL parser |
| 83 | compiler := metricssql.New(&metricssql.CompilerOptions{ |
| 84 | GetMetricsView: func(ctx context.Context, name string) (*runtimev1.Resource, error) { |
| 85 | mv, err := ctrl.Get(ctx, &runtimev1.ResourceName{Kind: runtime.ResourceKindMetricsView, Name: name}, false) |
| 86 | if err != nil { |
| 87 | return nil, err |
| 88 | } |
| 89 | sec, err := opts.Runtime.ResolveSecurity(ctx, ctrl.InstanceID, opts.Claims, mv) |
| 90 | if err != nil { |
| 91 | return nil, err |
| 92 | } |
| 93 | if !sec.CanAccess() { |
| 94 | return nil, runtime.ErrForbidden |
| 95 | } |
| 96 | return mv, nil |
| 97 | }, |
| 98 | GetTimestamps: func(ctx context.Context, mv *runtimev1.Resource, timeDim string) (metricsview.TimestampsResult, error) { |
| 99 | sec, err := opts.Runtime.ResolveSecurity(ctx, ctrl.InstanceID, opts.Claims, mv) |
| 100 | if err != nil { |
no test coverage detected