Skip to content

Commit

Permalink
add prefix to scalars and objects also
Browse files Browse the repository at this point in the history
  • Loading branch information
hgiasac committed Nov 16, 2024
1 parent 86d6e6e commit 6c06e70
Show file tree
Hide file tree
Showing 18 changed files with 459 additions and 404 deletions.
107 changes: 0 additions & 107 deletions ndc-http-schema/openapi/internal/cleanup.go

This file was deleted.

190 changes: 190 additions & 0 deletions ndc-http-schema/openapi/internal/ndc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package internal

import (
"errors"
"fmt"

rest "github.com/hasura/ndc-http/ndc-http-schema/schema"
"github.com/hasura/ndc-http/ndc-http-schema/utils"
"github.com/hasura/ndc-sdk-go/schema"
)

// NDCBuilder the NDC schema builder to validate REST connector schema.
type NDCBuilder struct {
*ConvertOptions

schema *rest.NDCHttpSchema
newSchema *rest.NDCHttpSchema
usedTypes map[string]string
}

// NewNDCBuilder creates a new NDCBuilder instance.
func NewNDCBuilder(httpSchema *rest.NDCHttpSchema, options ConvertOptions) *NDCBuilder {
newSchema := rest.NewNDCHttpSchema()
newSchema.Settings = httpSchema.Settings

return &NDCBuilder{
ConvertOptions: &options,
usedTypes: make(map[string]string),
schema: httpSchema,
newSchema: newSchema,
}
}

// Build validates and build the REST connector schema.
func (ndc *NDCBuilder) Build() (*rest.NDCHttpSchema, error) {
if err := ndc.validate(); err != nil {
return nil, err
}

return ndc.newSchema, nil
}

// Validate checks if the schema is valid
func (nsc *NDCBuilder) validate() error {
for key, operation := range nsc.schema.Functions {
op, err := nsc.validateOperation(key, operation)
if err != nil {
return err
}

newName := nsc.formatOperationName(key)
nsc.newSchema.Functions[newName] = *op
}

for key, operation := range nsc.schema.Procedures {
op, err := nsc.validateOperation(key, operation)
if err != nil {
return err
}

newName := nsc.formatOperationName(key)
nsc.newSchema.Procedures[newName] = *op
}

return nil
}

// recursively validate and clean unused objects as well as their inner properties
func (nsc *NDCBuilder) validateOperation(operationName string, operation rest.OperationInfo) (*rest.OperationInfo, error) {
result := &rest.OperationInfo{
Request: operation.Request,
Description: operation.Description,
Arguments: make(map[string]rest.ArgumentInfo),
}
for key, field := range operation.Arguments {
fieldType, err := nsc.validateType(field.Type)
if err != nil {
return nil, fmt.Errorf("%s: arguments.%s: %w", operationName, key, err)
}
result.Arguments[key] = rest.ArgumentInfo{
HTTP: field.HTTP,
ArgumentInfo: schema.ArgumentInfo{
Description: field.ArgumentInfo.Description,
Type: fieldType.Encode(),
},
}
}

resultType, err := nsc.validateType(operation.ResultType)
if err != nil {
return nil, fmt.Errorf("%s: result_type: %w", operationName, err)
}
result.ResultType = resultType.Encode()

return result, nil
}

// recursively validate used types as well as their inner properties
func (nsc *NDCBuilder) validateType(schemaType schema.Type) (schema.TypeEncoder, error) {
rawType, err := schemaType.InterfaceT()

switch t := rawType.(type) {
case *schema.NullableType:
underlyingType, err := nsc.validateType(t.UnderlyingType)
if err != nil {
return nil, err
}

return schema.NewNullableType(underlyingType), nil
case *schema.ArrayType:
elementType, err := nsc.validateType(t.ElementType)
if err != nil {
return nil, err
}

return schema.NewArrayType(elementType), nil
case *schema.NamedType:
if t.Name == "" {
return nil, errors.New("named type is empty")
}

if newName, ok := nsc.usedTypes[t.Name]; ok {
return schema.NewNamedType(newName), nil
}

if st, ok := nsc.schema.ScalarTypes[t.Name]; ok {
newName := t.Name
if !rest.IsDefaultScalar(t.Name) {
newName = nsc.formatTypeName(t.Name)
}
newNameType := schema.NewNamedType(newName)
nsc.usedTypes[t.Name] = newName
if _, ok := nsc.newSchema.ScalarTypes[newName]; !ok {
nsc.newSchema.ScalarTypes[newName] = st
}

return newNameType, nil
}

objectType, ok := nsc.schema.ObjectTypes[t.Name]
if !ok {
return nil, errors.New(t.Name + ": named type does not exist")
}

newName := nsc.formatTypeName(t.Name)
newNameType := schema.NewNamedType(newName)
nsc.usedTypes[t.Name] = newName

newObjectType := rest.ObjectType{
Description: objectType.Description,
Fields: make(map[string]rest.ObjectField),
}

for key, field := range objectType.Fields {
fieldType, err := nsc.validateType(field.Type)
if err != nil {
return nil, fmt.Errorf("%s.%s: %w", t.Name, key, err)
}
newObjectType.Fields[key] = rest.ObjectField{
ObjectField: schema.ObjectField{
Type: fieldType.Encode(),
Description: field.Description,
Arguments: field.Arguments,
},
HTTP: field.HTTP,
}
}
nsc.newSchema.ObjectTypes[newName] = newObjectType

return newNameType, nil
default:
return nil, err
}
}

