Skip to content

Commit 3c816c0

Browse files
feat(devops): process multi interface struct
1 parent 8f2b4f6 commit 3c816c0

File tree

3 files changed

+40
-103
lines changed

3 files changed

+40
-103
lines changed

devops/internal/apihandler/types/debug.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,6 @@ type ListInputTypesResponse struct {
119119
type InputFormat int
120120

121121
const (
122-
InputFormatOfCode InputFormat = 0
122+
InputFormatOfCode InputFormat = 0 // default
123123
InputFormatOfJson InputFormat = 1
124124
)

devops/internal/model/container.go

Lines changed: 39 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -565,81 +565,6 @@ type FieldInfo struct {
565565
Schema *devmodel.JsonSchema
566566
}
567567

568-
//func ConvertCodeToValue(code string, schema *devmodel.JsonSchema, inputType reflect.Type) (reflect.Value, error) {
569-
// fullCode := `package main
570-
//
571-
// func ToPtr[T any](v T) *T {
572-
// return &v
573-
// }
574-
// ` + code
575-
//
576-
// //node, err := parser.ParseFile(token.NewFileSet(), "", "package main\n"+code, parser.ParseComments)
577-
// node, err := parser.ParseFile(token.NewFileSet(), "", fullCode, parser.ParseComments)
578-
// if err != nil {
579-
// return reflect.Value{}, err
580-
// }
581-
//
582-
// var result interface{}
583-
// ast.Inspect(node, func(n ast.Node) bool {
584-
// vs, ok := n.(*ast.ValueSpec)
585-
// if !ok {
586-
// return true
587-
// }
588-
//
589-
// for _, value := range vs.Values {
590-
// var cl *ast.CompositeLit
591-
// switch v := value.(type) {
592-
// case *ast.UnaryExpr:
593-
// cl, ok = v.X.(*ast.CompositeLit)
594-
// if !ok {
595-
// continue
596-
// }
597-
// result = parseCompositeLit(cl, schema, "")
598-
// case *ast.CompositeLit:
599-
// if schema.Type == devmodel.JsonTypeOfArray {
600-
// result = parseArrayLit(v, schema)
601-
// } else if schema.Type == devmodel.JsonTypeOfObject && schema.AdditionalProperties != nil {
602-
// result = parseMapLit(v, schema)
603-
// } else {
604-
// result = parseCompositeLit(v, schema, "schema.Message")
605-
// }
606-
// case *ast.BasicLit:
607-
// result = parseBasicLit(v)
608-
// case *ast.Ident:
609-
// switch v.Name {
610-
// case "true":
611-
// result = true
612-
// case "false":
613-
// result = false
614-
// case "nil":
615-
// result = nil
616-
// default:
617-
// result = v.Name
618-
// }
619-
// case *ast.CallExpr:
620-
// result = parseCallExpr(v)
621-
// default:
622-
// continue
623-
// }
624-
// }
625-
// return false
626-
// })
627-
//
628-
// val := reflect.New(inputType)
629-
// if schema.Type == "interface" {
630-
// implType, ok := GetRegisteredType("schema.Message")
631-
// if ok {
632-
// val = reflect.New(implType.Type)
633-
// }
634-
// }
635-
//
636-
// if err := convertToValue(result, val.Elem()); err != nil {
637-
// return reflect.Value{}, err
638-
// }
639-
//
640-
// return val.Elem(), nil
641-
//}
642-
643568
func ConvertCodeToValue(code string, schema *devmodel.JsonSchema, inputType reflect.Type) (reflect.Value, error) {
644569
fullCode := `package main
645570
@@ -655,6 +580,7 @@ func ConvertCodeToValue(code string, schema *devmodel.JsonSchema, inputType refl
655580

656581
var result interface{}
657582
var structTypeName string
583+
var ptrNum int
658584
ast.Inspect(node, func(n ast.Node) bool {
659585
vs, ok := n.(*ast.ValueSpec)
660586
if !ok {
@@ -663,7 +589,7 @@ func ConvertCodeToValue(code string, schema *devmodel.JsonSchema, inputType refl
663589

664590
// Try to extract struct type name from value spec
665591
if len(vs.Values) > 0 {
666-
structTypeName = extractStructTypeName(vs.Values[0])
592+
structTypeName, ptrNum = extractStructTypeName(vs.Values[0])
667593
}
668594

669595
for _, value := range vs.Values {
@@ -709,7 +635,12 @@ func ConvertCodeToValue(code string, schema *devmodel.JsonSchema, inputType refl
709635
if schema.Type == "interface" && structTypeName != "" {
710636
implType, ok := GetRegisteredType(structTypeName)
711637
if ok {
712-
val = reflect.New(implType.Type)
638+
// create a type with the correct pointer depth.
639+
valType := implType.Type
640+
for i := 0; i < ptrNum; i++ {
641+
valType = reflect.PointerTo(valType)
642+
}
643+
val = reflect.New(valType)
713644
}
714645
}
715646

@@ -720,38 +651,47 @@ func ConvertCodeToValue(code string, schema *devmodel.JsonSchema, inputType refl
720651
return val.Elem(), nil
721652
}
722653

723-
// extractStructTypeName extracts struct type name from an expression
724-
func extractStructTypeName(expr ast.Expr) string {
654+
// extractStructTypeName extracts struct type name and pointer depth from an expression
655+
// Returns the struct type name and number of pointer levels
656+
func extractStructTypeName(expr ast.Expr) (string, int) {
725657
switch v := expr.(type) {
726658
case *ast.CompositeLit:
727659
// Handle direct struct initialization: schema.Message{...}
728660
switch t := v.Type.(type) {
729661
case *ast.SelectorExpr:
730662
if x, ok := t.X.(*ast.Ident); ok {
731-
return x.Name + "." + t.Sel.Name
663+
return x.Name + "." + t.Sel.Name, 0
732664
}
733665
case *ast.Ident:
734-
return t.Name
666+
return t.Name, 0
735667
}
736668
case *ast.UnaryExpr:
737669
// Handle pointer expressions: &schema.Message{...}
738-
if cl, ok := v.X.(*ast.CompositeLit); ok {
739-
switch t := cl.Type.(type) {
740-
case *ast.SelectorExpr:
741-
if x, ok := t.X.(*ast.Ident); ok {
742-
return x.Name + "." + t.Sel.Name
743-
}
744-
case *ast.Ident:
745-
return t.Name
746-
}
670+
if v.Op == token.AND {
671+
typeName, ptrCount := extractStructTypeName(v.X)
672+
return typeName, ptrCount + 1
747673
}
748674
case *ast.CallExpr:
749-
// Handle ToPtr(schema.Message{...}) calls
750-
if len(v.Args) > 0 {
751-
return extractStructTypeName(v.Args[0])
675+
// Check if this is a ToPtr call
676+
if fun, ok := v.Fun.(*ast.Ident); ok && fun.Name == "ToPtr" && len(v.Args) > 0 {
677+
// Handle ToPtr(schema.Message{...}) calls
678+
typeName, ptrCount := extractStructTypeName(v.Args[0])
679+
return typeName, ptrCount + 1
680+
} else if _, ok := v.Fun.(*ast.SelectorExpr); ok {
681+
// Handle other function calls that might return a struct
682+
return "", 0
683+
} else {
684+
// Handle nested ToPtr calls: ToPtr(ToPtr(...))
685+
typeName, ptrCount := extractStructTypeName(v.Fun)
686+
if typeName != "" && len(v.Args) > 0 {
687+
innerTypeName, innerPtrCount := extractStructTypeName(v.Args[0])
688+
if innerTypeName != "" {
689+
return innerTypeName, ptrCount + innerPtrCount
690+
}
691+
}
752692
}
753693
}
754-
return ""
694+
return "", 0
755695
}
756696

757697
func parseCallExpr(call *ast.CallExpr) interface{} {
@@ -818,9 +758,13 @@ func parseExpr(expr ast.Expr, schema *devmodel.JsonSchema) interface{} {
818758
if schema.AdditionalProperties != nil {
819759
return parseMapLit(v, schema)
820760
}
821-
return parseCompositeLit(v, schema, "")
761+
structName, _ := extractStructTypeName(v)
762+
return parseCompositeLit(v, schema, structName)
822763
case devmodel.JsonTypeOfArray:
823764
return parseArrayLit(v, schema)
765+
case devmodel.JsonTypeOfInterface:
766+
structName, _ := extractStructTypeName(v)
767+
return parseCompositeLit(v, schema, structName)
824768
default:
825769
return nil
826770
}

devops/internal/model/runnable_test.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -775,13 +775,6 @@ func Test_GraphInfo_InferGraphInputType(t *testing.T) {
775775
}`
776776
_, err = UnmarshalJson([]byte(userInput), tc.gi.InputType)
777777
assert.Error(t, err)
778-
//resp, err := r.Invoke(ctx, input)
779-
//assert.Equal(t, resp, map[string]string{
780-
// "A": "hello world",
781-
// "B": "hello world",
782-
// "sub_A": "hello world",
783-
// "sub_B": "hello world",
784-
//})
785778
})
786779

787780
t.Run("graph=any, start nodes=(struct1, struct2, subgraph(graph=any, start nodes=(struct1, struct2), withInputKey), withInputKey)", func(t *testing.T) {

0 commit comments

Comments
 (0)