diff --git a/codegen/service/service_data.go b/codegen/service/service_data.go index 7d927832fd..b55cc98d2e 100644 --- a/codegen/service/service_data.go +++ b/codegen/service/service_data.go @@ -598,7 +598,16 @@ func (d ServicesData) analyze(service *expr.ServiceExpr) *Data { projected := seenProj[rt.ID()] projAtt := &expr.AttributeExpr{Type: projected.Type} vrt := buildViewedResultType(e.Result, projAtt, viewspkg, scope, viewScope) - viewedRTs = append(viewedRTs, vrt) + found := false + for _, rt := range viewedRTs { + if rt.Type.ID() == vrt.Type.ID() { + found = true + break + } + } + if !found { + viewedRTs = append(viewedRTs, vrt) + } m.ViewedResult = vrt seenViewed[vrt.Name+"::"+view] = vrt } diff --git a/codegen/service/service_test.go b/codegen/service/service_test.go index 6ecf30534f..e40fd66b44 100644 --- a/codegen/service/service_test.go +++ b/codegen/service/service_test.go @@ -25,6 +25,7 @@ func TestService(t *testing.T) { {"no-payload-result", testdata.EmptyPayloadMethodDSL, testdata.EmptyPayloadMethod}, {"payload-result-with-default", testdata.WithDefaultDSL, testdata.WithDefault}, {"result-with-multiple-views", testdata.MultipleMethodsResultMultipleViewsDSL, testdata.MultipleMethodsResultMultipleViews}, + {"result-with-explicit-and-default-views", testdata.WithExplicitAndDefaultViewsDSL, testdata.WithExplicitAndDefaultViews}, {"result-collection-multiple-views", testdata.ResultCollectionMultipleViewsMethodDSL, testdata.ResultCollectionMultipleViewsMethod}, {"result-with-other-result", testdata.ResultWithOtherResultMethodDSL, testdata.ResultWithOtherResultMethod}, {"result-with-result-collection", testdata.ResultWithResultCollectionMethodDSL, testdata.ResultWithResultCollectionMethod}, diff --git a/codegen/service/testdata/service_code.go b/codegen/service/testdata/service_code.go index 5951e05dfe..961fb7ce5b 100644 --- a/codegen/service/testdata/service_code.go +++ b/codegen/service/testdata/service_code.go @@ -539,6 +539,106 @@ func newSingleViewView(res *SingleView) *multiplemethodsresultmultipleviewsviews } ` +const WithExplicitAndDefaultViews = ` +// Service is the WithExplicitAndDefaultViews service interface. +type Service interface { + // A implements A. + // The "view" return value must have one of the following views + // - "default" + // - "tiny" + A(context.Context) (res *MultipleViews, view string, err error) + // A implements A. + AEndpoint(context.Context) (res *MultipleViews, err error) +} + +// ServiceName is the name of the service as defined in the design. This is the +// same value that is set in the endpoint request contexts under the ServiceKey +// key. +const ServiceName = "WithExplicitAndDefaultViews" + +// MethodNames lists the service method names as defined in the design. These +// are the same values that are set in the endpoint request contexts under the +// MethodKey key. +var MethodNames = [2]string{"A", "A"} + +// MultipleViews is the result type of the WithExplicitAndDefaultViews service +// A method. +type MultipleViews struct { + A string + B int +} + +// NewMultipleViews initializes result type MultipleViews from viewed result +// type MultipleViews. +func NewMultipleViews(vres *withexplicitanddefaultviewsviews.MultipleViews) *MultipleViews { + var res *MultipleViews + switch vres.View { + case "default", "": + res = newMultipleViews(vres.Projected) + case "tiny": + res = newMultipleViewsTiny(vres.Projected) + } + return res +} + +// NewViewedMultipleViews initializes viewed result type MultipleViews from +// result type MultipleViews using the given view. +func NewViewedMultipleViews(res *MultipleViews, view string) *withexplicitanddefaultviewsviews.MultipleViews { + var vres *withexplicitanddefaultviewsviews.MultipleViews + switch view { + case "default", "": + p := newMultipleViewsView(res) + vres = &withexplicitanddefaultviewsviews.MultipleViews{Projected: p, View: "default"} + case "tiny": + p := newMultipleViewsViewTiny(res) + vres = &withexplicitanddefaultviewsviews.MultipleViews{Projected: p, View: "tiny"} + } + return vres +} + +// newMultipleViews converts projected type MultipleViews to service type +// MultipleViews. +func newMultipleViews(vres *withexplicitanddefaultviewsviews.MultipleViewsView) *MultipleViews { + res := &MultipleViews{} + if vres.A != nil { + res.A = *vres.A + } + if vres.B != nil { + res.B = *vres.B + } + return res +} + +// newMultipleViewsTiny converts projected type MultipleViews to service type +// MultipleViews. +func newMultipleViewsTiny(vres *withexplicitanddefaultviewsviews.MultipleViewsView) *MultipleViews { + res := &MultipleViews{} + if vres.A != nil { + res.A = *vres.A + } + return res +} + +// newMultipleViewsView projects result type MultipleViews to projected type +// MultipleViewsView using the "default" view. +func newMultipleViewsView(res *MultipleViews) *withexplicitanddefaultviewsviews.MultipleViewsView { + vres := &withexplicitanddefaultviewsviews.MultipleViewsView{ + A: &res.A, + B: &res.B, + } + return vres +} + +// newMultipleViewsViewTiny projects result type MultipleViews to projected +// type MultipleViewsView using the "tiny" view. +func newMultipleViewsViewTiny(res *MultipleViews) *withexplicitanddefaultviewsviews.MultipleViewsView { + vres := &withexplicitanddefaultviewsviews.MultipleViewsView{ + A: &res.A, + } + return vres +} +` + const ResultCollectionMultipleViewsMethod = ` // Service is the ResultCollectionMultipleViewsMethod service interface. type Service interface { diff --git a/codegen/service/testdata/service_dsls.go b/codegen/service/testdata/service_dsls.go index 3aa9dd2a7e..b61c128d94 100644 --- a/codegen/service/testdata/service_dsls.go +++ b/codegen/service/testdata/service_dsls.go @@ -201,6 +201,34 @@ var MultipleMethodsResultMultipleViewsDSL = func() { }) } +var WithExplicitAndDefaultViewsDSL = func() { + var RTWithViews = ResultType("application/vnd.result.multiple.views", func() { + TypeName("MultipleViews") + Attributes(func() { + Attribute("a", String) + Attribute("b", Int) + Required("a", "b") + }) + View("default", func() { + Attribute("a") + Attribute("b") + }) + View("tiny", func() { + Attribute("a") + }) + }) + Service("WithExplicitAndDefaultViews", func() { + Method("A", func() { + Result(RTWithViews) + }) + Method("A", func() { + Result(RTWithViews, func() { + View("tiny") + }) + }) + }) +} + var ResultCollectionMultipleViewsMethodDSL = func() { var RTWithViews = ResultType("application/vnd.result.multiple.views", func() { TypeName("MultipleViews")