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

fix(137): Merge Validations When Using ReferenceTo #264

Merged
merged 3 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ generate: ## Generate files locally

.PHONY: lint
lint: ## Lint the code locally
@go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55 run ./...
@go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.0 run ./...

.PHONY: local-env/start
local-env/start: ## Start the local environment
@go run ./tools/generate-certs
@docker-compose local-env/start -d
@docker-compose up -d

.PHONY: local-env/stop
local-env/stop: ## Stop the local environment
Expand Down
2 changes: 1 addition & 1 deletion build/ci/dagger/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

const (
// linterImage is the image used for linter.
linterImage = "golangci/golangci-lint:v1.55"
linterImage = "golangci/golangci-lint:v1.62.0"
// golangImage is the image used as base for golang operations.
golangImage = "golang:1.21.4-alpine"
)
Expand Down
66 changes: 66 additions & 0 deletions pkg/asyncapi/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,69 @@ type Validations[T any] struct {
// --- Non JSON Schema/AsyncAPI fields -------------------------------------
IsRequired bool `json:"-"`
}

// Merge merges the newV into the current Validations.
//
//nolint:cyclop // This function is a merge function and it is expected to have a high cyclomatic complexity.
func (v *Validations[T]) Merge(newV Validations[T]) {
if len(newV.Required) > 0 {
v.Required = newV.Required
}
if len(newV.MultipleOf) > 0 {
v.MultipleOf = newV.MultipleOf
}
if newV.Maximum != 0 {
v.Maximum = newV.Maximum
}
if newV.ExclusiveMaximum != 0 {
v.ExclusiveMaximum = newV.ExclusiveMaximum
}
if newV.Minimum != 0 {
v.Minimum = newV.Minimum
}
if newV.ExclusiveMinimum != 0 {
v.ExclusiveMinimum = newV.ExclusiveMinimum
}
if newV.MaxLength != 0 {
v.MaxLength = newV.MaxLength
}
if newV.MinLength != 0 {
v.MinLength = newV.MinLength
}
if newV.Pattern != "" {
v.Pattern = newV.Pattern
}
if newV.MaxItems != 0 {
v.MaxItems = newV.MaxItems
}
if newV.MinItems != 0 {
v.MinItems = newV.MinItems
}
if newV.UniqueItems {
v.UniqueItems = newV.UniqueItems
}
if newV.MaxProperties != 0 {
v.MaxProperties = newV.MaxProperties
}
if newV.MinProperties != 0 {
v.MinProperties = newV.MinProperties
}
if len(newV.Enum) > 0 {
v.Enum = newV.Enum
}
if newV.Const != nil {
v.Const = newV.Const
}
if len(newV.AllOf) > 0 {
v.AllOf = newV.AllOf
}
if len(newV.AnyOf) > 0 {
v.AnyOf = newV.AnyOf
}
if len(newV.OneOf) > 0 {
v.OneOf = newV.OneOf
}
if newV.IsRequired {
v.IsRequired = newV.IsRequired
}
}
8 changes: 8 additions & 0 deletions pkg/asyncapi/v2/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ func (s *Schema) generateMetadata(name string, isRequired bool) error {
return nil
}

func (s *Schema) setValidationsFromReferenced(refTo *Schema) {
if refTo == nil {
return
}
s.Validations.Merge(refTo.Validations)
}

// setDependencies sets dependencies for the schema from the specification.
func (s *Schema) setDependencies(spec Specification) error {
// Reference to another schema if specified
Expand All @@ -113,6 +120,7 @@ func (s *Schema) setDependencies(spec Specification) error {
return err
}
s.ReferenceTo = refTo
s.setValidationsFromReferenced(refTo)
}

// Set properties dependencies
Expand Down
1 change: 1 addition & 0 deletions pkg/asyncapi/v3/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ func (s *Schema) setReference(spec Specification) error {
return err
}
s.ReferenceTo = refTo
s.Validations.Merge(refTo.Validations)

return nil
}
Expand Down
77 changes: 77 additions & 0 deletions test/v2/issues/137/asyncapi.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions test/v2/issues/137/asyncapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
asyncapi: 2.6.0
components:
schemas:
audit:
type: object
description: An audit event is a record of an event that has occurred in a system.
required:
- channel
properties:
channel:
$ref: '#/components/schemas/channel'
channel:
type: string
example: API
enum:
- API0
- API1
- API2
- API3
- API4
28 changes: 28 additions & 0 deletions test/v2/issues/137/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//go:generate go run ../../../../cmd/asyncapi-codegen -g types -p issue137 -i asyncapi.yaml -o ./asyncapi.gen.go
package issue137

import (
"reflect"
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestValidateOneOfExist(t *testing.T) {
var schema AuditSchema
field, ok := reflect.TypeOf(schema).FieldByName("Channel")
assert.True(t, ok)

validateTag, ok := field.Tag.Lookup("validate")
assert.True(t, ok)

var oneOfTag string
for _, tag := range strings.Split(validateTag, ",") {
if strings.HasPrefix(tag, "oneof=") {
oneOfTag = tag
}
}

assert.Equal(t, "oneof=API0 API1 API2 API3 API4", oneOfTag)
}
77 changes: 77 additions & 0 deletions test/v3/issues/137/asyncapi.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions test/v3/issues/137/asyncapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
asyncapi: 3.0.0
components:
schemas:
audit:
type: object
description: An audit event is a record of an event that has occurred in a system.
required:
- channel
properties:
channel:
$ref: '#/components/schemas/channel'
channel:
type: string
example: API
enum:
- API0
- API1
- API2
- API3
- API4
28 changes: 28 additions & 0 deletions test/v3/issues/137/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//go:generate go run ../../../../cmd/asyncapi-codegen -g types -p issue137 -i asyncapi.yaml -o ./asyncapi.gen.go
package issue137

import (
"reflect"
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestValidateOneOfExist(t *testing.T) {
var schema AuditSchema
field, ok := reflect.TypeOf(schema).FieldByName("Channel")
assert.True(t, ok)

validateTag, ok := field.Tag.Lookup("validate")
assert.True(t, ok)

var oneOfTag string
for _, tag := range strings.Split(validateTag, ",") {
if strings.HasPrefix(tag, "oneof=") {
oneOfTag = tag
}
}

assert.Equal(t, "oneof=API0 API1 API2 API3 API4", oneOfTag)
}