Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Service() #1139

Merged
merged 19 commits into from Apr 18, 2017
Merged

Implement Service() #1139

merged 19 commits into from Apr 18, 2017

Conversation

tchssk
Copy link
Member

@tchssk tchssk commented Mar 23, 2017

Copy link
Member

@raphael raphael left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Left a few small comments.
One thing that might be missing is the case where a payload or result type uses another type in the design. In this case that other type also needs to be generated. Seems like the code needs to traverse all the attributes recursively and collect all the types (using Walk https://github.com/goadesign/goa/blob/v2/design/types.go#L68).

{
header = codegen.Header(s.service.Name+"Services", "services",
[]*codegen.ImportSpec{
&codegen.ImportSpec{Path: "context"},

This comment was marked as off-topic.

This comment was marked as off-topic.

methods := make([]*serviceMethod, len(s.service.Endpoints))
for i, v := range s.service.Endpoints {
fields := make(map[string]string)
if o, ok := v.Payload.Attribute().Type.(design.Object); ok {

This comment was marked as off-topic.

This comment was marked as off-topic.

const serviceT = `type (
// {{ .VarName }} is the {{ .Name }} service interface.
{{ .VarName }} interface {
{{ range .Methods }} // {{ .Name }} implements the {{ .Name }} endpoint.

This comment was marked as off-topic.

This comment was marked as off-topic.

&b,
},
}
_ = multipleEndpoints

This comment was marked as off-topic.

This comment was marked as off-topic.

@raphael
Copy link
Member

raphael commented Mar 24, 2017

Thanks for all the changes, looks good. Are you working on recursively tracking the types that need to be generated? seems like it's the last item remaining.

@tchssk
Copy link
Member Author

tchssk commented Mar 26, 2017

Yes, I'm working on that.

It seems we have to improve GoTypeName() and GoNativeType() before using Walk() so I'll add some commits first.

@tchssk
Copy link
Member Author

tchssk commented Mar 26, 2017

I'm going forward step by step so I pushed commits about GoNativeType first. Please take a look these commits.

  • de8d8c6 adds tests for GoNativeType().
  • abddedc supports Map, Object and UserType in GoNativeType().

@raphael
Copy link
Member

raphael commented Mar 27, 2017

The GoNativeType implementation and tests look good. Something I've been wondering is whether we should add back DateTime as a type in v2. I was thinking initially that it could just be String with a special datetime format. But after thinking it through and looking at real APIs it seems having a DateTime as first class type in the design might be better. What do you think?

@tchssk
Copy link
Member Author

tchssk commented Mar 27, 2017

v1 has DateTimeKind and has DateTime as Primitive so we can design v2 as same way as that. Maybe it's useful for OpenAPI (Swagger) but v2 supports also gRPC.

It's a big topic for v2. Do we open a new issue and discuss about that? At this point, I can continue this PR to support only existing types and we can add more types support as needed in the future.

@tchssk
Copy link
Member Author

tchssk commented Mar 27, 2017

I pushed a new commit.

  • 3264349 tracks the types recursively in Service().

@tchssk
Copy link
Member Author

tchssk commented Mar 28, 2017

In the way you shown, I could track only top level fields (means Parent in your example) in the payload. It seems we have to track the types recursively using ut.Walk().

We also might need a function like GoTypeDef() in v1 to write each type definitions.

@raphael
Copy link
Member

raphael commented Mar 28, 2017

Yes you're right - it has to be recursive. And also agree on needing something like GoTypeDef. Last commit looks great BTW.

@tchssk
Copy link
Member Author

tchssk commented Mar 30, 2017

I pushed new commits.

41a41a2 implements GoTypeDef().
9c6ddd8 renders results in Service().
47757ca tracks the types recursively in Service().

I didn't add an argument to indent codes in GoTypeDef() but the codes will be gofmt ed, right?

@raphael
Copy link
Member

raphael commented Mar 30, 2017

Looks good overall! a couple of comments:

Cycles

I think the walker code needs to handle cycles, consider this design:

var Parent = Type("parent", func() {
    Attribute("c", Child)
})

var Child = Type("child", func() {
    Attribute("p", "parent")
})

This is a legal definition that will cause the walker to recurse infinitely. I think it needs to recurse only if the type is not already in the hash.

Indenting

Yes the code gets gofmted however the idea so far has been to render code that was properly formatted and use gofmt as a last resort. However it might be better to give up on trying to generate code that is properly indented and just rely on gofmt. The added complexity involved in generating the proper level of indentation (esp. with recursive algorithms) may not be worth it. However if we do that we should do it consistently everywhere.

So @michaelboke @tchssk let's do a quick vote here :) do we indent the generated code using gofmt or via the templates? I vote gofmt.

@tchssk
Copy link
Member Author

tchssk commented Mar 30, 2017

gofmt +1

@tchssk
Copy link
Member Author

tchssk commented Mar 30, 2017

Cycles

ea09cbe avoids infinite recursion in Service().

@michaelboke
Copy link
Contributor

michaelboke commented Mar 30, 2017 via email

@raphael
Copy link
Member

raphael commented Mar 30, 2017

Agree on keeping formatting as good as possible. The idea here is mainly to remove the tracking of indentation - that is remove the depth argument from all the template functions and instead always format properly but with a level of indentation of 0.

@tchssk
Copy link
Member Author

tchssk commented Mar 30, 2017

I tried to write the codes from the idea.

f0ed658 removes indents and use gofmt for tests.

or another implementation.

f628868 formats codes by gofmt in Section.Write().

@tchssk
Copy link
Member Author

tchssk commented Apr 7, 2017

Once it seems finished. or Do I have anything to do more?

Copy link
Member

@raphael raphael left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! thank you. It might be good to have a few more tests that cover all the case, something like:

  • With empty payload, empty result
  • With non empty payload but empty result
  • With empty payload and non empty result
  • With non empty payload and non empty result.

For the non empty tests it would also be good to cover all the data types (primitive, array, map, object, user and media types).

The tests here are good, I'm hoping we can be systematic and use variable names that are consistent for the others as well (like you have with APayload etc.).

codegen/types.go Outdated
return fmt.Sprintf("map[%s]%s", keyDef, elemDef)
case design.Object:
return goTypeDefObject(actual)
case *design.UserTypeExpr:

This comment was marked as off-topic.

This comment was marked as off-topic.

codegen/types.go Outdated
return fmt.Sprintf("map[%s]%s", GoNativeType(actual.KeyType.Type), GoNativeType(actual.ElemType.Type))
case design.Object:
return "map[string]interface{}"
case *design.UserTypeExpr:

This comment was marked as off-topic.

This comment was marked as off-topic.

codegen/types.go Outdated
return fmt.Sprintf("map[%s]%s", GoNativeType(actual.KeyType.Type), GoNativeType(actual.ElemType.Type))
case design.Object:
return "map[string]interface{}"
case *design.UserTypeExpr:

This comment was marked as off-topic.

This comment was marked as off-topic.

codegen/types.go Outdated
@@ -143,7 +143,7 @@ func goTypeDefObject(o design.Object) string {
var ss []string
ss = append(ss, "struct {")
o.WalkAttributes(func(name string, at *design.AttributeExpr) error {
ss = append(ss, fmt.Sprintf("%s %s", name, GoTypeName(at.Type)))
ss = append(ss, fmt.Sprintf("\t%s %s", name, GoTypeName(at.Type)))

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

@tchssk
Copy link
Member Author

tchssk commented Apr 9, 2017

a97bc6b uses UserType instead of UserTypeExpr.

codegen/types.go Outdated
case *design.UserTypeExpr:
return GoTypeName(actual)
case design.UserType:
return GoTypeName(actual.Attribute().Type)

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

@tchssk
Copy link
Member Author

tchssk commented Apr 17, 2017

fc7a5b1 adds tests about empty payload and empty result.

@tchssk
Copy link
Member Author

tchssk commented Apr 18, 2017

Travis failed with error that WalkAttributes() methods of design.Object not found. This seems to be caused by #1164.

@raphael
Copy link
Member

raphael commented Apr 18, 2017

Yes this PR moved the walkers to the code generation package (files.WalkAttributes) because the design and DSL engine don't use it, only code generation does.

@tchssk
Copy link
Member Author

tchssk commented Apr 18, 2017

Shoud I rebase this branch onto v2?

@raphael
Copy link
Member

raphael commented Apr 18, 2017

Yeah, that would probably make sense

@raphael
Copy link
Member

raphael commented Apr 18, 2017

Actually I'll merge and rebase since I need some of the changes in this PR (the GoTypeName changes).

@raphael raphael merged commit 444cdf1 into goadesign:v2 Apr 18, 2017
raphael pushed a commit that referenced this pull request Apr 18, 2017
* Implement Service()

* Use design.AsObject() instead of type assertion

* Elide the respective literal type

* Delete debug codes

* Use Name and VarName differently in serviceMethod

* Add tests for GoNativeType()

* Support Map, Object and UserType in GoNativeType()

* Track the types recursively in Service()

* Separate template using define

* Implement GoTypeDef()

* Render results in Service()

* Track the types recursively in Service()

* Avoid infinite recursion in Service()

* Remove indents and use gofmt for tests

* Set indents in goTypeDefObject()

* Set indents in Service()

* Use UserType instead of UserTypeExpr

* Fix GoTypeDef() about UserType

* Add tests about empty payload and empty result
@tchssk tchssk deleted the v2-writers-service branch April 25, 2017 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants