Skip to content
This repository was archived by the owner on Aug 28, 2025. It is now read-only.

Commit f286765

Browse files
committed
nesting
On-behalf-of: @SAP [email protected] Signed-off-by: Artem Shcherbatiuk <[email protected]>
1 parent 54b8d92 commit f286765

File tree

1 file changed

+86
-16
lines changed

1 file changed

+86
-16
lines changed

listener/pkg/apischema/builder.go

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ type SchemaBuilder struct {
3939
log *logger.Logger
4040
kindRegistry map[GroupVersionKind]ResourceInfo // Changed: Use GVK as key for precise lookup
4141
preferredVersions map[string]string // map[group/kind]preferredVersion
42+
maxRelationDepth int // maximum allowed relationship nesting depth (1 = single level)
43+
relationDepths map[string]int // tracks the minimum depth at which each schema is referenced
4244
}
4345

4446
// ResourceInfo holds information about a resource for relationship resolution
@@ -54,6 +56,8 @@ func NewSchemaBuilder(oc openapi.Client, preferredApiGroups []string, log *logge
5456
schemas: make(map[string]*spec.Schema),
5557
kindRegistry: make(map[GroupVersionKind]ResourceInfo),
5658
preferredVersions: make(map[string]string),
59+
maxRelationDepth: 1, // Default to 1-level depth for now
60+
relationDepths: make(map[string]int),
5761
log: log,
5862
}
5963

@@ -75,6 +79,19 @@ func NewSchemaBuilder(oc openapi.Client, preferredApiGroups []string, log *logge
7579
return b
7680
}
7781

