Compare commits

..

2 Commits

Author SHA1 Message Date
grandwizard28
01c7e9954e chore(api): regenerate openapi spec and frontend client
Regenerates docs/api/openapi.yml (`generate openapi`) and the orval
frontend client (`generate:api`) for the v5 schema typing. The four
value/spec fields are now typed instead of untyped `{}`, and the
QueryEnvelope DTO collapses from a union of `& { spec?: unknown }`
intersections into a clean discriminated union.
2026-06-25 06:04:13 +05:30
grandwizard28
9f168c381b feat(querybuilder): type untyped value fields in v5 openapi schema
The query-builder v5 types FunctionArg, VariableItem and Label carry a
`Value any` field that the reflector rendered as an untyped `{}` in the
OpenAPI spec, and QueryEnvelope left an untyped `spec: {}` on its oneOf
base. Add PrepareJSONSchema methods that document the real wire contract:

- FunctionArg.value  -> oneOf [number, string]
- VariableItem.value -> oneOf [string, number, boolean, array<scalar>]
- Label.value        -> oneOf [string, number, boolean]
- QueryEnvelope      -> drop the duplicate base properties so only the
                        typed oneOf-of-$ref variants remain

The Go fields stay `any`; this only shapes the generated schema, so the
runtime decode paths and the existing wire format are unchanged.
2026-06-25 06:00:01 +05:30
5 changed files with 137 additions and 38 deletions

View File

@@ -5701,7 +5701,10 @@ components:
properties:
name:
type: string
value: {}
value:
oneOf:
- type: number
- type: string
type: object
Querybuildertypesv5FunctionName:
enum:
@@ -5750,7 +5753,11 @@ components:
properties:
key:
$ref: '#/components/schemas/TelemetrytypesTelemetryFieldKey'
value: {}
value:
oneOf:
- type: string
- type: number
- type: boolean
type: object
Querybuildertypesv5LimitBy:
properties:
@@ -6081,10 +6088,6 @@ components:
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopeTraceOperator'
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopePromQL'
- $ref: '#/components/schemas/Querybuildertypesv5QueryEnvelopeClickHouseSQL'
properties:
spec: {}
type:
$ref: '#/components/schemas/Querybuildertypesv5QueryType'
type: object
Querybuildertypesv5QueryEnvelopeBuilderLog:
properties:
@@ -6337,7 +6340,17 @@ components:
properties:
type:
$ref: '#/components/schemas/Querybuildertypesv5VariableType'
value: {}
value:
oneOf:
- type: string
- type: number
- type: boolean
- items:
oneOf:
- type: string
- type: number
- type: boolean
type: array
type: object
Querybuildertypesv5VariableType:
enum:

View File

