From 07465cfafeaeae5431b2a64e217396ceabfb15b4 Mon Sep 17 00:00:00 2001 From: RPJosh Date: Tue, 9 Apr 2024 19:10:16 +0200 Subject: [PATCH] Add json tags and fix smaller issues --- go.mod | 11 ++++--- mariadb.go | 3 +- mariadb_test.go | 2 +- struct.go | 3 -- structt/struct.go | 66 +++++++++++++++++++++++++++++++++++------- structt/struct_test.go | 5 ++-- 6 files changed, 69 insertions(+), 21 deletions(-) delete mode 100644 struct.go diff --git a/go.mod b/go.mod index 68be373..9bbf4f0 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,14 @@ module git.rpjosh.de/RPJosh/go-ddl-parser go 1.22.1 +require ( + git.rpjosh.de/RPJosh/go-logger v1.3.2 + github.com/davecgh/go-spew v1.1.1 + github.com/go-sql-driver/mysql v1.8.1 + github.com/google/go-cmp v0.6.0 +) + require ( filippo.io/edwards25519 v1.1.0 // indirect - git.rpjosh.de/RPJosh/go-logger v1.3.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/google/go-cmp v0.6.0 // indirect golang.org/x/sys v0.19.0 // indirect ) diff --git a/mariadb.go b/mariadb.go index 6ed331b..99258b7 100644 --- a/mariadb.go +++ b/mariadb.go @@ -70,7 +70,7 @@ func (s *Mariadb) GetTable(schema, name string) (*Table, error) { c.IS_NULLABLE, c.DATA_TYPE, c.COLUMN_TYPE, - COALESCE(c.CHARACTER_MAXIMUM_LENGTH, c.NUMERIC_PRECISION, c.DATETIME_PRECISION), + COALESCE(c.CHARACTER_MAXIMUM_LENGTH, c.NUMERIC_PRECISION, c.DATETIME_PRECISION, 0), c.COLUMN_KEY, c.COLUMN_COMMENT, c.extra, @@ -142,6 +142,7 @@ func (s *Mariadb) GetTables(schema string) ([]*Table, error) { t.TABLE_NAME FROM information_schema.tables t WHERE t.table_schema = ? + ORDER BY t.TABLE_NAME ASC ` rows, err := s.db.Query(sql, schema) if err != nil { diff --git a/mariadb_test.go b/mariadb_test.go index 2d933fa..0b16e1f 100644 --- a/mariadb_test.go +++ b/mariadb_test.go @@ -280,7 +280,7 @@ func ConnectToMariadb(t *testing.T) *sql.DB { } // createMariadbTable creates a table with the provided column configuration -// in statementand returns the created table name +// in statement and returns the created table name func createMariadbTable(db *sql.DB, statement string) (string, error) { name, _ := GenerateRandomString(8) name = "ddl_test_" + name diff --git a/struct.go b/struct.go deleted file mode 100644 index 7368f00..0000000 --- a/struct.go +++ /dev/null @@ -1,3 +0,0 @@ -package ddl - -// @TODO hier table -> struct diff --git a/structt/struct.go b/structt/struct.go index d3f10ad..c1fe25b 100644 --- a/structt/struct.go +++ b/structt/struct.go @@ -4,9 +4,12 @@ import ( "errors" "fmt" "os" + "os/exec" "regexp" "sort" "strings" + "unicode" + "unicode/utf8" "git.rpjosh.de/RPJosh/go-ddl-parser" @@ -114,6 +117,13 @@ func CreateStructs(conf *StructConfig, tables []*ddl.Table) error { return fmt.Errorf("failed to write file %q: %s", tblConfig.Path, err) } f.Close() + + // Lint go file + cmd := exec.Command("go", "fmt", tblConfig.Path) + if err := cmd.Run(); err != nil { + logger.Warning("Failed to run go fmt: %s", err) + } + cmd.Wait() } return nil @@ -144,6 +154,24 @@ func GetFieldName(fieldName string) string { return rtc } +// GetJsonName returns the json key value for the provided fildName of +// the database. +// The json keys are CamelCased +func GetJsonName(fieldName string) string { + structField := GetFieldName(fieldName) + + // Lowercase the first character for json + r, size := utf8.DecodeRuneInString(structField) + if r == utf8.RuneError && size <= 1 { + return structField + } + lc := unicode.ToLower(r) + if r == lc { + return structField + } + return string(lc) + structField[size:] +} + // findTableConfig returns a specific table configuration for the table // or an empty configuration struct if no one was provided func (c *constructor) findTableConfig(tbl *ddl.Table) *TableConfig { @@ -215,7 +243,8 @@ func (c *constructor) getGoFile(existingContent string, tbl *ddl.Table, tblConfi } fieldName := GetFieldName(col.Name) - rtc += fmt.Sprintf("\t%s %s `%s:\"%s\"`\n", fieldName, dataType, ColumnTagId, tags.ToTag()) + jsonName := GetJsonName(col.Name) + rtc += fmt.Sprintf("\t%s %s `json:\"%s\" %s:\"%s\"`\n", fieldName, dataType, jsonName, ColumnTagId, tags.ToTag()) columns += fmt.Sprintf("\t %s_%s string = \"%s\"\n", tableName, fieldName, fieldName) } @@ -235,7 +264,7 @@ func (c *constructor) getGoFile(existingContent string, tbl *ddl.Table, tblConfi Schema: tbl.Schema, Table: tbl.Name, } - rtc += fmt.Sprintf("\t%s any `%s:\"%s\"`\n", MetadataFieldName, MetadataTagId, metaData.ToTag()) + rtc += fmt.Sprintf("\t%s any `json:\"-\" %s:\"%s\"`\n", MetadataFieldName, MetadataTagId, metaData.ToTag()) // Add closing line rtc += "}\n" @@ -243,7 +272,7 @@ func (c *constructor) getGoFile(existingContent string, tbl *ddl.Table, tblConfi // Add package header if no file exists already if existingContent == "" { - header := fmt.Sprintf("package %s\n", tblConfig.PackageName) + header := fmt.Sprintf("package %s\n\n", tblConfig.PackageName) importStr := "" if len(imports) != 0 { importStr = "import (\n" @@ -253,9 +282,9 @@ func (c *constructor) getGoFile(existingContent string, tbl *ddl.Table, tblConfi importStr += ")\n" } - rtc = header + importStr + rtc + columns + rtc = header + importStr + "\n" + rtc + columns } else { - // @TODO merge file... + rtc = c.patchFile(existingContent, rtc+columns, tbl, tblConfig, imports) } return rtc @@ -277,9 +306,9 @@ func (c *constructor) getDataType(column *ddl.Column, tblConfig *TableConfig, ta case ddl.StringType: return "sql.NullString", "database/sql" case ddl.IntType: - return "sql.NullInt", "database/sql" + return "sql.NullInt64", "database/sql" case ddl.DoubleType: - return "sql.NullFloat", "database/sql" + return "sql.NullFloat64", "database/sql" case ddl.DateType: return "sql.NullTime", "database/sql" } @@ -291,7 +320,7 @@ func (c *constructor) getDataType(column *ddl.Column, tblConfig *TableConfig, ta case ddl.IntType: return "int", "" case ddl.DoubleType: - return "float", "" + return "float64", "" case ddl.DateType: return "time.Time", "time" } @@ -397,7 +426,7 @@ func (c *constructor) patchFile(existingContent string, newStruct string, tbl *d if reg.MatchString(existingContent) { // Replace content - return reg.ReplaceAllString(existingContent, newStruct+"\n") + return reg.ReplaceAllString(existingContent, newStruct) } else { // Append content return existingContent + "\n" + newStruct @@ -413,11 +442,12 @@ func (c *constructor) patchImports(existingContent string, imports map[string]bo reg := regexp.MustCompile(`"([^"]+)"`) var importStart, importEnd int + importFound := true // Find any existing import clause within the first 5 lines for i, line := range strings.Split(existingContent, "\n") { // No import found if i > 5 && importStart == 0 { - return existingContent, nil + importFound = false } // Trim any whitespace for import @@ -480,6 +510,22 @@ func (c *constructor) patchImports(existingContent string, imports map[string]bo } newImport += ")" + // We didn't found an existing import statment yet that we could replace + if !importFound { + lines := strings.Split(existingContent, "\n") + + // Only a single line -> add it directly below + if len(lines) <= 1 { + lines = append(lines, "") + lines = append(lines, strings.Split(newImport, "\n")...) + } else { + // Insert it into existing, empty line + return replaceLines(existingContent, 1, 1, strings.Split("\n"+newImport, "\n")), nil + } + + return strings.Join(lines, "\n"), nil + } + // Replace import string return replaceLines(existingContent, importStart, importEnd, strings.Split(newImport, "\n")), nil } diff --git a/structt/struct_test.go b/structt/struct_test.go index bd4723d..88b9dd9 100644 --- a/structt/struct_test.go +++ b/structt/struct_test.go @@ -393,6 +393,7 @@ func TestPatchFilePatchSelf(t *testing.T) { // Replace a single column ID to test some change. // WithUnder -> ReplacedColumn expected = strings.ReplaceAll(expected, "WithUnder", "ReplacedColumn") + expected = strings.ReplaceAll(expected, "withUnder", "replacedColumn") expected = strings.ReplaceAll(expected, "with_under", "replaced_column") tbl.Columns[1].Name = "replaced_column" @@ -429,13 +430,13 @@ func replaceWhitespaces(val string) string { // getStructTag returns the tag for a struct to append to. // We already tested the struct tags in another test! func getStructTag(col *ddl.Column) string { - tagStart := "`" + ColumnTagId + ":\"" + tagStart := "`json:\"" + GetJsonName(col.Name) + "\" " + ColumnTagId + ":\"" tagEnd := "\"`" return tagStart + GetColumnTag(col).ToTag() + tagEnd } func getMetadataTag(tbl *ddl.Table) string { - tagStart := "`" + MetadataTagId + ":\"" + tagStart := "`json:\"-\" " + MetadataTagId + ":\"" tagEnd := "\"`" m := &MetadataTag{