From eb4827f2b98558f229244aab3b18d916722e81af Mon Sep 17 00:00:00 2001 From: Alec Thomas Date: Sat, 20 Jan 2024 13:09:28 +1100 Subject: [PATCH] feat: Go support for parametric types (#822) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` 🐚 ~/dev/ftl $ ftl schema module time { data TimeRequest { data T } data TimeResponse { time Time } // Time returns the current time. verb time(time.TimeRequest) time.TimeResponse ingress ftl GET /time } ``` After modifying time to have a generic request and echo to use it: ``` 🐚 ~/dev/ftl $ ftl call echo.echo {"message":"Hello, anonymous!!! It is 2024-01-20 12:38:24.254176 +1100 AEDT!"} ``` --- backend/controller/ingress/ingress.go | 10 +- backend/schema/data.go | 103 ++++- backend/schema/data_test.go | 26 ++ backend/schema/dataref.go | 23 +- backend/schema/module.go | 5 + backend/schema/parser.go | 2 +- backend/schema/protobuf_dec.go | 4 +- backend/schema/protobuf_enc.go | 2 +- backend/schema/typeparameter.go | 19 +- backend/schema/validate.go | 12 +- .../xyz/block/ftl/v1/schema/schema_pb.ts | 66 ++- go-runtime/compile/build.go | 18 +- .../external_module.go | 7 +- go-runtime/compile/schema.go | 74 ++-- go-runtime/compile/schema_test.go | 36 +- go-runtime/compile/testdata/two/two.go | 20 +- protos/xyz/block/ftl/v1/schema/schema.pb.go | 378 ++++++++++++------ protos/xyz/block/ftl/v1/schema/schema.proto | 11 +- 18 files changed, 610 insertions(+), 206 deletions(-) create mode 100644 backend/schema/data_test.go diff --git a/backend/controller/ingress/ingress.go b/backend/controller/ingress/ingress.go index 776ea6dd69..807e5d288c 100644 --- a/backend/controller/ingress/ingress.go +++ b/backend/controller/ingress/ingress.go @@ -184,6 +184,14 @@ func validateRequestMap(dataRef *schema.DataRef, path path, request map[string]a return fmt.Errorf("unknown data %v", dataRef) } + if len(dataRef.TypeParameters) > 0 { + var err error + data, err = data.Monomorphise(dataRef.TypeParameters...) + if err != nil { + return err + } + } + var errs []error for _, field := range data.Fields { fieldPath := append(path, "."+field.Name) //nolint:gocritic @@ -324,7 +332,7 @@ func validateValue(fieldType schema.Type, path path, value any, sch *schema.Sche } case *schema.TypeParameter: - panic("unreachable") + panic("data structures with type parameters should be monomorphised") } if !typeMatches { diff --git a/backend/schema/data.go b/backend/schema/data.go index d29a70efe2..c2cde26843 100644 --- a/backend/schema/data.go +++ b/backend/schema/data.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "golang.design/x/reflect" "google.golang.org/protobuf/proto" schemapb "github.com/TBD54566975/ftl/protos/xyz/block/ftl/v1/schema" @@ -31,6 +32,79 @@ func (d *Data) Scope() Scope { return scope } +// Monomorphise this data type with the given type arguments. +// +// Will return nil if it is not a parametric type. +// +// This will return a new Data structure with all type parameters replaced with +// the given types. +func (d *Data) Monomorphise(types ...Type) (*Data, error) { + if len(d.TypeParameters) != len(types) { + return nil, fmt.Errorf("expected %d type arguments, got %d", len(d.TypeParameters), len(types)) + } + if len(d.TypeParameters) == 0 { + return nil, nil + } + names := map[string]Type{} + for i, t := range d.TypeParameters { + names[t.Name] = types[i] + } + monomorphised := reflect.DeepCopy(d) + monomorphised.TypeParameters = nil + + // Because we don't have parent links in the AST allowing us to visit on + // Type and replace it on the parent, we have to do a full traversal to find + // the parents of all the Type nodes we need to replace. This will be a bit + // tricky to maintain, but it's basically any type that has parametric + // types: maps, slices, fields, etc. + err := Visit(monomorphised, func(n Node, next func() error) error { + switch n := n.(type) { + case *Map: + k, err := maybeMonomorphiseType(n.Key, names) + if err != nil { + return fmt.Errorf("%s: map key: %w", n.Key.Position(), err) + } + v, err := maybeMonomorphiseType(n.Value, names) + if err != nil { + return fmt.Errorf("%s: map value: %w", n.Value.Position(), err) + } + n.Key = k + n.Value = v + + case *Array: + t, err := maybeMonomorphiseType(n.Element, names) + if err != nil { + return fmt.Errorf("%s: array element: %w", n.Element.Position(), err) + } + n.Element = t + + case *Field: + t, err := maybeMonomorphiseType(n.Type, names) + if err != nil { + return fmt.Errorf("%s: field type: %w", n.Type.Position(), err) + } + n.Type = t + + case *Optional: + t, err := maybeMonomorphiseType(n.Type, names) + if err != nil { + return fmt.Errorf("%s: optional type: %w", n.Type.Position(), err) + } + n.Type = t + + case *Any, *Bool, *Bytes, *Data, *DataRef, *Database, Decl, *Float, + IngressPathComponent, *IngressPathLiteral, *IngressPathParameter, *Int, + Metadata, *MetadataCalls, *MetadataDatabases, *MetadataIngress, *Module, + *Schema, *String, *Time, Type, *TypeParameter, *Unit, *Verb: + } + return next() + }) + if err != nil { + return nil, fmt.Errorf("%s: failed to monomorphise: %w", d.Pos, err) + } + return monomorphised, nil +} + func (d *Data) Position() Position { return d.Pos } func (*Data) schemaDecl() {} func (d *Data) schemaChildren() []Node { @@ -72,18 +146,31 @@ func (d *Data) String() string { func (d *Data) ToProto() proto.Message { return &schemapb.Data{ - Pos: posToProto(d.Pos), - Name: d.Name, - Fields: nodeListToProto[*schemapb.Field](d.Fields), - Comments: d.Comments, + Pos: posToProto(d.Pos), + TypeParameters: nodeListToProto[*schemapb.TypeParameter](d.TypeParameters), + Name: d.Name, + Fields: nodeListToProto[*schemapb.Field](d.Fields), + Comments: d.Comments, } } func DataToSchema(s *schemapb.Data) *Data { return &Data{ - Pos: posFromProto(s.Pos), - Name: s.Name, - Fields: fieldListToSchema(s.Fields), - Comments: s.Comments, + Pos: posFromProto(s.Pos), + Name: s.Name, + TypeParameters: typeParametersToSchema(s.TypeParameters), + Fields: fieldListToSchema(s.Fields), + Comments: s.Comments, + } +} + +// MonoType returns the monomorphised type of this data type if applicable, or returns the original type. +func maybeMonomorphiseType(t Type, typeParameters map[string]Type) (Type, error) { + if t, ok := t.(*TypeParameter); ok { + if tp, ok := typeParameters[t.Name]; ok { + return tp, nil + } + return nil, fmt.Errorf("%s: unknown type parameter %q", t.Position(), t.Name) } + return t, nil } diff --git a/backend/schema/data_test.go b/backend/schema/data_test.go new file mode 100644 index 0000000000..a5c270ccb5 --- /dev/null +++ b/backend/schema/data_test.go @@ -0,0 +1,26 @@ +package schema + +import ( + "testing" + + "github.com/alecthomas/assert/v2" +) + +func TestMonomorphisation(t *testing.T) { + data := &Data{ + Name: "Data", + TypeParameters: []*TypeParameter{{Name: "T"}}, + Fields: []*Field{ + {Name: "a", Type: &TypeParameter{Name: "T"}}, + }, + } + actual, err := data.Monomorphise(&String{}) + assert.NoError(t, err) + expected := &Data{ + Comments: []string{}, + Name: "Data", + Fields: []*Field{{Comments: []string{}, Name: "a", Type: &String{}}}, + Metadata: []Metadata{}, + } + assert.Equal(t, expected, actual, assert.OmitEmpty()) +} diff --git a/backend/schema/dataref.go b/backend/schema/dataref.go index ffe8ffa7d1..fdef34431d 100644 --- a/backend/schema/dataref.go +++ b/backend/schema/dataref.go @@ -3,6 +3,7 @@ package schema import ( "google.golang.org/protobuf/reflect/protoreflect" + "github.com/TBD54566975/ftl/backend/common/slices" schemapb "github.com/TBD54566975/ftl/protos/xyz/block/ftl/v1/schema" ) @@ -43,7 +44,12 @@ func (d *DataRef) String() string { } func (d *DataRef) ToProto() protoreflect.ProtoMessage { - return &schemapb.DataRef{Pos: posToProto(d.Pos), Module: d.Module, Name: d.Name} + return &schemapb.DataRef{ + Pos: posToProto(d.Pos), + Module: d.Module, + Name: d.Name, + TypeParameters: slices.Map(d.TypeParameters, typeToProto), + } } func (*DataRef) schemaChildren() []Node { return nil } @@ -55,16 +61,9 @@ func ParseDataRef(ref string) (*DataRef, error) { func DataRefFromProto(s *schemapb.DataRef) *DataRef { return &DataRef{ - Pos: posFromProto(s.Pos), - Name: s.Name, - Module: s.Module, - } -} - -func dataRefToSchema(s *schemapb.DataRef) *DataRef { - return &DataRef{ - Pos: posFromProto(s.Pos), - Name: s.Name, - Module: s.Module, + Pos: posFromProto(s.Pos), + Name: s.Name, + Module: s.Module, + TypeParameters: slices.Map(s.TypeParameters, typeToSchema), } } diff --git a/backend/schema/module.go b/backend/schema/module.go index 76092b0dc3..09aee4e6b8 100644 --- a/backend/schema/module.go +++ b/backend/schema/module.go @@ -23,6 +23,7 @@ type Module struct { var _ Node = (*Module)(nil) var _ Decl = (*Module)(nil) +// Scope returns a scope containing all the declarations in this module. func (m *Module) Scope() Scope { scope := Scope{} for _, d := range m.Decls { @@ -40,7 +41,11 @@ func (m *Module) Scope() Scope { return scope } +// Resolve returns the declaration in this module with the given name, or nil func (m *Module) Resolve(ref Ref) *ModuleDecl { + if ref.Module != "" && ref.Module != m.Name { + return nil + } for _, d := range m.Decls { switch d := d.(type) { case *Data: diff --git a/backend/schema/parser.go b/backend/schema/parser.go index 30880774f5..7d2ca09f23 100644 --- a/backend/schema/parser.go +++ b/backend/schema/parser.go @@ -15,7 +15,7 @@ var ( declUnion = []Decl{&Data{}, &Verb{}, &Database{}} nonOptionalTypeUnion = []Type{ &Int{}, &Float{}, &String{}, &Bytes{}, &Bool{}, &Time{}, &Array{}, - &Map{}, &DataRef{}, &Unit{}, &Any{}, + &Map{}, &DataRef{}, &Unit{}, &Any{}, &TypeParameter{}, } typeUnion = append(nonOptionalTypeUnion, &Optional{}) metadataUnion = []Metadata{&MetadataCalls{}, &MetadataIngress{}, &MetadataDatabases{}} diff --git a/backend/schema/protobuf_dec.go b/backend/schema/protobuf_dec.go index 6bf62368d7..f022b4f180 100644 --- a/backend/schema/protobuf_dec.go +++ b/backend/schema/protobuf_dec.go @@ -37,7 +37,7 @@ func typeToSchema(s *schemapb.Type) Type { // case *schemapb.Type_VerbRef: // return verbRefToSchema(s.VerbRef) case *schemapb.Type_DataRef: - return dataRefToSchema(s.DataRef) + return DataRefFromProto(s.DataRef) case *schemapb.Type_Int: return &Int{Pos: posFromProto(s.Int.Pos)} case *schemapb.Type_Float: @@ -60,6 +60,8 @@ func typeToSchema(s *schemapb.Type) Type { return &Unit{Pos: posFromProto(s.Unit.Pos)} case *schemapb.Type_Any: return &Any{Pos: posFromProto(s.Any.Pos)} + case *schemapb.Type_Parameter: + return &TypeParameter{Pos: posFromProto(s.Parameter.Pos), Name: s.Parameter.Name} } panic(fmt.Sprintf("unhandled type: %T", s.Value)) } diff --git a/backend/schema/protobuf_enc.go b/backend/schema/protobuf_enc.go index a81f898a66..817930658f 100644 --- a/backend/schema/protobuf_enc.go +++ b/backend/schema/protobuf_enc.go @@ -123,7 +123,7 @@ func typeToProto(t Type) *schemapb.Type { return &schemapb.Type{Value: &schemapb.Type_Optional{Optional: t.ToProto().(*schemapb.Optional)}} case *TypeParameter: - panic("unreachable") + return &schemapb.Type{Value: &schemapb.Type_Parameter{Parameter: t.ToProto().(*schemapb.TypeParameter)}} } panic(fmt.Sprintf("unhandled type: %T", t)) } diff --git a/backend/schema/typeparameter.go b/backend/schema/typeparameter.go index 697653f315..4c6a337981 100644 --- a/backend/schema/typeparameter.go +++ b/backend/schema/typeparameter.go @@ -1,6 +1,10 @@ package schema -import "google.golang.org/protobuf/reflect/protoreflect" +import ( + "google.golang.org/protobuf/reflect/protoreflect" + + schemapb "github.com/TBD54566975/ftl/protos/xyz/block/ftl/v1/schema" +) type TypeParameter struct { Pos Position `parser:"" protobuf:"1,optional"` @@ -15,7 +19,18 @@ func (*TypeParameter) schemaType() {} func (t *TypeParameter) Position() Position { return t.Pos } func (t *TypeParameter) String() string { return t.Name } func (t *TypeParameter) ToProto() protoreflect.ProtoMessage { - panic("unimplemented") + return &schemapb.TypeParameter{Pos: posToProto(t.Pos), Name: t.Name} } func (t *TypeParameter) schemaChildren() []Node { return nil } func (t *TypeParameter) schemaDecl() {} + +func typeParametersToSchema(s []*schemapb.TypeParameter) []*TypeParameter { + var out []*TypeParameter + for _, n := range s { + out = append(out, &TypeParameter{ + Pos: posFromProto(n.Pos), + Name: n.Name, + }) + } + return out +} diff --git a/backend/schema/validate.go b/backend/schema/validate.go index d478a9be92..12e5de5c43 100644 --- a/backend/schema/validate.go +++ b/backend/schema/validate.go @@ -105,11 +105,15 @@ func Validate(schema *Schema) (*Schema, error) { case *DataRef: if mdecl := scopes.Resolve(n.Untyped()); mdecl != nil { - switch mdecl.Decl.(type) { + switch decl := mdecl.Decl.(type) { case *Data: if mdecl.Module != nil { n.Module = mdecl.Module.Name } + if len(n.TypeParameters) != len(decl.TypeParameters) { + merr = append(merr, fmt.Errorf("%s: reference to data structure %s has %d type parameters, but %d were expected", + n.Pos, n.Name, len(n.TypeParameters), len(decl.TypeParameters))) + } case *TypeParameter: @@ -196,11 +200,15 @@ func ValidateModule(module *Module) error { case *DataRef: if mdecl := scopes.Resolve(n.Untyped()); mdecl != nil { - switch mdecl.Decl.(type) { + switch decl := mdecl.Decl.(type) { case *Data: if n.Module == "" { n.Module = mdecl.Module.Name } + if len(n.TypeParameters) != len(decl.TypeParameters) { + merr = append(merr, fmt.Errorf("%s: reference to data structure %s has %d type parameters, but %d were expected", + n.Pos, n.Name, len(n.TypeParameters), len(decl.TypeParameters))) + } case *TypeParameter: diff --git a/frontend/src/protos/xyz/block/ftl/v1/schema/schema_pb.ts b/frontend/src/protos/xyz/block/ftl/v1/schema/schema_pb.ts index ffefb35e81..73ba6f9929 100644 --- a/frontend/src/protos/xyz/block/ftl/v1/schema/schema_pb.ts +++ b/frontend/src/protos/xyz/block/ftl/v1/schema/schema_pb.ts @@ -340,9 +340,9 @@ export class Data extends Message { metadata: Metadata[] = []; /** - * @generated from field: repeated string typeParameters = 6; + * @generated from field: repeated xyz.block.ftl.v1.schema.TypeParameter typeParameters = 6; */ - typeParameters: string[] = []; + typeParameters: TypeParameter[] = []; constructor(data?: PartialMessage) { super(); @@ -357,7 +357,7 @@ export class Data extends Message { { no: 3, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 4, name: "fields", kind: "message", T: Field, repeated: true }, { no: 5, name: "metadata", kind: "message", T: Metadata, repeated: true }, - { no: 6, name: "typeParameters", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + { no: 6, name: "typeParameters", kind: "message", T: TypeParameter, repeated: true }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): Data { @@ -396,6 +396,11 @@ export class DataRef extends Message { */ module = ""; + /** + * @generated from field: repeated xyz.block.ftl.v1.schema.Type typeParameters = 4; + */ + typeParameters: Type[] = []; + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); @@ -407,6 +412,7 @@ export class DataRef extends Message { { no: 1, name: "pos", kind: "message", T: Position, opt: true }, { no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "module", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "typeParameters", kind: "message", T: Type, repeated: true }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): DataRef { @@ -1395,7 +1401,13 @@ export class Type extends Message { case: "any"; } | { /** - * @generated from field: xyz.block.ftl.v1.schema.Optional optional = 12; + * @generated from field: xyz.block.ftl.v1.schema.TypeParameter parameter = 12; + */ + value: TypeParameter; + case: "parameter"; + } | { + /** + * @generated from field: xyz.block.ftl.v1.schema.Optional optional = 13; */ value: Optional; case: "optional"; @@ -1420,7 +1432,8 @@ export class Type extends Message { { no: 9, name: "dataRef", kind: "message", T: DataRef, oneof: "value" }, { no: 10, name: "unit", kind: "message", T: Unit, oneof: "value" }, { no: 11, name: "any", kind: "message", T: Any, oneof: "value" }, - { no: 12, name: "optional", kind: "message", T: Optional, oneof: "value" }, + { no: 12, name: "parameter", kind: "message", T: TypeParameter, oneof: "value" }, + { no: 13, name: "optional", kind: "message", T: Optional, oneof: "value" }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): Type { @@ -1440,6 +1453,49 @@ export class Type extends Message { } } +/** + * @generated from message xyz.block.ftl.v1.schema.TypeParameter + */ +export class TypeParameter extends Message { + /** + * @generated from field: optional xyz.block.ftl.v1.schema.Position pos = 1; + */ + pos?: Position; + + /** + * @generated from field: string name = 2; + */ + name = ""; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "xyz.block.ftl.v1.schema.TypeParameter"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "pos", kind: "message", T: Position, opt: true }, + { no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): TypeParameter { + return new TypeParameter().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): TypeParameter { + return new TypeParameter().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): TypeParameter { + return new TypeParameter().fromJsonString(jsonString, options); + } + + static equals(a: TypeParameter | PlainMessage | undefined, b: TypeParameter | PlainMessage | undefined): boolean { + return proto3.util.equals(TypeParameter, a, b); + } +} + /** * @generated from message xyz.block.ftl.v1.schema.Unit */ diff --git a/go-runtime/compile/build.go b/go-runtime/compile/build.go index 754d09135e..d19fbc9b82 100644 --- a/go-runtime/compile/build.go +++ b/go-runtime/compile/build.go @@ -131,7 +131,6 @@ var scaffoldFuncs = scaffolder.FuncMap{ } return "// " + strings.Join(s, "\n// ") }, - // Overridden in ExternalModule(). "type": genType, "is": func(kind string, t schema.Node) bool { return reflect.Indirect(reflect.ValueOf(t)).Type().Name() == kind @@ -163,10 +162,23 @@ var scaffoldFuncs = scaffolder.FuncMap{ func genType(module *schema.Module, t schema.Type) string { switch t := t.(type) { case *schema.DataRef: + desc := "" if module != nil && t.Module == module.Name { - return t.Name + desc = t.Name + } else { + desc = "ftl" + t.Module + "." + t.Name } - return "ftl" + t.String() + if len(t.TypeParameters) > 0 { + desc += "[" + for i, tp := range t.TypeParameters { + if i != 0 { + desc += ", " + } + desc += genType(module, tp) + } + desc += "]" + } + return desc case *schema.VerbRef: if module != nil && t.Module == module.Name { diff --git a/go-runtime/compile/external-module-template/_ftl/go/modules/{{ range .NonMainModules }}{{ push .Name . }}{{ end }}/external_module.go b/go-runtime/compile/external-module-template/_ftl/go/modules/{{ range .NonMainModules }}{{ push .Name . }}{{ end }}/external_module.go index f829487cdc..73d017c79a 100644 --- a/go-runtime/compile/external-module-template/_ftl/go/modules/{{ range .NonMainModules }}{{ push .Name . }}{{ end }}/external_module.go +++ b/go-runtime/compile/external-module-template/_ftl/go/modules/{{ range .NonMainModules }}{{ push .Name . }}{{ end }}/external_module.go @@ -14,7 +14,12 @@ var _ = context.Background {{- range .Decls }} {{if is "Data" . }} -type {{.Name|title}} struct { +type {{.Name|title}} +{{- if .TypeParameters}}[ +{{- range $i, $tp := .TypeParameters}} +{{- if $i}}, {{end}}{{$tp}} any +{{- end -}} +]{{- end}} struct { {{- range .Fields}} {{.Name|title}} {{type $ .Type}} `json:"{{.Name}}"` {{- end}} diff --git a/go-runtime/compile/schema.go b/go-runtime/compile/schema.go index 630a843b2e..a596b5bf0f 100644 --- a/go-runtime/compile/schema.go +++ b/go-runtime/compile/schema.go @@ -134,7 +134,7 @@ func visitFile(pctx *parseContext, node *ast.File) error { if err != nil { return err } - pctx.module.Comments = parseComments(node.Doc) + pctx.module.Comments = visitComments(node.Doc) for _, dir := range directives { switch dir := dir.(type) { case *directiveModule: @@ -249,7 +249,7 @@ func visitFuncDecl(pctx *parseContext, node *ast.FuncDecl) (verb *schema.Verb, e } var req schema.Type if reqt != nil { - req, err = parseType(pctx, node, params.At(1).Type()) + req, err = visitType(pctx, node, params.At(1).Type()) if err != nil { return nil, err } @@ -258,7 +258,7 @@ func visitFuncDecl(pctx *parseContext, node *ast.FuncDecl) (verb *schema.Verb, e } var resp schema.Type if respt != nil { - resp, err = parseType(pctx, node, results.At(0).Type()) + resp, err = visitType(pctx, node, results.At(0).Type()) if err != nil { return nil, err } @@ -267,7 +267,7 @@ func visitFuncDecl(pctx *parseContext, node *ast.FuncDecl) (verb *schema.Verb, e } verb = &schema.Verb{ Pos: goPosToSchemaPos(node.Pos()), - Comments: parseComments(node.Doc), + Comments: visitComments(node.Doc), Name: strcase.ToLowerCamel(node.Name.Name), Request: req, Response: resp, @@ -292,7 +292,7 @@ func parsePathComponents(path string, pos schema.Position) []schema.IngressPathC return out } -func parseComments(doc *ast.CommentGroup) []string { +func visitComments(doc *ast.CommentGroup) []string { comments := []string{} if doc := doc.Text(); doc != "" { comments = strings.Split(strings.TrimSpace(doc), "\n") @@ -300,7 +300,7 @@ func parseComments(doc *ast.CommentGroup) []string { return comments } -func parseStruct(pctx *parseContext, node ast.Node, tnode types.Type) (*schema.DataRef, error) { +func visitStruct(pctx *parseContext, node ast.Node, tnode types.Type) (*schema.DataRef, error) { named, ok := tnode.(*types.Named) if !ok { return nil, fmt.Errorf("expected named type but got %s", tnode) @@ -319,6 +319,28 @@ func parseStruct(pctx *parseContext, node ast.Node, tnode types.Type) (*schema.D Pos: goPosToSchemaPos(node.Pos()), Name: named.Obj().Name(), } + dataRef := &schema.DataRef{ + Pos: goPosToSchemaPos(node.Pos()), + Name: out.Name, + } + for i := 0; i < named.TypeParams().Len(); i++ { + param := named.TypeParams().At(i) + out.TypeParameters = append(out.TypeParameters, &schema.TypeParameter{ + Pos: goPosToSchemaPos(node.Pos()), + Name: param.Obj().Name(), + }) + typeArg, err := visitType(pctx, node, named.TypeArgs().At(i)) + if err != nil { + return nil, fmt.Errorf("type parameter %s: %w", param.Obj().Name(), err) + } + dataRef.TypeParameters = append(dataRef.TypeParameters, typeArg) + } + + // If the struct is generic, we need to use the origin type to get the + // fields. + if named.TypeParams().Len() > 0 { + named = named.Origin() + } // Find type declaration so we can extract comments. pos := named.Obj().Pos() @@ -331,23 +353,23 @@ func parseStruct(pctx *parseContext, node ast.Node, tnode types.Type) (*schema.D switch path := path[i].(type) { case *ast.TypeSpec: if path.Doc != nil { - out.Comments = parseComments(path.Doc) + out.Comments = visitComments(path.Doc) } case *ast.GenDecl: if path.Doc != nil { - out.Comments = parseComments(path.Doc) + out.Comments = visitComments(path.Doc) } } } } - s, ok := tnode.Underlying().(*types.Struct) + s, ok := named.Underlying().(*types.Struct) if !ok { - return nil, fmt.Errorf("expected struct but got %s", tnode) + return nil, fmt.Errorf("expected struct but got %s", named) } for i := 0; i < s.NumFields(); i++ { f := s.Field(i) - ft, err := parseType(pctx, node, f.Type()) + ft, err := visitType(pctx, node, f.Type()) if err != nil { return nil, fmt.Errorf("field %s: %w", f.Name(), err) } @@ -358,13 +380,13 @@ func parseStruct(pctx *parseContext, node ast.Node, tnode types.Type) (*schema.D }) } pctx.module.AddData(out) - return &schema.DataRef{ - Pos: goPosToSchemaPos(node.Pos()), - Name: out.Name, - }, nil + return dataRef, nil } -func parseType(pctx *parseContext, node ast.Node, tnode types.Type) (schema.Type, error) { +func visitType(pctx *parseContext, node ast.Node, tnode types.Type) (schema.Type, error) { + if tparam, ok := tnode.(*types.TypeParam); ok { + return &schema.TypeParameter{Name: tparam.Obj().Id()}, nil + } switch underlying := tnode.Underlying().(type) { case *types.Basic: switch underlying.Kind() { @@ -387,7 +409,7 @@ func parseType(pctx *parseContext, node ast.Node, tnode types.Type) (schema.Type case *types.Struct: named, ok := tnode.(*types.Named) if !ok { - return parseStruct(pctx, node, tnode) + return visitStruct(pctx, node, tnode) } // Special-cased types. @@ -399,21 +421,21 @@ func parseType(pctx *parseContext, node ast.Node, tnode types.Type) (schema.Type return &schema.Unit{Pos: goPosToSchemaPos(node.Pos())}, nil case "github.com/TBD54566975/ftl/go-runtime/sdk.Option": - underlying, err := parseType(pctx, node, named.TypeArgs().At(0)) + underlying, err := visitType(pctx, node, named.TypeArgs().At(0)) if err != nil { return nil, err } return &schema.Optional{Type: underlying}, nil default: - return parseStruct(pctx, node, tnode) + return visitStruct(pctx, node, tnode) } case *types.Map: - return parseMap(pctx, node, underlying) + return visitMap(pctx, node, underlying) case *types.Slice: - return parseSlice(pctx, node, underlying) + return visitSlice(pctx, node, underlying) case *types.Interface: if underlying.String() == "any" { @@ -426,12 +448,12 @@ func parseType(pctx *parseContext, node ast.Node, tnode types.Type) (schema.Type } } -func parseMap(pctx *parseContext, node ast.Node, tnode *types.Map) (*schema.Map, error) { - key, err := parseType(pctx, node, tnode.Key()) +func visitMap(pctx *parseContext, node ast.Node, tnode *types.Map) (*schema.Map, error) { + key, err := visitType(pctx, node, tnode.Key()) if err != nil { return nil, err } - value, err := parseType(pctx, node, tnode.Elem()) + value, err := visitType(pctx, node, tnode.Elem()) if err != nil { return nil, err } @@ -442,12 +464,12 @@ func parseMap(pctx *parseContext, node ast.Node, tnode *types.Map) (*schema.Map, }, nil } -func parseSlice(pctx *parseContext, node ast.Node, tnode *types.Slice) (schema.Type, error) { +func visitSlice(pctx *parseContext, node ast.Node, tnode *types.Slice) (schema.Type, error) { // If it's a []byte, treat it as a Bytes type. if basic, ok := tnode.Elem().Underlying().(*types.Basic); ok && basic.Kind() == types.Byte { return &schema.Bytes{Pos: goPosToSchemaPos(node.Pos())}, nil } - value, err := parseType(pctx, node, tnode.Elem()) + value, err := visitType(pctx, node, tnode.Elem()) if err != nil { return nil, err } diff --git a/go-runtime/compile/schema_test.go b/go-runtime/compile/schema_test.go index 621bf1dfc8..ab7397e533 100644 --- a/go-runtime/compile/schema_test.go +++ b/go-runtime/compile/schema_test.go @@ -1,13 +1,17 @@ package compile import ( - "github.com/alecthomas/participle/v2/lexer" + "fmt" "go/ast" "go/types" + "strings" "testing" - "github.com/TBD54566975/ftl/backend/schema" "github.com/alecthomas/assert/v2" + "github.com/alecthomas/participle/v2/lexer" + + "github.com/TBD54566975/ftl/backend/common/slices" + "github.com/TBD54566975/ftl/backend/schema" ) func TestExtractModuleSchema(t *testing.T) { @@ -41,6 +45,26 @@ func TestExtractModuleSchema(t *testing.T) { assert.Equal(t, expected, actual.String()) } +func TestExtractModuleSchemaTwo(t *testing.T) { + actual, err := ExtractModuleSchema("testdata/two") + fmt.Println(actual) + assert.NoError(t, err) + actual = schema.Normalise(actual) + expected := `module two { + data Payload { + body T + } + + verb two(two.Payload) two.Payload + + verb callsTwo(two.Payload) two.Payload + calls two.two + +} +` + assert.Equal(t, normaliseString(expected), normaliseString(actual.String())) +} + func TestParseDirectives(t *testing.T) { tests := []struct { name string @@ -88,7 +112,7 @@ func TestParseDirectives(t *testing.T) { func TestParseTypesTime(t *testing.T) { timeRef := mustLoadRef("time", "Time").Type() - parsed, err := parseType(nil, &ast.Ident{}, timeRef) + parsed, err := visitType(nil, &ast.Ident{}, timeRef) assert.NoError(t, err) _, ok := parsed.(*schema.Time) assert.True(t, ok) @@ -107,9 +131,13 @@ func TestParseBasicTypes(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - parsed, err := parseType(nil, &ast.Ident{}, tt.input) + parsed, err := visitType(nil, &ast.Ident{}, tt.input) assert.NoError(t, err) assert.Equal(t, tt.expected, parsed) }) } } + +func normaliseString(s string) string { + return strings.TrimSpace(strings.Join(slices.Map(strings.Split(s, "\n"), strings.TrimSpace), "\n")) +} diff --git a/go-runtime/compile/testdata/two/two.go b/go-runtime/compile/testdata/two/two.go index bb3b8efc7f..780f903233 100644 --- a/go-runtime/compile/testdata/two/two.go +++ b/go-runtime/compile/testdata/two/two.go @@ -1,16 +1,26 @@ //ftl:module two package two -import "context" +import ( + "context" + + "github.com/TBD54566975/ftl/go-runtime/sdk" +) type User struct { Name string } -type Request struct{} +type Payload[T any] struct { + Body T +} -type Response struct{} +//ftl:verb +func Two(ctx context.Context, req Payload[string]) (Payload[string], error) { + return Payload[string]{}, nil +} -func Two(ctx context.Context, req Request) (Response, error) { - return Response{}, nil +//ftl:verb +func CallsTwo(ctx context.Context, req Payload[string]) (Payload[string], error) { + return sdk.Call(ctx, Two, req) } diff --git a/protos/xyz/block/ftl/v1/schema/schema.pb.go b/protos/xyz/block/ftl/v1/schema/schema.pb.go index 27511d9883..bcba6a1b50 100644 --- a/protos/xyz/block/ftl/v1/schema/schema.pb.go +++ b/protos/xyz/block/ftl/v1/schema/schema.pb.go @@ -412,12 +412,12 @@ type Data struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Pos *Position `protobuf:"bytes,1,opt,name=pos,proto3,oneof" json:"pos,omitempty"` - Comments []string `protobuf:"bytes,2,rep,name=comments,proto3" json:"comments,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Fields []*Field `protobuf:"bytes,4,rep,name=fields,proto3" json:"fields,omitempty"` - Metadata []*Metadata `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty"` - TypeParameters []string `protobuf:"bytes,6,rep,name=typeParameters,proto3" json:"typeParameters,omitempty"` + Pos *Position `protobuf:"bytes,1,opt,name=pos,proto3,oneof" json:"pos,omitempty"` + Comments []string `protobuf:"bytes,2,rep,name=comments,proto3" json:"comments,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Fields []*Field `protobuf:"bytes,4,rep,name=fields,proto3" json:"fields,omitempty"` + Metadata []*Metadata `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty"` + TypeParameters []*TypeParameter `protobuf:"bytes,6,rep,name=typeParameters,proto3" json:"typeParameters,omitempty"` } func (x *Data) Reset() { @@ -487,7 +487,7 @@ func (x *Data) GetMetadata() []*Metadata { return nil } -func (x *Data) GetTypeParameters() []string { +func (x *Data) GetTypeParameters() []*TypeParameter { if x != nil { return x.TypeParameters } @@ -499,9 +499,10 @@ type DataRef struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Pos *Position `protobuf:"bytes,1,opt,name=pos,proto3,oneof" json:"pos,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Module string `protobuf:"bytes,3,opt,name=module,proto3" json:"module,omitempty"` + Pos *Position `protobuf:"bytes,1,opt,name=pos,proto3,oneof" json:"pos,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Module string `protobuf:"bytes,3,opt,name=module,proto3" json:"module,omitempty"` + TypeParameters []*Type `protobuf:"bytes,4,rep,name=typeParameters,proto3" json:"typeParameters,omitempty"` } func (x *DataRef) Reset() { @@ -557,6 +558,13 @@ func (x *DataRef) GetModule() string { return "" } +func (x *DataRef) GetTypeParameters() []*Type { + if x != nil { + return x.TypeParameters + } + return nil +} + type Database struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1782,6 +1790,7 @@ type Type struct { // *Type_DataRef // *Type_Unit // *Type_Any + // *Type_Parameter // *Type_Optional Value isType_Value `protobuf_oneof:"value"` } @@ -1902,6 +1911,13 @@ func (x *Type) GetAny() *Any { return nil } +func (x *Type) GetParameter() *TypeParameter { + if x, ok := x.GetValue().(*Type_Parameter); ok { + return x.Parameter + } + return nil +} + func (x *Type) GetOptional() *Optional { if x, ok := x.GetValue().(*Type_Optional); ok { return x.Optional @@ -1957,8 +1973,12 @@ type Type_Any struct { Any *Any `protobuf:"bytes,11,opt,name=any,proto3,oneof"` } +type Type_Parameter struct { + Parameter *TypeParameter `protobuf:"bytes,12,opt,name=parameter,proto3,oneof"` +} + type Type_Optional struct { - Optional *Optional `protobuf:"bytes,12,opt,name=optional,proto3,oneof"` + Optional *Optional `protobuf:"bytes,13,opt,name=optional,proto3,oneof"` } func (*Type_Int) isType_Value() {} @@ -1983,8 +2003,65 @@ func (*Type_Unit) isType_Value() {} func (*Type_Any) isType_Value() {} +func (*Type_Parameter) isType_Value() {} + func (*Type_Optional) isType_Value() {} +type TypeParameter struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pos *Position `protobuf:"bytes,1,opt,name=pos,proto3,oneof" json:"pos,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *TypeParameter) Reset() { + *x = TypeParameter{} + if protoimpl.UnsafeEnabled { + mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TypeParameter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TypeParameter) ProtoMessage() {} + +func (x *TypeParameter) ProtoReflect() protoreflect.Message { + mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TypeParameter.ProtoReflect.Descriptor instead. +func (*TypeParameter) Descriptor() ([]byte, []int) { + return file_xyz_block_ftl_v1_schema_schema_proto_rawDescGZIP(), []int{29} +} + +func (x *TypeParameter) GetPos() *Position { + if x != nil { + return x.Pos + } + return nil +} + +func (x *TypeParameter) GetName() string { + if x != nil { + return x.Name + } + return "" +} + type Unit struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1996,7 +2073,7 @@ type Unit struct { func (x *Unit) Reset() { *x = Unit{} if protoimpl.UnsafeEnabled { - mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[29] + mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2009,7 +2086,7 @@ func (x *Unit) String() string { func (*Unit) ProtoMessage() {} func (x *Unit) ProtoReflect() protoreflect.Message { - mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[29] + mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2022,7 +2099,7 @@ func (x *Unit) ProtoReflect() protoreflect.Message { // Deprecated: Use Unit.ProtoReflect.Descriptor instead. func (*Unit) Descriptor() ([]byte, []int) { - return file_xyz_block_ftl_v1_schema_schema_proto_rawDescGZIP(), []int{29} + return file_xyz_block_ftl_v1_schema_schema_proto_rawDescGZIP(), []int{30} } func (x *Unit) GetPos() *Position { @@ -2049,7 +2126,7 @@ type Verb struct { func (x *Verb) Reset() { *x = Verb{} if protoimpl.UnsafeEnabled { - mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[30] + mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2062,7 +2139,7 @@ func (x *Verb) String() string { func (*Verb) ProtoMessage() {} func (x *Verb) ProtoReflect() protoreflect.Message { - mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[30] + mi := &file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2075,7 +2152,7 @@ func (x *Verb) ProtoReflect() protoreflect.Message { // Deprecated: Use Verb.ProtoReflect.Descriptor instead. func (*Verb) Descriptor() ([]byte, []int) { - return file_xyz_block_ftl_v1_schema_schema_proto_rawDescGZIP(), []int{30} + return file_xyz_block_ftl_v1_schema_schema_proto_rawDescGZIP(), []int{31} } func (x *Verb) GetRuntime() *VerbRuntime { @@ -2181,7 +2258,7 @@ var file_xyz_block_ftl_v1_schema_schema_proto_rawDesc = []byte{ 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x88, 0x01, 0x01, 0x42, 0x06, - 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x22, 0x97, 0x02, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x22, 0xbf, 0x02, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, @@ -2196,17 +2273,24 @@ var file_xyz_block_ftl_v1_schema_schema_proto_rawDesc = []byte{ 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x26, 0x0a, 0x0e, 0x74, 0x79, 0x70, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x79, 0x70, 0x65, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, - 0x22, 0x77, 0x0a, 0x07, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x66, 0x12, 0x38, 0x0a, 0x03, 0x70, - 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, + 0x12, 0x4e, 0x0a, 0x0e, 0x74, 0x79, 0x70, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x70, - 0x6f, 0x73, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x22, 0x7c, 0x0a, 0x08, 0x44, 0x61, 0x74, + 0x6d, 0x61, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x52, 0x0e, 0x74, 0x79, 0x70, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x07, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x65, 0x66, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, + 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x88, 0x01, 0x01, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x74, 0x79, + 0x70, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, + 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x0e, 0x74, 0x79, 0x70, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x73, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x22, 0x7c, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, @@ -2380,7 +2464,7 @@ var file_xyz_block_ftl_v1_schema_schema_proto_rawDesc = []byte{ 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x88, 0x01, 0x01, 0x42, 0x06, 0x0a, 0x04, - 0x5f, 0x70, 0x6f, 0x73, 0x22, 0xa6, 0x05, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x30, 0x0a, + 0x5f, 0x70, 0x6f, 0x73, 0x22, 0xee, 0x05, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x30, 0x0a, 0x03, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x49, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x03, 0x69, 0x6e, 0x74, 0x12, @@ -2418,45 +2502,56 @@ var file_xyz_block_ftl_v1_schema_schema_proto_rawDesc = []byte{ 0x74, 0x12, 0x30, 0x0a, 0x03, 0x61, 0x6e, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x41, 0x6e, 0x79, 0x48, 0x00, 0x52, 0x03, - 0x61, 0x6e, 0x79, 0x12, 0x3f, 0x0a, 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x48, 0x0a, - 0x04, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, - 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x88, 0x01, 0x01, 0x42, - 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x22, 0xfe, 0x02, 0x0a, 0x04, 0x56, 0x65, 0x72, 0x62, - 0x12, 0x45, 0x0a, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x92, 0xf7, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, - 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x56, 0x65, - 0x72, 0x62, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x48, 0x00, 0x52, 0x07, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, - 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x01, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x88, 0x01, - 0x01, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x12, 0x37, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, - 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x08, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x78, - 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, - 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x42, 0x46, 0x50, 0x01, 0x5a, 0x42, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x42, 0x44, 0x35, 0x34, 0x35, 0x36, - 0x36, 0x39, 0x37, 0x35, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, - 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x76, 0x31, - 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x3b, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x70, 0x62, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x6e, 0x79, 0x12, 0x46, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x2e, 0x54, 0x79, 0x70, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x48, 0x00, + 0x52, 0x09, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x08, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, + 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x48, 0x00, 0x52, 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x07, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x65, 0x0a, 0x0d, 0x54, 0x79, 0x70, 0x65, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x88, 0x01, 0x01, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x22, 0x48, 0x0a, 0x04, + 0x55, 0x6e, 0x69, 0x74, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, + 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x88, 0x01, 0x01, 0x42, 0x06, + 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x22, 0xfe, 0x02, 0x0a, 0x04, 0x56, 0x65, 0x72, 0x62, 0x12, + 0x45, 0x0a, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x92, 0xf7, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, + 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x56, 0x65, 0x72, + 0x62, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x48, 0x00, 0x52, 0x07, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x03, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x50, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x01, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x88, 0x01, 0x01, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x12, 0x37, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, + 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x08, 0x72, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x78, 0x79, + 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x42, + 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x6f, 0x73, 0x42, 0x46, 0x50, 0x01, 0x5a, 0x42, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x42, 0x44, 0x35, 0x34, 0x35, 0x36, 0x36, + 0x39, 0x37, 0x35, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x78, + 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x76, 0x31, 0x2f, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x3b, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x70, 0x62, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2471,7 +2566,7 @@ func file_xyz_block_ftl_v1_schema_schema_proto_rawDescGZIP() []byte { return file_xyz_block_ftl_v1_schema_schema_proto_rawDescData } -var file_xyz_block_ftl_v1_schema_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 31) +var file_xyz_block_ftl_v1_schema_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 32) var file_xyz_block_ftl_v1_schema_schema_proto_goTypes = []interface{}{ (*SinkRef)(nil), // 0: xyz.block.ftl.v1.schema.SinkRef (*SourceRef)(nil), // 1: xyz.block.ftl.v1.schema.SourceRef @@ -2502,10 +2597,11 @@ var file_xyz_block_ftl_v1_schema_schema_proto_goTypes = []interface{}{ (*String)(nil), // 26: xyz.block.ftl.v1.schema.String (*Time)(nil), // 27: xyz.block.ftl.v1.schema.Time (*Type)(nil), // 28: xyz.block.ftl.v1.schema.Type - (*Unit)(nil), // 29: xyz.block.ftl.v1.schema.Unit - (*Verb)(nil), // 30: xyz.block.ftl.v1.schema.Verb - (*ModuleRuntime)(nil), // 31: xyz.block.ftl.v1.schema.ModuleRuntime - (*VerbRuntime)(nil), // 32: xyz.block.ftl.v1.schema.VerbRuntime + (*TypeParameter)(nil), // 29: xyz.block.ftl.v1.schema.TypeParameter + (*Unit)(nil), // 30: xyz.block.ftl.v1.schema.Unit + (*Verb)(nil), // 31: xyz.block.ftl.v1.schema.Verb + (*ModuleRuntime)(nil), // 32: xyz.block.ftl.v1.schema.ModuleRuntime + (*VerbRuntime)(nil), // 33: xyz.block.ftl.v1.schema.VerbRuntime } var file_xyz_block_ftl_v1_schema_schema_proto_depIdxs = []int32{ 24, // 0: xyz.block.ftl.v1.schema.SinkRef.pos:type_name -> xyz.block.ftl.v1.schema.Position @@ -2519,63 +2615,67 @@ var file_xyz_block_ftl_v1_schema_schema_proto_depIdxs = []int32{ 24, // 8: xyz.block.ftl.v1.schema.Data.pos:type_name -> xyz.block.ftl.v1.schema.Position 11, // 9: xyz.block.ftl.v1.schema.Data.fields:type_name -> xyz.block.ftl.v1.schema.Field 18, // 10: xyz.block.ftl.v1.schema.Data.metadata:type_name -> xyz.block.ftl.v1.schema.Metadata - 24, // 11: xyz.block.ftl.v1.schema.DataRef.pos:type_name -> xyz.block.ftl.v1.schema.Position - 24, // 12: xyz.block.ftl.v1.schema.Database.pos:type_name -> xyz.block.ftl.v1.schema.Position - 7, // 13: xyz.block.ftl.v1.schema.Decl.data:type_name -> xyz.block.ftl.v1.schema.Data - 30, // 14: xyz.block.ftl.v1.schema.Decl.verb:type_name -> xyz.block.ftl.v1.schema.Verb - 9, // 15: xyz.block.ftl.v1.schema.Decl.database:type_name -> xyz.block.ftl.v1.schema.Database - 24, // 16: xyz.block.ftl.v1.schema.Field.pos:type_name -> xyz.block.ftl.v1.schema.Position - 28, // 17: xyz.block.ftl.v1.schema.Field.type:type_name -> xyz.block.ftl.v1.schema.Type - 24, // 18: xyz.block.ftl.v1.schema.Float.pos:type_name -> xyz.block.ftl.v1.schema.Position - 14, // 19: xyz.block.ftl.v1.schema.IngressPathComponent.ingressPathLiteral:type_name -> xyz.block.ftl.v1.schema.IngressPathLiteral - 15, // 20: xyz.block.ftl.v1.schema.IngressPathComponent.ingressPathParameter:type_name -> xyz.block.ftl.v1.schema.IngressPathParameter - 24, // 21: xyz.block.ftl.v1.schema.IngressPathLiteral.pos:type_name -> xyz.block.ftl.v1.schema.Position - 24, // 22: xyz.block.ftl.v1.schema.IngressPathParameter.pos:type_name -> xyz.block.ftl.v1.schema.Position - 24, // 23: xyz.block.ftl.v1.schema.Int.pos:type_name -> xyz.block.ftl.v1.schema.Position - 24, // 24: xyz.block.ftl.v1.schema.Map.pos:type_name -> xyz.block.ftl.v1.schema.Position - 28, // 25: xyz.block.ftl.v1.schema.Map.key:type_name -> xyz.block.ftl.v1.schema.Type - 28, // 26: xyz.block.ftl.v1.schema.Map.value:type_name -> xyz.block.ftl.v1.schema.Type - 19, // 27: xyz.block.ftl.v1.schema.Metadata.calls:type_name -> xyz.block.ftl.v1.schema.MetadataCalls - 21, // 28: xyz.block.ftl.v1.schema.Metadata.ingress:type_name -> xyz.block.ftl.v1.schema.MetadataIngress - 20, // 29: xyz.block.ftl.v1.schema.Metadata.databases:type_name -> xyz.block.ftl.v1.schema.MetadataDatabases - 24, // 30: xyz.block.ftl.v1.schema.MetadataCalls.pos:type_name -> xyz.block.ftl.v1.schema.Position - 2, // 31: xyz.block.ftl.v1.schema.MetadataCalls.calls:type_name -> xyz.block.ftl.v1.schema.VerbRef - 24, // 32: xyz.block.ftl.v1.schema.MetadataDatabases.pos:type_name -> xyz.block.ftl.v1.schema.Position - 9, // 33: xyz.block.ftl.v1.schema.MetadataDatabases.calls:type_name -> xyz.block.ftl.v1.schema.Database - 24, // 34: xyz.block.ftl.v1.schema.MetadataIngress.pos:type_name -> xyz.block.ftl.v1.schema.Position - 13, // 35: xyz.block.ftl.v1.schema.MetadataIngress.path:type_name -> xyz.block.ftl.v1.schema.IngressPathComponent - 31, // 36: xyz.block.ftl.v1.schema.Module.runtime:type_name -> xyz.block.ftl.v1.schema.ModuleRuntime - 24, // 37: xyz.block.ftl.v1.schema.Module.pos:type_name -> xyz.block.ftl.v1.schema.Position - 10, // 38: xyz.block.ftl.v1.schema.Module.decls:type_name -> xyz.block.ftl.v1.schema.Decl - 24, // 39: xyz.block.ftl.v1.schema.Optional.pos:type_name -> xyz.block.ftl.v1.schema.Position - 28, // 40: xyz.block.ftl.v1.schema.Optional.type:type_name -> xyz.block.ftl.v1.schema.Type - 24, // 41: xyz.block.ftl.v1.schema.Schema.pos:type_name -> xyz.block.ftl.v1.schema.Position - 22, // 42: xyz.block.ftl.v1.schema.Schema.modules:type_name -> xyz.block.ftl.v1.schema.Module - 24, // 43: xyz.block.ftl.v1.schema.String.pos:type_name -> xyz.block.ftl.v1.schema.Position - 24, // 44: xyz.block.ftl.v1.schema.Time.pos:type_name -> xyz.block.ftl.v1.schema.Position - 16, // 45: xyz.block.ftl.v1.schema.Type.int:type_name -> xyz.block.ftl.v1.schema.Int - 12, // 46: xyz.block.ftl.v1.schema.Type.float:type_name -> xyz.block.ftl.v1.schema.Float - 26, // 47: xyz.block.ftl.v1.schema.Type.string:type_name -> xyz.block.ftl.v1.schema.String - 6, // 48: xyz.block.ftl.v1.schema.Type.bytes:type_name -> xyz.block.ftl.v1.schema.Bytes - 5, // 49: xyz.block.ftl.v1.schema.Type.bool:type_name -> xyz.block.ftl.v1.schema.Bool - 27, // 50: xyz.block.ftl.v1.schema.Type.time:type_name -> xyz.block.ftl.v1.schema.Time - 4, // 51: xyz.block.ftl.v1.schema.Type.array:type_name -> xyz.block.ftl.v1.schema.Array - 17, // 52: xyz.block.ftl.v1.schema.Type.map:type_name -> xyz.block.ftl.v1.schema.Map - 8, // 53: xyz.block.ftl.v1.schema.Type.dataRef:type_name -> xyz.block.ftl.v1.schema.DataRef - 29, // 54: xyz.block.ftl.v1.schema.Type.unit:type_name -> xyz.block.ftl.v1.schema.Unit - 3, // 55: xyz.block.ftl.v1.schema.Type.any:type_name -> xyz.block.ftl.v1.schema.Any - 23, // 56: xyz.block.ftl.v1.schema.Type.optional:type_name -> xyz.block.ftl.v1.schema.Optional - 24, // 57: xyz.block.ftl.v1.schema.Unit.pos:type_name -> xyz.block.ftl.v1.schema.Position - 32, // 58: xyz.block.ftl.v1.schema.Verb.runtime:type_name -> xyz.block.ftl.v1.schema.VerbRuntime - 24, // 59: xyz.block.ftl.v1.schema.Verb.pos:type_name -> xyz.block.ftl.v1.schema.Position - 28, // 60: xyz.block.ftl.v1.schema.Verb.request:type_name -> xyz.block.ftl.v1.schema.Type - 28, // 61: xyz.block.ftl.v1.schema.Verb.response:type_name -> xyz.block.ftl.v1.schema.Type - 18, // 62: xyz.block.ftl.v1.schema.Verb.metadata:type_name -> xyz.block.ftl.v1.schema.Metadata - 63, // [63:63] is the sub-list for method output_type - 63, // [63:63] is the sub-list for method input_type - 63, // [63:63] is the sub-list for extension type_name - 63, // [63:63] is the sub-list for extension extendee - 0, // [0:63] is the sub-list for field type_name + 29, // 11: xyz.block.ftl.v1.schema.Data.typeParameters:type_name -> xyz.block.ftl.v1.schema.TypeParameter + 24, // 12: xyz.block.ftl.v1.schema.DataRef.pos:type_name -> xyz.block.ftl.v1.schema.Position + 28, // 13: xyz.block.ftl.v1.schema.DataRef.typeParameters:type_name -> xyz.block.ftl.v1.schema.Type + 24, // 14: xyz.block.ftl.v1.schema.Database.pos:type_name -> xyz.block.ftl.v1.schema.Position + 7, // 15: xyz.block.ftl.v1.schema.Decl.data:type_name -> xyz.block.ftl.v1.schema.Data + 31, // 16: xyz.block.ftl.v1.schema.Decl.verb:type_name -> xyz.block.ftl.v1.schema.Verb + 9, // 17: xyz.block.ftl.v1.schema.Decl.database:type_name -> xyz.block.ftl.v1.schema.Database + 24, // 18: xyz.block.ftl.v1.schema.Field.pos:type_name -> xyz.block.ftl.v1.schema.Position + 28, // 19: xyz.block.ftl.v1.schema.Field.type:type_name -> xyz.block.ftl.v1.schema.Type + 24, // 20: xyz.block.ftl.v1.schema.Float.pos:type_name -> xyz.block.ftl.v1.schema.Position + 14, // 21: xyz.block.ftl.v1.schema.IngressPathComponent.ingressPathLiteral:type_name -> xyz.block.ftl.v1.schema.IngressPathLiteral + 15, // 22: xyz.block.ftl.v1.schema.IngressPathComponent.ingressPathParameter:type_name -> xyz.block.ftl.v1.schema.IngressPathParameter + 24, // 23: xyz.block.ftl.v1.schema.IngressPathLiteral.pos:type_name -> xyz.block.ftl.v1.schema.Position + 24, // 24: xyz.block.ftl.v1.schema.IngressPathParameter.pos:type_name -> xyz.block.ftl.v1.schema.Position + 24, // 25: xyz.block.ftl.v1.schema.Int.pos:type_name -> xyz.block.ftl.v1.schema.Position + 24, // 26: xyz.block.ftl.v1.schema.Map.pos:type_name -> xyz.block.ftl.v1.schema.Position + 28, // 27: xyz.block.ftl.v1.schema.Map.key:type_name -> xyz.block.ftl.v1.schema.Type + 28, // 28: xyz.block.ftl.v1.schema.Map.value:type_name -> xyz.block.ftl.v1.schema.Type + 19, // 29: xyz.block.ftl.v1.schema.Metadata.calls:type_name -> xyz.block.ftl.v1.schema.MetadataCalls + 21, // 30: xyz.block.ftl.v1.schema.Metadata.ingress:type_name -> xyz.block.ftl.v1.schema.MetadataIngress + 20, // 31: xyz.block.ftl.v1.schema.Metadata.databases:type_name -> xyz.block.ftl.v1.schema.MetadataDatabases + 24, // 32: xyz.block.ftl.v1.schema.MetadataCalls.pos:type_name -> xyz.block.ftl.v1.schema.Position + 2, // 33: xyz.block.ftl.v1.schema.MetadataCalls.calls:type_name -> xyz.block.ftl.v1.schema.VerbRef + 24, // 34: xyz.block.ftl.v1.schema.MetadataDatabases.pos:type_name -> xyz.block.ftl.v1.schema.Position + 9, // 35: xyz.block.ftl.v1.schema.MetadataDatabases.calls:type_name -> xyz.block.ftl.v1.schema.Database + 24, // 36: xyz.block.ftl.v1.schema.MetadataIngress.pos:type_name -> xyz.block.ftl.v1.schema.Position + 13, // 37: xyz.block.ftl.v1.schema.MetadataIngress.path:type_name -> xyz.block.ftl.v1.schema.IngressPathComponent + 32, // 38: xyz.block.ftl.v1.schema.Module.runtime:type_name -> xyz.block.ftl.v1.schema.ModuleRuntime + 24, // 39: xyz.block.ftl.v1.schema.Module.pos:type_name -> xyz.block.ftl.v1.schema.Position + 10, // 40: xyz.block.ftl.v1.schema.Module.decls:type_name -> xyz.block.ftl.v1.schema.Decl + 24, // 41: xyz.block.ftl.v1.schema.Optional.pos:type_name -> xyz.block.ftl.v1.schema.Position + 28, // 42: xyz.block.ftl.v1.schema.Optional.type:type_name -> xyz.block.ftl.v1.schema.Type + 24, // 43: xyz.block.ftl.v1.schema.Schema.pos:type_name -> xyz.block.ftl.v1.schema.Position + 22, // 44: xyz.block.ftl.v1.schema.Schema.modules:type_name -> xyz.block.ftl.v1.schema.Module + 24, // 45: xyz.block.ftl.v1.schema.String.pos:type_name -> xyz.block.ftl.v1.schema.Position + 24, // 46: xyz.block.ftl.v1.schema.Time.pos:type_name -> xyz.block.ftl.v1.schema.Position + 16, // 47: xyz.block.ftl.v1.schema.Type.int:type_name -> xyz.block.ftl.v1.schema.Int + 12, // 48: xyz.block.ftl.v1.schema.Type.float:type_name -> xyz.block.ftl.v1.schema.Float + 26, // 49: xyz.block.ftl.v1.schema.Type.string:type_name -> xyz.block.ftl.v1.schema.String + 6, // 50: xyz.block.ftl.v1.schema.Type.bytes:type_name -> xyz.block.ftl.v1.schema.Bytes + 5, // 51: xyz.block.ftl.v1.schema.Type.bool:type_name -> xyz.block.ftl.v1.schema.Bool + 27, // 52: xyz.block.ftl.v1.schema.Type.time:type_name -> xyz.block.ftl.v1.schema.Time + 4, // 53: xyz.block.ftl.v1.schema.Type.array:type_name -> xyz.block.ftl.v1.schema.Array + 17, // 54: xyz.block.ftl.v1.schema.Type.map:type_name -> xyz.block.ftl.v1.schema.Map + 8, // 55: xyz.block.ftl.v1.schema.Type.dataRef:type_name -> xyz.block.ftl.v1.schema.DataRef + 30, // 56: xyz.block.ftl.v1.schema.Type.unit:type_name -> xyz.block.ftl.v1.schema.Unit + 3, // 57: xyz.block.ftl.v1.schema.Type.any:type_name -> xyz.block.ftl.v1.schema.Any + 29, // 58: xyz.block.ftl.v1.schema.Type.parameter:type_name -> xyz.block.ftl.v1.schema.TypeParameter + 23, // 59: xyz.block.ftl.v1.schema.Type.optional:type_name -> xyz.block.ftl.v1.schema.Optional + 24, // 60: xyz.block.ftl.v1.schema.TypeParameter.pos:type_name -> xyz.block.ftl.v1.schema.Position + 24, // 61: xyz.block.ftl.v1.schema.Unit.pos:type_name -> xyz.block.ftl.v1.schema.Position + 33, // 62: xyz.block.ftl.v1.schema.Verb.runtime:type_name -> xyz.block.ftl.v1.schema.VerbRuntime + 24, // 63: xyz.block.ftl.v1.schema.Verb.pos:type_name -> xyz.block.ftl.v1.schema.Position + 28, // 64: xyz.block.ftl.v1.schema.Verb.request:type_name -> xyz.block.ftl.v1.schema.Type + 28, // 65: xyz.block.ftl.v1.schema.Verb.response:type_name -> xyz.block.ftl.v1.schema.Type + 18, // 66: xyz.block.ftl.v1.schema.Verb.metadata:type_name -> xyz.block.ftl.v1.schema.Metadata + 67, // [67:67] is the sub-list for method output_type + 67, // [67:67] is the sub-list for method input_type + 67, // [67:67] is the sub-list for extension type_name + 67, // [67:67] is the sub-list for extension extendee + 0, // [0:67] is the sub-list for field type_name } func init() { file_xyz_block_ftl_v1_schema_schema_proto_init() } @@ -2934,7 +3034,7 @@ func file_xyz_block_ftl_v1_schema_schema_proto_init() { } } file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Unit); i { + switch v := v.(*TypeParameter); i { case 0: return &v.state case 1: @@ -2946,6 +3046,18 @@ func file_xyz_block_ftl_v1_schema_schema_proto_init() { } } file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Unit); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Verb); i { case 0: return &v.state @@ -3008,17 +3120,19 @@ func file_xyz_block_ftl_v1_schema_schema_proto_init() { (*Type_DataRef)(nil), (*Type_Unit)(nil), (*Type_Any)(nil), + (*Type_Parameter)(nil), (*Type_Optional)(nil), } file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[29].OneofWrappers = []interface{}{} file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[30].OneofWrappers = []interface{}{} + file_xyz_block_ftl_v1_schema_schema_proto_msgTypes[31].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_xyz_block_ftl_v1_schema_schema_proto_rawDesc, NumEnums: 0, - NumMessages: 31, + NumMessages: 32, NumExtensions: 0, NumServices: 0, }, diff --git a/protos/xyz/block/ftl/v1/schema/schema.proto b/protos/xyz/block/ftl/v1/schema/schema.proto index 96e9666c2a..bd1a2f3a71 100644 --- a/protos/xyz/block/ftl/v1/schema/schema.proto +++ b/protos/xyz/block/ftl/v1/schema/schema.proto @@ -49,13 +49,14 @@ message Data { string name = 3; repeated Field fields = 4; repeated Metadata metadata = 5; - repeated string typeParameters = 6; + repeated TypeParameter typeParameters = 6; } message DataRef { optional Position pos = 1; string name = 2; string module = 3; + repeated Type typeParameters = 4; } message Database { @@ -182,10 +183,16 @@ message Type { DataRef dataRef = 9; Unit unit = 10; Any any = 11; - Optional optional = 12; + TypeParameter parameter = 12; + Optional optional = 13; } } +message TypeParameter { + optional Position pos = 1; + string name = 2; +} + message Unit { optional Position pos = 1; }