Skip to content

Commit

Permalink
chore(): breu orm related features
Browse files Browse the repository at this point in the history
  • Loading branch information
Yousuf Jawwad committed Nov 26, 2023
1 parent add3126 commit fee285d
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 22 deletions.
50 changes: 39 additions & 11 deletions pkg/codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ import (
"bytes"
"context"
"embed"
"errors"
"fmt"
"io"
"io/fs"
"net/http"
"os"
"path"
"runtime/debug"
"sort"
"strings"
Expand Down Expand Up @@ -132,18 +134,43 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
return "", fmt.Errorf("error parsing oapi-codegen templates: %w", err)
}

// load user-provided templates. Will Override built-in versions.
for name, template := range opts.OutputOptions.UserTemplates {
utpl := t.New(name)

txt, err := GetUserTemplateText(template)
if err != nil {
return "", fmt.Errorf("error loading user-provided template %q: %w", name, err)
// Override built-in templates with user-provided versions
for _, tpl := range t.Templates() {
// Check for template in provided template directory
if dir := opts.OutputOptions.UserTemplatesDir; dir != "" {
fp := path.Join(dir, tpl.Name())
_, err := os.Stat(fp)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("error accessing user-provided template %q: %w", fp, err)
}
if err == nil {
utpl := t.New(tpl.Name())
data, err := os.ReadFile(fp)
if err != nil {
return "", fmt.Errorf("error reading user-provided template %q: %w", fp, err)
}
if _, err := utpl.Parse(string(data)); err != nil {
return "", fmt.Errorf("error parsing user-provided template %q: %w", fp, err)
}
}
}

_, err = utpl.Parse(txt)
if err != nil {
return "", fmt.Errorf("error parsing user-provided template %q: %w", name, err)
// Check for template in a provided file path
if fp, ok := opts.OutputOptions.UserTemplateFiles[tpl.Name()]; ok {
utpl := t.New(tpl.Name())
data, err := os.ReadFile(fp)
if err != nil {
return "", fmt.Errorf("error reading user-provided template %q: %w", fp, err)
}
if _, err := utpl.Parse(string(data)); err != nil {
return "", fmt.Errorf("error parsing user-provided template %q: %w", fp, err)
}
}
// Check for template provided inline in the configuration
if _, ok := opts.OutputOptions.UserTemplates[tpl.Name()]; ok {
utpl := t.New(tpl.Name())
if _, err := utpl.Parse(opts.OutputOptions.UserTemplates[tpl.Name()]); err != nil {
return "", fmt.Errorf("error parsing user-provided template %q: %w", tpl.Name(), err)
}
}
}

Expand Down Expand Up @@ -515,6 +542,7 @@ func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.

types = append(types, goSchema.GetAdditionalTypeDefs()...)
}

return types, nil
}

