Исправление типов в файле миграции БД
continuous-integration/drone/tag Build is passing Details

This commit is contained in:
Ymnuk 2023-09-01 10:39:12 +03:00
parent 913fc3b80a
commit 73f2b83112
9 changed files with 191 additions and 24 deletions

View File

@ -67,6 +67,17 @@ db:
name: test___test_1
idTable: 5fb86d34-aada-409a-ac9d-29fd1f7c2d1b
tableName: test___test_1
- id: c9dbaa06-5672-454d-8ee0-d04ec940dfa9
name: test3
pk: uuid
fields:
- id: 207ef8e5-816f-400a-934d-40b65360cc15
name: F1
type: text
- id: fc008a66-0c3d-48d2-9009-9e2b0765fcd8
name: F2
type: text
includeValues: ./test_external_data
roles:
- id: 0ef16d57-deba-4b09-a147-cb311d20b383
name: APP_ADMIN

24
lib/json-pretty.go Normal file
View File

@ -0,0 +1,24 @@
package lib
import (
"bytes"
"encoding/json"
"io"
)
func PrettyString(str string) (string, error) {
var prettyJSON bytes.Buffer
if err := json.Indent(&prettyJSON, []byte(str), "", " "); err != nil {
return "", err
}
return prettyJSON.String(), nil
}
func PrettyEncode(data interface{}, out io.Writer) error {
enc := json.NewEncoder(out)
enc.SetIndent("", " ")
if err := enc.Encode(data); err != nil {
return err
}
return nil
}

View File

