From dee183ae76f5fb379d7e02848ea83cea9b4afc29 Mon Sep 17 00:00:00 2001 From: ycc Date: Fri, 3 Dec 2021 11:19:53 +0100 Subject: [PATCH] schema and template functions --- go.sum | 2 - pfn.json | 67 ++++++++++++++++++ pg.go | 163 +++++++++++++++++++++++++++++++++++++++++++- pg_test.go | 52 +++++++++++++- plantuml.tmpl | 14 ++++ table.tmpl | 1 + testtype_table.json | 17 ++--- 7 files changed, 299 insertions(+), 17 deletions(-) create mode 100644 pfn.json create mode 100644 plantuml.tmpl create mode 100644 table.tmpl diff --git a/go.sum b/go.sum index 9d1653a..8288f47 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,2 @@ -github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= -github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg= github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= diff --git a/pfn.json b/pfn.json new file mode 100644 index 0000000..0cdfcdb --- /dev/null +++ b/pfn.json @@ -0,0 +1,67 @@ + +[ + { + "name":"computer", + "columns": + { + "id":"integer", + "name":"varchar(255)|comment", + "description":"varchar(1000)", + "os":"varchar(255)" + } + }, + { + "name":"software", + "columns": + { + "id":"integer", + "name":"varchar(255)|comment", + "description":"varchar(1000)", + "licenseend":"date", + "support":"varchar(255)", + "company":"varchar(255)" + } + }, + { + "name":"software_computer", + "columns": + { + "id":"integer", + "computer_id":"integer", + "software_id":"integer" + } + }, + { + "name":"person", + "columns": + { + "id":"integer", + "name":"varchar(255)", + "firstname":"varchar(255)", + "email":"varchar(255)", + "mobile":"varchar(255)" + } + }, + { + "name":"entity", + "columns": + { + "id":"integer", + "name":"varchar(255)", + "type":"varchar(255)", + "startdate":"date", + "enddate":"date" + } + }, + { + "name":"timetracking", + "columns": + { + "id":"integer", + "day":"date", + "morning_entity_id":"integer", + "afternoon_entity_id":"integer", + "comment":"varchar(255)" + } + } +] \ No newline at end of file diff --git a/pg.go b/pg.go index 8bf671f..2773f0f 100755 --- a/pg.go +++ b/pg.go @@ -2,8 +2,12 @@ package sqldb import ( "database/sql" + "encoding/json" "fmt" + "html/template" + "io/ioutil" "log" + "os" "strconv" "strings" @@ -29,6 +33,11 @@ type TableInfo struct { db *Db } +type Link struct { + Source string + Destination string +} + // Open the database func Open(driver string, url string) *Db { var database Db @@ -135,6 +144,30 @@ func (t *TableInfo) GetSchema() (*TableInfo, error) { return &ti, nil } +func (db *Db) GetSchema() ([]TableInfo, error) { + var res []TableInfo + tables, err := db.ListTables() + if err != nil { + log.Println(err.Error()) + return nil, err + } + for _, row := range tables { + for _, element := range row { + var ti TableInfo + var fullti *TableInfo + ti.Name = fmt.Sprintf("%v", element) + ti.db = db + fullti, err = ti.GetSchema() + if err != nil { + log.Println(err.Error()) + return nil, err + } + res = append(res, *fullti) + } + } + return res, nil +} + func (db *Db) ListTables() (Rows, error) { return db.QueryAssociativeArray("SELECT table_name :: varchar as name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name;") } @@ -220,6 +253,46 @@ func (t *TableInfo) DeleteColumn(name string) error { return nil } +func (db *Db) ImportSchema(filename string) { + jsonFile, err := os.Open(filename) + if err != nil { + log.Println(err) + } + defer jsonFile.Close() + + byteValue, _ := ioutil.ReadAll(jsonFile) + + var jsonSource []TableInfo + json.Unmarshal([]byte(byteValue), &jsonSource) + for _, ti := range jsonSource { + ti.db = db + err = db.CreateTable(ti) + if err != nil { + log.Println(err.Error()) + } + } +} + +func (db *Db) ClearImportSchema(filename string) { + jsonFile, err := os.Open(filename) + if err != nil { + log.Println(err) + } + defer jsonFile.Close() + + byteValue, _ := ioutil.ReadAll(jsonFile) + + var jsonSource []TableInfo + json.Unmarshal([]byte(byteValue), &jsonSource) + for _, ti := range jsonSource { + ti.db = db + err = ti.DeleteTable() + if err != nil { + log.Println(err.Error()) + } + } +} + func (db *Db) ListSequences() (Rows, error) { return db.QueryAssociativeArray("SELECT sequence_name :: varchar FROM information_schema.sequences WHERE sequence_schema = 'public' ORDER BY sequence_name;") } @@ -340,7 +413,6 @@ func (t *TableInfo) UpdateOrInsert(record AssRow) (int, error) { t.Update(record) return id, nil } - } func removeLastChar(s string) string { @@ -368,3 +440,92 @@ func (ar *AssRow) GetFloat(column string) float64 { func Quote(str string) string { return pq.QuoteLiteral(str) } + +func (db *Db) SaveSchema(generatedFilename string) error { + schema, err := db.GetSchema() + if err != nil { + log.Println(err) + return err + } + file, _ := json.MarshalIndent(schema, "", " ") + _ = ioutil.WriteFile(generatedFilename, file, 0644) + return nil +} + +func buildLinks(schema []TableInfo) []Link { + var links []Link + for _, ti := range schema { + fmt.Println(ti.Name) + for column, _ := range ti.Columns { + if strings.HasSuffix(column, "_id") { + tokens := strings.Split(column, "_") + linkedtable := tokens[len(tokens)-2] + var link Link + link.Source = ti.Name + link.Destination = linkedtable + links = append(links, link) + } + } + } + return links +} + +func (db *Db) GenerateTemplate(templateFilename string, generatedFilename string) error { + schema, err := db.GetSchema() + if err != nil { + log.Println(err) + return err + } + links := buildLinks(schema) + data := struct { + Tbl []TableInfo + Lnk []Link + }{ + schema, + links, + } + + t, err := template.ParseFiles(templateFilename) + if err != nil { + log.Println(err) + return err + } + f, err := os.Create(generatedFilename) + if err != nil { + log.Println("create file: ", err) + return err + } + err = t.Execute(f, data) + if err != nil { + log.Println(err) + return err + } + return nil +} + +func (db *Db) GenerateTableTemplates(templateFilename string, outputFolder string, extension string) error { + schema, err := db.GetSchema() + if err != nil { + log.Println(err) + return err + } + for _, ti := range schema { + + t, err := template.ParseFiles(templateFilename) + if err != nil { + log.Println(err) + return err + } + f, err := os.Create(outputFolder + string(os.PathSeparator) + ti.Name + "." + extension) + if err != nil { + log.Println("create file: ", err) + return err + } + err = t.Execute(f, ti) + if err != nil { + log.Println(err) + return err + } + } + return nil +} diff --git a/pg_test.go b/pg_test.go index db84649..fb8a187 100755 --- a/pg_test.go +++ b/pg_test.go @@ -12,7 +12,7 @@ func TestCreateTable(t *testing.T) { db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") defer db.Close() - jsonFile, err := os.Open("test_table.json") + jsonFile, err := os.Open("testtype_table.json") if err != nil { fmt.Println(err) } @@ -171,7 +171,55 @@ func TestDeleteColumn(t *testing.T) { func TestDeleteTable(t *testing.T) { db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") defer db.Close() - db.Table("test").DeleteTable() } + +func TestImportSchema(t *testing.T) { + db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") + defer db.Close() + db.ImportSchema("pfn.json") +} + +func TestClearImportSchema(t *testing.T) { + db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") + defer db.Close() + db.ClearImportSchema("pfn.json") +} + +func TestGetSchema(t *testing.T) { + db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") + defer db.Close() + data, err := db.GetSchema() + if err != nil { + fmt.Println(err.Error()) + } + val, _ := json.Marshal(data) + fmt.Println(string(val)) +} + +func TestSaveSchema(t *testing.T) { + db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") + defer db.Close() + err := db.SaveSchema("schema.json") + if err != nil { + fmt.Println(err.Error()) + } +} +func TestGenerateTemplate(t *testing.T) { + db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") + defer db.Close() + err := db.GenerateTemplate("plantuml.tmpl", "schema.puml") + if err != nil { + fmt.Println(err.Error()) + } +} + +func TestGenerateTableTemplate(t *testing.T) { + db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") + defer db.Close() + err := db.GenerateTableTemplates("table.tmpl", "gen", "html") + if err != nil { + fmt.Println(err.Error()) + } +} diff --git a/plantuml.tmpl b/plantuml.tmpl new file mode 100644 index 0000000..36a9871 --- /dev/null +++ b/plantuml.tmpl @@ -0,0 +1,14 @@ +@startuml + +{{range .Tbl}} +entity {{.Name}} { +{{range $key, $value := .Columns}} {{$key}} : {{$value}} +{{end}}} +{{end}} + +{{range .Lnk}} +{{.Source}} ||..|| {{.Destination}} +{{end}} + +@enduml + diff --git a/table.tmpl b/table.tmpl new file mode 100644 index 0000000..6d5232f --- /dev/null +++ b/table.tmpl @@ -0,0 +1 @@ +{{.Name}} \ No newline at end of file diff --git a/testtype_table.json b/testtype_table.json index 63a00db..fc67366 100644 --- a/testtype_table.json +++ b/testtype_table.json @@ -1,17 +1,10 @@ { "name":"testtype", - "columns":[ + "columns": { - "name":"id", - "type":"integer" - }, - { - "name":"name", - "type":"varchar(255)" - }, - { - "name":"detail", - "type":"varchar(255)" + "id":"integer", + "name":"varchar(255)", + "detail":"varchar(255)" } - ] + } \ No newline at end of file