From d4f8196920edb632b625f70526a456495e556117 Mon Sep 17 00:00:00 2001 From: "S.W.H" Date: Mon, 27 Jan 2014 21:28:13 +0800 Subject: [PATCH 1/2] fixbug: parse DECIMAL(10, 2) failure. --- engine.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/engine.go b/engine.go index 1f2312de..e0aa2bf2 100644 --- a/engine.go +++ b/engine.go @@ -484,7 +484,8 @@ func (engine *Engine) mapType(t reflect.Type) *Table { var indexType int var indexName string var preKey string - for j, key := range tags { + for j,ln := 0,len(tags); j < ln; j++ { + key := tags[j] k := strings.ToUpper(key) switch { case k == "<-": @@ -535,7 +536,18 @@ func (engine *Engine) mapType(t reflect.Type) *Table { if preKey != "DEFAULT" { col.Name = key[1 : len(key)-1] } - } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { + } else if strings.Contains(k, "(") && (strings.HasSuffix(k, ")") || strings.HasSuffix(k, ",")) { + //[SWH|+] + if strings.HasSuffix(k, ",") { + j++ + for j < ln { + k += tags[j] + if strings.HasSuffix(tags[j], ")") { + break + } + j++ + } + } fs := strings.Split(k, "(") if _, ok := sqlTypes[fs[0]]; !ok { preKey = k From 46fe2ce87ed20148720734f0b642a179b86337c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=95=86=E8=AE=AF=E5=9C=A8=E7=BA=BF?= Date: Thu, 30 Jan 2014 13:10:15 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=B8=80=E3=80=81xorm=E5=8F=8D=E8=BD=AC?= =?UTF-8?q?=E5=B7=A5=E5=85=B7bug=E4=BF=AE=E5=A4=8D=EF=BC=9A=201=E3=80=81xo?= =?UTF-8?q?rm=E5=8F=8D=E8=BD=AC=E5=B7=A5=E5=85=B7=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=A1=A8=E5=89=8D=E7=BC=80=E6=94=AF=E6=8C=81=EF=BC=9B=202?= =?UTF-8?q?=E3=80=81=E4=BF=AE=E6=AD=A3decimal(5,=202)=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E4=B8=AD=E6=8B=AC=E5=8F=B7=E5=86=85=E5=87=BA=E7=8E=B0=E7=A9=BA?= =?UTF-8?q?=E6=A0=BC=E5=AF=BC=E8=87=B4=E8=A7=A3=E6=9E=90=E5=87=BA=E9=94=99?= =?UTF-8?q?=E7=9A=84bug=EF=BC=9B=203=E3=80=81=E4=BF=AE=E6=AD=A3xorm?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=B7=A5=E5=85=B7=E5=9C=A8windows=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E4=B8=8B=EF=BC=8C=E6=8C=87=E5=AE=9A=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E6=97=B6model=E5=90=8D=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=B8=8D=E6=AD=A3=E7=A1=AE=E7=9A=84bug=20=E4=BA=8C=E3=80=81xor?= =?UTF-8?q?m=E5=AF=B9=E4=BA=8E=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E4=B8=BA=E6=96=87=E6=9C=AC=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC=E4=B8=BA=E7=A9=BA=E7=99=BD=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=9A=84struct=E4=B8=ADdefault=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E4=B8=A2=E5=A4=B1=E7=9A=84bug=EF=BC=8C=E5=B7=B2=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 商讯在线 --- engine.go | 37 ++-- mssql.go | 32 +-- mysql.go | 7 + oracle.go | 7 + postgres.go | 7 + table.go | 1 + xorm/go.go | 2 +- xorm/reverse.go | 419 ++++++++++++++++++----------------- xorm/templates/goxorm/config | 1 + 9 files changed, 278 insertions(+), 235 deletions(-) diff --git a/engine.go b/engine.go index e0aa2bf2..71ef63b4 100644 --- a/engine.go +++ b/engine.go @@ -484,8 +484,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { var indexType int var indexName string var preKey string - for j,ln := 0,len(tags); j < ln; j++ { - key := tags[j] + for j, key := range tags { k := strings.ToUpper(key) switch { case k == "<-": @@ -536,18 +535,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table { if preKey != "DEFAULT" { col.Name = key[1 : len(key)-1] } - } else if strings.Contains(k, "(") && (strings.HasSuffix(k, ")") || strings.HasSuffix(k, ",")) { - //[SWH|+] - if strings.HasSuffix(k, ",") { - j++ - for j < ln { - k += tags[j] - if strings.HasSuffix(tags[j], ")") { - break - } - j++ - } - } + } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { fs := strings.Split(k, "(") if _, ok := sqlTypes[fs[0]]; !ok { preKey = k @@ -623,9 +611,24 @@ func (engine *Engine) mapType(t reflect.Type) *Table { } } else { sqlType := Type2SQLType(fieldType) - col = &Column{engine.columnMapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType, - sqlType.DefaultLength, sqlType.DefaultLength2, true, "", make(map[string]bool), false, false, - TWOSIDES, false, false, false, false} + col = &Column{ + Name: engine.columnMapper.Obj2Table(t.Field(i).Name), + FieldName: t.Field(i).Name, + SQLType: sqlType, + Length: sqlType.DefaultLength, + Length2: sqlType.DefaultLength2, + Nullable: true, + Default: "", + Indexes: make(map[string]bool), + IsPrimaryKey: false, + IsAutoIncrement:false, + MapType: TWOSIDES, + IsCreated: false, + IsUpdated: false, + IsCascade: false, + IsVersion: false, + DefaultIsEmpty: false, + } } if col.IsAutoIncrement { col.Nullable = false diff --git a/mssql.go b/mssql.go index 3606332f..6e9776d2 100644 --- a/mssql.go +++ b/mssql.go @@ -136,8 +136,8 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) { func (db *mssql) GetColumns(tableName string) ([]string, map[string]*Column, error) { args := []interface{}{} - s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale -from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id + s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale +from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id where a.object_id=object_id('` + tableName + `')` cnn, err := sql.Open(db.driverName, db.dataSourceName) if err != nil { @@ -187,6 +187,10 @@ where a.object_id=object_id('` + tableName + `')` if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" + }else{ + if col.DefaultIsEmpty { + col.Default = "''" + } } } cols[col.Name] = col @@ -224,18 +228,18 @@ func (db *mssql) GetTables() ([]*Table, error) { func (db *mssql) GetIndexes(tableName string) (map[string]*Index, error) { args := []interface{}{tableName} - s := `SELECT -IXS.NAME AS [INDEX_NAME], -C.NAME AS [COLUMN_NAME], -IXS.is_unique AS [IS_UNIQUE], -CASE IXCS.IS_INCLUDED_COLUMN -WHEN 0 THEN 'NONE' -ELSE 'INCLUDED' END AS [IS_INCLUDED_COLUMN] -FROM SYS.INDEXES IXS -INNER JOIN SYS.INDEX_COLUMNS IXCS -ON IXS.OBJECT_ID=IXCS.OBJECT_ID AND IXS.INDEX_ID = IXCS.INDEX_ID -INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID -AND IXCS.COLUMN_ID=C.COLUMN_ID + s := `SELECT +IXS.NAME AS [INDEX_NAME], +C.NAME AS [COLUMN_NAME], +IXS.is_unique AS [IS_UNIQUE], +CASE IXCS.IS_INCLUDED_COLUMN +WHEN 0 THEN 'NONE' +ELSE 'INCLUDED' END AS [IS_INCLUDED_COLUMN] +FROM SYS.INDEXES IXS +INNER JOIN SYS.INDEX_COLUMNS IXCS +ON IXS.OBJECT_ID=IXCS.OBJECT_ID AND IXS.INDEX_ID = IXCS.INDEX_ID +INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID +AND IXCS.COLUMN_ID=C.COLUMN_ID WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? ` cnn, err := sql.Open(db.driverName, db.dataSourceName) diff --git a/mysql.go b/mysql.go index 4dcde839..aff13333 100644 --- a/mysql.go +++ b/mysql.go @@ -212,6 +212,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err case "COLUMN_DEFAULT": // add '' col.Default = string(content) + if col.Default == "" { + col.DefaultIsEmpty = true + } case "COLUMN_TYPE": cts := strings.Split(string(content), "(") var len1, len2 int @@ -256,6 +259,10 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*Column, err if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" + }else{ + if col.DefaultIsEmpty { + col.Default = "''" + } } } cols[col.Name] = col diff --git a/oracle.go b/oracle.go index 4e3c6fb6..0b4238ca 100644 --- a/oracle.go +++ b/oracle.go @@ -139,6 +139,9 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er col.Name = strings.Trim(string(content), `" `) case "data_default": col.Default = string(content) + if col.Default == "" { + col.DefaultIsEmpty = true + } case "nullable": if string(content) == "Y" { col.Nullable = true @@ -171,6 +174,10 @@ func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, er if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" + }else{ + if col.DefaultIsEmpty { + col.Default = "''" + } } } cols[col.Name] = col diff --git a/postgres.go b/postgres.go index 97550543..4c7f97e2 100644 --- a/postgres.go +++ b/postgres.go @@ -177,6 +177,9 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, col.IsPrimaryKey = true } else { col.Default = string(content) + if col.Default == "" { + col.DefaultIsEmpty = true + } } case "is_nullable": if string(content) == "YES" { @@ -218,6 +221,10 @@ func (db *postgres) GetColumns(tableName string) ([]string, map[string]*Column, if col.SQLType.IsText() { if col.Default != "" { col.Default = "'" + col.Default + "'" + }else{ + if col.DefaultIsEmpty { + col.Default = "''" + } } } cols[col.Name] = col diff --git a/table.go b/table.go index 76b4c3ae..34cb0862 100644 --- a/table.go +++ b/table.go @@ -275,6 +275,7 @@ type Column struct { IsUpdated bool IsCascade bool IsVersion bool + DefaultIsEmpty bool } // generate column description string according dialect diff --git a/xorm/go.go b/xorm/go.go index 682f6b0b..533ce026 100644 --- a/xorm/go.go +++ b/xorm/go.go @@ -241,7 +241,7 @@ func tag(table *xorm.Table, col *xorm.Column) string { nstr := col.SQLType.Name if col.Length != 0 { if col.Length2 != 0 { - nstr += fmt.Sprintf("(%v, %v)", col.Length, col.Length2) + nstr += fmt.Sprintf("(%v,%v)", col.Length, col.Length2) } else { nstr += fmt.Sprintf("(%v)", col.Length) } diff --git a/xorm/reverse.go b/xorm/reverse.go index 17accfe5..7eab1980 100644 --- a/xorm/reverse.go +++ b/xorm/reverse.go @@ -1,26 +1,27 @@ package main import ( - "bytes" - "fmt" - _ "github.com/bylevel/pq" - "github.com/dvirsky/go-pylog/logging" - _ "github.com/go-sql-driver/mysql" - "github.com/lunny/xorm" - _ "github.com/mattn/go-sqlite3" - _ "github.com/ziutek/mymysql/godrv" - "io/ioutil" - "os" - "path" - "path/filepath" - "strconv" - "text/template" + "bytes" + "fmt" + _ "github.com/bylevel/pq" + "github.com/dvirsky/go-pylog/logging" + _ "github.com/go-sql-driver/mysql" + "github.com/lunny/xorm" + _ "github.com/mattn/go-sqlite3" + _ "github.com/ziutek/mymysql/godrv" + "io/ioutil" + "os" + "path" + "path/filepath" + "strconv" + "strings" //[SWH|+] + "text/template" ) var CmdReverse = &Command{ - UsageLine: "reverse [-m] driverName datasourceName tmplPath [generatedPath]", - Short: "reverse a db to codes", - Long: ` + UsageLine: "reverse [-m] driverName datasourceName tmplPath [generatedPath]", + Short: "reverse a db to codes", + Long: ` according database's tables and columns to generate codes for Go, C++ and etc. -m Generated one go file for every table @@ -33,236 +34,248 @@ according database's tables and columns to generate codes for Go, C++ and etc. } func init() { - CmdReverse.Run = runReverse - CmdReverse.Flags = map[string]bool{ - "-s": false, - "-l": false, - } + CmdReverse.Run = runReverse + CmdReverse.Flags = map[string]bool{ + "-s": false, + "-l": false, + } } var ( - genJson bool = false + genJson bool = false ) func printReversePrompt(flag string) { } type Tmpl struct { - Tables []*xorm.Table - Imports map[string]string - Model string + Tables []*xorm.Table + Imports map[string]string + Model string } func dirExists(dir string) bool { - d, e := os.Stat(dir) - switch { - case e != nil: - return false - case !d.IsDir(): - return false - } + d, e := os.Stat(dir) + switch { + case e != nil: + return false + case !d.IsDir(): + return false + } - return true + return true } func runReverse(cmd *Command, args []string) { - num := checkFlags(cmd.Flags, args, printReversePrompt) - if num == -1 { - return - } - args = args[num:] + num := checkFlags(cmd.Flags, args, printReversePrompt) + if num == -1 { + return + } + args = args[num:] - if len(args) < 3 { - fmt.Println("params error, please see xorm help reverse") - return - } + if len(args) < 3 { + fmt.Println("params error, please see xorm help reverse") + return + } - var isMultiFile bool = true - if use, ok := cmd.Flags["-s"]; ok { - isMultiFile = !use - } + var isMultiFile bool = true + if use, ok := cmd.Flags["-s"]; ok { + isMultiFile = !use + } - curPath, err := os.Getwd() - if err != nil { - fmt.Println(curPath) - return - } + curPath, err := os.Getwd() + if err != nil { + fmt.Println(curPath) + return + } - var genDir string - var model string - if len(args) == 4 { + var genDir string + var model string + if len(args) == 4 { - genDir, err = filepath.Abs(args[3]) - if err != nil { - fmt.Println(err) - return - } - model = path.Base(genDir) - } else { - model = "model" - genDir = path.Join(curPath, model) - } + genDir, err = filepath.Abs(args[3]) + if err != nil { + fmt.Println(err) + return + } + //[SWH|+] 经测试,path.Base不能解析windows下的“\”,需要替换为“/” + genDir = strings.Replace(genDir, "\\", "/", -1) + model = path.Base(genDir) + } else { + model = "model" + genDir = path.Join(curPath, model) + } - dir, err := filepath.Abs(args[2]) - if err != nil { - logging.Error("%v", err) - return - } + dir, err := filepath.Abs(args[2]) + if err != nil { + logging.Error("%v", err) + return + } - if !dirExists(dir) { - logging.Error("Template %v path is not exist", dir) - return - } + if !dirExists(dir) { + logging.Error("Template %v path is not exist", dir) + return + } - var langTmpl LangTmpl - var ok bool - var lang string = "go" + var langTmpl LangTmpl + var ok bool + var lang string = "go" + var prefix string = "" //[SWH|+] + cfgPath := path.Join(dir, "config") + info, err := os.Stat(cfgPath) + var configs map[string]string + if err == nil && !info.IsDir() { + configs = loadConfig(cfgPath) + if l, ok := configs["lang"]; ok { + lang = l + } + if j, ok := configs["genJson"]; ok { + genJson, err = strconv.ParseBool(j) + } + //[SWH|+] + if j, ok := configs["prefix"]; ok { + prefix = j + } + } - cfgPath := path.Join(dir, "config") - info, err := os.Stat(cfgPath) - var configs map[string]string - if err == nil && !info.IsDir() { - configs = loadConfig(cfgPath) - if l, ok := configs["lang"]; ok { - lang = l - } - if j, ok := configs["genJson"]; ok { - genJson, err = strconv.ParseBool(j) - } - } + if langTmpl, ok = langTmpls[lang]; !ok { + fmt.Println("Unsupported programing language", lang) + return + } - if langTmpl, ok = langTmpls[lang]; !ok { - fmt.Println("Unsupported programing language", lang) - return - } + os.MkdirAll(genDir, os.ModePerm) - os.MkdirAll(genDir, os.ModePerm) + Orm, err := xorm.NewEngine(args[0], args[1]) + if err != nil { + logging.Error("%v", err) + return + } - Orm, err := xorm.NewEngine(args[0], args[1]) - if err != nil { - logging.Error("%v", err) - return - } + tables, err := Orm.DBMetas() + if err != nil { + logging.Error("%v", err) + return + } - tables, err := Orm.DBMetas() - if err != nil { - logging.Error("%v", err) - return - } + filepath.Walk(dir, func(f string, info os.FileInfo, err error) error { + if info.IsDir() { + return nil + } - filepath.Walk(dir, func(f string, info os.FileInfo, err error) error { - if info.IsDir() { - return nil - } + if info.Name() == "config" { + return nil + } - if info.Name() == "config" { - return nil - } + bs, err := ioutil.ReadFile(f) + if err != nil { + logging.Error("%v", err) + return err + } - bs, err := ioutil.ReadFile(f) - if err != nil { - logging.Error("%v", err) - return err - } + t := template.New(f) + t.Funcs(langTmpl.Funcs) - t := template.New(f) - t.Funcs(langTmpl.Funcs) + tmpl, err := t.Parse(string(bs)) + if err != nil { + logging.Error("%v", err) + return err + } - tmpl, err := t.Parse(string(bs)) - if err != nil { - logging.Error("%v", err) - return err - } + var w *os.File + fileName := info.Name() + newFileName := fileName[:len(fileName)-4] + ext := path.Ext(newFileName) - var w *os.File - fileName := info.Name() - newFileName := fileName[:len(fileName)-4] - ext := path.Ext(newFileName) + if !isMultiFile { + w, err = os.OpenFile(path.Join(genDir, newFileName), os.O_RDWR|os.O_CREATE, 0600) + if err != nil { + logging.Error("%v", err) + return err + } - if !isMultiFile { - w, err = os.OpenFile(path.Join(genDir, newFileName), os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - logging.Error("%v", err) - return err - } + imports := langTmpl.GenImports(tables) + tbls := make([]*xorm.Table, 0) + for _, table := range tables { + //[SWH|+] + if prefix != "" { + table.Name = strings.TrimPrefix(table.Name, prefix) + } + tbls = append(tbls, table) + } - imports := langTmpl.GenImports(tables) + newbytes := bytes.NewBufferString("") - tbls := make([]*xorm.Table, 0) - for _, table := range tables { - tbls = append(tbls, table) - } + t := &Tmpl{Tables: tbls, Imports: imports, Model: model} + err = tmpl.Execute(newbytes, t) + if err != nil { + logging.Error("%v", err) + return err + } - newbytes := bytes.NewBufferString("") + tplcontent, err := ioutil.ReadAll(newbytes) + if err != nil { + logging.Error("%v", err) + return err + } + var source string + if langTmpl.Formater != nil { + source, err = langTmpl.Formater(string(tplcontent)) + if err != nil { + logging.Error("%v", err) + return err + } + } else { + source = string(tplcontent) + } - t := &Tmpl{Tables: tbls, Imports: imports, Model: model} - err = tmpl.Execute(newbytes, t) - if err != nil { - logging.Error("%v", err) - return err - } + w.WriteString(source) + w.Close() + } else { + for _, table := range tables { + //[SWH|+] + if prefix != "" { + table.Name = strings.TrimPrefix(table.Name, prefix) + } + // imports + tbs := []*xorm.Table{table} + imports := langTmpl.GenImports(tbs) + w, err := os.OpenFile(path.Join(genDir, unTitle(mapper.Table2Obj(table.Name))+ext), os.O_RDWR|os.O_CREATE, 0600) + if err != nil { + logging.Error("%v", err) + return err + } - tplcontent, err := ioutil.ReadAll(newbytes) - if err != nil { - logging.Error("%v", err) - return err - } - var source string - if langTmpl.Formater != nil { - source, err = langTmpl.Formater(string(tplcontent)) - if err != nil { - logging.Error("%v", err) - return err - } - } else { - source = string(tplcontent) - } + newbytes := bytes.NewBufferString("") - w.WriteString(source) - w.Close() - } else { - for _, table := range tables { - // imports - tbs := []*xorm.Table{table} - imports := langTmpl.GenImports(tbs) + t := &Tmpl{Tables: tbs, Imports: imports, Model: model} + err = tmpl.Execute(newbytes, t) + if err != nil { + logging.Error("%v", err) + return err + } - w, err := os.OpenFile(path.Join(genDir, unTitle(mapper.Table2Obj(table.Name))+ext), os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - logging.Error("%v", err) - return err - } + tplcontent, err := ioutil.ReadAll(newbytes) + if err != nil { + logging.Error("%v", err) + return err + } + var source string + if langTmpl.Formater != nil { + source, err = langTmpl.Formater(string(tplcontent)) + if err != nil { + logging.Error("%v-%v", err, string(tplcontent)) + return err + } + } else { + source = string(tplcontent) + } - newbytes := bytes.NewBufferString("") + w.WriteString(source) + w.Close() + } + } - t := &Tmpl{Tables: tbs, Imports: imports, Model: model} - err = tmpl.Execute(newbytes, t) - if err != nil { - logging.Error("%v", err) - return err - } - - tplcontent, err := ioutil.ReadAll(newbytes) - if err != nil { - logging.Error("%v", err) - return err - } - var source string - if langTmpl.Formater != nil { - source, err = langTmpl.Formater(string(tplcontent)) - if err != nil { - logging.Error("%v-%v", err, string(tplcontent)) - return err - } - } else { - source = string(tplcontent) - } - - w.WriteString(source) - w.Close() - } - } - - return nil - }) + return nil + }) } diff --git a/xorm/templates/goxorm/config b/xorm/templates/goxorm/config index e99ad029..5d7bf321 100644 --- a/xorm/templates/goxorm/config +++ b/xorm/templates/goxorm/config @@ -1,2 +1,3 @@ lang=go genJson=0 +prefix=cos_