@@ -3427,12 +3427,14 @@ export interface Querybuildertypesv5FilterDTO {
expression?: string;
}
export type Querybuildertypesv5FunctionArgDTOValue = number | string;
export interface Querybuildertypesv5FunctionArgDTO {
/**
* @type string
*/
name?: string;
value?: unknown;
value?: Querybuildertypesv5FunctionArgDTOValue;
}
export enum Querybuildertypesv5FunctionNameDTO {
@@ -4441,34 +4443,13 @@ export interface Querybuildertypesv5QueryEnvelopeClickHouseSQLDTO {
}
export type Querybuildertypesv5QueryEnvelopeDTO =
| (Querybuildertypesv5QueryEnvelopeBuilderTraceDTO & {
spec?: unknown;
type?: Querybuildertypesv5QueryTypeDTO;
})
| (Querybuildertypesv5QueryEnvelopeBuilderLogDTO & {
spec?: unknown;
type?: Querybuildertypesv5QueryTypeDTO;
})
| (Querybuildertypesv5QueryEnvelopeBuilderMetricDTO & {
spec?: unknown;
type?: Querybuildertypesv5QueryTypeDTO;
})
| (Querybuildertypesv5QueryEnvelopeFormulaDTO & {
spec?: unknown;
type?: Querybuildertypesv5QueryTypeDTO;
})
| (Querybuildertypesv5QueryEnvelopeTraceOperatorDTO & {
spec?: unknown;
type?: Querybuildertypesv5QueryTypeDTO;
})
| (Querybuildertypesv5QueryEnvelopePromQLDTO & {
spec?: unknown;
type?: Querybuildertypesv5QueryTypeDTO;
})
| (Querybuildertypesv5QueryEnvelopeClickHouseSQLDTO & {
spec?: unknown;
type?: Querybuildertypesv5QueryTypeDTO;
});
| Querybuildertypesv5QueryEnvelopeBuilderTraceDTO
| Querybuildertypesv5QueryEnvelopeBuilderLogDTO
| Querybuildertypesv5QueryEnvelopeBuilderMetricDTO
| Querybuildertypesv5QueryEnvelopeFormulaDTO
| Querybuildertypesv5QueryEnvelopeTraceOperatorDTO
| Querybuildertypesv5QueryEnvelopePromQLDTO
| Querybuildertypesv5QueryEnvelopeClickHouseSQLDTO;
/**
* Composite query containing one or more query envelopes. Each query envelope specifies its type and corresponding spec.
@@ -6707,9 +6688,11 @@ export interface MetricsexplorertypesInspectMetricsRequestDTO {
start: number;
}
export type Querybuildertypesv5LabelDTOValue = string | number | boolean;
export interface Querybuildertypesv5LabelDTO {
key?: TelemetrytypesTelemetryFieldKeyDTO;
value?: unknown;
value?: Querybuildertypesv5LabelDTOValue;
}
export interface Querybuildertypesv5BucketDTO {
@@ -7319,9 +7302,20 @@ export enum Querybuildertypesv5VariableTypeDTO {
custom = 'custom',
text = 'text',
}
export type Querybuildertypesv5VariableItemDTOValueOneOfItem =
| string
| number
| boolean;
export type Querybuildertypesv5VariableItemDTOValue =
| string
| number
| boolean
| Querybuildertypesv5VariableItemDTOValueOneOfItem[];
export interface Querybuildertypesv5VariableItemDTO {
type?: Querybuildertypesv5VariableTypeDTO;
value?: unknown;
value?: Querybuildertypesv5VariableItemDTOValue;
}
export type Querybuildertypesv5QueryRangeRequestDTOVariables = {

View File

@@ -621,6 +621,27 @@ func (f FunctionArg) Copy() FunctionArg {
return f
}
var _ jsonschema.Preparer = FunctionArg{}
// PrepareJSONSchema types the `value` property as a scalar instead of an untyped
// {}: function arguments are numbers (clamp/ewma/timeShift/fillZero) or a string
// (the anomaly `seasonality` arg). The Go field stays `any`; this only documents
// the wire contract in the generated OpenAPI schema.
func (FunctionArg) PrepareJSONSchema(s *jsonschema.Schema) error {
if _, ok := s.Properties["value"]; !ok {
return nil
}
value := jsonschema.Schema{}
value.OneOf = []jsonschema.SchemaOrBool{
jsonschema.Number.ToSchemaOrBool(),
jsonschema.String.ToSchemaOrBool(),
}
s.Properties["value"] = value.ToSchemaOrBool()
return nil
}
type Function struct {
// name of the function
Name FunctionName `json:"name"`

View File

@@ -86,6 +86,19 @@ func (QueryEnvelope) JSONSchemaOneOf() []any {
}
}
var _ jsonschema.Preparer = QueryEnvelope{}
// PrepareJSONSchema drops the envelope's reflected base properties. Each variant
// returned by JSONSchemaOneOf already declares its own `type` and typed `spec`,
// so the base object's `type` and untyped `spec: {}` only duplicate them (and
// leave `spec` untyped). Removing them leaves a clean oneOf-of-$ref.
func (QueryEnvelope) PrepareJSONSchema(s *jsonschema.Schema) error {
s.Properties = nil
s.Required = nil
return nil
}
// implement custom json unmarshaler for the QueryEnvelope.
func (q *QueryEnvelope) UnmarshalJSON(data []byte) error {
var shadow struct {
@@ -276,6 +289,42 @@ type VariableItem struct {
Value any `json:"value"`
}
var _ jsonschema.Preparer = VariableItem{}
// PrepareJSONSchema types the `value` property instead of leaving it as an
// untyped {}: a variable resolves to a scalar (string/number/bool) or, for
// multi-select, a list of scalars. The Go field stays `any`; this only documents
// the wire contract in the generated OpenAPI schema.
func (VariableItem) PrepareJSONSchema(s *jsonschema.Schema) error {
if _, ok := s.Properties["value"]; !ok {
return nil
}
item := jsonschema.Schema{}
item.OneOf = []jsonschema.SchemaOrBool{
jsonschema.String.ToSchemaOrBool(),
jsonschema.Number.ToSchemaOrBool(),
jsonschema.Boolean.ToSchemaOrBool(),
}
list := jsonschema.Schema{}
list.WithType(jsonschema.Array.Type())
items := jsonschema.Items{}
items.WithSchemaOrBool(item.ToSchemaOrBool())
list.WithItems(items)
value := jsonschema.Schema{}
value.OneOf = []jsonschema.SchemaOrBool{
jsonschema.String.ToSchemaOrBool(),
jsonschema.Number.ToSchemaOrBool(),
jsonschema.Boolean.ToSchemaOrBool(),
list.ToSchemaOrBool(),
}
s.Properties["value"] = value.ToSchemaOrBool()
return nil
}
type QueryRangeRequest struct {
// SchemaVersion is the version of the schema to use for the request payload.
SchemaVersion string `json:"schemaVersion"`

View File

@@ -116,6 +116,28 @@ type Label struct {
Value any `json:"value"`
}
var _ jsonschema.Preparer = Label{}
// PrepareJSONSchema types the `value` property as a scalar instead of an untyped
// {}: a label value is whatever the grouped-by column holds (string/number/bool).
// The Go field stays `any`; this only documents the wire contract in the
// generated OpenAPI schema.
func (Label) PrepareJSONSchema(s *jsonschema.Schema) error {
if _, ok := s.Properties["value"]; !ok {
return nil
}
value := jsonschema.Schema{}
value.OneOf = []jsonschema.SchemaOrBool{
jsonschema.String.ToSchemaOrBool(),
jsonschema.Number.ToSchemaOrBool(),
jsonschema.Boolean.ToSchemaOrBool(),
}
s.Properties["value"] = value.ToSchemaOrBool()
return nil
}
func GetUniqueSeriesKey(labels []*Label) string {
// Fast path for common cases
if len(labels) == 0 {