1
0
mirror of https://github.com/beego/bee.git synced 2024-11-27 03:01:29 +00:00
bee/g_hproseappcode.go
2016-03-31 00:22:27 +08:00

375 lines
12 KiB
Go

/**********************************************************\
| |
| hprose |
| |
| Official WebSite: http://www.hprose.com/ |
| http://www.hprose.org/ |
| |
\**********************************************************/
/**********************************************************\
* *
* Build rpc application use Hprose base on beego *
* *
* LastModified: Oct 23, 2014 *
* Author: Liu jian <laoliu@lanmv.com> *
* *
\**********************************************************/
package main
import (
"database/sql"
"os"
"path"
"strings"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
)
func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
var mode byte
switch level {
case "1":
mode = O_MODEL | O_STRUCTURE
case "2":
mode = O_MODEL | O_CONTROLLER
case "3":
mode = O_MODEL | O_CONTROLLER | O_ROUTER
default:
ColorLog("[ERRO] Invalid 'level' option: %s\n", level)
ColorLog("[HINT] Level must be either 1, 2 or 3\n")
os.Exit(2)
}
var selectedTables map[string]bool
if tables != "" {
selectedTables = make(map[string]bool)
for _, v := range strings.Split(tables, ",") {
selectedTables[v] = true
}
}
switch driver {
case "mysql":
case "postgres":
case "sqlite":
ColorLog("[ERRO] Generating app code from SQLite database is not supported yet.\n")
os.Exit(2)
default:
ColorLog("[ERRO] Unknown database driver: %s\n", driver)
ColorLog("[HINT] Driver must be one of mysql, postgres or sqlite\n")
os.Exit(2)
}
genHprose(driver, connStr, mode, selectedTables, currpath)
}
// Generate takes table, column and foreign key information from database connection
// and generate corresponding golang source files
func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bool, currpath string) {
db, err := sql.Open(dbms, connStr)
if err != nil {
ColorLog("[ERRO] Could not connect to %s database: %s, %s\n", dbms, connStr, err)
os.Exit(2)
}
defer db.Close()
if trans, ok := dbDriver[dbms]; ok {
ColorLog("[INFO] Analyzing database tables...\n")
tableNames := trans.GetTableNames(db)
tables := getTableObjects(tableNames, db, trans)
mvcPath := new(MvcPath)
mvcPath.ModelPath = path.Join(currpath, "models")
mvcPath.StructurePath = path.Join(currpath, "structures")
createPaths(mode, mvcPath)
pkgPath := getPackagePath(currpath)
writeHproseSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames)
} else {
ColorLog("[ERRO] Generating app code from %s database is not supported yet.\n", dbms)
os.Exit(2)
}
}
// writeHproseSourceFiles generates source files for model/controller/router
// It will wipe the following directories and recreate them:./models, ./controllers, ./routers
// Newly geneated files will be inside these folders.
func writeHproseSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) {
if (O_MODEL & mode) == O_MODEL {
ColorLog("[INFO] Creating model files...\n")
writeHproseModelFiles(tables, paths.ModelPath, selectedTables, pkgPath)
}
if (O_MODEL & mode) == O_MODEL {
ColorLog("[INFO] Creating structure files...\n")
writeHproseStructureFiles(tables, paths.StructurePath, selectedTables)
}
}
// writeHproseModelFiles generates model files
func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[string]bool, pkgPath string) {
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
if selectedTables != nil {
if _, selected := selectedTables[tb.Name]; !selected {
continue
}
}
filename := getFileName(tb.Name)
fpath := path.Join(mPath, filename+".go")
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath)
if askForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
continue
}
} else {
ColorLog("[WARN] skip create file\n")
continue
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
continue
}
}
template := ""
if tb.Pk == "" {
template = HPROSE_STRUCT_MODEL_TPL
} else {
template = HPROSE_MODEL_TPL
hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb.Name), -1))
}
fileStr := strings.Replace(template, "{{pkgPath}}", pkgPath, -1)
fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{tableName}}", tb.Name, -1)
// if table contains time field, import time.Time package
timePkg := ""
importTimePkg := ""
if tb.ImportTimePkg {
timePkg = "\"time\"\n"
importTimePkg = "import \"time\"\n"
}
fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1)
fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1)
if _, err := f.WriteString(fileStr); err != nil {
ColorLog("[ERRO] Could not write model file to %s\n", fpath)
os.Exit(2)
}
f.Close()
ColorLog("[INFO] model => %s\n", fpath)
formatSourceCode(fpath)
}
}
// writeHproseStructureFiles generates structure files
func writeHproseStructureFiles(tables []*Table, mPath string, selectedTables map[string]bool) {
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
if selectedTables != nil {
if _, selected := selectedTables[tb.Name]; !selected {
continue
}
}
filename := getFileName(tb.Name)
fpath := path.Join(mPath, filename+"_structure.go")
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] %v is exist, do you want to overwrite it? Yes or No?\n", fpath)
if askForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
continue
}
} else {
ColorLog("[WARN] skip create file\n")
continue
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
continue
}
}
template := HPROSE_STRUCT_TPL
fileStr := strings.Replace(template, "{{Struct}}", tb.String(), 1)
// if table contains time field, import time.Time package
timePkg := ""
importTimePkg := ""
if tb.ImportTimePkg {
timePkg = "\"time\"\n"
importTimePkg = "import \"time\"\n"
}
fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1)
fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1)
if _, err := f.WriteString(fileStr); err != nil {
ColorLog("[ERRO] Could not write model file to %s\n", fpath)
os.Exit(2)
}
f.Close()
ColorLog("[INFO] structure => %s\n", fpath)
formatSourceCode(fpath)
}
}
const (
HPROSE_ADDFUNCTION = `
// publish about {{modelName}} function
service.AddFunction("Add{{modelName}}", models.Add{{modelName}})
service.AddFunction("Get{{modelName}}ById", models.Get{{modelName}}ById)
service.AddFunction("GetAll{{modelName}}", models.GetAll{{modelName}})
service.AddFunction("Update{{modelName}}ById", models.Update{{modelName}}ById)
service.AddFunction("Delete{{modelName}}", models.Delete{{modelName}})
`
HPROSE_STRUCT_MODEL_TPL = `package models
`
HPROSE_STRUCT_TPL = `package structures
{{importTimePkg}}
{{Struct}}
`
HPROSE_MODEL_TPL = `package models
import (
"{{pkgPath}}/structures"
"errors"
"fmt"
"reflect"
"strings"
{{timePkg}}
"github.com/astaxie/beego/orm"
)
func init() {
orm.RegisterModel(new(structures.{{modelName}}))
}
// Add{{modelName}} insert a new {{modelName}} into database and returns
// last inserted Id on success.
func Add{{modelName}}(m *structures.{{modelName}}) (id int64, err error) {
o := orm.NewOrm()
id, err = o.Insert(m)
return
}
// Get{{modelName}}ById retrieves {{modelName}} by Id. Returns error if
// Id doesn't exist
func Get{{modelName}}ById(id int) (v *structures.{{modelName}}, err error) {
o := orm.NewOrm()
v = &structures.{{modelName}}{Id: id}
if err = o.Read(v); err == nil {
return v, nil
}
return nil, err
}
// GetAll{{modelName}} retrieves all {{modelName}} matches certain condition. Returns empty list if
// no records exist
func GetAll{{modelName}}(query map[string]string, fields []string, sortby []string, order []string,
offset int64, limit int64) (ml []interface{}, err error) {
o := orm.NewOrm()
qs := o.QueryTable(new(structures.{{modelName}}))
// query k=v
for k, v := range query {
// rewrite dot-notation to Object__Attribute
k = strings.Replace(k, ".", "__", -1)
qs = qs.Filter(k, v)
}
// order by:
var sortFields []string
if len(sortby) != 0 {
if len(sortby) == len(order) {
// 1) for each sort field, there is an associated order
for i, v := range sortby {
orderby := ""
if order[i] == "desc" {
orderby = "-" + v
} else if order[i] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
qs = qs.OrderBy(sortFields...)
} else if len(sortby) != len(order) && len(order) == 1 {
// 2) there is exactly one order, all the sorted fields will be sorted by this order
for _, v := range sortby {
orderby := ""
if order[0] == "desc" {
orderby = "-" + v
} else if order[0] == "asc" {
orderby = v
} else {
return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
}
sortFields = append(sortFields, orderby)
}
} else if len(sortby) != len(order) && len(order) != 1 {
return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
}
} else {
if len(order) != 0 {
return nil, errors.New("Error: unused 'order' fields")
}
}
var l []structures.{{modelName}}
qs = qs.OrderBy(sortFields...)
if _, err := qs.Limit(limit, offset).All(&l, fields...); err == nil {
if len(fields) == 0 {
for _, v := range l {
ml = append(ml, v)
}
} else {
// trim unused fields
for _, v := range l {
m := make(map[string]interface{})
val := reflect.ValueOf(v)
for _, fname := range fields {
m[fname] = val.FieldByName(fname).Interface()
}
ml = append(ml, m)
}
}
return ml, nil
}
return nil, err
}
// Update{{modelName}} updates {{modelName}} by Id and returns error if
// the record to be updated doesn't exist
func Update{{modelName}}ById(m *structures.{{modelName}}) (err error) {
o := orm.NewOrm()
v := structures.{{modelName}}{Id: m.Id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Update(m); err == nil {
fmt.Println("Number of records updated in database:", num)
}
}
return
}
// Delete{{modelName}} deletes {{modelName}} by Id and returns error if
// the record to be deleted doesn't exist
func Delete{{modelName}}(id int) (err error) {
o := orm.NewOrm()
v := structures.{{modelName}}{Id: id}
// ascertain id exists in the database
if err = o.Read(&v); err == nil {
var num int64
if num, err = o.Delete(&structures.{{modelName}}{Id: id}); err == nil {
fmt.Println("Number of records deleted in database:", num)
}
}
return
}
`
)