Рефакторинг
This commit is contained in:
parent
6deb8f7c27
commit
49e39dbe0e
33
example.yml
33
example.yml
|
@ -13,6 +13,13 @@ basePath: /api
|
|||
db:
|
||||
sqlite: true
|
||||
tables:
|
||||
- id: d62df683-7e0c-4b96-b8e6-11c660f58ff8
|
||||
name: test1
|
||||
pk: uuid
|
||||
fields:
|
||||
- id: e14d5504-fc3b-4ea1-9b5d-22bfa77fce94
|
||||
name: F1
|
||||
type: text
|
||||
- id: 5fb86d34-aada-409a-ac9d-29fd1f7c2d1b
|
||||
name: test___test_1
|
||||
pk: uuid
|
||||
|
@ -51,6 +58,32 @@ backend:
|
|||
- name: tile_server
|
||||
type: string
|
||||
help: Tile server for download tiles map
|
||||
rest:
|
||||
/reference/test1:
|
||||
groupName: nogroup
|
||||
data:
|
||||
id: 00000000-0000-0000-0000-000000000000
|
||||
name: db.test1
|
||||
visible:
|
||||
- id: 00000000-0000-0000-0000-000000000000
|
||||
name: F1
|
||||
filter:
|
||||
- id: 00000000-0000-0000-0000-000000000000
|
||||
name: F1
|
||||
editable: true
|
||||
fieldId:
|
||||
id: 00000000-0000-0000-0000-000000000000
|
||||
roles:
|
||||
GET:
|
||||
- APP_ADMIN
|
||||
LIST:
|
||||
- APP_ADMIN
|
||||
POST:
|
||||
- APP_ADMIN
|
||||
PUT:
|
||||
- APP_ADMIN
|
||||
DELETE:
|
||||
- APP_ADMIN
|
||||
frontend:
|
||||
lang: angular
|
||||
theme: primeng/resources/themes/mdc-light-indigo/theme.css
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/lib/templ"
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/structs"
|
||||
)
|
||||
|
||||
|
@ -115,7 +116,7 @@ func generateBackendTmpl() {
|
|||
}
|
||||
if len(staticTmpls) > 0 {
|
||||
for _, staticTmpl := range staticTmpls {
|
||||
if err := WriteTmplFile(staticTmpl.FileIn, staticTmpl.FileOut); err != nil {
|
||||
if err := templ.WriteTmplFile(staticTmpl.FileIn, staticTmpl.FileOut); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -124,82 +125,82 @@ func generateBackendTmpl() {
|
|||
|
||||
func generateModelBase() {
|
||||
// main
|
||||
if err := PrepareTmplFile("tmpl/backend/main.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "main.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/main.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "main.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/lib/config.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "lib", "config.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/lib/config.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "lib", "config.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// db
|
||||
if err := PrepareTmplFile("tmpl/backend/db/model/user.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "db", "model", "user.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/db/model/user.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "db", "model", "user.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/db/db.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "db", "db.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/db/db.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "db", "db.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(Project.DB.Tables) > 0 {
|
||||
for _, table := range Project.DB.Tables {
|
||||
if err := PrepareTmplFile("tmpl/backend/db/model/model.tmpl", table, filepath.Join(AppConfig.OutdirBackend, "db", "model", strings.ToLower(table.Name)+".go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/db/model/model.tmpl", table, filepath.Join(AppConfig.OutdirBackend, "db", "model", strings.ToLower(table.Name)+".go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// middleware
|
||||
if err := PrepareTmplFile("tmpl/backend/middleware/middleware.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "middleware", "middleware.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/middleware/middleware.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "middleware", "middleware.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/middleware/in-role.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "middleware", "in-role.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/middleware/in-role.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "middleware", "in-role.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// route
|
||||
if err := PrepareTmplFile("tmpl/backend/route/route.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "route.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/route.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "route.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// route/api
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/index.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "index.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/index.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "index.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// route/api/auth
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/auth/index.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "auth", "index.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/auth/index.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "auth", "index.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// route/api/user
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/index.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "index.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/index.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "index.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/ldap-search.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "ldap-search.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/ldap-search.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "ldap-search.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/get.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "get.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/get.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "get.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/list-users.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "list-users.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/list-users.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "list-users.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/post.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "post.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/post.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "post.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/lock.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "lock.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/lock.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "lock.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/unlock.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "unlock.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/unlock.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "unlock.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/put.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "put.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/put.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "put.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/delete.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "delete.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/delete.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "delete.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// route/api/user/role
|
||||
if err := PrepareTmplFile("tmpl/backend/route/api/user/role/index.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "role", "index.go")); err != nil {
|
||||
if err := templ.PrepareTmplFile("tmpl/backend/route/api/user/role/index.tmpl", Project, filepath.Join(AppConfig.OutdirBackend, "route", "api", "user", "role", "index.go")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/lib/templ"
|
||||
)
|
||||
|
||||
func execCommands() {
|
||||
|
@ -16,7 +18,7 @@ func execCommands() {
|
|||
log.Fatal(cmd.Err)
|
||||
}
|
||||
|
||||
if buff, err := content.ReadFile("tmpl/backend/go-list-module.txt"); err != nil {
|
||||
if buff, err := templ.Content.ReadFile("tmpl/backend/go-list-module.txt"); err != nil {
|
||||
log.Fatal(err)
|
||||
} else {
|
||||
strs := strings.Split(string(buff), "\n")
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/lib/templ"
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/structs"
|
||||
)
|
||||
|
||||
|
@ -205,7 +206,7 @@ func generateFrontendAngularTmpl() {
|
|||
|
||||
if len(staticTmpls) > 0 {
|
||||
for _, staticTmpl := range staticTmpls {
|
||||
if err := WriteTmplFile(staticTmpl.FileIn, staticTmpl.FileOut); err != nil {
|
||||
if err := templ.WriteTmplFile(staticTmpl.FileIn, staticTmpl.FileOut); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,24 +3,25 @@ package lib
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/lib/templ"
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/structs"
|
||||
)
|
||||
|
||||
func TestFieldType(t *testing.T) {
|
||||
if fieldDBName(&structs.Field{Name: "Field"}) != "field" {
|
||||
if templ.FieldDBName(&structs.Field{Name: "Field"}) != "field" {
|
||||
t.Fail()
|
||||
}
|
||||
if fieldDBName(&structs.Field{Name: "Field_NAME"}) != "field_name" {
|
||||
if templ.FieldDBName(&structs.Field{Name: "Field_NAME"}) != "field_name" {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if fieldDBName(&structs.Field{Name: "fIELD_nAMe"}) != "field_name" {
|
||||
if templ.FieldDBName(&structs.Field{Name: "fIELD_nAMe"}) != "field_name" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDBModelAttrib(t *testing.T) {
|
||||
str := fieldDescript(&structs.Field{
|
||||
str := templ.FieldDescript(&structs.Field{
|
||||
Name: "Field_naME1",
|
||||
Type: "int",
|
||||
Description: "Hello world",
|
||||
|
@ -31,14 +32,14 @@ func TestDBModelAttrib(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestVarNameUpper(t *testing.T) {
|
||||
if str := fieldNamePrepare("tile_server"); str != "TileServer" {
|
||||
if str := templ.FieldNamePrepare("tile_server"); str != "TileServer" {
|
||||
t.Error("Field name not equal")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestVarNameLower(t *testing.T) {
|
||||
if str := fieldNameLowerPrepare("TileServer"); str != "tile_server" {
|
||||
if str := templ.FieldNameLowerPrepare("TileServer"); str != "tile_server" {
|
||||
t.Error("Field name not equal")
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,135 +1,10 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/lib/prepare"
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/structs"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
func PrepareMetadata(project *structs.Project) {
|
||||
if project == nil {
|
||||
log.Fatal("Metadata is empty")
|
||||
}
|
||||
|
||||
if project.Name == "" {
|
||||
log.Fatal("Should be set project name")
|
||||
}
|
||||
|
||||
// Подготовка БД
|
||||
if len(project.DB.Tables) > 0 {
|
||||
for i := range project.DB.Tables {
|
||||
if project.DB.Tables[i].ID == uuid.Nil {
|
||||
project.DB.Tables[i].ID = uuid.NewV4()
|
||||
}
|
||||
if len(project.DB.Tables[i].Fields) > 0 {
|
||||
for j := range project.DB.Tables[i].Fields {
|
||||
project.DB.Tables[i].Fields[j].Name = fieldDBName(&project.DB.Tables[i].Fields[j])
|
||||
if project.DB.Tables[i].Fields[j].ID == uuid.Nil {
|
||||
project.DB.Tables[i].Fields[j].ID = uuid.NewV4()
|
||||
}
|
||||
project.DB.Tables[i].Fields[j].Type = strings.Trim(project.DB.Tables[i].Fields[j].Type, " ")
|
||||
project.DB.Tables[i].Fields[j].Type = strings.ToLower(project.DB.Tables[i].Fields[j].Type)
|
||||
if project.DB.Tables[i].Fields[j].Type == "" {
|
||||
project.DB.Tables[i].Fields[j].Type = "text"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if project.DB.Tables[i].Recursive {
|
||||
project.DB.Tables[i].FkFields = append(project.DB.Tables[i].FkFields, structs.Field{
|
||||
Name: "parent",
|
||||
Description: "Recursive foreign key for self table",
|
||||
})
|
||||
switch project.DB.Tables[i].Pk {
|
||||
case "uuid":
|
||||
project.DB.Tables[i].FkFields[len(project.DB.Tables[i].FkFields)-1].Type = "uuid"
|
||||
case "int":
|
||||
project.DB.Tables[i].FkFields[len(project.DB.Tables[i].FkFields)-1].Type = "bigint"
|
||||
case "bigintint":
|
||||
project.DB.Tables[i].FkFields[len(project.DB.Tables[i].FkFields)-1].Type = "bigint"
|
||||
default:
|
||||
log.Fatalf("Error primary key type '%s' in table '%s'", project.DB.Tables[i].Pk, project.DB.Tables[i].Name)
|
||||
}
|
||||
}
|
||||
if len(project.DB.Tables[i].FKs) > 0 {
|
||||
for j := range project.DB.Tables[i].FKs {
|
||||
if project.DB.Tables[i].FKs[j].ID == uuid.Nil {
|
||||
project.DB.Tables[i].FKs[j].ID = uuid.NewV4()
|
||||
}
|
||||
if project.DB.Tables[i].FKs[j].TableID == uuid.Nil && project.DB.Tables[i].FKs[j].TableName != "" {
|
||||
for k := range project.DB.Tables {
|
||||
if project.DB.Tables[k].Name == project.DB.Tables[i].FKs[j].TableName {
|
||||
project.DB.Tables[i].FKs[j].TableID = project.DB.Tables[k].ID
|
||||
project.DB.Tables[i].FKs[j].Type = project.DB.Tables[k].Pk
|
||||
/*project.DB.Tables[i].FkFields = append(project.DB.Tables[i].FkFields, structs.Field{
|
||||
Name: fmt.Sprintf("%s", project.DB.Tables[k].Name),
|
||||
Type: project.DB.Tables[k].Pk,
|
||||
})*/
|
||||
}
|
||||
}
|
||||
}
|
||||
if project.DB.Tables[i].FKs[j].TableID != uuid.Nil {
|
||||
for k := range project.DB.Tables {
|
||||
if project.DB.Tables[k].ID == project.DB.Tables[i].FKs[j].TableID {
|
||||
project.DB.Tables[i].FKs[j].TableName = project.DB.Tables[k].Name
|
||||
project.DB.Tables[k].Children = append(project.DB.Tables[k].Children, project.DB.Tables[i].Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if project.DB.Tables[i].FKs[j].TableName == "" {
|
||||
log.Fatalf("Error foreign key for '%s' table", project.DB.Tables[i].FKs[j].TableID.String())
|
||||
}
|
||||
project.DB.Tables[i].FkFields = append(project.DB.Tables[i].FkFields, structs.Field{
|
||||
Name: fmt.Sprintf("%s", strings.ToLower(project.DB.Tables[i].FKs[j].TableName)),
|
||||
Type: project.DB.Tables[i].Pk,
|
||||
Description: fmt.Sprintf("Foreign key for \\\"%s\\\" table", project.DB.Tables[i].FKs[j].TableName),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Подготовка ролей
|
||||
hasAppAdmin := false
|
||||
hasSecAdmin := false
|
||||
if len(project.Roles) > 0 {
|
||||
|
||||
for i := range project.Roles {
|
||||
project.Roles[i].Name = strings.Trim(project.Roles[i].Name, " ")
|
||||
if project.Roles[i].Name == "" {
|
||||
log.Fatal("Should be set role name")
|
||||
}
|
||||
project.Roles[i].Name = strings.ReplaceAll(project.Roles[i].Name, " ", "_")
|
||||
if project.Roles[i].ID == uuid.Nil {
|
||||
project.Roles[i].ID = uuid.NewV4()
|
||||
}
|
||||
if project.Roles[i].Display == "" {
|
||||
project.Roles[i].Display = project.Roles[i].Name
|
||||
}
|
||||
if project.Roles[i].Name == "APP_ADMIN" {
|
||||
hasAppAdmin = true
|
||||
}
|
||||
if project.Roles[i].Name == "SEC_ADMIN" {
|
||||
hasSecAdmin = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if !hasAppAdmin {
|
||||
project.Roles = append(project.Roles, structs.Role{
|
||||
ID: uuid.NewV4(),
|
||||
Name: "APP_ADMIN",
|
||||
Display: "Администратор приложения",
|
||||
})
|
||||
}
|
||||
if !hasSecAdmin {
|
||||
project.Roles = append(project.Roles, structs.Role{
|
||||
ID: uuid.NewV4(),
|
||||
Name: "SEC_ADMIN",
|
||||
Display: "Администратор безопасности",
|
||||
})
|
||||
}
|
||||
project = prepare.PrepareMetadata(project)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package prepare
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/lib/templ"
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/structs"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
// Подготовка БД
|
||||
func prepareDB(project *structs.Project) *structs.Project {
|
||||
if len(project.DB.Tables) > 0 {
|
||||
for i := range project.DB.Tables {
|
||||
if project.DB.Tables[i].ID == uuid.Nil {
|
||||
project.DB.Tables[i].ID = uuid.NewV4()
|
||||
}
|
||||
if len(project.DB.Tables[i].Fields) > 0 {
|
||||
for j := range project.DB.Tables[i].Fields {
|
||||
project.DB.Tables[i].Fields[j].Name = templ.FieldDBName(&project.DB.Tables[i].Fields[j])
|
||||
if project.DB.Tables[i].Fields[j].ID == uuid.Nil {
|
||||
project.DB.Tables[i].Fields[j].ID = uuid.NewV4()
|
||||
}
|
||||
project.DB.Tables[i].Fields[j].Type = strings.Trim(project.DB.Tables[i].Fields[j].Type, " ")
|
||||
project.DB.Tables[i].Fields[j].Type = strings.ToLower(project.DB.Tables[i].Fields[j].Type)
|
||||
if project.DB.Tables[i].Fields[j].Type == "" {
|
||||
project.DB.Tables[i].Fields[j].Type = "text"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if project.DB.Tables[i].Recursive {
|
||||
project.DB.Tables[i].FkFields = append(project.DB.Tables[i].FkFields, structs.Field{
|
||||
Name: "parent",
|
||||
Description: "Recursive foreign key for self table",
|
||||
})
|
||||
switch project.DB.Tables[i].Pk {
|
||||
case "uuid":
|
||||
project.DB.Tables[i].FkFields[len(project.DB.Tables[i].FkFields)-1].Type = "uuid"
|
||||
case "int":
|
||||
project.DB.Tables[i].FkFields[len(project.DB.Tables[i].FkFields)-1].Type = "bigint"
|
||||
case "bigintint":
|
||||
project.DB.Tables[i].FkFields[len(project.DB.Tables[i].FkFields)-1].Type = "bigint"
|
||||
default:
|
||||
log.Fatalf("Error primary key type '%s' in table '%s'", project.DB.Tables[i].Pk, project.DB.Tables[i].Name)
|
||||
}
|
||||
}
|
||||
if len(project.DB.Tables[i].FKs) > 0 {
|
||||
for j := range project.DB.Tables[i].FKs {
|
||||
if project.DB.Tables[i].FKs[j].ID == uuid.Nil {
|
||||
project.DB.Tables[i].FKs[j].ID = uuid.NewV4()
|
||||
}
|
||||
if project.DB.Tables[i].FKs[j].TableID == uuid.Nil && project.DB.Tables[i].FKs[j].TableName != "" {
|
||||
for k := range project.DB.Tables {
|
||||
if project.DB.Tables[k].Name == project.DB.Tables[i].FKs[j].TableName {
|
||||
project.DB.Tables[i].FKs[j].TableID = project.DB.Tables[k].ID
|
||||
project.DB.Tables[i].FKs[j].Type = project.DB.Tables[k].Pk
|
||||
}
|
||||
}
|
||||
}
|
||||
if project.DB.Tables[i].FKs[j].TableID != uuid.Nil {
|
||||
for k := range project.DB.Tables {
|
||||
if project.DB.Tables[k].ID == project.DB.Tables[i].FKs[j].TableID {
|
||||
project.DB.Tables[i].FKs[j].TableName = project.DB.Tables[k].Name
|
||||
project.DB.Tables[k].Children = append(project.DB.Tables[k].Children, project.DB.Tables[i].Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if project.DB.Tables[i].FKs[j].TableName == "" {
|
||||
log.Fatalf("Error foreign key for '%s' table", project.DB.Tables[i].FKs[j].TableID.String())
|
||||
}
|
||||
project.DB.Tables[i].FkFields = append(project.DB.Tables[i].FkFields, structs.Field{
|
||||
Name: fmt.Sprintf("%s", strings.ToLower(project.DB.Tables[i].FKs[j].TableName)),
|
||||
Type: project.DB.Tables[i].Pk,
|
||||
Description: fmt.Sprintf("Foreign key for \\\"%s\\\" table", project.DB.Tables[i].FKs[j].TableName),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return project
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package prepare
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/structs"
|
||||
)
|
||||
|
||||
func PrepareMetadata(project *structs.Project) *structs.Project {
|
||||
if project == nil {
|
||||
log.Fatal("Metadata is empty")
|
||||
}
|
||||
|
||||
if project.Name == "" {
|
||||
log.Fatal("Should be set project name")
|
||||
}
|
||||
|
||||
project = prepareDB(project)
|
||||
project = prepareRoles(project)
|
||||
project = prepareRest(project)
|
||||
|
||||
return project
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package prepare
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/structs"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
func prepareRest(project *structs.Project) *structs.Project {
|
||||
if project == nil {
|
||||
log.Fatal("Пустой проект")
|
||||
}
|
||||
if len(project.Backend.Rest) > 0 {
|
||||
// Обрабатываем REST для подготовки данных
|
||||
for i := range project.Backend.Rest {
|
||||
if _, ok := project.Backend.Rest[i]; !ok {
|
||||
log.Fatal("Нет пути в REST")
|
||||
}
|
||||
if project.Backend.Rest[i].Data.Name == "" && project.Backend.Rest[i].Data.ID == uuid.Nil {
|
||||
log.Fatal("Не указан источник данных")
|
||||
}
|
||||
if project.Backend.Rest[i].Data.Name != "" && project.Backend.Rest[i].Data.ID == uuid.Nil {
|
||||
// Есть имя, но нет ID. Найдем
|
||||
dataArr := strings.Split(project.Backend.Rest[i].Data.Name, ".")
|
||||
if len(dataArr) > 2 {
|
||||
log.Fatal("Неверно указано имя источника данных в REST. Формат: <db/interface>.<Название>")
|
||||
}
|
||||
if len(dataArr) == 2 {
|
||||
// Есть интерфейс
|
||||
switch strings.ToLower(dataArr[0]) {
|
||||
case "db":
|
||||
project.Backend.Rest[i].Data.ID = findSourceDataInDBByName(project, dataArr[1])
|
||||
case "interface":
|
||||
project.Backend.Rest[i].Data.ID = findSourceDataInInterfaceByName(project, dataArr[1])
|
||||
default:
|
||||
log.Fatal("Неизвестный формат источника")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if len(dataArr) == 1 {
|
||||
// Нет интерфейса, по этому ищем где первым попадется
|
||||
project.Backend.Rest[i].Data.ID = findSourceDataInDBByName(project, dataArr[1])
|
||||
if project.Backend.Rest[i].Data.ID != uuid.Nil {
|
||||
continue
|
||||
}
|
||||
project.Backend.Rest[i].Data.ID = findSourceDataInInterfaceByName(project, dataArr[1])
|
||||
if project.Backend.Rest[i].Data.ID == uuid.Nil {
|
||||
log.Fatal("Не найдена структура данных для REST")
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
if project.Backend.Rest[i].Data.Name == "" && project.Backend.Rest[i].Data.ID != uuid.Nil {
|
||||
// Есть имя, но нет ID. Найдем
|
||||
|
||||
project.Backend.Rest[i].Data.Name = findSourceDataInDBByID(project, project.Backend.Rest[i].Data.ID)
|
||||
if project.Backend.Rest[i].Data.ID != uuid.Nil {
|
||||
continue
|
||||
}
|
||||
project.Backend.Rest[i].Data.Name = findSourceDataInInterfaceByID(project, project.Backend.Rest[i].Data.ID)
|
||||
if project.Backend.Rest[i].Data.ID == uuid.Nil {
|
||||
log.Fatal("Не найдена структура данных для REST")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return project
|
||||
}
|
||||
|
||||
// Найти ID таблицы по имени
|
||||
func findSourceDataInDBByName(project *structs.Project, name string) uuid.UUID {
|
||||
if len(project.DB.Tables) == 0 {
|
||||
return uuid.Nil
|
||||
}
|
||||
for i := range project.DB.Tables {
|
||||
if project.DB.Tables[i].Name == name {
|
||||
return project.DB.Tables[i].ID
|
||||
}
|
||||
}
|
||||
return uuid.Nil
|
||||
}
|
||||
|
||||
// Найти имя таблицы по ID
|
||||
func findSourceDataInDBByID(project *structs.Project, id uuid.UUID) string {
|
||||
if len(project.DB.Tables) == 0 {
|
||||
return ""
|
||||
}
|
||||
for i := range project.DB.Tables {
|
||||
if project.DB.Tables[i].ID == id {
|
||||
return project.DB.Tables[i].Name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func findSourceDataInInterfaceByName(project *structs.Project, name string) uuid.UUID {
|
||||
// TODO
|
||||
log.Fatal("Функция в разработки")
|
||||
return uuid.Nil
|
||||
}
|
||||
|
||||
func findSourceDataInInterfaceByID(project *structs.Project, id uuid.UUID) string {
|
||||
// TODO
|
||||
log.Fatal("Функция в разработки")
|
||||
return ""
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package prepare
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"git.ymnuktech.ru/ymnuk/yt-gen-app/structs"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
// Подготовка ролей
|
||||
func prepareRoles(project *structs.Project) *structs.Project {
|
||||
hasAppAdmin := false
|
||||
hasSecAdmin := false
|
||||
if len(project.Roles) > 0 {
|
||||
|
||||
for i := range project.Roles {
|
||||
project.Roles[i].Name = strings.Trim(project.Roles[i].Name, " ")
|
||||
if project.Roles[i].Name == "" {
|
||||
log.Fatal("Should be set role name")
|
||||
}
|
||||
project.Roles[i].Name = strings.ReplaceAll(project.Roles[i].Name, " ", "_")
|
||||
if project.Roles[i].ID == uuid.Nil {
|
||||
project.Roles[i].ID = uuid.NewV4()
|
||||
}
|
||||
if project.Roles[i].Display == "" {
|
||||
project.Roles[i].Display = project.Roles[i].Name
|
||||
}
|
||||
if project.Roles[i].Name == "APP_ADMIN" {
|
||||
hasAppAdmin = true
|
||||
}
|
||||
if project.Roles[i].Name == "SEC_ADMIN" {
|
||||
hasSecAdmin = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if !hasAppAdmin {
|
||||
project.Roles = append(project.Roles, structs.Role{
|
||||
ID: uuid.NewV4(),
|
||||
Name: "APP_ADMIN",
|
||||
Display: "Администратор приложения",
|
||||
})
|
||||
}
|
||||
if !hasSecAdmin {
|
||||
project.Roles = append(project.Roles, structs.Role{
|
||||
ID: uuid.NewV4(),
|
||||
Name: "SEC_ADMIN",
|
||||
Display: "Администратор безопасности",
|
||||
})
|
||||
}
|
||||
|
||||
return project
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package lib
|
||||
package templ
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
|
@ -1,4 +1,4 @@
|
|||
package lib
|
||||
package templ
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
@ -15,21 +15,21 @@ import (
|
|||
)
|
||||
|
||||
//go:embed tmpl/*
|
||||
var content embed.FS
|
||||
var Content embed.FS
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"fieldName": fieldName,
|
||||
"fieldNamePrepare": fieldNamePrepare,
|
||||
"fieldNameLowerPrepare": fieldNameLowerPrepare,
|
||||
"fieldType": fieldType,
|
||||
"hasFieldType": hasFieldType,
|
||||
"fieldDescript": fieldDescript,
|
||||
"configParamName": configParamName,
|
||||
"configParamType": configParamType,
|
||||
"configParamTag": configParamTag,
|
||||
"fieldName": FieldName,
|
||||
"fieldNamePrepare": FieldNamePrepare,
|
||||
"fieldNameLowerPrepare": FieldNameLowerPrepare,
|
||||
"fieldType": FieldType,
|
||||
"hasFieldType": HasFieldType,
|
||||
"fieldDescript": FieldDescript,
|
||||
"configParamName": ConfigParamName,
|
||||
"configParamType": ConfigParamType,
|
||||
"configParamTag": ConfigParamTag,
|
||||
}
|
||||
|
||||
func fieldNamePrepare(value string) string {
|
||||
func FieldNamePrepare(value string) string {
|
||||
value = strings.Trim(value, " ")
|
||||
if value == "" {
|
||||
log.Fatal("Should be set name for field")
|
||||
|
@ -52,7 +52,7 @@ func fieldNamePrepare(value string) string {
|
|||
return value
|
||||
}
|
||||
|
||||
func fieldNameLowerPrepare(value string) string {
|
||||
func FieldNameLowerPrepare(value string) string {
|
||||
var regexpForReplace = regexp.MustCompile(`([A-Z])`)
|
||||
value = strings.ToLower(regexpForReplace.ReplaceAllString(value, "_$1"))
|
||||
if []rune(value)[0] == '_' {
|
||||
|
@ -62,7 +62,7 @@ func fieldNameLowerPrepare(value string) string {
|
|||
return value
|
||||
}
|
||||
|
||||
func fieldName(field *structs.Field) string {
|
||||
func FieldName(field *structs.Field) string {
|
||||
if field == nil {
|
||||
log.Fatal("Field is null")
|
||||
}
|
||||
|
@ -70,12 +70,12 @@ func fieldName(field *structs.Field) string {
|
|||
if field.Name == "" {
|
||||
log.Fatal("Should be set name for field")
|
||||
}
|
||||
field.Name = fieldNamePrepare(field.Name)
|
||||
field.Name = FieldNamePrepare(field.Name)
|
||||
return field.Name
|
||||
}
|
||||
|
||||
// Возвращает имя в БД
|
||||
func fieldDBName(field *structs.Field) (res string) {
|
||||
func FieldDBName(field *structs.Field) (res string) {
|
||||
res = strings.Trim(field.Name, " ")
|
||||
if res == "" {
|
||||
log.Fatal("Shoudl be set name for field")
|
||||
|
@ -84,7 +84,7 @@ func fieldDBName(field *structs.Field) (res string) {
|
|||
return
|
||||
}
|
||||
|
||||
func fieldType(field *structs.Field) string {
|
||||
func FieldType(field *structs.Field) string {
|
||||
if field == nil {
|
||||
log.Fatal("field is empty")
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ func fieldType(field *structs.Field) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func hasFieldType(fields []structs.Field, typeName string) (has bool) {
|
||||
func HasFieldType(fields []structs.Field, typeName string) (has bool) {
|
||||
for _, field := range fields {
|
||||
if (field.Type == "date" || field.Type == "time") && (typeName == "date" || typeName == "time") {
|
||||
return true
|
||||
|
@ -121,7 +121,7 @@ func hasFieldType(fields []structs.Field, typeName string) (has bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
func fieldTypeDB(field *structs.Field) string {
|
||||
func FieldTypeDB(field *structs.Field) string {
|
||||
field.Type = strings.ToLower(strings.Trim(field.Type, " "))
|
||||
switch field.Type {
|
||||
case "text":
|
||||
|
@ -148,8 +148,8 @@ func fieldTypeDB(field *structs.Field) string {
|
|||
}
|
||||
|
||||
// Генерирование описания таблиц в БД
|
||||
func fieldDescript(field *structs.Field) (str string) {
|
||||
str = fmt.Sprintf("`gorm:\"column:%s;type:%s", fieldDBName(field), fieldTypeDB(field))
|
||||
func FieldDescript(field *structs.Field) (str string) {
|
||||
str = fmt.Sprintf("`gorm:\"column:%s;type:%s", FieldDBName(field), FieldTypeDB(field))
|
||||
field.Description = strings.Trim(field.Description, " ")
|
||||
if field.Description != "" {
|
||||
str += fmt.Sprintf(";comment:%s", field.Description)
|
||||
|
@ -160,7 +160,7 @@ func fieldDescript(field *structs.Field) (str string) {
|
|||
}
|
||||
|
||||
// Вернуть название параметра
|
||||
func configParamName(field *structs.ParamConfig) string {
|
||||
func ConfigParamName(field *structs.ParamConfig) string {
|
||||
if field == nil {
|
||||
log.Fatal("Field is null")
|
||||
}
|
||||
|
@ -168,11 +168,11 @@ func configParamName(field *structs.ParamConfig) string {
|
|||
if field.Name == "" {
|
||||
log.Fatal("Should be set name for field")
|
||||
}
|
||||
return fieldNamePrepare(field.Name)
|
||||
return FieldNamePrepare(field.Name)
|
||||
}
|
||||
|
||||
// Вернуть тип параметра
|
||||
func configParamType(field *structs.ParamConfig) string {
|
||||
func ConfigParamType(field *structs.ParamConfig) string {
|
||||
if field == nil {
|
||||
log.Fatal("Param should be set")
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ func configParamType(field *structs.ParamConfig) string {
|
|||
}
|
||||
|
||||
// Вернуть строку для тэгирования параметров
|
||||
func configParamTag(field *structs.ParamConfig) string {
|
||||
func ConfigParamTag(field *structs.ParamConfig) string {
|
||||
if field == nil {
|
||||
log.Fatal("Param should be set")
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ func configParamTag(field *structs.ParamConfig) string {
|
|||
|
||||
func WriteTmplFile(filename string, outname string) error {
|
||||
fmt.Printf("Generate: %s\n", outname)
|
||||
if buff, err := content.ReadFile(filename); err != nil {
|
||||
if buff, err := Content.ReadFile(filename); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err = os.WriteFile(outname, buff, 0755); err != nil {
|
||||
|
@ -230,7 +230,7 @@ func PrepareTmplFile(filename string, data interface{}, outname string) (err err
|
|||
var (
|
||||
buff []byte
|
||||
)
|
||||
if buff, err = content.ReadFile(filename); err != nil {
|
||||
if buff, err = Content.ReadFile(filename); err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
Before Width: | Height: | Size: 948 B After Width: | Height: | Size: 948 B |
|
@ -1,11 +1,31 @@
|
|||
package structs
|
||||
|
||||
import uuid "github.com/satori/go.uuid"
|
||||
|
||||
type Backend struct {
|
||||
Config []ParamConfig `yaml:"config" json:"config"` // Параметры, передаваемые при запуске сервера
|
||||
Config []ParamConfig `yaml:"config,omitempty" json:"config,omitempty"` // Параметры, передаваемые при запуске сервера
|
||||
Rest map[string]*Rest `yaml:"rest,omitempty" json:"rest,omitempty"` // Подготовка REST для сервера
|
||||
RestGroups []string `yaml:"-" json:"-"` // Названия групп
|
||||
}
|
||||
|
||||
type ParamConfig struct {
|
||||
Name string `yaml:"name" json:"name"` // Название параметра
|
||||
Type string `yaml:"type" json:"type"` // Тип параметра
|
||||
Help string `yaml:"help" json:"help"` // Справка помощи параметра
|
||||
Name string `yaml:"name" json:"name,omitempty" default:"param"` // Название параметра
|
||||
Type string `yaml:"type" json:"type,omitempty" default:"string"` // Тип параметра
|
||||
Help string `yaml:"help" json:"help,omitempty"` // Справка помощи параметра
|
||||
}
|
||||
|
||||
type VisField struct {
|
||||
ID uuid.UUID `yaml:"id,omitempty" json:"id,omitempty"`
|
||||
Name string `yaml:"name,omitempty" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type Rest struct {
|
||||
GroupName string `yaml:"groupName,omitempty" json:"groupName,omitempty" default:"nogroup"` // Имя группы, в которую входит данный путь REST
|
||||
Data VisField `yaml:"data,omitempty" json:"data,omitempty"` // Модель данных, на основе которой строиться запрос
|
||||
Visible []VisField `yaml:"visible,omitempty" json:"visible,omitempty"` // Список видимых полей. Если указан хоть один, то отображаются только те, которые указаны, иначе отображаются все
|
||||
Invisible []VisField `yaml:"invisible,omitempty" json:"invisible,omitempty"` // Список невидимых полей. Если указан хоть один, то отображаются все кроме указанного, иначе берется правило из поля "visible". Является приоритетным и в данном случае поле "visible" игнорируется
|
||||
Filter []VisField `yaml:"filter,omitempty" json:"filter,omitempty"` // Указывается список полей, по которым будет осуществляться поиск
|
||||
Editable bool `yaml:"editable,omitempty" json:"editable,omitempty"` // Модель является редактируемой, т.е. необходимо сгенерировать rest для данной модели. Для данного пути будут сформированы методы GET, POST, PUT и DELETE с соответствующим путем /<path>/{id}
|
||||
FieldID VisField `yaml:"fieldId,omitempty" json:"fieldId,omitempty"` // Поле, которое является ключевым при работе с конкретной записью
|
||||
Roles map[string][]string `yaml:"roles,omitempty" json:"roles,omitempty"` // Список ролей, которым разрешено работать с данным. Операция: массив строк с названием ролей. Если не указано, то все роли. Операция для просмотра списка: LIST
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue