Documentation
¶
Index ¶
- Variables
- func GenerateDtos(writer io.Writer, def *Interface)
- func GenerateImplementation(writer io.Writer, def *Interface)
- func GenerateIntegrationTests(writer io.Writer, def *Interface)
- func GenerateInterface(writer io.Writer, def *Interface)
- func GenerateUnitTests(writer io.Writer, def *Interface)
- func GenerateValidations(writer io.Writer, def *Interface)
- func WriteCodeToFile(buffer *bytes.Buffer, fileName string)
- type Field
- func (field *Field) DtoDecl() string
- func (field *Field) DtoKind() string
- func (field *Field) HasAnyValidationInSubtree() bool
- func (field *Field) IsRoot() bool
- func (field *Field) IsStruct() bool
- func (field *Field) KindNoPtr() string
- func (field *Field) Path() string
- func (field *Field) ShouldBeInDto() bool
- func (field *Field) TagsPrintable() string
- func (field *Field) WithFields(fields []*Field) *Field
- func (field *Field) WithParent(parent *Field) *Field
- func (field *Field) WithRequired(required bool) *Field
- func (field *Field) WithValidations(validations []*Validation) *Field
- type Interface
- type Operation
- type Validation
- type ValidationType
Constants ¶
This section is empty.
Variables ¶
var DtoTemplate, _ = template.New("dtoTemplate").Parse(`
{{define "DTO_STRUCT"}}
type {{.DtoDecl}} struct {
{{- range .Fields}}
{{- if .ShouldBeInDto}}
{{.Name}} {{.DtoKind}} {{if .Required}}// required{{end}}
{{- end}}
{{- end}}
}
{{- range .Fields}}
{{if .IsStruct}}
{{template "DTO_STRUCT" .}}
{{end}}
{{- end}}
{{end}}
//go:generate go run ../../dto-builder-generator/main.go
var (
{{- range .Operations}}
_ optionsProvider[{{.OptsField.KindNoPtr}}] = new({{.OptsField.DtoDecl}})
{{- end}}
)
{{- range .Operations}}
{{template "DTO_STRUCT" .OptsField}}
{{- end}}
`)
var ImplementationTemplate, _ = template.New("implementationTemplate").Parse(`
{{define "MAPPING" -}}
&{{.KindNoPtr}}{
{{- range .Fields}}
{{- if .ShouldBeInDto}}
{{if .IsStruct}}{{else}}{{.Name}}: r{{.Path}},{{end}}
{{- end}}
{{- end}}
}
{{range .Fields}}
{{if .ShouldBeInDto}}
{{if .IsStruct}}
if r{{.Path}} != nil {
opts{{.Path}} = {{template "MAPPING" .}}
}
{{end}}
{{end}}
{{end}}
{{end}}
import "context"
{{$impl := .NameLowerCased}}
var _ {{.Name}} = (*{{$impl}})(nil)
type {{$impl}} struct {
client *Client
}
{{range .Operations}}
func (v *{{$impl}}) {{.Name}}(ctx context.Context, request *{{.OptsField.DtoDecl}}) error {
opts := request.toOpts()
return validateAndExec(v.client, ctx, opts)
}
{{end}}
{{range .Operations}}
func (r *{{.OptsField.DtoDecl}}) toOpts() *{{.OptsField.KindNoPtr}} {
opts := {{template "MAPPING" .OptsField}}
return opts
}
{{end}}
`)
var IntegrationTestsTemplate, _ = template.New("integrationTestsTemplate").Parse(`
import "testing"
func TestInt_{{.Name}}(t *testing.T) {
// TODO: fill me
}
`)
var InterfaceTemplate, _ = template.New("interfaceTemplate").Parse(`
import "context"
type {{.Name}} interface {
{{- range .Operations}}
{{.Name}}(ctx context.Context, request *{{.OptsField.DtoDecl}}) error
{{- end}}
}
`)
var OptionsTemplate, _ = template.New("optionsTemplate").Parse(`
// {{.OptsField.KindNoPtr}} is based on {{.Doc}}.
type {{.OptsField.KindNoPtr}} struct {
{{- range .OptsField.Fields}}
{{.Name}} {{.Kind}} {{.TagsPrintable}}
{{- end}}
}
`)
var PackageTemplate, _ = template.New("packageTemplate").Parse(`
package {{.}}
`)
var StructTemplate, _ = template.New("structTemplate").Parse(`
type {{.KindNoPtr}} struct {
{{- range .Fields}}
{{.Name}} {{.Kind}} {{.TagsPrintable}}
{{- end}}
}
`)
TODO: merge with template above? (requires moving Doc to field)
var TestFuncTemplate, _ = template.New("testFuncTemplate").Parse(`
{{define "VALIDATION_TEST"}}
{{$field := .}}
{{- range .Validations}}
{{.TodoComment $field}}
{{- end}}
{{end}}
{{define "VALIDATIONS"}}
{{template "VALIDATION_TEST" .}}
{{- range .Fields}}
{{if .HasAnyValidationInSubtree}}
{{template "VALIDATIONS" .}}
{{end}}
{{- end}}
{{end}}
import "testing"
{{- range .Operations}}
func Test{{.ObjectInterface.Name}}_{{.Name}}(t *testing.T) {
id := random{{.ObjectInterface.IdentifierKind}}(t)
defaultOpts := func() *{{.OptsField.KindNoPtr}} {
return &{{.OptsField.KindNoPtr}}{
name: id,
}
}
// TODO: remove me
_ = defaultOpts()
// TODO: fill me
{{template "VALIDATIONS" .OptsField}}
}
{{end}}
`)
var ValidationsImplTemplate, _ = template.New("validationsImplTemplate").Parse(`
{{define "VALIDATIONS"}}
{{$field := .}}
{{- range .Validations}}
if {{.Condition $field}} {
errs = append(errs, {{.Error}})
}
{{- end}}
{{- range .Fields}}
{{if .HasAnyValidationInSubtree}}
if valueSet(opts{{.Path}}) {
{{template "VALIDATIONS" .}}
}
{{end}}
{{- end}}
{{end}}
import "errors"
var (
{{- range .Operations}}
_ validatable = new({{.OptsField.KindNoPtr}})
{{- end}}
)
{{range .Operations}}
func (opts *{{.OptsField.KindNoPtr}}) validate() error {
if opts == nil {
return errors.Join(errNilOptions)
}
var errs []error
{{template "VALIDATIONS" .OptsField}}
return errors.Join(errs...)
}
{{end}}
`)
Functions ¶
func GenerateDtos ¶
func GenerateImplementation ¶
func GenerateInterface ¶
func GenerateUnitTests ¶
func GenerateValidations ¶
func WriteCodeToFile ¶
Types ¶
type Field ¶
type Field struct {
// Parent allows to traverse fields hierarchy more easily, nil for root
Parent *Field
// Fields defines children, use for struct fields
Fields []*Field
// Validations defines validations on given field level (e.g. oneOf for children)
Validations []*Validation
// Name is how field is called in parent struct
Name string
// Kind is fields type (e.g. string, *bool)
Kind string
// Tags should contain ddl and sql tags used for SQL generation
Tags map[string][]string
// Required is used to mark fields which are essential (it's used e.g. for DTO builders generation)
Required bool
}
Field defines properties of a single field or struct (by defining Fields)
func (*Field) DtoDecl ¶
DtoDecl returns how struct should be declared in generated DTO (e.g. definition is without a pointer)
func (*Field) DtoKind ¶
DtoKind returns what should be fields kind in generated DTO, because it may differ from Kind
func (*Field) HasAnyValidationInSubtree ¶
HasAnyValidationInSubtree checks if any validations are present from current field level downwards
func (*Field) IsRoot ¶
IsRoot checks if field is at the top of field hierarchy, basically it is true for Option structs
func (*Field) Path ¶
Path returns the way through the tree to the top, with dot separator (e.g. .SomeField.SomeChild)
func (*Field) ShouldBeInDto ¶
ShouldBeInDto checks if field is not some static SQL field which should not be interacted with by SDK user TODO: this is a very naive implementation, consider fixing it with DSL builder connection
func (*Field) TagsPrintable ¶
TagsPrintable defines how tags are printed in options structs, it ensures the same order of tags for every field
func (*Field) WithFields ¶
func (*Field) WithParent ¶
func (*Field) WithRequired ¶
func (*Field) WithValidations ¶
func (field *Field) WithValidations(validations []*Validation) *Field
type Interface ¶
type Interface struct {
// Name is the interface's name, e.g. "DatabaseRoles"
Name string
// NameSingular is the prefix/suffix which can be used to create other structs and methods, e.g. "DatabaseRole"
NameSingular string
// Operations contains all operations for given interface
Operations []*Operation
// IdentifierKind keeps identifier of the underlying object (e.g. DatabaseObjectIdentifier)
IdentifierKind string
}
Interface groups operations for particular object or objects family (e.g. DATABASE ROLE)
func NewInterface ¶
func (*Interface) NameLowerCased ¶
NameLowerCased returns interface name starting with a lower case letter
func (*Interface) WithOperations ¶
type Operation ¶
type Operation struct {
// Name is the operation's name, e.g. "Create"
Name string
// ObjectInterface points to the containing interface
ObjectInterface *Interface
// Doc is the URL for the doc used to create given operation, e.g. https://docs.snowflake.com/en/sql-reference/sql/create-database-role
Doc string
// OptsField defines opts used to create SQL for given operation
OptsField *Field
}
Operation defines a single operation for given object or objects family (e.g. CREATE DATABASE ROLE)
func NewOperation ¶
func (*Operation) WithObjectInterface ¶
func (*Operation) WithOptsField ¶
type Validation ¶
type Validation struct {
Type ValidationType
FieldNames []string
}
func NewValidation ¶
func NewValidation( vType ValidationType, fieldNames []string, ) *Validation
func (*Validation) Condition ¶
func (v *Validation) Condition(field *Field) string
func (*Validation) Error ¶
func (v *Validation) Error() string
func (*Validation) TodoComment ¶
func (v *Validation) TodoComment(field *Field) string
type ValidationType ¶
type ValidationType int64
ValidationType contains all handled validation types. Below validations are marked to be contained here or not: - opts not nil - not present here, handled on template level - valid identifier - present here, for now put on level containing given field - conflicting fields - present here, put on level containing given fields - exactly one value set - present here, put on level containing given fields - at least one value set - present here, put on level containing given fields - nested validation conditionally - not present here, handled by putting validations on lower level fields
const ( ValidIdentifier ValidationType = iota ConflictingFields ExactlyOneValueSet AtLeastOneValueSet )