Skip to content

Commit

Permalink
- decoupled openapi documentation from struct tag
Browse files Browse the repository at this point in the history
  • Loading branch information
adranwit committed Nov 14, 2024
1 parent 1bdbafb commit 8c0a152
Show file tree
Hide file tree
Showing 21 changed files with 267 additions and 190 deletions.
18 changes: 18 additions & 0 deletions gateway/router/openapi/openapi3.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/viant/datly/shared"
"github.com/viant/datly/view"
"github.com/viant/datly/view/state"
"github.com/viant/datly/view/tags"
"github.com/viant/xdatly/handler/response"
"net/http"
"reflect"
Expand Down Expand Up @@ -270,6 +271,15 @@ func (g *generator) appendBuiltInParam(ctx context.Context, params *[]*openapi.P
}

func (g *generator) convertParam(ctx context.Context, component *ComponentSchema, param *state.Parameter, description string) ([]*openapi.Parameter, bool, error) {

docs := component.component.Docs()
parameters := docs.Parameters
if len(parameters) > 0 && param.Description == "" {
if desc, ok := parameters.ByName(param.Name); ok {
param.Description = desc
description = desc
}
}
if param.In.Kind == state.KindParam {
baseParam := component.component.LookupParameter(param.In.Name)
return g.convertParam(ctx, component, baseParam, description)
Expand Down Expand Up @@ -307,9 +317,17 @@ func (g *generator) convertParam(ctx context.Context, component *ComponentSchema
return []*openapi.Parameter{{Ref: "#/components/parameters/" + param.Name}}, true, nil
}

table := ""
if param.Tag != "" {
if datlyTags, _ := tags.Parse(reflect.StructTag(param.Tag), nil, tags.ViewTag); datlyTags != nil && datlyTags.View != nil {
table = datlyTags.View.Table
}

}
schema, err := component.GenerateSchema(ctx, component.SchemaWithTag(param.Name, param.Schema.Type(), "Parameter "+param.Name+" schema", component.component.IOConfig(), Tag{
Format: param.DateFormat,
IsNullable: !param.IsRequired(),
Table: table,
}))

if err != nil {
Expand Down
55 changes: 54 additions & 1 deletion gateway/router/openapi/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ type (
component *repository.Component
components *repository.Service
schemas *SchemaContainer
docs *state.Docs
doc docs.Service
}

Schema struct {
docs *state.Docs
pkg string
path string
fieldName string
Expand Down Expand Up @@ -84,6 +86,7 @@ func (s *Schema) Field(field reflect.StructField, tag *Tag) (*Schema, error) {

result.description = field.Tag.Get(tags.DescriptionTag)
result.example = field.Tag.Get(tags.ExampleTag)

return &result, nil
}

Expand Down Expand Up @@ -159,6 +162,7 @@ func (c *ComponentSchema) TypedSchema(ctx context.Context, stateType state.Type,
rType: rType,
ioConfig: ioConfig,
isInput: isInput,
docs: c.component.Docs(),
}, nil
}

Expand Down Expand Up @@ -237,6 +241,7 @@ func (c *ComponentSchema) SchemaWithTag(fieldName string, rType reflect.Type, de
rType: rType,
tag: tag,
ioConfig: ioConfig,
docs: c.component.Docs(),
}
}
func (c *ComponentSchema) GenerateSchema(ctx context.Context, schema *Schema) (*openapi3.Schema, error) {
Expand Down Expand Up @@ -278,6 +283,7 @@ func (c *SchemaContainer) addToSchema(ctx context.Context, component *ComponentS
if schema.tag.Example != "" {
dst.Example = schema.tag.Example
}
rootTable := component.component.View.Table

switch rType.Kind() {
case reflect.Slice, reflect.Array:
Expand Down Expand Up @@ -314,13 +320,14 @@ func (c *SchemaContainer) addToSchema(ctx context.Context, component *ComponentS
dst.Properties = openapi3.Schemas{}
dst.Type = objectOutput
numField := rType.NumField()
table := schema.tag.Table
for i := 0; i < numField; i++ {
aField := rType.Field(i)
if aField.PkgPath != "" {
continue
}

aTag, err := ParseTag(aField, aField.Tag, schema.isInput)
aTag, err := ParseTag(aField, aField.Tag, schema.isInput, rootTable)
if err != nil {
return err
}
Expand All @@ -329,6 +336,27 @@ func (c *SchemaContainer) addToSchema(ctx context.Context, component *ComponentS
continue
}

if aTag.Column != "" && table == "" {
table = rootTable
}

if table != "" && aTag.Column == "" {
aTag.Column = text.DetectCaseFormat(aField.Name).To(text.CaseFormatUpperUnderscore).Format(aField.Name)
}

if aTag.Column != "" {
columns := component.component.Docs().Columns
if aTag.Description == "" {
aTag.Description, _ = columns.ColumnDescription(table, aTag.Column)
}
if aTag.Description == "" {
aTag.Description, _ = columns.ColumnDescription(table, aTag.Column)
}
if aTag.Example == "" {
aTag.Description, _ = columns.ColumnExample(table, aTag.Column)
}
}

if aTag.Inlined {
dst.AdditionalPropertiesAllowed = setter.BoolPtr(true)
continue
Expand All @@ -342,6 +370,31 @@ func (c *SchemaContainer) addToSchema(ctx context.Context, component *ComponentS
continue
}

if strings.Contains(fieldSchema.name, "ata") {
fmt.Printf("")
}
docs := component.component.Docs()
documentedPaths := docs.Paths
if aTag.Description == "" && len(documentedPaths) > 0 {
if desc, ok := documentedPaths.ByName(fieldSchema.path); ok {
aTag.Description = desc
fieldSchema.description = desc
} else if desc, ok := documentedPaths.ByName(aField.Name); ok {
aTag.Description = desc
fieldSchema.description = desc
}
}

if aTag.Example == "" && len(documentedPaths) > 0 {
if example, ok := documentedPaths.ByName(fieldSchema.path + "$example"); ok {
aTag.Example = example
fieldSchema.example = example
} else if example, ok := documentedPaths.ByName(aField.Name + "$example"); ok {
aTag.Example = example
fieldSchema.example = example
}
}

if aField.Anonymous {
if err := c.addToSchema(ctx, component, dst, fieldSchema); err != nil {
return err
Expand Down
29 changes: 26 additions & 3 deletions gateway/router/openapi/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (
"github.com/viant/datly/view/state"
"github.com/viant/datly/view/tags"
"github.com/viant/govalidator"
"github.com/viant/sqlx/io"
"github.com/viant/tagly/format"
"github.com/viant/xreflect"
"reflect"
"strings"
)

type (
Expand All @@ -34,10 +36,12 @@ type (
_tag format.Tag
TypeName string
Parameter *tags.Parameter
Column string
Table string
}
)

func ParseTag(field reflect.StructField, tag reflect.StructTag, isInput bool) (*Tag, error) {
func ParseTag(field reflect.StructField, tag reflect.StructTag, isInput bool, rootTable string) (*Tag, error) {

aTag, err := format.Parse(tag, "json", "openapi")
if err != nil {
Expand Down Expand Up @@ -77,15 +81,34 @@ func ParseTag(field reflect.StructField, tag reflect.StructTag, isInput bool) (*
_tag: *aTag,
}

if tags, _ := tags.Parse(tag, nil, tags.ParameterTag); tags != nil && isInput {
if tags, _ := tags.Parse(tag, nil, tags.ParameterTag); tags != nil {
ret.Parameter = tags.Parameter
if parameter := ret.Parameter; parameter != nil && parameter.Kind != "" {
switch state.Kind(parameter.Kind) {
case state.KindForm, state.KindRequestBody:
case state.KindOutput:
switch parameter.In {
case "summary":
ret.Table = strings.ToUpper(parameter.In)
case "view":
ret.Table = rootTable
}
default:
ret.Ignore = true
if isInput {
ret.Ignore = true
}
}
}
}

if tags, _ := tags.Parse(tag, nil, tags.ViewTag); tags != nil && isInput {
if tags.View != nil && tags.View.Table != "" {
ret.Table = tags.View.Table
}
}
if sqlxTag := io.ParseTag(tag); sqlxTag != nil {
ret.Column = sqlxTag.Column
}

return ret, nil
}
4 changes: 2 additions & 2 deletions internal/inference/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ func (s *Spec) EnsureRelationType() {
}

// BuildType build a type from infered table/SQL definition
func (s *Spec) BuildType(pkg, name string, cardinality state.Cardinality, whitelist, blacklist map[string]bool, doc state.Documentation) error {
func (s *Spec) BuildType(pkg, name string, cardinality state.Cardinality, whitelist, blacklist map[string]bool) error {
var aType = &Type{Package: pkg, Name: name, Cardinality: cardinality}
for i, column := range s.Columns {
skipped := s.shouldSkipColumn(whitelist, blacklist, column)
field, err := aType.AppendColumnField(s.Columns[i], skipped, doc, s.Table)
field, err := aType.AppendColumnField(s.Columns[i], skipped, s.Table)
if err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions internal/inference/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ func (t *Tags) Stringify() string {
return builder.String()
}

func (t *Tags) ViewTag(table string) {
t.Set("view", TagValue{"table=", table})
}

func SqlxTag(tag reflect.StructTag) *io.Tag {
datlyTagString, _ := tag.Lookup(io.TagSqlx)
if datlyTagString == "" {
Expand Down
23 changes: 8 additions & 15 deletions internal/inference/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/viant/datly/view"
dConfig "github.com/viant/datly/view/extension"
"github.com/viant/datly/view/state"
"github.com/viant/datly/view/tags"
"github.com/viant/sqlparser"
"github.com/viant/structology"
"github.com/viant/tagly/format/text"
Expand Down Expand Up @@ -83,7 +82,7 @@ func (t *Type) ExpandType(simpleName string) string {
return pkg + "." + simpleName
}

func (t *Type) AppendColumnField(column *sqlparser.Column, skipped bool, doc state.Documentation, table string) (*Field, error) {
func (t *Type) AppendColumnField(column *sqlparser.Column, skipped bool, table string) (*Field, error) {
columnNameOrAlias := column.Alias
if columnNameOrAlias == "" {
columnNameOrAlias = column.Name
Expand All @@ -98,15 +97,6 @@ func (t *Type) AppendColumnField(column *sqlparser.Column, skipped bool, doc sta
Ptr: column.IsNullable,
Tags: Tags{},
}

if doc != nil {
if fieldDoc, ok := doc.ColumnDescription(table, field.Column.Name); ok {
field.Tags.Set(tags.DescriptionTag, TagValue{fieldDoc})
}
if fieldDoc, ok := doc.ColumnExample(table, field.Column.Name); ok {
field.Tags.Set(tags.ExampleTag, TagValue{fieldDoc})
}
}
if column.Type == "" {
return nil, fmt.Errorf("failed to match type: %v %v %v\n", column.Alias, column.Name, column.Expression)
}
Expand Down Expand Up @@ -164,10 +154,10 @@ func (t *Type) ColumnFields(table string, doc state.Documentation) []*view.Field
field.Ptr = true
}

if doc != nil {
field.Description, _ = doc.ColumnDescription(table, t.columnFields[i].Column.Name)
field.Example, _ = doc.ColumnExample(table, t.columnFields[i].Column.Name)
}
//if doc != nil {
// field.Description, _ = doc.ColumnDescription(table, t.columnFields[i].Column.Name)
// field.Example, _ = doc.ColumnExample(table, t.columnFields[i].Column.Name)
//}

result = append(result, &field)
}
Expand All @@ -184,6 +174,9 @@ func (t *Type) AddRelation(name string, spec *Spec, relation *Relation) *Field {
field.Tags.Set("sqlx", TagValue{"-"})
field.Relation = relation.Name
field.Tags.buildRelation(spec, relation)
if relation.Table != "" {
field.Tags.ViewTag(relation.Table)
}
field.Tag = field.Tags.Stringify()
t.RelationFields = append(t.RelationFields, field)
return field
Expand Down
2 changes: 1 addition & 1 deletion internal/translator/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (s *Service) updateOutputParameters(resource *Resource, rootViewlet *Viewle
s.updateParameterWithComponentOutputType(dataParameter, rootViewlet)
}

if err := contract.EnsureParameterTypes(outputParameters, nil, resource.Rule.Doc.Parameters, resource.Rule.Doc.Filter); err != nil {
if err := contract.EnsureParameterTypes(outputParameters, nil); err != nil {
return err
}
for _, parameter := range outputParameters {
Expand Down
6 changes: 5 additions & 1 deletion internal/translator/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,12 @@ func (r *Repository) RuleBaseURL(rule *options.Rule) string {
return url.Join(r.Config.Config.RouteURL, rule.ModulePrefix)
}

func (r *Repository) DocBaseURL() string {
return url.Join(r.Config.repository.RepositoryURL, "Datly/doc")
}

func (r *Repository) ContentBaseURL(rule *options.Rule) string {
return url.Join(r.Config.Config.ContentURL, rule.ModulePrefix)
return url.Join(r.Config.Config.DependencyURL, "doc")
}

func (r *Repository) LookupDb(name string) (*sql.DB, error) {
Expand Down
9 changes: 2 additions & 7 deletions internal/translator/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,6 @@ func (r *Resource) ExtractDeclared(dSQL *string) (err error) {
if r.State, err = r.State.NormalizeComposites(); err != nil {
return fmt.Errorf("failed to normalize input state: %w", err)
}

if doc := r.Rule.Doc.Parameters; doc != nil {
r.State.AddDescriptions(doc)
}

if r.OutputState, err = r.OutputState.NormalizeComposites(); err != nil {
return fmt.Errorf("failed to normalize output state: %w", err)
}
Expand Down Expand Up @@ -438,7 +433,7 @@ func (r *Resource) expandSQL(viewlet *Viewlet) (*sqlx.SQL, error) {
return viewlet.View.BuildParametrizedSQL(templateParameters, types, sourceSQL, bindingArgs, options...)
}

func (r *Resource) ensureViewParametersSchema(ctx context.Context, setType func(ctx context.Context, setType *Viewlet, doc state.Documentation) error, aDoc state.Documentation) error {
func (r *Resource) ensureViewParametersSchema(ctx context.Context, setType func(ctx context.Context, setType *Viewlet) error) error {
viewParameters := r.State.FilterByKind(state.KindView)
for _, viewParameter := range viewParameters {
if viewParameter.Schema != nil && viewParameter.Schema.Type() != nil {
Expand All @@ -449,7 +444,7 @@ func (r *Resource) ensureViewParametersSchema(ctx context.Context, setType func(
}
viewParameter.EnsureSchema()
aViewNamespace := r.Rule.Viewlets.Lookup(viewParameter.In.Name)
if err := setType(ctx, aViewNamespace, aDoc); err != nil {
if err := setType(ctx, aViewNamespace); err != nil {
return err
}
fields := aViewNamespace.Spec.Type.Fields()
Expand Down
Loading

0 comments on commit 8c0a152

Please sign in to comment.