Шаблоны¶
Работа с шаблонами генерации кода.
Расположение¶
internal/pkg/backend/
├── postgres/
│ └── tmpl/
│ ├── pkg/
│ │ ├── main.tmpl # Основная структура
│ │ ├── select.tmpl # Селекторы
│ │ ├── mutator.tmpl # Мутаторы
│ │ └── ...
│ └── fixture/
│ └── ... # Шаблоны фикстур
└── octopus/
└── tmpl/
└── ...
Формат шаблонов¶
Используется стандартный text/template:
package {{ .PackageName }}
type {{ .StructName }} struct {
activerecord.BaseField
Exists bool
IsReplica bool
{{- range .Fields }}
{{ .Name | lower }} {{ .GoType }}
{{- end }}
}
Данные шаблона¶
Основная структура — *ds.RecordPackage:
type RecordPackage struct {
Namespace Namespace
Server Server
Fields []FieldDeclaration
Indexes []IndexDeclaration
IndexParts []IndexPartDeclaration
Serializers []SerializerDeclaration
Mutators []MutatorDeclaration
Flags []FlagDeclaration
Triggers []TriggerDeclaration
FieldsObjectMap []FieldsObjectDeclaration
// ...
}
Функции шаблонов¶
Определены в internal/pkg/generator/template.go:
| Функция | Описание | Пример |
|---|---|---|
lower |
Нижний регистр | {{ .Name \| lower }} |
upper |
Верхний регистр | {{ .Name \| upper }} |
title |
Title Case | {{ .Name \| title }} |
join |
Объединение слайса | {{ join .Fields ", " }} |
sub |
Вычитание | {{ sub (len .Fields) 1 }} |
add |
Сложение | {{ add .Index 1 }} |
Пример шаблона¶
Генерация геттеров¶
{{- range .Fields }}
// Get{{ .Name }} returns {{ .Name }} field value
func (obj *{{ $.StructName }}) Get{{ .Name }}() {{ .GoType }} {
return obj.{{ .Name | lower }}
}
{{- end }}
Генерация сеттеров¶
{{- range .Fields }}
{{- if not .PrimaryKey }}
// Set{{ .Name }} sets {{ .Name }} field value
func (obj *{{ $.StructName }}) Set{{ .Name }}(v {{ .GoType }}) {
obj.{{ .Name | lower }} = v
obj.UpdateOps = append(obj.UpdateOps, OpSet{
Field: "{{ .Name | lower }}",
Value: v,
})
}
{{- end }}
{{- end }}
Условная генерация¶
{{- if .HasSerializers }}
// Serializer imports
import (
{{- range .Serializers }}
"{{ .Package }}"
{{- end }}
)
{{- end }}
Модификация шаблонов¶
1. Найдите нужный шаблон¶
2. Внесите изменения¶
// internal/pkg/backend/postgres/tmpl/pkg/select.tmpl
func SelectBy{{ .Selector }}(ctx context.Context, key {{ .KeyType }}) (*{{ .StructName }}, error) {
// Ваши изменения
}
3. Протестируйте¶
4. Проверьте генерацию¶
# Генерация тестовой модели
argen --path "test/model" --declaration "decl" --destination "gen"
# Проверка сгенерированного кода
cat test/model/gen/mymodel/postgres.go
Добавление нового шаблона¶
1. Создайте файл¶
2. Добавьте в генератор¶
internal/pkg/backend/postgres/generator.go:
func (g *Generator) Generate(pkg *ds.RecordPackage) error {
// ...
if err := g.executeTemplate("myfeature.tmpl", pkg); err != nil {
return err
}
// ...
}
3. Зарегистрируйте шаблон¶
//go:embed tmpl/pkg/myfeature.tmpl
var myfeatureTmpl string
func init() {
templates["myfeature.tmpl"] = myfeatureTmpl
}
Отладка шаблонов¶
Вывод данных¶
{{/* Отладочный вывод */}}
// DEBUG: Fields count = {{ len .Fields }}
// DEBUG: First field = {{ (index .Fields 0).Name }}
Проверка ошибок¶
# Подробный вывод
argen --path "model" -v
# Проверка синтаксиса шаблона
go run ./cmd/argen --dry-run --path "model"
Best Practices¶
1. Комментируйте сгенерированный код¶
// {{ .StructName }} represents {{ .Namespace.ObjectName }} table
// Generated by argen. DO NOT EDIT.
type {{ .StructName }} struct {
2. Используйте whitespace control¶
3. Группируйте связанный код¶
{{- /* ===== GETTERS ===== */ -}}
{{- range .Fields }}
func (obj *{{ $.StructName }}) Get{{ .Name }}() {{ .GoType }} {
return obj.{{ .Name | lower }}
}
{{- end }}
{{- /* ===== SETTERS ===== */ -}}
{{- range .Fields }}
{{- if not .PrimaryKey }}
func (obj *{{ $.StructName }}) Set{{ .Name }}(v {{ .GoType }}) {
// ...
}
{{- end }}
{{- end }}
Следующие шаги¶
- Архитектура — обзор системы
- Генерация кода — процесс генерации