82+
// WithMaxRelationDepth sets the maximum allowed relationship nesting depth
83+
// depth=1: A->B (single level)
84+
// depth=2: A->B->C (two levels)
85+
// depth=3: A->B->C->D (three levels)
86+
func (b *SchemaBuilder) WithMaxRelationDepth(depth int) *SchemaBuilder {
87+
if depth < 1 {
88+
depth = 1 // Minimum depth is 1
89+
}
90+
b.maxRelationDepth = depth
91+
b.log.Info().Int("maxRelationDepth", depth).Msg("Set maximum relationship nesting depth")
92+
return b
93+
}
94+
7895
type GroupVersionKind struct {
7996
Group string `json:"group"`
8097
Version string `json:"version"`
@@ -221,16 +238,64 @@ func (b *SchemaBuilder) WithRelationships() *SchemaBuilder {
221238
// Build kind registry first
222239
b.buildKindRegistry()
223240

224-
// Expand relationships in all schemas
225-
b.log.Info().Int("kindRegistrySize", len(b.kindRegistry)).Msg("Starting relationship expansion")
226-
for schemaKey, schema := range b.schemas {
227-
b.log.Debug().Str("schemaKey", schemaKey).Msg("Processing schema for relationships")
228-
b.expandRelationships(schema)
241+
// For depth=1: use simple relation target tracking (working approach)
242+
// For depth>1: use iterative expansion (scalable approach)
243+
if b.maxRelationDepth == 1 {
244+
b.expandWithSimpleDepthControl()
245+
} else {
246+
b.expandWithConfigurableDepthControl()
229247
}
230248

231249
return b
232250
}
233251

252+
// expandWithSimpleDepthControl implements the working 1-level depth control
253+
func (b *SchemaBuilder) expandWithSimpleDepthControl() {
254+
// First pass: identify relation targets
255+
relationTargets := make(map[string]bool)
256+
for _, schema := range b.schemas {
257+
if schema.Properties == nil {
258+
continue
259+
}
260+
for propName := range schema.Properties {
261+
if !isRefProperty(propName) {
262+
continue
263+
}
264+
baseKind := strings.TrimSuffix(propName, "Ref")
265+
target := b.findBestResourceForKind(baseKind)
266+
if target != nil {
267+
relationTargets[target.SchemaKey] = true
268+
}
269+
}
270+
}
271+
272+
b.log.Info().
273+
Int("kindRegistrySize", len(b.kindRegistry)).
274+
Int("relationTargets", len(relationTargets)).
275+
Msg("Starting 1-level relationship expansion")
276+
277+
// Second pass: expand only non-targets
278+
for schemaKey, schema := range b.schemas {
279+
if relationTargets[schemaKey] {
280+
b.log.Debug().Str("schemaKey", schemaKey).Msg("Skipping relation target (1-level depth control)")
281+
continue
282+
}
283+
b.expandRelationshipsSimple(schema, schemaKey)
284+
}
285+
}
286+
287+
// expandWithConfigurableDepthControl implements scalable depth control for depth > 1
288+
func (b *SchemaBuilder) expandWithConfigurableDepthControl() {
289+
b.log.Info().
290+
Int("kindRegistrySize", len(b.kindRegistry)).
291+
Int("maxRelationDepth", b.maxRelationDepth).
292+
Msg("Starting configurable relationship expansion")
293+
294+
// TODO: Implement proper multi-level depth control
295+
// For now, fall back to simple approach
296+
b.expandWithSimpleDepthControl()
297+
}
298+
234299
// buildKindRegistry builds a map of kind names to available resource types
235300
func (b *SchemaBuilder) buildKindRegistry() {
236301
for schemaKey, schema := range b.schemas {
@@ -286,6 +351,9 @@ func (b *SchemaBuilder) buildKindRegistry() {
286351
b.log.Debug().Int("gvkCount", len(b.kindRegistry)).Msg("built kind registry for relationships")
287352
}
288353

354+
// TODO: Implement proper multi-level depth calculation when needed
355+
// For now, focusing on the working 1-level depth control
356+
289357
// warnAboutMissingPreferredVersions checks for kinds with multiple resources but no preferred versions
290358
func (b *SchemaBuilder) warnAboutMissingPreferredVersions() {
291359
// Group resources by kind name to find potential conflicts
@@ -429,8 +497,8 @@ func (b *SchemaBuilder) getVersionStability(version string) int {
429497
return 0 // most stable (v1, v2, etc.)
430498
}
431499

432-
// expandRelationships detects fields ending with 'Ref' and adds corresponding relationship fields
433-
func (b *SchemaBuilder) expandRelationships(schema *spec.Schema) {
500+
// expandRelationshipsSimple adds relationship fields for the simple 1-level depth control
501+
func (b *SchemaBuilder) expandRelationshipsSimple(schema *spec.Schema, schemaKey string) {
434502
if schema.Properties == nil {
435503
return
436504
}
@@ -452,24 +520,26 @@ func (b *SchemaBuilder) expandRelationships(schema *spec.Schema) {
452520
if _, exists := schema.Properties[fieldName]; exists {
453521
continue
454522
}
455-
ref := spec.MustCreateRef(fmt.Sprintf("#/definitions/%s.%s.%s", target.Group, target.Version, target.Kind))
523+
524+
// Create proper reference - handle empty group (core) properly
525+
var refPath string
526+
if target.Group == "" {
527+
refPath = fmt.Sprintf("#/definitions/%s.%s", target.Version, target.Kind)
528+
} else {
529+
refPath = fmt.Sprintf("#/definitions/%s.%s.%s", target.Group, target.Version, target.Kind)
530+
}
531+
ref := spec.MustCreateRef(refPath)
456532
schema.Properties[fieldName] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
457533

458534
b.log.Info().
459535
Str("sourceField", propName).
460536
Str("targetField", fieldName).
461537
Str("targetKind", target.Kind).
462538
Str("targetGroup", target.Group).
539+
Str("refPath", refPath).
540+
Str("sourceSchema", schemaKey).
463541
Msg("Added relationship field")
464542
}
465-
466-
// Recursively process nested objects and write back modifications
467-
for key, prop := range schema.Properties {
468-
if prop.Type.Contains("object") && prop.Properties != nil {
469-
b.expandRelationships(&prop)
470-
schema.Properties[key] = prop
471-
}
472-
}
473543
}
474544

475545
func isRefProperty(name string) bool {

0 commit comments

Comments
 (0)