@ -64,6 +64,60 @@ func GetModelNameAngular(project *structs.Project, value structs.VisField) strin
return ""
}
func FieldInTableByName(name string, table *structs.Table) *structs.Field {
for i := range table.Fields {
if table.Fields[i].Name == FieldNamePrepare(name) {
return &table.Fields[i]
}
}
for i := range table.FkFields {
if table.FkFields[i].Name == FieldNamePrepare(name) ||
table.FkFields[i].Name+"ID" == FieldNamePrepare(name) {
return &structs.Field{
Name: table.FkFields[i].Name,
Type: table.FkFields[i].TypeParentTable,
}
}
}
log.Fatalf(`Field "%s" not found in "%s"`, name, table.Name)
return nil
}
func FieldStringToType(value interface{}, field *structs.Field) string {
//value = strings.ReplaceAll(value, "\"", "\\\"")
switch field.Type {
case "text":
return fmt.Sprintf("&[]string{`%s`}[0]", value)
case "string":
return fmt.Sprintf("&[]string{`%s`}[0]", value)
case "int":
return fmt.Sprintf("&[]int{%d}[0]", value)
case "bigint":
return fmt.Sprintf("&[]int64{%d}[0]", value)
case "double":
return fmt.Sprintf("&[]float64{%f}[0]", value)
case "float":
return fmt.Sprintf("&[]float32{%f}[0]", value)
case "uuid":
return fmt.Sprintf("&[]uuid.UUID{uuid.FromStringOrNil(`%s`)}[0]", value)
case "date":
return fmt.Sprintf("&[]time.Time{time.Parse(\"2006-01-02\",`%s`)}[0]", value)
case "time":
return fmt.Sprintf("&[]time.Time{time.Parse(\"2006-01-02 15:04:05\",`%s`)}[0]", value)
case "bool":
return fmt.Sprintf("&[]bool{%t}[0]", value)
case "any":
return fmt.Sprintf("&[]byte{%s}", value)
default:
fkTmp := &structs.Field{
Name: field.Type,
}
return fmt.Sprintf("&[]%s{%s}", FieldName(fkTmp), value)
//log.Fatalf("Unknow format %s", field.Type)
}
}
func DisplayMethodNamePost(value string) string {
// TODO
//log.Fatal("not released")

View File

@ -27,6 +27,7 @@ var funcMap = template.FuncMap{
"fieldNameLowerPrepare": FieldNameLowerPrepare,
"fieldJsonNameStr": FieldJsonNameStr,
"fieldType": FieldType,
"fieldStringToType": FieldStringToType,
//"fieldDbTableType": FieldDbTableType,
"fieldTypeParentTable": FieldTypeParentTable,
"hasFieldType": HasFieldType,
@ -67,6 +68,7 @@ var funcMap = template.FuncMap{
"parseRestPath": ParseRestPath,
"parseRestPathForName": ParseRestPathForName,
"parseRestPathParams": ParseRestPathParams,
"fieldInTableByName": FieldInTableByName,
}
func IsMethod(arr map[string][]string, method string) bool {

View File

@ -1,27 +1,25 @@
package db
import (
"{{.Name}}/db/model"
"{{ .Name }}/db/model"
{{ $hasFieldTime := false }}{{ range $idxTbl, $tbl := .DB.Tables }}{{ if $tbl.Values }}{{ $hasFldTime := hasFieldType $tbl.Fields "time" }}{{ if eq $hasFldTime true }}{{ $hasFieldTime = true }}{{ end }}{{ end }}{{ if $hasFieldTime }}"time"{{ end }}{{ end }}
uuid "github.com/satori/go.uuid"
)
{{ range $index, $item := .DB.Tables }}
{{ if $item.Values }}
{{ range $index, $item := .DB.Tables }}{{ if $item.Values }}
func update{{ fieldNamePrepare $item.Name}}() {
records:=[]model.{{ fieldNamePrepare $item.Name }} {
records := []model.{{ fieldNamePrepare $item.Name }} {
{{ range $i, $field := $item.Values }}
{
{{ range $name, $value := $field }}
{{ if eq $name "id" }}
Base: model.Base{
ID: uuid.FromStringOrNil("{{ $value }}"),
ID: uuid.FromStringOrNil(`{{ $value }}`),
},
{{ end }}
{{ if ne $name "id" }}
{{ fieldNamePrepare $name }}: &[]string{"{{ $value }}"}[0],
{{ end }}
{{ if ne $name "id" }}{{ fieldNamePrepare $name }}: {{ $fld := fieldInTableByName $name $item }}{{ $fldTypeName := fieldType $fld }}{{ fieldStringToType $value $fld }},{{ end }}
{{ end }}
},
{{ end }}
@ -40,5 +38,4 @@ func update{{ fieldNamePrepare $item.Name}}() {
panic(err)
}
}
{{ end }}
{{ end }}
{{ end }}{{ end }}

77
main.go
View File

@ -1,6 +1,7 @@
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
@ -48,6 +49,40 @@ func main() {
} else {
log.Fatal("Ошибка открытия файла")
}
dir := filepath.Dir(lib.AppConfig.Filename)
// Загрузка значений для таблиц БД из файлов
for i := range lib.Project.DB.Tables {
if lib.Project.DB.Tables[i].IncludeValues != "" {
var values []map[string]interface{}
if _, err = os.Stat(filepath.Join(dir, fmt.Sprintf("%s.yml", lib.Project.DB.Tables[i].IncludeValues))); os.IsNotExist(err) {
if _, err = os.Stat(filepath.Join(dir, fmt.Sprintf("%s.json", lib.Project.DB.Tables[i].IncludeValues))); os.IsNotExist(err) {
log.Fatalf("Data not found in table %s", lib.Project.DB.Tables[i].Name)
} else {
// Загружаем
if buff, err = os.ReadFile(filepath.Join(dir, fmt.Sprintf("%s.json", lib.Project.DB.Tables[i].IncludeValues))); err != nil {
log.Fatal(err)
}
if err = json.Unmarshal(buff, &values); err != nil {
log.Fatal(err)
}
}
} else {
// Загружаем
if buff, err = os.ReadFile(filepath.Join(dir, fmt.Sprintf("%s.yml", lib.Project.DB.Tables[i].IncludeValues))); err != nil {
log.Fatal(err)
}
if err = yaml.Unmarshal(buff, &values); err != nil {
log.Fatal(err)
}
}
lib.Project.DB.Tables[i].Values = append(lib.Project.DB.Tables[i].Values, values...)
}
}
// Подготовка значений по умолчанию
if err = defaults.Set(lib.Project); err != nil {
log.Fatal(err)
}
@ -68,15 +103,51 @@ func main() {
lib.Generate()
dir := filepath.Dir(lib.AppConfig.Filename)
filename := filepath.Base(lib.AppConfig.Filename)
filenameWithoutExt := fileNameWithoutExtSliceNotation(filename)
// Сохраняем значения таблиц (если они есть) во внешние файлы
for i := range lib.Project.DB.Tables {
if len(lib.Project.DB.Tables[i].Values) == 0 {
lib.Project.DB.Tables[i].IncludeValues = ""
continue
}
if lib.Project.DB.Tables[i].IncludeValues == "" {
lib.Project.DB.Tables[i].IncludeValues = fmt.Sprintf("./%s", lib.Project.DB.Tables[i].Name)
}
buff, err = yaml.Marshal(lib.Project.DB.Tables[i].Values)
if err != nil {
log.Fatal(err)
}
if err = os.WriteFile(filepath.Join(dir, fmt.Sprintf("%s.yml", lib.Project.DB.Tables[i].IncludeValues)), buff, 0755); err != nil {
log.Fatal(err)
}
/*buff, err = json.Marshal(lib.Project.DB.Tables[i].Values)
if err != nil {
log.Fatal(err)
}*/
var buffer bytes.Buffer
err := lib.PrettyEncode(lib.Project.DB.Tables[i].Values, &buffer)
if err != nil {
log.Fatal(err)
}
/*if err = os.WriteFile(filepath.Join(dir, fmt.Sprintf("%s.json", lib.Project.DB.Tables[i].IncludeValues)), buff, 0755); err != nil {
log.Fatal(err)
}*/
if err = os.WriteFile(filepath.Join(dir, fmt.Sprintf("%s.json", lib.Project.DB.Tables[i].IncludeValues)), buffer.Bytes(), 0755); err != nil {
log.Fatal(err)
}
lib.Project.DB.Tables[i].Values = nil
buff = nil
}
buff = nil
if buff, err = yaml.Marshal(&lib.Project); err != nil {
log.Fatal(err)
}
if err = os.WriteFile(fmt.Sprintf("%s/%s.yml", dir, filenameWithoutExt), buff, 0755); err != nil {
if err = os.WriteFile(filepath.Join(dir, fmt.Sprintf("%s.yml", filenameWithoutExt)), buff, 0755); err != nil {
log.Fatal(err)
}
@ -84,7 +155,7 @@ func main() {
if buff, err = json.Marshal(&lib.Project); err != nil {
log.Fatal(err)
}
if err = os.WriteFile(fmt.Sprintf("%s/%s.json", dir, filenameWithoutExt), buff, 0755); err != nil {
if err = os.WriteFile(filepath.Join(dir, fmt.Sprintf("%s.json", filenameWithoutExt)), buff, 0755); err != nil {
log.Fatal(err)
}

View File

@ -10,17 +10,18 @@ type DB struct {
// Описание таблицы. Поле ID (индентификатор и первичный ключ) присутствуют всегда
type Table struct {
ID uuid.UUID `yaml:"id,omitempty" json:"id,omitempty"` // Идентификатор таблицы. Если пустой, то генерируется автоматически для дальнейше работы
Name string `yaml:"name,omitempty" json:"name,omitempty"` // Название таблицы
Schema string `yaml:"schema,omitempty" json:"schema,omitempty"` // Схема таблицы (для PostgreSQL либо префикс для остальных)
Pk string `yaml:"pk,omitempty" json:"pk,omitempty" default:"uuid"` // Тип первичного ключа. Если uuid, то генерируется V4, int и bigint - используется bigint с автоинкрементом, string - первичный ключ как текстовое поле. Если не указано, то поумолчанию используется UUID
Description string `yaml:"description,omitempty" json:"description,omitempty"` // Описание таблицы
Fields []Field `yaml:"fields,omitempty" json:"fields,omitempty"` // Поля таблицы
Recursive bool `yaml:"recursive,omitempty" json:"recursive,omitempty"` // Рекурсивная таблица
FKs []FK `yaml:"fks,omitempty" json:"fks,omitempty"` // Внешние ключи
Values []map[string]interface{} `yaml:"values,omitempty" json:"values,omitempty"` // Значения для заполняемого справочника
FkFields []Field `yaml:"-" json:"-"` // Поля с описанием внешних ключей
Children []Field `yaml:"-" json:"-"` // Дочерние (подчиненные) таблицы
ID uuid.UUID `yaml:"id,omitempty" json:"id,omitempty"` // Идентификатор таблицы. Если пустой, то генерируется автоматически для дальнейше работы
Name string `yaml:"name,omitempty" json:"name,omitempty"` // Название таблицы
Schema string `yaml:"schema,omitempty" json:"schema,omitempty"` // Схема таблицы (для PostgreSQL либо префикс для остальных)
Pk string `yaml:"pk,omitempty" json:"pk,omitempty" default:"uuid"` // Тип первичного ключа. Если uuid, то генерируется V4, int и bigint - используется bigint с автоинкрементом, string - первичный ключ как текстовое поле. Если не указано, то поумолчанию используется UUID
Description string `yaml:"description,omitempty" json:"description,omitempty"` // Описание таблицы
Fields []Field `yaml:"fields,omitempty" json:"fields,omitempty"` // Поля таблицы
Recursive bool `yaml:"recursive,omitempty" json:"recursive,omitempty"` // Рекурсивная таблица
FKs []FK `yaml:"fks,omitempty" json:"fks,omitempty"` // Внешние ключи
Values []map[string]interface{} `yaml:"values,omitempty" json:"values,omitempty"` // Значения для заполняемого справочника
IncludeValues string `yaml:"includeValues,omitempty" json:"includeValues,omitempty"` // Относительный путь к файлу со значениями для заполнения справочника. yml и json будут подставлены автоматически
FkFields []Field `yaml:"-" json:"-"` // Поля с описанием внешних ключей
Children []Field `yaml:"-" json:"-"` // Дочерние (подчиненные) таблицы
}
// Описание поля

1
test_external_data.json Executable file
View File

@ -0,0 +1 @@
[{"f1":"value1","f2":"value2","id":"049cf030-118b-46f3-91ea-ad6ce29521ae"},{"f1":"value3","f2":"value4","id":"d0d8fc52-3651-413b-bccd-45846cc9a6eb"}]

6
test_external_data.yml Executable file
View File

@ -0,0 +1,6 @@
- f1: value1
f2: value2
id: 049cf030-118b-46f3-91ea-ad6ce29521ae
- f1: value3
f2: value4
id: d0d8fc52-3651-413b-bccd-45846cc9a6eb