chore(querybuilder): defer builder_join until it has a proper aggregation discriminator

The join aggregation oneOf (trace/log/metric) has no discriminator — trace and
log aggregations are byte-identical, and a join carries no `signal` to dispatch
on (unlike a builder query) — so code generators can't map it. Comment out
JoinAggregation (with a TODO for when full join support lands), revert
QueryBuilderJoin.Aggregations to []any, and drop the builder_join variant from
QueryEnvelope's discriminated union (oneOf + `type` mapping). Runtime decoding of
builder_join is unchanged.
This commit is contained in:
grandwizard28
2026-06-25 22:52:09 +05:30
parent 3719dfde2f
commit ee62289460
3 changed files with 45 additions and 40 deletions

View File

@@ -1,11 +1,8 @@
package querybuildertypesv5
import (
"encoding/json"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/swaggest/jsonschema-go"
)
// JoinType is the SQLstyle join operator.
@@ -52,8 +49,9 @@ type QueryBuilderJoin struct {
On string `json:"on"`
// primary aggregations: if empty ⇒ raw columns. Each item is a trace, log,
// or metric aggregation (see JoinAggregation).
Aggregations []JoinAggregation `json:"aggregations,omitempty"`
// or metric aggregation. Untyped for now — joins are deferred and this oneOf
// has no discriminator (see the commented JoinAggregation below).
Aggregations []any `json:"aggregations,omitempty"`
// select columns to select
SelectFields []telemetrytypes.TelemetryFieldKey `json:"selectFields,omitempty"`
@@ -67,33 +65,37 @@ type QueryBuilderJoin struct {
Functions []Function `json:"functions,omitempty"`
}
// JoinAggregation is one item of QueryBuilderJoin.aggregations: a trace, log, or
// metric aggregation. The runtime value is kept opaque (as the field was when it
// was a []any), but exposing the three shapes as a named oneOf makes the
// generated schema a `oneOf`-of-`$ref` *component* — which code generators can
// flatten — instead of an inline union inside the array items, which they can't.
type JoinAggregation struct {
value any
}
var _ jsonschema.OneOfExposer = JoinAggregation{}
// JSONSchemaOneOf documents the aggregation shapes a join item can take.
func (JoinAggregation) JSONSchemaOneOf() []any {
return []any{
TraceAggregation{},
LogAggregation{},
MetricAggregation{},
}
}
func (j JoinAggregation) MarshalJSON() ([]byte, error) {
return json.Marshal(j.value)
}
func (j *JoinAggregation) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &j.value)
}
// JoinAggregation modelled a join aggregation as a trace/log/metric oneOf. It is
// commented out because that oneOf has no discriminator: trace and log
// aggregations are byte-identical, and a join carries no `signal` to dispatch on
// (unlike a builder query). Without a discriminator, code generators can't map
// it, so the builder_join variant stays deferred (out of
// QueryEnvelope.JSONSchemaOneOf).
//
// TODO: when full support for joins is launched, this needs a proper
// discriminator before it can be re-enabled.
//
// type JoinAggregation struct {
// value any
// }
//
// var _ jsonschema.OneOfExposer = JoinAggregation{}
//
// func (JoinAggregation) JSONSchemaOneOf() []any {
// return []any{
// TraceAggregation{},
// LogAggregation{},
// MetricAggregation{},
// }
// }
//
// func (j JoinAggregation) MarshalJSON() ([]byte, error) {
// return json.Marshal(j.value)
// }
//
// func (j *JoinAggregation) UnmarshalJSON(data []byte) error {
// return json.Unmarshal(data, &j.value)
// }
// Copy creates a deep copy of QueryBuilderJoin.
func (q QueryBuilderJoin) Copy() QueryBuilderJoin {
@@ -104,7 +106,7 @@ func (q QueryBuilderJoin) Copy() QueryBuilderJoin {
c.Right = q.Right.Copy()
if q.Aggregations != nil {
c.Aggregations = make([]JoinAggregation, len(q.Aggregations))
c.Aggregations = make([]any, len(q.Aggregations))
copy(c.Aggregations, q.Aggregations)
}

View File

@@ -92,10 +92,14 @@ type queryEnvelopeFormula struct {
}
// queryEnvelopeJoin is the OpenAPI schema for a QueryEnvelope with type=builder_join.
type queryEnvelopeJoin struct {
Type QueryType `json:"type" required:"true" description:"The type of the query."`
Spec QueryBuilderJoin `json:"spec" description:"The join specification."`
}
// Deferred: joins aren't fully supported yet. Re-add this variant to
// JSONSchemaOneOf and the `type` discriminator mapping when join support lands —
// but only after the join aggregations get a proper discriminator (see the
// commented JoinAggregation in join.go).
// type queryEnvelopeJoin struct {
// Type QueryType `json:"type" required:"true" description:"The type of the query."`
// Spec QueryBuilderJoin `json:"spec" description:"The join specification."`
// }
// queryEnvelopeTraceOperator is the OpenAPI schema for a QueryEnvelope with type=builder_trace_operator.
type queryEnvelopeTraceOperator struct {
@@ -123,7 +127,7 @@ func (QueryEnvelope) JSONSchemaOneOf() []any {
return []any{
queryEnvelopeBuilder{},
queryEnvelopeFormula{},
queryEnvelopeJoin{},
// queryEnvelopeJoin{}, // deferred — see commented queryEnvelopeJoin above
queryEnvelopeTraceOperator{},
queryEnvelopePromQL{},
queryEnvelopeClickHouseSQL{},
@@ -144,7 +148,6 @@ func (QueryEnvelope) PrepareJSONSchema(s *jsonschema.Schema) error {
return markDiscriminator(s, "type", map[string]string{
QueryTypeBuilder.StringValue(): schemaRef("Querybuildertypesv5QueryEnvelopeBuilder"),
QueryTypeFormula.StringValue(): schemaRef("Querybuildertypesv5QueryEnvelopeFormula"),
QueryTypeJoin.StringValue(): schemaRef("Querybuildertypesv5QueryEnvelopeJoin"),
QueryTypeTraceOperator.StringValue(): schemaRef("Querybuildertypesv5QueryEnvelopeTraceOperator"),
QueryTypePromQL.StringValue(): schemaRef("Querybuildertypesv5QueryEnvelopePromQL"),
QueryTypeClickHouseSQL.StringValue(): schemaRef("Querybuildertypesv5QueryEnvelopeClickHouseSQL"),

View File

@@ -677,7 +677,7 @@ func TestQueryRangeRequest_UnmarshalJSON(t *testing.T) {
Right: QueryRef{Name: "B"},
Type: JoinTypeInner,
On: "trace_id = trace_id",
Aggregations: []JoinAggregation{},
Aggregations: []any{},
Limit: 1000,
},
}},