Expand Down
12 changes: 7 additions & 5 deletions pkg/codegen/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,13 @@ type CompatibilityOptions struct {

// OutputOptions are used to modify the output code in some way.
type OutputOptions struct {
SkipFmt bool `yaml:"skip-fmt,omitempty"` // Whether to skip go imports on the generated code
SkipPrune bool `yaml:"skip-prune,omitempty"` // Whether to skip pruning unused components on the generated code
IncludeTags []string `yaml:"include-tags,omitempty"` // Only include operations that have one of these tags. Ignored when empty.
ExcludeTags []string `yaml:"exclude-tags,omitempty"` // Exclude operations that have one of these tags. Ignored when empty.
UserTemplates map[string]string `yaml:"user-templates,omitempty"` // Override built-in templates from user-provided files
SkipFmt bool `yaml:"skip-fmt,omitempty"` // Whether to skip go imports on the generated code
SkipPrune bool `yaml:"skip-prune,omitempty"` // Whether to skip pruning unused components on the generated code
IncludeTags []string `yaml:"include-tags,omitempty"` // Only include operations that have one of these tags. Ignored when empty.
ExcludeTags []string `yaml:"exclude-tags,omitempty"` // Exclude operations that have one of these tags. Ignored when empty.
UserTemplates map[string]string `yaml:"user-templates,omitempty"` // Override built-in templates from user-provided files
UserTemplateFiles map[string]string `yaml:"user-template-files,omitempty"` // Same as UserTemplates, with filenames as values instead
UserTemplatesDir string `yaml:"user-templates-dir,omitempty"`

ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"` // Exclude from generation schemas with given names. Ignored when empty.
ResponseTypeSuffix string `yaml:"response-type-suffix,omitempty"` // The suffix used for responses types
Expand Down
2 changes: 2 additions & 0 deletions pkg/codegen/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const (
extEnumVarNames = "x-enum-varnames"
extEnumNames = "x-enumNames"
extDeprecationReason = "x-deprecated-reason"
extBreuEntity = "x-breu-entity"
extBreuEntityType = "x-breu-entity-type"
)

func extString(extPropValue interface{}) (string, error) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/codegen/merge_schemas_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, err
return "", err
}
objectParts = append(objectParts, " // Embedded fields due to inline allOf schema")
objectParts = append(objectParts, GenFieldsFromProperties(goSchema.Properties)...)
objectParts = append(objectParts, GenStuctFieldsFromSchema(goSchema)...)

if goSchema.HasAdditionalProperties {
addPropsType := goSchema.AdditionalPropertiesType.GoType
Expand Down
35 changes: 30 additions & 5 deletions pkg/codegen/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ type Schema struct {
// type definition `type Foo bool`
DefineViaAlias bool

BreuEntity string // BreuEntity is the name of the entity in the Breu schema.
BreuEntityType string // BreuEntityType is the type of the entity in the Breu schema.

// The original OpenAPIv3 Schema.
OAPISchema *openapi3.Schema
}
Expand Down Expand Up @@ -219,6 +222,8 @@ func PropertiesEqual(a, b Property) bool {
}

func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
entity := ""
entitype := ""
// Add a fallback value in case the sref is nil.
// i.e. the parent schema defines a type:array, but the array has
// no items defined. Therefore, we have at least valid Go-Code.
Expand All @@ -228,6 +233,16 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {

schema := sref.Value

// Check for x-breu-entity
if extension, ok := schema.Extensions[extBreuEntity]; ok {
entity = extension.(string)
}

// Check for x-breu-entity-type
if extension, ok := schema.Extensions[extBreuEntityType]; ok {
entitype = extension.(string)
}

// If Ref is set on the SchemaRef, it means that this type is actually a reference to
// another type. We're not de-referencing, so simply use the referenced type.
if IsGoTypeReference(sref.Ref) {
Expand All @@ -246,8 +261,10 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
}

outSchema := Schema{
Description: schema.Description,
OAPISchema: schema,
Description: schema.Description,
OAPISchema: schema,
BreuEntity: entity,
BreuEntityType: entitype,
}

// AllOf is interesting, and useful. It's the union of a number of other
Expand Down Expand Up @@ -635,9 +652,10 @@ type FieldDescriptor struct {
IsRef bool // Is this schema a reference to predefined object?
}

// GenFieldsFromProperties produce corresponding field names with JSON annotations,
// GenStuctFieldsFromSchema produce corresponding field names with JSON annotations,
// given a list of schema descriptors
func GenFieldsFromProperties(props []Property) []string {
func GenStuctFieldsFromSchema(schema Schema) []string {
props := schema.Properties
var fields []string
for i, p := range props {
field := ""
Expand Down Expand Up @@ -722,6 +740,12 @@ func GenFieldsFromProperties(props []Property) []string {
}
}
}

// Support x-breu-entity
if schema.BreuEntity != "" && schema.BreuEntityType == "cql" {
fieldTags["cql"] = p.JsonFieldName
}

// Convert the fieldTags map into Go field annotations.
keys := SortedStringKeys(fieldTags)
tags := make([]string, len(keys))
Expand All @@ -731,6 +755,7 @@ func GenFieldsFromProperties(props []Property) []string {
field += "`" + strings.Join(tags, " ") + "`"
fields = append(fields, field)
}

return fields
}

Expand All @@ -749,7 +774,7 @@ func GenStructFromSchema(schema Schema) string {
// Start out with struct {
objectParts := []string{"struct {"}
// Append all the field definitions
objectParts = append(objectParts, GenFieldsFromProperties(schema.Properties)...)
objectParts = append(objectParts, GenStuctFieldsFromSchema(schema)...)
// Close the struct
if schema.HasAdditionalProperties {
objectParts = append(objectParts,
Expand Down
39 changes: 39 additions & 0 deletions pkg/codegen/template_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"bytes"
"fmt"
"os"
"strconv"
"strings"
"text/template"

Expand Down Expand Up @@ -294,6 +295,41 @@ func stripNewLines(s string) string {
return r.Replace(s)
}

func split(sep, orig string) map[string]string {
parts := strings.Split(orig, sep)
res := make(map[string]string, len(parts))
for i, v := range parts {
res["_"+strconv.Itoa(i)] = v
}
return res
}

func splitn(sep string, n int, orig string) map[string]string {
parts := strings.SplitN(orig, sep, n)
res := make(map[string]string, len(parts))
for i, v := range parts {
res["_"+strconv.Itoa(i)] = v
}
return res
}

// substring creates a substring of the given string.
//
// If start is < 0, this calls string[:end].
//
// If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:]
//
// Otherwise, this calls string[start, end].
func substring(start, end int, s string) string {
if start < 0 {
return s[:end]
}
if end < 0 || end > len(s) {
return s[start:]
}
return s[start:end]
}

// TemplateFunctions is passed to the template engine, and we can call each
// function here by keyName from the template code.
var TemplateFunctions = template.FuncMap{
Expand Down Expand Up @@ -321,4 +357,7 @@ var TemplateFunctions = template.FuncMap{
"stripNewLines": stripNewLines,
"sanitizeGoIdentity": SanitizeGoIdentity,
"toGoComment": StringWithTypeNameToGoComment,
"split": split,
"splitn": splitn,
"substring": substring,
}

0 comments on commit fee285d

Please sign in to comment.