Skip to content

Commit

Permalink
fix repeated field inputting logic (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
ktr authored Feb 3, 2018
1 parent 253e591 commit fff2d19
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 54 deletions.
136 changes: 85 additions & 51 deletions adapter/gateway/prompt_inputter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
var (
ErrUnknownOneofFieldName = errors.New("unknown oneof field name")
ErrUnknownEnumName = errors.New("unknown enum name")
EORF = errors.New("end of repeated field")
)

// for mocking
Expand Down Expand Up @@ -102,6 +103,10 @@ type fieldInputter struct {
color prompt.Color

isTopLevelMessage bool

// enteredEmptyInput is used to terminate repeated field inputting
// if input is empty and enteredEmptyInput is true, exit repeated input prompt
enteredEmptyInput bool
}

type messageDependency map[string]*desc.MessageDescriptor
Expand Down Expand Up @@ -154,60 +159,21 @@ func (i *fieldInputter) Input(fields []*desc.FieldDescriptor) (proto.Message, er
}

for _, field := range fields {
switch {
case entity.IsOneOf(field):
oneof := field.GetOneOf()
if i.encounteredOneof(oneof) {
continue
}
f, err := i.chooseOneof(oneof)
if err != nil {
return nil, err
}

msgType := f.GetMessageType()
fields := msgType.GetFields()
v, err := newFieldInputter(i.prompt, i.prefixFormat, dynamic.NewMessage(msgType), msgType, false, i.color).Input(fields)
if err != nil {
return nil, err
}
if err := i.msg.TrySetField(f, v); err != nil {
return nil, err
}
case entity.IsEnumType(field):
enum := field.GetEnumType()
if i.encounteredEnum(enum) {
continue
}
v, err := i.chooseEnum(enum)
if err != nil {
return nil, err
}
if err := i.msg.TrySetField(field, v.GetNumber()); err != nil {
return nil, err
}
case entity.IsMessageType(field.GetType()):
nestedFields := i.dep[field.GetMessageType().GetFullyQualifiedName()].GetFields()
msgType := field.GetMessageType()
msg, err := newFieldInputter(i.prompt, i.prefixFormat, dynamic.NewMessage(msgType), msgType, false, i.color).Input(nestedFields)
if err != nil {
return nil, err
}
if err := i.msg.TrySetField(field, msg); err != nil {
return nil, err
}
if err := i.inputField(field); err != nil {
return nil, err
}

// increment prompt color to next one
i.color = (i.color + 1) % 16
default: // primitive type
if err := i.prompt.SetPrefix(makePrefix(i.prefixFormat, field, i.isTopLevelMessage)); err != nil {
return nil, err
}
if err := i.inputField(i.msg, field); err != nil {
return nil, err
if field.IsRepeated() {
for {
if err := i.inputField(field); err == EORF {
break
} else if err != nil {
return nil, err
}
}
}
}

return i.msg, nil
}

Expand Down Expand Up @@ -265,13 +231,81 @@ func (i *fieldInputter) chooseEnum(enum *desc.EnumDescriptor) (*desc.EnumValueDe
return d, nil
}

func (i *fieldInputter) inputField(req *dynamic.Message, field *desc.FieldDescriptor) error {
func (i *fieldInputter) inputField(field *desc.FieldDescriptor) error {
// if oneof, choose one from selection
if entity.IsOneOf(field) {
oneof := field.GetOneOf()
if i.encounteredOneof(oneof) {
return nil
}
var err error
field, err = i.chooseOneof(oneof)
if err != nil {
return err
}
}

switch {
case entity.IsEnumType(field):
enum := field.GetEnumType()
if i.encounteredEnum(enum) {
return nil
}
v, err := i.chooseEnum(enum)
if err != nil {
return err
}
if err := i.setField(i.msg, field, v.GetNumber()); err != nil {
return err
}
case entity.IsMessageType(field.GetType()):
nestedFields := i.dep[field.GetMessageType().GetFullyQualifiedName()].GetFields()
msgType := field.GetMessageType()
msg, err := newFieldInputter(i.prompt, i.prefixFormat, dynamic.NewMessage(msgType), msgType, false, i.color).Input(nestedFields)
if err != nil {
return err
}
if err := i.setField(i.msg, field, msg); err != nil {
return err
}

// increment prompt color to next one
i.color = (i.color + 1) % 16
default: // primitive type
if err := i.prompt.SetPrefix(makePrefix(i.prefixFormat, field, i.isTopLevelMessage)); err != nil {
return err
}
if err := i.inputPrimitiveField(i.msg, field); err != nil {
return err
}
}
return nil
}

func (i *fieldInputter) inputPrimitiveField(req *dynamic.Message, field *desc.FieldDescriptor) error {
in := i.prompt.Input()

if in == "" {
if i.enteredEmptyInput {
i.enteredEmptyInput = false
return EORF
}
i.enteredEmptyInput = true
// ignore the input
return i.inputPrimitiveField(req, field)
}

v, err := i.convertValue(in, field)
if err != nil {
return err
}
return i.setField(req, field, v)
}

func (i *fieldInputter) setField(req *dynamic.Message, field *desc.FieldDescriptor, v interface{}) error {
if field.IsRepeated() {
return req.TryAddRepeatedField(field, v)
}

return req.TrySetField(field, v)
}
Expand Down
2 changes: 1 addition & 1 deletion entity/field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func TestField(t *testing.T) {
t.Run("repeated", func(t *testing.T) {
d := parseFile(t, "repeated.proto")
msgs := d.GetMessageTypes()
assert.Len(t, msgs, 2)
assert.Len(t, msgs, 4)

m := newMessage(msgs[0])

Expand Down
2 changes: 1 addition & 1 deletion entity/oneof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
func TestOneOf(t *testing.T) {
d := parseFile(t, "oneof.proto")
msgs := d.GetMessageTypes()
require.Len(t, msgs, 1)
require.Len(t, msgs, 2)

m := newMessage(msgs[0])
require.Equal(t, m.Name(), "Example")
Expand Down
10 changes: 10 additions & 0 deletions entity/testdata/enum.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,13 @@ enum BookType {
HISTORY = 2;
SCIENCE = 3;
}

service Foo {
rpc Bar (Example) returns (ExampleResponse) {}
}

message Example {
BookType type = 1;
}

message ExampleResponse {}
6 changes: 6 additions & 0 deletions entity/testdata/oneof.proto
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
syntax = "proto3";
package example;

service Foo {
rpc Bar (Example) returns (ExampleResponse) {}
}

message Example {
oneof oneof_example {
string makise = 1;
string shiina = 2;
}
}

message ExampleResponse {}
10 changes: 10 additions & 0 deletions entity/testdata/repeated.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package helloworld;

service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse) {}
rpc SayHello2 (HelloRequest2) returns (HelloResponse) {}
}

message HelloRequest {
Expand All @@ -13,3 +14,12 @@ message HelloRequest {
message HelloResponse {
string message = 1;
}

message Person {
string first = 1;
string last = 2;
}

message HelloRequest2 {
repeated Person persons = 1;
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

const (
name = "evans"
version = "0.2.0"
version = "0.2.1"
)

func main() {
Expand Down

0 comments on commit fff2d19

Please sign in to comment.