Skip to content

Commit

Permalink
chore: remove type-specific Ref variants from schema
Browse files Browse the repository at this point in the history
fixes #1043
fixes #1063
  • Loading branch information
worstell committed Mar 13, 2024
1 parent e564ab1 commit 96540ab
Show file tree
Hide file tree
Showing 71 changed files with 3,061 additions and 5,748 deletions.
8 changes: 4 additions & 4 deletions backend/controller/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (c *ConsoleService) GetModules(ctx context.Context, req *connect.Request[pb
v := decl.ToProto().(*schemapb.Verb)
verbSchema := schema.VerbFromProto(v) // TODO: include all of the types that the verb references
var jsonRequestSchema string
if requestData, ok := verbSchema.Request.(*schema.DataRef); ok {
if requestData, ok := verbSchema.Request.(*schema.Ref); ok {
jsonSchema, err := schema.DataToJSONSchema(sch, *requestData)
if err != nil {
return nil, err
Expand Down Expand Up @@ -291,9 +291,9 @@ func eventDALToProto(event dal.Event) *pbconsole.Event {
rstr := r.String()
requestName = &rstr
}
var sourceVerbRef *schemapb.VerbRef
var sourceVerbRef *schemapb.Ref
if sourceVerb, ok := event.SourceVerb.Get(); ok {
sourceVerbRef = sourceVerb.ToProto().(*schemapb.VerbRef) //nolint:forcetypeassert
sourceVerbRef = sourceVerb.ToProto().(*schemapb.Ref) //nolint:forcetypeassert
}
return &pbconsole.Event{
TimeStamp: timestamppb.New(event.Time),
Expand All @@ -304,7 +304,7 @@ func eventDALToProto(event dal.Event) *pbconsole.Event {
DeploymentName: event.DeploymentName.String(),
TimeStamp: timestamppb.New(event.Time),
SourceVerbRef: sourceVerbRef,
DestinationVerbRef: &schemapb.VerbRef{
DestinationVerbRef: &schemapb.Ref{
Module: event.DestVerb.Module,
Name: event.DestVerb.Name,
},
Expand Down
6 changes: 3 additions & 3 deletions backend/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ func (s *Service) Status(ctx context.Context, req *connect.Request[ftlv1.StatusR
IngressRoutes: slices.Map(status.IngressRoutes, func(r dal.IngressRouteEntry) *ftlv1.StatusResponse_IngressRoute {
return &ftlv1.StatusResponse_IngressRoute{
DeploymentName: r.Deployment.String(),
Verb: &schemapb.VerbRef{Module: r.Module, Name: r.Verb},
Verb: &schemapb.Ref{Module: r.Module, Name: r.Verb},
Method: r.Method,
Path: r.Path,
}
Expand Down Expand Up @@ -571,7 +571,7 @@ func (s *Service) Call(ctx context.Context, req *connect.Request[ftlv1.CallReque
if req.Msg.Body == nil {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("body is required"))
}
verbRef := schema.VerbRefFromProto(req.Msg.Verb)
verbRef := schema.RefFromProto(req.Msg.Verb)

sch, err := s.getActiveSchema(ctx)
if err != nil {
Expand Down Expand Up @@ -612,7 +612,7 @@ func (s *Service) Call(ctx context.Context, req *connect.Request[ftlv1.CallReque
}

ctx = rpc.WithVerbs(ctx, append(callers, verbRef))
headers.AddCaller(req.Header(), schema.VerbRefFromProto(req.Msg.Verb))
headers.AddCaller(req.Header(), schema.RefFromProto(req.Msg.Verb))

resp, err := client.verb.Call(ctx, req)
var maybeResponse optional.Option[*ftlv1.CallResponse]
Expand Down
2 changes: 1 addition & 1 deletion backend/controller/dal/dal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func TestDAL(t *testing.T) {
RequestName: optional.Some(requestName),
Request: []byte("{}"),
Response: []byte(`{"time": "now"}`),
DestVerb: schema.VerbRef{Module: "time", Name: "time"},
DestVerb: schema.Ref{Module: "time", Name: "time"},
}
t.Run("InsertCallEvent", func(t *testing.T) {
err = dal.InsertCallEvent(ctx, callEvent)
Expand Down
10 changes: 5 additions & 5 deletions backend/controller/dal/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ type CallEvent struct {
DeploymentName model.DeploymentName
RequestName optional.Option[model.RequestName]
Time time.Time
SourceVerb optional.Option[schema.VerbRef]
DestVerb schema.VerbRef
SourceVerb optional.Option[schema.Ref]
DestVerb schema.Ref
Duration time.Duration
Request []byte
Response []byte
Expand Down Expand Up @@ -372,19 +372,19 @@ func transformRowsToEvents(deploymentNames map[int64]model.DeploymentName, rows
if err := json.Unmarshal(row.Payload, &jsonPayload); err != nil {
return nil, err
}
var sourceVerb optional.Option[schema.VerbRef]
var sourceVerb optional.Option[schema.Ref]
sourceModule, smok := row.CustomKey1.Get()
sourceName, snok := row.CustomKey2.Get()
if smok && snok {
sourceVerb = optional.Some(schema.VerbRef{Module: sourceModule, Name: sourceName})
sourceVerb = optional.Some(schema.Ref{Module: sourceModule, Name: sourceName})
}
out = append(out, &CallEvent{
ID: row.ID,
DeploymentName: row.DeploymentName,
RequestName: requestName,
Time: row.TimeStamp,
SourceVerb: sourceVerb,
DestVerb: schema.VerbRef{Module: row.CustomKey3.MustGet(), Name: row.CustomKey4.MustGet()},
DestVerb: schema.Ref{Module: row.CustomKey3.MustGet(), Name: row.CustomKey4.MustGet()},
Duration: time.Duration(jsonPayload.DurationMS) * time.Millisecond,
Request: jsonPayload.Request,
Response: jsonPayload.Response,
Expand Down
12 changes: 6 additions & 6 deletions backend/controller/ingress/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ func transformAliasedFields(sch *schema.Schema, t schema.Type, obj any, aliaser
return nil
}
switch t := t.(type) {
case *schema.DataRef:
data, err := sch.ResolveDataRefMonomorphised(t)
case *schema.Ref:
data, err := sch.ResolveRefMonomorphised(t)
if err != nil {
return fmt.Errorf("%s: failed to resolve data type: %w", t.Pos, err)
}
Expand Down Expand Up @@ -64,8 +64,8 @@ func transformAliasedFields(sch *schema.Schema, t schema.Type, obj any, aliaser
return nil
}

func transformFromAliasedFields(dataRef *schema.DataRef, sch *schema.Schema, request map[string]any) (map[string]any, error) {
return request, transformAliasedFields(sch, dataRef, request, func(obj map[string]any, field *schema.Field) string {
func transformFromAliasedFields(ref *schema.Ref, sch *schema.Schema, request map[string]any) (map[string]any, error) {
return request, transformAliasedFields(sch, ref, request, func(obj map[string]any, field *schema.Field) string {
jsonAlias := field.Alias(schema.AliasKindJSON)
if _, ok := obj[field.Name]; !ok && jsonAlias != "" && obj[jsonAlias] != nil {
obj[field.Name] = obj[jsonAlias]
Expand All @@ -75,8 +75,8 @@ func transformFromAliasedFields(dataRef *schema.DataRef, sch *schema.Schema, req
})
}

func transformToAliasedFields(dataRef *schema.DataRef, sch *schema.Schema, request map[string]any) (map[string]any, error) {
return request, transformAliasedFields(sch, dataRef, request, func(obj map[string]any, field *schema.Field) string {
func transformToAliasedFields(ref *schema.Ref, sch *schema.Schema, request map[string]any) (map[string]any, error) {
return request, transformAliasedFields(sch, ref, request, func(obj map[string]any, field *schema.Field) string {
jsonAlias := field.Alias(schema.AliasKindJSON)
if jsonAlias != "" && field.Name != jsonAlias {
obj[jsonAlias] = obj[field.Name]
Expand Down
4 changes: 2 additions & 2 deletions backend/controller/ingress/alias_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestTransformFromAliasedFields(t *testing.T) {
`
sch, err := schema.ParseString("test", schemaText)
assert.NoError(t, err)
actual, err := transformFromAliasedFields(&schema.DataRef{Module: "test", Name: "Test"}, sch, map[string]any{
actual, err := transformFromAliasedFields(&schema.Ref{Module: "test", Name: "Test"}, sch, map[string]any{
"bar": "value",
"inner": map[string]any{
"foo": "value",
Expand Down Expand Up @@ -86,7 +86,7 @@ func TestTransformToAliasedFields(t *testing.T) {
`
sch, err := schema.ParseString("test", schemaText)
assert.NoError(t, err)
actual, err := transformToAliasedFields(&schema.DataRef{Module: "test", Name: "Test"}, sch, map[string]any{
actual, err := transformToAliasedFields(&schema.Ref{Module: "test", Name: "Test"}, sch, map[string]any{
"scalar": "value",
"inner": map[string]any{
"waz": "value",
Expand Down
9 changes: 7 additions & 2 deletions backend/controller/ingress/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func Handle(

creq := connect.NewRequest(&ftlv1.CallRequest{
Metadata: &ftlv1.Metadata{},
Verb: &schemapb.VerbRef{Module: route.Module, Name: route.Verb},
Verb: &schemapb.Ref{Module: route.Module, Name: route.Verb},
Body: body,
})

Expand All @@ -62,7 +62,12 @@ func Handle(
}
switch msg := resp.Msg.Response.(type) {
case *ftlv1.CallResponse_Body:
verb := sch.ResolveVerbRef(&schema.VerbRef{Name: route.Verb, Module: route.Module})
verb := &schema.Verb{}
err = sch.ResolveRefToType(&schema.Ref{Name: route.Verb, Module: route.Module}, verb)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var responseBody []byte

if metadata, ok := verb.GetMetadataIngress().Get(); ok && metadata.Type == "http" {
Expand Down
79 changes: 41 additions & 38 deletions backend/controller/ingress/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,24 @@ func matchSegments(pattern, urlPath string, onMatch func(segment, value string))
return true
}

func ValidateCallBody(body []byte, verbRef *schema.VerbRef, sch *schema.Schema) error {
verb := sch.ResolveVerbRef(verbRef)
if verb == nil {
return fmt.Errorf("unknown verb %s", verbRef)
func ValidateCallBody(body []byte, ref *schema.Ref, sch *schema.Schema) error {
verb := &schema.Verb{}
err := sch.ResolveRefToType(ref, verb)
if err != nil {
return err
}

var requestMap map[string]any
err := json.Unmarshal(body, &requestMap)
err = json.Unmarshal(body, &requestMap)
if err != nil {
return fmt.Errorf("HTTP request body is not valid JSON: %w", err)
}

return validateValue(verb.Request, []string{verb.Request.String()}, requestMap, sch)
}

func getBodyField(dataRef *schema.DataRef, sch *schema.Schema) (*schema.Field, error) {
data, err := sch.ResolveDataRefMonomorphised(dataRef)
func getBodyField(ref *schema.Ref, sch *schema.Schema) (*schema.Field, error) {
data, err := sch.ResolveRefMonomorphised(ref)
if err != nil {
return nil, err
}
Expand All @@ -87,7 +88,7 @@ func getBodyField(dataRef *schema.DataRef, sch *schema.Schema) (*schema.Field, e
}

if bodyField == nil {
return nil, fmt.Errorf("verb %s must have a 'body' field", dataRef.Name)
return nil, fmt.Errorf("verb %s must have a 'body' field", ref.Name)
}

return bodyField, nil
Expand Down Expand Up @@ -184,41 +185,43 @@ func validateValue(fieldType schema.Type, path path, value any, sch *schema.Sche
}
}
typeMatches = true

case *schema.DataRef:
if valueMap, ok := value.(map[string]any); ok {
if err := validateRequestMap(fieldType, path, valueMap, sch); err != nil {
return err
case *schema.Ref:
decl := sch.ResolveRef(fieldType)
if decl == nil {
return fmt.Errorf("unknown ref %v", fieldType)
}

switch d := decl.(type) {
case *schema.Verb:
case *schema.Data:
if valueMap, ok := value.(map[string]any); ok {
if err := validateRequestMap(fieldType, path, valueMap, sch); err != nil {
return err
}
typeMatches = true
}
typeMatches = true
}

case *schema.EnumRef:
enum := sch.ResolveEnumRef(fieldType)
if enum == nil {
return fmt.Errorf("unknown enum %v", fieldType)
}

for _, v := range enum.Variants {
switch t := v.Value.(type) {
case *schema.StringValue:
if valueStr, ok := value.(string); ok {
if t.Value == valueStr {
typeMatches = true
break
case *schema.Enum:
for _, v := range d.Variants {
switch t := v.Value.(type) {
case *schema.StringValue:
if valueStr, ok := value.(string); ok {
if t.Value == valueStr {
typeMatches = true
break
}
}
}
case *schema.IntValue:
if valueInt, ok := value.(int); ok {
if t.Value == valueInt {
typeMatches = true
break
case *schema.IntValue:
if valueInt, ok := value.(int); ok {
if t.Value == valueInt {
typeMatches = true
break
}
}
}
}
}
if !typeMatches {
return fmt.Errorf("%s is not a valid variant of enum %s", value, fieldType)
if !typeMatches {
return fmt.Errorf("%s is not a valid variant of enum %s", value, fieldType)
}
}

case *schema.Bytes:
Expand Down
28 changes: 14 additions & 14 deletions backend/controller/ingress/ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func TestValidation(t *testing.T) {
sch, err := schema.ParseString("", test.schema)
assert.NoError(t, err)

err = validateRequestMap(&schema.DataRef{Module: "test", Name: "Test"}, nil, test.request, sch)
err = validateRequestMap(&schema.Ref{Module: "test", Name: "Test"}, nil, test.request, sch)
if test.err != "" {
assert.EqualError(t, err, test.err)
} else {
Expand Down Expand Up @@ -198,8 +198,8 @@ func TestParseQueryJson(t *testing.T) {
func TestResponseBodyForVerb(t *testing.T) {
jsonVerb := &schema.Verb{
Name: "Json",
Response: &schema.DataRef{Module: "builtin", Name: "HttpResponse", TypeParameters: []schema.Type{
&schema.DataRef{
Response: &schema.Ref{Module: "builtin", Name: "HttpResponse", TypeParameters: []schema.Type{
&schema.Ref{
Module: "test",
Name: "Test",
},
Expand All @@ -208,7 +208,7 @@ func TestResponseBodyForVerb(t *testing.T) {
}
stringVerb := &schema.Verb{
Name: "String",
Response: &schema.DataRef{Module: "builtin", Name: "HttpResponse", TypeParameters: []schema.Type{
Response: &schema.Ref{Module: "builtin", Name: "HttpResponse", TypeParameters: []schema.Type{
&schema.String{},
&schema.String{},
}},
Expand Down Expand Up @@ -287,7 +287,7 @@ func TestValueForData(t *testing.T) {
{&schema.Bool{}, []byte("true"), true},
{&schema.Array{Element: &schema.String{}}, []byte(`["test1", "test2"]`), []any{"test1", "test2"}},
{&schema.Map{Key: &schema.String{}, Value: &schema.String{}}, []byte(`{"key1": "value1", "key2": "value2"}`), obj{"key1": "value1", "key2": "value2"}},
{&schema.DataRef{Module: "test", Name: "Test"}, []byte(`{"intValue": 10.0}`), obj{"intValue": 10.0}},
{&schema.Ref{Module: "test", Name: "Test"}, []byte(`{"intValue": 10.0}`), obj{"intValue": 10.0}},
}

for _, test := range tests {
Expand Down Expand Up @@ -322,20 +322,20 @@ func TestEnumValidation(t *testing.T) {
&schema.Data{
Name: "StringEnumRequest",
Fields: []*schema.Field{
{Name: "message", Type: &schema.EnumRef{Name: "Color", Module: "test"}},
{Name: "message", Type: &schema.Ref{Name: "Color", Module: "test"}},
},
},
&schema.Data{
Name: "IntEnumRequest",
Fields: []*schema.Field{
{Name: "message", Type: &schema.EnumRef{Name: "ColorInt", Module: "test"}},
{Name: "message", Type: &schema.Ref{Name: "ColorInt", Module: "test"}},
},
},
&schema.Data{
Name: "OptionalEnumRequest",
Fields: []*schema.Field{
{Name: "message", Type: &schema.Optional{
Type: &schema.EnumRef{Name: "Color", Module: "test"},
Type: &schema.Ref{Name: "Color", Module: "test"},
}},
},
},
Expand All @@ -344,15 +344,15 @@ func TestEnumValidation(t *testing.T) {
}

tests := []struct {
validateRoot *schema.DataRef
validateRoot *schema.Ref
req obj
err string
}{
{&schema.DataRef{Name: "StringEnumRequest", Module: "test"}, obj{"message": "Red"}, ""},
{&schema.DataRef{Name: "IntEnumRequest", Module: "test"}, obj{"message": 0}, ""},
{&schema.DataRef{Name: "OptionalEnumRequest", Module: "test"}, obj{}, ""},
{&schema.DataRef{Name: "OptionalEnumRequest", Module: "test"}, obj{"message": "Red"}, ""},
{&schema.DataRef{Name: "StringEnumRequest", Module: "test"}, obj{"message": "akxznc"},
{&schema.Ref{Name: "StringEnumRequest", Module: "test"}, obj{"message": "Red"}, ""},
{&schema.Ref{Name: "IntEnumRequest", Module: "test"}, obj{"message": 0}, ""},
{&schema.Ref{Name: "OptionalEnumRequest", Module: "test"}, obj{}, ""},
{&schema.Ref{Name: "OptionalEnumRequest", Module: "test"}, obj{"message": "Red"}, ""},
{&schema.Ref{Name: "StringEnumRequest", Module: "test"}, obj{"message": "akxznc"},
"akxznc is not a valid variant of enum test.Color"},
}

Expand Down
Loading

0 comments on commit 96540ab

Please sign in to comment.