Repository: ogen-go/ogen
Pull request #74 (2021-12-10 19:22:54)

refactor(spec): maps have pointer values


Patch:
diff --git a/internal/oas/parser/parse_parameter.go b/internal/oas/parser/parse_parameter.go
index 5662ba0d..2b8d33f2 100644
--- a/internal/oas/parser/parse_parameter.go
+++ b/internal/oas/parser/parse_parameter.go
@@ -9,7 +9,7 @@ import (
 	"github.com/ogen-go/ogen/internal/oas"
 )
 
-func (p *parser) parseParams(params []ogen.Parameter) ([]*oas.Parameter, error) {
+func (p *parser) parseParams(params []*ogen.Parameter) ([]*oas.Parameter, error) {
 	// Unique parameter is defined by a combination of a name and location.
 	type pnameLoc struct {
 		name     string
@@ -42,7 +42,7 @@ func (p *parser) parseParams(params []ogen.Parameter) ([]*oas.Parameter, error)
 	return result, nil
 }
 
-func (p *parser) parseParameter(param ogen.Parameter) (*oas.Parameter, error) {
+func (p *parser) parseParameter(param *ogen.Parameter) (*oas.Parameter, error) {
 	if ref := param.Ref; ref != "" {
 		parsed, err := p.resolveParameter(ref)
 		if err != nil {
@@ -68,7 +68,7 @@ func (p *parser) parseParameter(param ogen.Parameter) (*oas.Parameter, error) {
 		return nil, errors.New("path parameters must be required")
 	}
 
-	schema, err := p.parseSchema(param.Schema)
+	schema, err := p.parseSchema(&param.Schema)
 	if err != nil {
 		return nil, errors.Wrap(err, "schema")
 	}
diff --git a/internal/oas/parser/parse_request_body.go b/internal/oas/parser/parse_request_body.go
index ad84eb9b..524d7d4e 100644
--- a/internal/oas/parser/parse_request_body.go
+++ b/internal/oas/parser/parse_request_body.go
@@ -32,7 +32,7 @@ func (p *parser) parseRequestBody(body *ogen.RequestBody) (*oas.RequestBody, err
 			}
 		}
 
-		schema, err := p.parseSchema(media.Schema)
+		schema, err := p.parseSchema(&media.Schema)
 		if err != nil {
 			return nil, errors.Wrapf(err, "content: %s: parse schema", contentType)
 		}
diff --git a/internal/oas/parser/parse_response.go b/internal/oas/parser/parse_response.go
index 5d7b8b2a..3618e3cd 100644
--- a/internal/oas/parser/parse_response.go
+++ b/internal/oas/parser/parse_response.go
@@ -45,7 +45,7 @@ func (p *parser) parseResponses(responses ogen.Responses) (*oas.OperationRespons
 	return result, nil
 }
 
-func (p *parser) parseResponse(resp ogen.Response) (*oas.Response, error) {
+func (p *parser) parseResponse(resp *ogen.Response) (*oas.Response, error) {
 	if ref := resp.Ref; ref != "" {
 		resp, err := p.resolveResponse(ref)
 		if err != nil {
@@ -66,7 +66,7 @@ func (p *parser) parseResponse(resp ogen.Response) (*oas.Response, error) {
 			}
 		}
 
-		schema, err := p.parseSchema(media.Schema)
+		schema, err := p.parseSchema(&media.Schema)
 		if err != nil {
 			return nil, errors.Wrapf(err, "content: %s: schema", contentType)
 		}
diff --git a/internal/oas/parser/ref.go b/internal/oas/parser/ref.go
index 97decd45..5348230e 100644
--- a/internal/oas/parser/ref.go
+++ b/internal/oas/parser/ref.go
@@ -24,7 +24,7 @@ func (p *parser) resolveRequestBody(ref string) (*oas.RequestBody, error) {
 		return nil, errors.Errorf("component by reference %q not found", ref)
 	}
 
-	r, err := p.parseRequestBody(&component)
+	r, err := p.parseRequestBody(component)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/oas/parser/schema.go b/internal/oas/parser/schema.go
index d3860aa7..e8250a38 100644
--- a/internal/oas/parser/schema.go
+++ b/internal/oas/parser/schema.go
@@ -9,7 +9,7 @@ import (
 	"github.com/ogen-go/ogen/internal/oas"
 )
 
-func (p *parser) parseSchema(schema ogen.Schema) (*oas.Schema, error) {
+func (p *parser) parseSchema(schema *ogen.Schema) (*oas.Schema, error) {
 	gen := &schemaGen{
 		spec:       p.spec,
 		globalRefs: p.refs.schemas,
diff --git a/internal/oas/parser/schema_gen.go b/internal/oas/parser/schema_gen.go
index 94ffaea8..09e55bc1 100644
--- a/internal/oas/parser/schema_gen.go
+++ b/internal/oas/parser/schema_gen.go
@@ -26,7 +26,7 @@ type schemaGen struct {
 //
 // If ogen.Schema contains references to schema components,
 // these referenced schemas will be saved in g.localRefs.
-func (g *schemaGen) Generate(schema ogen.Schema) (*oas.Schema, error) {
+func (g *schemaGen) Generate(schema *ogen.Schema) (*oas.Schema, error) {
 	s, err := g.generate(schema, "")
 	if err != nil {
 		return nil, errors.Wrap(err, "gen")
@@ -35,7 +35,7 @@ func (g *schemaGen) Generate(schema ogen.Schema) (*oas.Schema, error) {
 	return s, nil
 }
 
-func (g *schemaGen) generate(schema ogen.Schema, ref string) (*oas.Schema, error) {
+func (g *schemaGen) generate(schema *ogen.Schema, ref string) (*oas.Schema, error) {
 	if ref := schema.Ref; ref != "" {
 		s, err := g.ref(ref)
 		if err != nil {
@@ -164,7 +164,7 @@ func (g *schemaGen) generate(schema ogen.Schema, ref string) (*oas.Schema, error
 			return nil, errors.New("array cannot contain properties")
 		}
 
-		item, err := g.generate(*schema.Items, "")
+		item, err := g.generate(schema.Items, "")
 		if err != nil {
 			return nil, errors.Wrap(err, "item")
 		}
diff --git a/internal/oas/parser/utils.go b/internal/oas/parser/utils.go
index 4b0d749f..ff642a23 100644
--- a/internal/oas/parser/utils.go
+++ b/internal/oas/parser/utils.go
@@ -2,7 +2,7 @@ package parser
 
 import "github.com/ogen-go/ogen"
 
-func forEachOps(item ogen.PathItem, f func(method string, op ogen.Operation) error) error {
+func forEachOps(item *ogen.PathItem, f func(method string, op ogen.Operation) error) error {
 	var err error
 	handle := func(method string, op *ogen.Operation) {
 		if err != nil || op == nil {
diff --git a/spec.go b/spec.go
index 319034cf..1216d4bb 100644
--- a/spec.go
+++ b/spec.go
@@ -26,16 +26,16 @@ func (s *Spec) Init() {
 
 	c := s.Components
 	if c.Schemas == nil {
-		c.Schemas = make(map[string]Schema)
+		c.Schemas = make(map[string]*Schema)
 	}
 	if c.Responses == nil {
-		c.Responses = make(map[string]Response)
+		c.Responses = make(map[string]*Response)
 	}
 	if c.Parameters == nil {
-		c.Parameters = make(map[string]Parameter)
+		c.Parameters = make(map[string]*Parameter)
 	}
 	if c.RequestBodies == nil {
-		c.RequestBodies = make(map[string]RequestBody)
+		c.RequestBodies = make(map[string]*RequestBody)
 	}
 }
 
@@ -82,11 +82,11 @@ type Server struct {
 // All objects defined within the components object will have no effect on the API
 // unless they are explicitly referenced from properties outside the components object.
 type Components struct {
-	Schemas    map[string]Schema    `json:"schemas,omitempty"`
-	Responses  map[string]Response  `json:"responses,omitempty"`
-	Parameters map[string]Parameter `json:"parameters,omitempty"`
+	Schemas    map[string]*Schema    `json:"schemas,omitempty"`
+	Responses  map[string]*Response  `json:"responses,omitempty"`
+	Parameters map[string]*Parameter `json:"parameters,omitempty"`
 	// Examples        map[string]Example         `json:"example"`
-	RequestBodies map[string]RequestBody `json:"requestBodies,omitempty"`
+	RequestBodies map[string]*RequestBody `json:"requestBodies,omitempty"`
 	// Headers         map[string]Header          `json:"headers"`
 	// SecuritySchemes map[string]SecuritySchema  `json:"securitySchemes"`
 	// Links           map[string]Link            `json:"links"`
@@ -96,7 +96,7 @@ type Components struct {
 // Paths holds the relative paths to the individual endpoints and their operations.
 // The path is appended to the URL from the Server Object in order to construct the full URL.
 // The Paths MAY be empty, due to ACL constraints.
-type Paths map[string]PathItem
+type Paths map[string]*PathItem
 
 // PathItem describes the operations available on a single path.
 // A Path Item MAY be empty, due to ACL constraints.
@@ -107,18 +107,18 @@ type PathItem struct {
 	// The referenced structure MUST be in the format of a Path Item Object.
 	// In case a Path Item Object field appears both
 	// in the defined object and the referenced object, the behavior is undefined.
-	Ref         string      `json:"$ref,omitempty"`
-	Description string      `json:"description,omitempty"`
-	Get         *Operation  `json:"get,omitempty"`
-	Put         *Operation  `json:"put,omitempty"`
-	Post        *Operation  `json:"post,omitempty"`
-	Delete      *Operation  `json:"delete,omitempty"`
-	Options     *Operation  `json:"options,omitempty"`
-	Head        *Operation  `json:"head,omitempty"`
-	Patch       *Operation  `json:"patch,omitempty"`
-	Trace       *Operation  `json:"trace,omitempty"`
-	Servers     []Server    `json:"servers,omitempty"`
-	Parameters  []Parameter `json:"parameters,omitempty"`
+	Ref         string       `json:"$ref,omitempty"`
+	Description string       `json:"description,omitempty"`
+	Get         *Operation   `json:"get,omitempty"`
+	Put         *Operation   `json:"put,omitempty"`
+	Post        *Operation   `json:"post,omitempty"`
+	Delete      *Operation   `json:"delete,omitempty"`
+	Options     *Operation   `json:"options,omitempty"`
+	Head        *Operation   `json:"head,omitempty"`
+	Patch       *Operation   `json:"patch,omitempty"`
+	Trace       *Operation   `json:"trace,omitempty"`
+	Servers     []Server     `json:"servers,omitempty"`
+	Parameters  []*Parameter `json:"parameters,omitempty"`
 }
 
 // Operation describes a single API operation on a path.
@@ -129,7 +129,7 @@ type Operation struct {
 	Summary     string       `json:"summary,omitempty"`
 	Description string       `json:"description,omitempty"`
 	OperationID string       `json:"operationId,omitempty"`
-	Parameters  []Parameter  `json:"parameters,omitempty"`
+	Parameters  []*Parameter `json:"parameters,omitempty"`
 	RequestBody *RequestBody `json:"requestBody,omitempty"`
 	Responses   Responses    `json:"responses,omitempty"`
 }
@@ -193,7 +193,7 @@ type RequestBody struct {
 
 // Responses is a container for the expected responses of an operation.
 // The container maps the HTTP response code to the expected response
-type Responses map[string]Response
+type Responses map[string]*Response
 
 // Response describes a single response from an API Operation,
 // including design-time, static links to operations based on the response.
@@ -257,13 +257,13 @@ type Schema struct {
 	// for independent validation but together compose a single object.
 	// Still, it does not imply a hierarchy between the models.
 	// For that purpose, you should include the discriminator.
-	AllOf []Schema `json:"allOf,omitempty"` // TODO: implement.
+	AllOf []*Schema `json:"allOf,omitempty"` // TODO: implement.
 
 	// OneOf validates the value against exactly one of the subschemas
-	OneOf []Schema `json:"oneOf,omitempty"` // TODO: implement.
+	OneOf []*Schema `json:"oneOf,omitempty"` // TODO: implement.
 
 	// AnyOf validates the value against any (one or more) of the subschemas
-	AnyOf []Schema `json:"anyOf,omitempty"` // TODO: implement.
+	AnyOf []*Schema `json:"anyOf,omitempty"` // TODO: implement.
 
 	// Discriminator for subschemas.
 	Discriminator *Discriminator `json:"discriminator,omitempty"`
@@ -401,7 +401,7 @@ type Schema struct {
 
 type Property struct {
 	Name   string
-	Schema Schema
+	Schema *Schema
 }
 
 type Properties []Property
@@ -426,13 +426,13 @@ func (p Properties) MarshalJSON() ([]byte, error) {
 func (p *Properties) UnmarshalJSON(data []byte) error {
 	d := jx.DecodeBytes(data)
 	return d.Obj(func(d *jx.Decoder, key string) error {
-		var s Schema
+		s := new(Schema)
 		b, err := d.Raw()
 		if err != nil {
 			return err
 		}
 
-		if err := json.Unmarshal(b, &s); err != nil {
+		if err := json.Unmarshal(b, s); err != nil {
 			return err
 		}
 


Test patch:
diff --git a/internal/oas/parser/schema_gen_test.go b/internal/oas/parser/schema_gen_test.go
index 97b2c182..a02e34a6 100644
--- a/internal/oas/parser/schema_gen_test.go
+++ b/internal/oas/parser/schema_gen_test.go
@@ -14,16 +14,16 @@ func TestSchemaSimple(t *testing.T) {
 		localRefs: make(map[string]*oas.Schema),
 	}
 
-	out, err := gen.Generate(ogen.Schema{
+	out, err := gen.Generate(&ogen.Schema{
 		Type: "object",
 		Properties: []ogen.Property{
 			{
 				Name:   "id",
-				Schema: ogen.Schema{Type: "integer"},
+				Schema: &ogen.Schema{Type: "integer"},
 			},
 			{
 				Name:   "name",
-				Schema: ogen.Schema{Type: "string"},
+				Schema: &ogen.Schema{Type: "string"},
 			},
 		},
 		Required: []string{"id", "name"},
@@ -52,21 +52,21 @@ func TestSchemaSimple(t *testing.T) {
 func TestSchemaRecursive(t *testing.T) {
 	spec := &ogen.Spec{
 		Components: &ogen.Components{
-			Schemas: map[string]ogen.Schema{
+			Schemas: map[string]*ogen.Schema{
 				"Pet": {
 					Type: "object",
 					Properties: []ogen.Property{
 						{
 							Name:   "id",
-							Schema: ogen.Schema{Type: "integer"},
+							Schema: &ogen.Schema{Type: "integer"},
 						},
 						{
 							Name:   "name",
-							Schema: ogen.Schema{Type: "string"},
+							Schema: &ogen.Schema{Type: "string"},
 						},
 						{
 							Name: "friends",
-							Schema: ogen.Schema{
+							Schema: &ogen.Schema{
 								Type: "array",
 								Items: &ogen.Schema{
 									Ref: "#/components/schemas/Pet",
@@ -137,7 +137,7 @@ func TestSchemaRecursive(t *testing.T) {
 		localRefs: make(map[string]*oas.Schema),
 	}
 
-	out, err := gen.Generate(ogen.Schema{
+	out, err := gen.Generate(&ogen.Schema{
 		Ref: "#/components/schemas/Pet",
 	})
 	require.NoError(t, err)
@@ -189,29 +189,29 @@ func TestSchemaSideEffects(t *testing.T) {
 		localRefs: make(map[string]*oas.Schema),
 	}
 
-	out, err := gen.Generate(ogen.Schema{
+	out, err := gen.Generate(&ogen.Schema{
 		Type: "object",
 		Properties: []ogen.Property{
 			{
 				Name:   "name",
-				Schema: ogen.Schema{Type: "string"},
+				Schema: &ogen.Schema{Type: "string"},
 			},
 			{
 				Name: "owner",
-				Schema: ogen.Schema{
+				Schema: &ogen.Schema{
 					Type: "object",
 					Properties: []ogen.Property{
 						{
 							Name:   "name",
-							Schema: ogen.Schema{Type: "string"},
+							Schema: &ogen.Schema{Type: "string"},
 						},
 						{
 							Name:   "age",
-							Schema: ogen.Schema{Type: "integer"},
+							Schema: &ogen.Schema{Type: "integer"},
 						},
 						{
 							Name:   "id",
-							Schema: ogen.Schema{Type: "integer"},
+							Schema: &ogen.Schema{Type: "integer"},
 						},
 					},
 					Required: []string{"name", "id", "age"},
@@ -228,7 +228,7 @@ func TestSchemaSideEffects(t *testing.T) {
 func TestSchemaReferencedArray(t *testing.T) {
 	spec := &ogen.Spec{
 		Components: &ogen.Components{
-			Schemas: map[string]ogen.Schema{
+			Schemas: map[string]*ogen.Schema{
 				"Pets": {
 					Type: "array",
 					Items: &ogen.Schema{
@@ -265,12 +265,12 @@ func TestSchemaReferencedArray(t *testing.T) {
 		localRefs: make(map[string]*oas.Schema),
 	}
 
-	out, err := gen.Generate(ogen.Schema{
+	out, err := gen.Generate(&ogen.Schema{
 		Type: "object",
 		Properties: []ogen.Property{
 			{
 				Name: "pets",
-				Schema: ogen.Schema{
+				Schema: &ogen.Schema{
 					Ref: "#/components/schemas/Pets",
 				},
 			},
diff --git a/spec_test.go b/spec_test.go
index 2089bb62..88bbc77b 100644
--- a/spec_test.go
+++ b/spec_test.go
@@ -15,11 +15,11 @@ func TestPropertiesJSON(t *testing.T) {
 	expect := Properties{
 		{
 			Name:   "foo",
-			Schema: Schema{Type: "integer"},
+			Schema: &Schema{Type: "integer"},
 		},
 		{
 			Name:   "bar",
-			Schema: Schema{Type: "string"},
+			Schema: &Schema{Type: "string"},
 		},
 	}
 	require.Equal(t, expect, props)