func (nsc *NDCBuilder) formatTypeName(name string) string {
if nsc.Prefix == "" {
return name
}

return utils.StringSliceToPascalCase([]string{nsc.Prefix, name})
}

func (nsc *NDCBuilder) formatOperationName(name string) string {
if nsc.Prefix == "" {
return name
}

return utils.StringSliceToCamelCase([]string{nsc.Prefix, name})
}
22 changes: 7 additions & 15 deletions ndc-http-schema/openapi/internal/oas2.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,17 @@ type OAS2Builder struct {
}

// NewOAS2Builder creates an OAS3Builder instance
func NewOAS2Builder(schema *rest.NDCHttpSchema, options ConvertOptions) *OAS2Builder {
func NewOAS2Builder(options ConvertOptions) *OAS2Builder {
builder := &OAS2Builder{
schema: schema,
schema: rest.NewNDCHttpSchema(),
schemaCache: make(map[string]SchemaInfoCache),
ConvertOptions: applyConvertOptions(options),
}

return builder
}

// Schema returns the inner NDC HTTP schema
func (oc *OAS2Builder) Schema() *rest.NDCHttpSchema {
return oc.schema
}

func (oc *OAS2Builder) BuildDocumentModel(docModel *libopenapi.DocumentModel[v2.Swagger]) error {
func (oc *OAS2Builder) BuildDocumentModel(docModel *libopenapi.DocumentModel[v2.Swagger]) (*rest.NDCHttpSchema, error) {
if docModel.Model.Info != nil {
oc.schema.Settings.Version = docModel.Model.Info.Version
}
Expand All @@ -65,14 +60,14 @@ func (oc *OAS2Builder) BuildDocumentModel(docModel *libopenapi.DocumentModel[v2.

for iterPath := docModel.Model.Paths.PathItems.First(); iterPath != nil; iterPath = iterPath.Next() {
if err := oc.pathToNDCOperations(iterPath); err != nil {
return err
return nil, err
}
}

if docModel.Model.Definitions != nil {
for cSchema := docModel.Model.Definitions.Definitions.First(); cSchema != nil; cSchema = cSchema.Next() {
if err := oc.convertComponentSchemas(cSchema); err != nil {
return err
return nil, err
}
}
}
Expand All @@ -82,17 +77,14 @@ func (oc *OAS2Builder) BuildDocumentModel(docModel *libopenapi.DocumentModel[v2.
for scheme := docModel.Model.SecurityDefinitions.Definitions.First(); scheme != nil; scheme = scheme.Next() {
err := oc.convertSecuritySchemes(scheme)
if err != nil {
return err
return nil, err
}
}
}

oc.schema.Settings.Security = convertSecurities(docModel.Model.Security)
if err := cleanUnusedSchemaTypes(oc.schema); err != nil {
return err
}

return nil
return NewNDCBuilder(oc.schema, *oc.ConvertOptions).Build()
}

func (oc *OAS2Builder) convertSecuritySchemes(scheme orderedmap.Pair[string, *v2.SecurityScheme]) error {
Expand Down
6 changes: 0 additions & 6 deletions ndc-http-schema/openapi/internal/oas2_operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ func (oc *oas2OperationBuilder) BuildFunction(pathKey string, operation *v2.Oper
if funcName == "" {
funcName = buildPathMethodName(pathKey, "get", oc.builder.ConvertOptions)
}
if oc.builder.Prefix != "" {
funcName = utils.StringSliceToCamelCase([]string{oc.builder.Prefix, funcName})
}
oc.builder.Logger.Info("function",
slog.String("name", funcName),
slog.String("path", pathKey),
Expand Down Expand Up @@ -96,9 +93,6 @@ func (oc *oas2OperationBuilder) BuildProcedure(pathKey string, method string, op
procName = buildPathMethodName(pathKey, method, oc.builder.ConvertOptions)
}

if oc.builder.Prefix != "" {
procName = utils.StringSliceToCamelCase([]string{oc.builder.Prefix, procName})
}
oc.builder.Logger.Info("procedure",
slog.String("name", procName),
slog.String("path", pathKey),
Expand Down
Loading

0 comments on commit 6c06e70

Please sign in to comment.