mirror of
https://github.com/zhufuyi/sponge.git
synced 2025-11-03 09:41:07 +08:00
support mongodb generate code
This commit is contained in:
391
pkg/sql2code/parser/mongodb.go
Normal file
391
pkg/sql2code/parser/mongodb.go
Normal file
@@ -0,0 +1,391 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/zhufuyi/sponge/pkg/mgo"
|
||||
"github.com/zhufuyi/sponge/pkg/utils"
|
||||
|
||||
"github.com/huandu/xstrings"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/bsontype"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
mgoOptions "go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
const (
|
||||
goTypeOID = "primitive.ObjectID"
|
||||
goTypeInt = "int"
|
||||
goTypeInt64 = "int64"
|
||||
goTypeFloat64 = "float64"
|
||||
goTypeString = "string"
|
||||
goTypeTime = "time.Time"
|
||||
goTypeBool = "bool"
|
||||
goTypeNil = "nil"
|
||||
goTypeBytes = "[]byte"
|
||||
goTypeStrings = "[]string"
|
||||
goTypeInts = "[]int"
|
||||
goTypeInterface = "interface{}"
|
||||
goTypeSliceInterface = "[]interface{}"
|
||||
|
||||
// SubStructKey sub struct key
|
||||
SubStructKey = "_sub_struct_"
|
||||
// ProtoSubStructKey proto sub struct key
|
||||
ProtoSubStructKey = "_proto_sub_struct_"
|
||||
|
||||
oidName = "_id"
|
||||
)
|
||||
|
||||
var mgoTypeToGo = map[bsontype.Type]string{
|
||||
bson.TypeObjectID: goTypeOID,
|
||||
bson.TypeInt32: goTypeInt,
|
||||
bson.TypeInt64: goTypeInt64,
|
||||
bson.TypeDouble: goTypeFloat64,
|
||||
bson.TypeString: goTypeString,
|
||||
bson.TypeArray: goTypeSliceInterface,
|
||||
bson.TypeEmbeddedDocument: goTypeInterface,
|
||||
bson.TypeTimestamp: goTypeTime,
|
||||
bson.TypeDateTime: goTypeTime,
|
||||
bson.TypeBoolean: goTypeBool,
|
||||
bson.TypeNull: goTypeNil,
|
||||
bson.TypeBinary: goTypeBytes,
|
||||
bson.TypeUndefined: goTypeInterface,
|
||||
bson.TypeCodeWithScope: goTypeString,
|
||||
bson.TypeSymbol: goTypeString,
|
||||
bson.TypeRegex: goTypeString,
|
||||
bson.TypeDecimal128: goTypeInterface,
|
||||
bson.TypeDBPointer: goTypeInterface,
|
||||
bson.TypeMinKey: goTypeInt,
|
||||
bson.TypeMaxKey: goTypeInt,
|
||||
bson.TypeJavaScript: goTypeString,
|
||||
}
|
||||
|
||||
var jsonTagFormat int32 // 0: camel case, 1: snake case
|
||||
|
||||
// SetJSONTagSnakeCase set json tag format to snake case
|
||||
func SetJSONTagSnakeCase() {
|
||||
atomic.AddInt32(&jsonTagFormat, 1)
|
||||
}
|
||||
|
||||
// SetJSONTagCamelCase set json tag format to camel case
|
||||
func SetJSONTagCamelCase() {
|
||||
atomic.AddInt32(&jsonTagFormat, -jsonTagFormat)
|
||||
}
|
||||
|
||||
// MgoField mongo field
|
||||
type MgoField struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Comment string `json:"comment"`
|
||||
ObjectStr string `json:"objectStr"`
|
||||
ProtoObjectStr string `json:"protoObjectStr"`
|
||||
}
|
||||
|
||||
// GetMongodbTableInfo get table info from mongodb
|
||||
func GetMongodbTableInfo(dsn string, tableName string) ([]*MgoField, error) {
|
||||
timeout := time.Second * 5
|
||||
opts := &mgoOptions.ClientOptions{Timeout: &timeout}
|
||||
dsn = utils.AdaptiveMongodbDsn(dsn)
|
||||
db, err := mgo.Init(dsn, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return getMongodbTableFields(db, tableName)
|
||||
}
|
||||
|
||||
func getMongodbTableFields(db *mongo.Database, collectionName string) ([]*MgoField, error) {
|
||||
findOpts := new(mgoOptions.FindOneOptions)
|
||||
findOpts.Sort = bson.M{oidName: -1}
|
||||
result := db.Collection(collectionName).FindOne(context.Background(), bson.M{}, findOpts)
|
||||
raw, err := result.Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
elements, err := raw.Elements()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fields := []*MgoField{}
|
||||
names := []string{}
|
||||
for _, element := range elements {
|
||||
name := element.Key()
|
||||
if name == "deleted_at" { // filter deleted_at, used for soft delete
|
||||
continue
|
||||
}
|
||||
names = append(names, name)
|
||||
t, o, p := getTypeFromMgo(name, element)
|
||||
fields = append(fields, &MgoField{
|
||||
Name: name,
|
||||
Type: t,
|
||||
ObjectStr: o,
|
||||
ProtoObjectStr: p,
|
||||
})
|
||||
}
|
||||
|
||||
return embedTimeField(names, fields), nil
|
||||
}
|
||||
|
||||
func getTypeFromMgo(name string, element bson.RawElement) (goTypeStr string, goObjectStr string, protoObjectStr string) {
|
||||
v := element.Value()
|
||||
switch v.Type {
|
||||
case bson.TypeEmbeddedDocument:
|
||||
var br bson.Raw = v.Value
|
||||
es, err := br.Elements()
|
||||
if err != nil {
|
||||
return goTypeInterface, "", ""
|
||||
}
|
||||
return parseObject(name, es)
|
||||
|
||||
case bson.TypeArray:
|
||||
var br bson.Raw = v.Value
|
||||
es, err := br.Elements()
|
||||
if err != nil {
|
||||
return goTypeInterface, "", ""
|
||||
}
|
||||
if len(es) == 0 {
|
||||
return goTypeInterface, "", ""
|
||||
}
|
||||
t, o, p := parseArray(name, es[0])
|
||||
return convertToSingular(t, o, p)
|
||||
}
|
||||
|
||||
if goType, ok := mgoTypeToGo[v.Type]; !ok {
|
||||
return goTypeInterface, "", ""
|
||||
} else { //nolint
|
||||
return goType, "", ""
|
||||
}
|
||||
}
|
||||
|
||||
func parseObject(name string, elements []bson.RawElement) (goTypeStr string, goObjectStr string, protoObjectStr string) {
|
||||
var goObjStr string
|
||||
var protoObjStr string
|
||||
for num, element := range elements {
|
||||
t, _, _ := getTypeFromMgo(name, element)
|
||||
k := element.Key()
|
||||
|
||||
var jsonTag string
|
||||
if jsonTagFormat == 0 {
|
||||
jsonTag = toLowerFirst(xstrings.ToCamelCase(k))
|
||||
} else {
|
||||
jsonTag = xstrings.ToSnakeCase(k)
|
||||
}
|
||||
|
||||
goObjStr += fmt.Sprintf(" %s %s `bson:\"%s\" json:\"%s\"`\n", xstrings.ToCamelCase(k), t, k, jsonTag)
|
||||
num++
|
||||
protoObjStr += fmt.Sprintf(" %s %s = %d;\n", convertToProtoFieldType(name, t), k, num)
|
||||
}
|
||||
return "*" + xstrings.ToCamelCase(name),
|
||||
fmt.Sprintf("type %s struct {\n%s}\n", xstrings.ToCamelCase(name), goObjStr),
|
||||
fmt.Sprintf("message %s {\n%s}\n", xstrings.ToCamelCase(name), protoObjStr)
|
||||
}
|
||||
|
||||
func parseArray(name string, element bson.RawElement) (goTypeStr string, goObjectStr string, protoObjectStr string) {
|
||||
t, o, p := getTypeFromMgo(name, element)
|
||||
if o != "" {
|
||||
return "[]" + t, o, p
|
||||
}
|
||||
return "[]" + t, "", ""
|
||||
}
|
||||
|
||||
func toLowerFirst(str string) string {
|
||||
if len(str) == 0 {
|
||||
return str
|
||||
}
|
||||
return strings.ToLower(string(str[0])) + str[1:]
|
||||
}
|
||||
|
||||
func embedTimeField(names []string, fields []*MgoField) []*MgoField {
|
||||
isHaveCreatedAt, isHaveUpdatedAt := false, false
|
||||
for _, name := range names {
|
||||
if name == "created_at" {
|
||||
isHaveCreatedAt = true
|
||||
}
|
||||
if name == "updated_at" {
|
||||
isHaveUpdatedAt = true
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
var timeFields []*MgoField
|
||||
if !isHaveCreatedAt {
|
||||
timeFields = append(timeFields, &MgoField{
|
||||
Name: "created_at",
|
||||
Type: goTypeTime,
|
||||
})
|
||||
}
|
||||
if !isHaveUpdatedAt {
|
||||
timeFields = append(timeFields, &MgoField{
|
||||
Name: "updated_at",
|
||||
Type: goTypeTime,
|
||||
})
|
||||
}
|
||||
|
||||
if len(timeFields) == 0 {
|
||||
return fields
|
||||
}
|
||||
|
||||
return append(fields, timeFields...)
|
||||
}
|
||||
|
||||
// ConvertToSQLByMgoFields convert to mysql table ddl
|
||||
func ConvertToSQLByMgoFields(tableName string, fields []*MgoField) (string, map[string]string) {
|
||||
isHaveID := false
|
||||
fieldStr := ""
|
||||
srcMongoTypeMap := make(map[string]string) // name:type
|
||||
objectStrs := []string{}
|
||||
protoObjectStrs := []string{}
|
||||
|
||||
for _, field := range fields {
|
||||
switch field.Type {
|
||||
case goTypeInterface, goTypeSliceInterface:
|
||||
srcMongoTypeMap[field.Name] = xstrings.ToCamelCase(field.Name)
|
||||
default:
|
||||
srcMongoTypeMap[field.Name] = field.Type
|
||||
}
|
||||
if field.Name == oidName {
|
||||
isHaveID = true
|
||||
srcMongoTypeMap["id"] = field.Type
|
||||
continue
|
||||
}
|
||||
|
||||
fieldStr += fmt.Sprintf(" %s %s,\n", field.Name, convertMongoToMysqlType(field.Type))
|
||||
if field.ObjectStr != "" {
|
||||
objectStrs = append(objectStrs, field.ObjectStr)
|
||||
protoObjectStrs = append(protoObjectStrs, field.ProtoObjectStr)
|
||||
}
|
||||
}
|
||||
if isHaveID {
|
||||
fieldStr = " id bigint unsigned primary key,\n" + fieldStr
|
||||
}
|
||||
fieldStr = strings.TrimSuffix(fieldStr, ",\n")
|
||||
|
||||
if len(objectStrs) > 0 {
|
||||
srcMongoTypeMap[SubStructKey] = strings.Join(objectStrs, "\n") + "\n"
|
||||
srcMongoTypeMap[ProtoSubStructKey] = strings.Join(protoObjectStrs, "\n") + "\n"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("CREATE TABLE %s (\n%s\n);", tableName, fieldStr), srcMongoTypeMap
|
||||
}
|
||||
|
||||
// nolint
|
||||
func convertMongoToMysqlType(goType string) string {
|
||||
switch goType {
|
||||
case goTypeInt:
|
||||
return "int"
|
||||
case goTypeInt64:
|
||||
return "bigint"
|
||||
case goTypeFloat64:
|
||||
return "double"
|
||||
case goTypeString:
|
||||
return "varchar(255)"
|
||||
case goTypeTime:
|
||||
return "timestamp" //nolint
|
||||
case goTypeBool:
|
||||
return "tinyint(1)"
|
||||
case goTypeOID, goTypeNil, goTypeBytes, goTypeInterface, goTypeSliceInterface, goTypeInts, goTypeStrings:
|
||||
return "json"
|
||||
}
|
||||
return "json"
|
||||
}
|
||||
|
||||
// nolint
|
||||
func convertToProtoFieldType(name string, goType string) string {
|
||||
switch goType {
|
||||
case "int":
|
||||
return "int32"
|
||||
case "uint":
|
||||
return "uint32" //nolint
|
||||
case "time.Time":
|
||||
return "int64"
|
||||
case "float32":
|
||||
return "float"
|
||||
case "float64":
|
||||
return "double"
|
||||
case goTypeInts, "[]int64":
|
||||
return "repeated int64"
|
||||
case "[]int32":
|
||||
return "repeated int32"
|
||||
case "[]byte":
|
||||
return "string"
|
||||
case goTypeStrings:
|
||||
return "repeated string"
|
||||
}
|
||||
|
||||
if strings.Contains(goType, "[]") {
|
||||
t := strings.TrimLeft(goType, "[]")
|
||||
if strings.Contains(name, t) {
|
||||
return "repeated " + t
|
||||
}
|
||||
}
|
||||
|
||||
return goType
|
||||
}
|
||||
|
||||
// MgoFieldToGoStruct convert to go struct
|
||||
func MgoFieldToGoStruct(name string, fs []*MgoField) string {
|
||||
var str = ""
|
||||
var objStr string
|
||||
|
||||
for _, f := range fs {
|
||||
if f.Name == oidName {
|
||||
str += " ID primitive.ObjectID `bson:\"_id\" json:\"id\"`\n"
|
||||
continue
|
||||
}
|
||||
if f.Type == goTypeInterface || f.Type == goTypeSliceInterface {
|
||||
f.Type = xstrings.ToCamelCase(f.Name)
|
||||
}
|
||||
str += fmt.Sprintf(" %s %s `bson:\"%s\" json:\"%s\"`\n", xstrings.ToCamelCase(f.Name), f.Type, f.Name, f.Name)
|
||||
if f.ObjectStr != "" {
|
||||
objStr += f.ObjectStr + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("type %s struct {\n%s}\n\n%s\n", xstrings.ToCamelCase(name), str, objStr)
|
||||
}
|
||||
|
||||
func toSingular(word string) string {
|
||||
if strings.HasSuffix(word, "es") {
|
||||
if len(word) > 2 {
|
||||
return word[:len(word)-2]
|
||||
}
|
||||
} else if strings.HasSuffix(word, "s") {
|
||||
if len(word) > 1 {
|
||||
return word[:len(word)-1]
|
||||
}
|
||||
}
|
||||
return word
|
||||
}
|
||||
|
||||
func nameToSingular(goTypeStr string, targetObjectStr string, markStr string) string {
|
||||
name := strings.ReplaceAll(goTypeStr, "[]*", "")
|
||||
prefixStr := markStr + " " + name
|
||||
l := len(prefixStr)
|
||||
if len(targetObjectStr) <= l {
|
||||
return targetObjectStr
|
||||
}
|
||||
|
||||
if prefixStr == targetObjectStr[:l] {
|
||||
targetObjectStr = toSingular(prefixStr) + " " + targetObjectStr[l:]
|
||||
return targetObjectStr
|
||||
}
|
||||
return targetObjectStr
|
||||
}
|
||||
|
||||
func convertToSingular(goTypeStr string, objectStr string, protoObjectStr string) (tStr string, oStr string, pObjStr string) {
|
||||
if !strings.Contains(goTypeStr, "[]*") || objectStr == "" {
|
||||
return goTypeStr, objectStr, protoObjectStr
|
||||
}
|
||||
|
||||
objectStr = nameToSingular(goTypeStr, objectStr, "type")
|
||||
protoObjectStr = nameToSingular(goTypeStr, protoObjectStr, "message")
|
||||
goTypeStr = toSingular(goTypeStr)
|
||||
|
||||
return goTypeStr, objectStr, protoObjectStr
|
||||
}
|
||||
@@ -43,6 +43,8 @@ const (
|
||||
DBDriverTidb = "tidb"
|
||||
// DBDriverSqlite sqlite driver
|
||||
DBDriverSqlite = "sqlite"
|
||||
// DBDriverMongodb mongodb driver
|
||||
DBDriverMongodb = "mongodb"
|
||||
)
|
||||
|
||||
// Codes content
|
||||
@@ -126,12 +128,15 @@ func ParseSQL(sql string, options ...Option) (map[string]string, error) {
|
||||
}
|
||||
|
||||
type tmplData struct {
|
||||
TableName string
|
||||
TName string
|
||||
NameFunc bool
|
||||
RawTableName string
|
||||
Fields []tmplField
|
||||
Comment string
|
||||
TableName string
|
||||
TName string
|
||||
NameFunc bool
|
||||
RawTableName string
|
||||
Fields []tmplField
|
||||
Comment string
|
||||
SubStructs string // sub structs for model
|
||||
ProtoSubStructs string // sub structs for protobuf
|
||||
DBDriver string
|
||||
}
|
||||
|
||||
type tmplField struct {
|
||||
@@ -141,9 +146,10 @@ type tmplField struct {
|
||||
Tag string
|
||||
Comment string
|
||||
JSONName string
|
||||
DBDriver string
|
||||
}
|
||||
|
||||
// ConditionZero type of condition 0
|
||||
// ConditionZero type of condition 0, used in dao template code
|
||||
func (t tmplField) ConditionZero() string {
|
||||
switch t.GoType {
|
||||
case "int8", "int16", "int32", "int64", "int", "uint8", "uint16", "uint32", "uint64", "uint", "float64", "float32", //nolint
|
||||
@@ -153,12 +159,28 @@ func (t tmplField) ConditionZero() string {
|
||||
return `!= ""`
|
||||
case "time.Time", "*time.Time", "sql.NullTime": //nolint
|
||||
return `.IsZero() == false`
|
||||
case "[]byte", "[]string", "[]int", "interface{}": //nolint
|
||||
return `!= nil` //nolint
|
||||
case "bool": //nolint
|
||||
return `!= false /*Warning: if the value itself is false, can't be updated*/`
|
||||
}
|
||||
|
||||
if t.DBDriver == DBDriverMongodb {
|
||||
if t.GoType == goTypeOID {
|
||||
return `!= primitive.NilObjectID`
|
||||
}
|
||||
if t.GoType == "*"+t.Name {
|
||||
return `!= nil`
|
||||
}
|
||||
if strings.Contains(t.GoType, "[]") {
|
||||
return `!= nil`
|
||||
}
|
||||
}
|
||||
|
||||
return `!= ` + t.GoType
|
||||
}
|
||||
|
||||
// GoZero type of 0
|
||||
// GoZero type of 0, used in model to json template code
|
||||
func (t tmplField) GoZero() string {
|
||||
switch t.GoType {
|
||||
case "int8", "int16", "int32", "int64", "int", "uint8", "uint16", "uint32", "uint64", "uint", "float64", "float32",
|
||||
@@ -168,12 +190,28 @@ func (t tmplField) GoZero() string {
|
||||
return `= "string"`
|
||||
case "time.Time", "*time.Time", "sql.NullTime":
|
||||
return `= "0000-01-00T00:00:00.000+08:00"`
|
||||
case "[]byte", "[]string", "[]int", "interface{}": //nolint
|
||||
return `= nil` //nolint
|
||||
case "bool": //nolint
|
||||
return `= false`
|
||||
}
|
||||
|
||||
if t.DBDriver == DBDriverMongodb {
|
||||
if t.GoType == goTypeOID {
|
||||
return `= primitive.NilObjectID`
|
||||
}
|
||||
if t.GoType == "*"+t.Name {
|
||||
return `= nil`
|
||||
}
|
||||
if strings.Contains(t.GoType, "[]") {
|
||||
return `= nil`
|
||||
}
|
||||
}
|
||||
|
||||
return `= ` + t.GoType
|
||||
}
|
||||
|
||||
// GoTypeZero type of 0
|
||||
// GoTypeZero type of 0, used in service template code
|
||||
func (t tmplField) GoTypeZero() string {
|
||||
switch t.GoType {
|
||||
case "int8", "int16", "int32", "int64", "int", "uint8", "uint16", "uint32", "uint64", "uint", "float64", "float32",
|
||||
@@ -183,6 +221,22 @@ func (t tmplField) GoTypeZero() string {
|
||||
return `""`
|
||||
case "time.Time", "*time.Time", "sql.NullTime":
|
||||
return `0 /*time.Now().Second()*/`
|
||||
case "[]byte", "[]string", "[]int", "interface{}": //nolint
|
||||
return `nil` //nolint
|
||||
case "bool": //nolint
|
||||
return `false`
|
||||
}
|
||||
|
||||
if t.DBDriver == DBDriverMongodb {
|
||||
if t.GoType == goTypeOID {
|
||||
return `primitive.NilObjectID`
|
||||
}
|
||||
if t.GoType == "*"+t.Name {
|
||||
return `nil` //nolint
|
||||
}
|
||||
if strings.Contains(t.GoType, "[]") {
|
||||
return `nil` //nolint
|
||||
}
|
||||
}
|
||||
|
||||
return t.GoType
|
||||
@@ -214,6 +268,7 @@ var replaceFields = map[string]string{
|
||||
|
||||
const (
|
||||
columnID = "id"
|
||||
_columnID = "_id"
|
||||
columnCreatedAt = "created_at"
|
||||
columnUpdatedAt = "updated_at"
|
||||
columnDeletedAt = "deleted_at"
|
||||
@@ -349,30 +404,56 @@ func makeCode(stmt *ast.CreateTableStmt, opt options) (*codeText, error) {
|
||||
//return "", nil, errors.Errorf(" unsupport option %d\n", o.Tp)
|
||||
}
|
||||
}
|
||||
if !isPrimaryKey[colName] && isNotNull {
|
||||
gormTag.WriteString(";NOT NULL")
|
||||
}
|
||||
tags = append(tags, "gorm", gormTag.String())
|
||||
|
||||
if opt.JSONTag {
|
||||
tags = append(tags, "json", jsonName)
|
||||
}
|
||||
field.DBDriver = opt.DBDriver
|
||||
switch opt.DBDriver {
|
||||
case DBDriverMongodb: // mongodb
|
||||
tags = append(tags, "bson", gormTag.String())
|
||||
if opt.JSONTag {
|
||||
if strings.ToLower(jsonName) == "_id" {
|
||||
jsonName = "id"
|
||||
}
|
||||
field.JSONName = jsonName
|
||||
tags = append(tags, "json", jsonName)
|
||||
}
|
||||
field.Tag = makeTagStr(tags)
|
||||
field.GoType = opt.FieldTypes[colName]
|
||||
if field.GoType == "time.Time" {
|
||||
importPath = append(importPath, "time")
|
||||
}
|
||||
|
||||
field.Tag = makeTagStr(tags)
|
||||
default: // gorm
|
||||
if !isPrimaryKey[colName] && isNotNull {
|
||||
gormTag.WriteString(";NOT NULL")
|
||||
}
|
||||
tags = append(tags, "gorm", gormTag.String())
|
||||
|
||||
// get type in golang
|
||||
nullStyle := opt.NullStyle
|
||||
if !canNull {
|
||||
nullStyle = NullDisable
|
||||
if opt.JSONTag {
|
||||
tags = append(tags, "json", jsonName)
|
||||
}
|
||||
field.Tag = makeTagStr(tags)
|
||||
|
||||
// get type in golang
|
||||
nullStyle := opt.NullStyle
|
||||
if !canNull {
|
||||
nullStyle = NullDisable
|
||||
}
|
||||
goType, pkg := mysqlToGoType(col.Tp, nullStyle)
|
||||
if pkg != "" {
|
||||
importPath = append(importPath, pkg)
|
||||
}
|
||||
field.GoType = goType
|
||||
}
|
||||
goType, pkg := mysqlToGoType(col.Tp, nullStyle)
|
||||
if pkg != "" {
|
||||
importPath = append(importPath, pkg)
|
||||
}
|
||||
field.GoType = goType
|
||||
|
||||
data.Fields = append(data.Fields, field)
|
||||
}
|
||||
if v, ok := opt.FieldTypes[SubStructKey]; ok {
|
||||
data.SubStructs = v
|
||||
}
|
||||
if v, ok := opt.FieldTypes[ProtoSubStructKey]; ok {
|
||||
data.ProtoSubStructs = v
|
||||
}
|
||||
data.DBDriver = opt.DBDriver
|
||||
|
||||
updateFieldsCode, err := getUpdateFieldsCode(data, opt.IsEmbed)
|
||||
if err != nil {
|
||||
@@ -454,13 +535,22 @@ func getModelStructCode(data tmplData, importPaths []string, isEmbed bool) (stri
|
||||
newImportPaths = append(newImportPaths, "github.com/zhufuyi/sponge/pkg/ggorm")
|
||||
} else {
|
||||
for i, field := range data.Fields {
|
||||
if strings.Contains(field.GoType, "time.Time") {
|
||||
data.Fields[i].GoType = "*time.Time"
|
||||
continue
|
||||
}
|
||||
// force conversion of ID field to uint64 type
|
||||
if field.Name == "ID" {
|
||||
data.Fields[i].GoType = "uint64"
|
||||
switch field.DBDriver {
|
||||
case DBDriverMongodb:
|
||||
if field.Name == "ID" {
|
||||
data.Fields[i].GoType = goTypeOID
|
||||
importPaths = append(importPaths, "go.mongodb.org/mongo-driver/bson/primitive")
|
||||
}
|
||||
|
||||
default:
|
||||
if strings.Contains(field.GoType, "time.Time") {
|
||||
data.Fields[i].GoType = "*time.Time"
|
||||
continue
|
||||
}
|
||||
// force conversion of ID field to uint64 type
|
||||
if field.Name == "ID" {
|
||||
data.Fields[i].GoType = "uint64"
|
||||
}
|
||||
}
|
||||
}
|
||||
newImportPaths = importPaths
|
||||
@@ -482,6 +572,16 @@ func getModelStructCode(data tmplData, importPaths []string, isEmbed bool) (stri
|
||||
structCode = strings.ReplaceAll(structCode, __type__, replaceFields[__type__])
|
||||
}
|
||||
|
||||
if data.SubStructs != "" {
|
||||
structCode += data.SubStructs
|
||||
}
|
||||
if data.DBDriver == DBDriverMongodb {
|
||||
structCode = strings.ReplaceAll(structCode, `bson:"column:`, `bson:"`)
|
||||
structCode = strings.ReplaceAll(structCode, `;type:"`, `"`)
|
||||
structCode = strings.ReplaceAll(structCode, `;type:;primary_key`, ``)
|
||||
structCode = strings.ReplaceAll(structCode, `bson:"id" json:"id"`, `bson:"_id" json:"id"`)
|
||||
}
|
||||
|
||||
return structCode, newImportPaths, nil
|
||||
}
|
||||
|
||||
@@ -507,28 +607,39 @@ func getUpdateFieldsCode(data tmplData, isEmbed bool) (string, error) {
|
||||
var newFields = []tmplField{}
|
||||
for _, field := range data.Fields {
|
||||
falseColumns := []string{}
|
||||
if isIgnoreFields(field.ColName, falseColumns...) {
|
||||
if isIgnoreFields(field.ColName, falseColumns...) || field.ColName == columnID || field.ColName == _columnID {
|
||||
continue
|
||||
}
|
||||
newFields = append(newFields, field)
|
||||
}
|
||||
data.Fields = newFields
|
||||
|
||||
builder := strings.Builder{}
|
||||
err := updateFieldTmpl.Execute(&builder, data)
|
||||
buf := new(bytes.Buffer)
|
||||
err := updateFieldTmpl.Execute(buf, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
code, err := format.Source([]byte(builder.String()))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(code), nil
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func getHandlerStructCodes(data tmplData) (string, error) {
|
||||
newFields := []tmplField{}
|
||||
for _, field := range data.Fields {
|
||||
if field.DBDriver == DBDriverMongodb { // mongodb
|
||||
if field.Name == "ID" {
|
||||
field.GoType = "string"
|
||||
}
|
||||
if "*"+field.Name == field.GoType {
|
||||
field.GoType = "*model." + field.Name
|
||||
}
|
||||
if strings.Contains(field.GoType, "[]*") {
|
||||
field.GoType = "[]*model." + strings.ReplaceAll(field.GoType, "[]*", "")
|
||||
}
|
||||
}
|
||||
newFields = append(newFields, field)
|
||||
}
|
||||
data.Fields = newFields
|
||||
|
||||
postStructCode, err := tmplExecuteWithFilter(data, handlerCreateStructTmpl)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("handlerCreateStructTmpl error: %v", err)
|
||||
@@ -554,6 +665,11 @@ func tmplExecuteWithFilter(data tmplData, tmpl *template.Template, reservedColum
|
||||
if isIgnoreFields(field.ColName, reservedColumns...) {
|
||||
continue
|
||||
}
|
||||
if field.DBDriver == DBDriverMongodb { // mongodb
|
||||
if strings.ToLower(field.Name) == "id" {
|
||||
field.GoType = "string"
|
||||
}
|
||||
}
|
||||
newFields = append(newFields, field)
|
||||
}
|
||||
data.Fields = newFields
|
||||
@@ -624,10 +740,86 @@ func getProtoFileCode(data tmplData, isWebProto bool) (string, error) {
|
||||
code = strings.ReplaceAll(code, "// protoMessageDetailCode", protoMessageDetailCode)
|
||||
code = strings.ReplaceAll(code, "*time.Time", "int64")
|
||||
code = strings.ReplaceAll(code, "time.Time", "int64")
|
||||
code = adaptedDbType(data, isWebProto, code)
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
||||
const (
|
||||
createTableReplyFieldCodeMark = "// createTableReplyFieldCode"
|
||||
deleteTableByIDRequestFieldCodeMark = "// deleteTableByIDRequestFieldCode"
|
||||
deleteTableByIDsRequestFieldCodeMark = "// deleteTableByIDsRequestFieldCode"
|
||||
getTableByIDRequestFieldCodeMark = "// getTableByIDRequestFieldCode"
|
||||
getTableByIDsRequestFieldCodeMark = "// getTableByIDsRequestFieldCode"
|
||||
listTableByLastIDRequestFieldCodeMark = "// listTableByLastIDRequestFieldCode"
|
||||
)
|
||||
|
||||
var grpcDefaultProtoMessageFieldCodes = map[string]string{
|
||||
createTableReplyFieldCodeMark: "uint64 id = 1;",
|
||||
deleteTableByIDRequestFieldCodeMark: "uint64 id = 1 [(validate.rules).uint64.gt = 0];",
|
||||
deleteTableByIDsRequestFieldCodeMark: "repeated uint64 ids = 1 [(validate.rules).repeated.min_items = 1];",
|
||||
getTableByIDRequestFieldCodeMark: "uint64 id = 1 [(validate.rules).uint64.gt = 0];",
|
||||
getTableByIDsRequestFieldCodeMark: "repeated uint64 ids = 1 [(validate.rules).repeated.min_items = 1];",
|
||||
listTableByLastIDRequestFieldCodeMark: "uint64 lastID = 1; // last id",
|
||||
}
|
||||
|
||||
var webDefaultProtoMessageFieldCodes = map[string]string{
|
||||
createTableReplyFieldCodeMark: "uint64 id = 1;",
|
||||
deleteTableByIDRequestFieldCodeMark: `uint64 id =1 [(validate.rules).uint64.gt = 0, (tagger.tags) = "uri:\"id\""];`,
|
||||
deleteTableByIDsRequestFieldCodeMark: "repeated uint64 ids = 1 [(validate.rules).repeated.min_items = 1];",
|
||||
getTableByIDRequestFieldCodeMark: `uint64 id =1 [(validate.rules).uint64.gt = 0, (tagger.tags) = "uri:\"id\"" ];`,
|
||||
getTableByIDsRequestFieldCodeMark: "repeated uint64 ids = 1 [(validate.rules).repeated.min_items = 1];",
|
||||
listTableByLastIDRequestFieldCodeMark: `uint64 lastID = 1 [(tagger.tags) = "form:\"lastID\""]; // last id`,
|
||||
}
|
||||
|
||||
var grpcProtoMessageFieldCodes = map[string]string{
|
||||
createTableReplyFieldCodeMark: "string id = 1;",
|
||||
deleteTableByIDRequestFieldCodeMark: "string id = 1 [(validate.rules).string.min_len = 6];",
|
||||
deleteTableByIDsRequestFieldCodeMark: "repeated string ids = 1 [(validate.rules).repeated.min_items = 1];",
|
||||
getTableByIDRequestFieldCodeMark: "string id = 1 [(validate.rules).string.min_len = 6];",
|
||||
getTableByIDsRequestFieldCodeMark: "repeated string ids = 1 [(validate.rules).repeated.min_items = 1];",
|
||||
listTableByLastIDRequestFieldCodeMark: "string lastID = 1; // last id",
|
||||
}
|
||||
|
||||
var webProtoMessageFieldCodes = map[string]string{
|
||||
createTableReplyFieldCodeMark: "string id = 1;",
|
||||
deleteTableByIDRequestFieldCodeMark: `string id =1 [(validate.rules).string.min_len = 6, (tagger.tags) = "uri:\"id\""];`,
|
||||
deleteTableByIDsRequestFieldCodeMark: "repeated string ids = 1 [(validate.rules).repeated.min_items = 1];",
|
||||
getTableByIDRequestFieldCodeMark: `string id =1 [(validate.rules).string.min_len = 6, (tagger.tags) = "uri:\"id\"" ];`,
|
||||
getTableByIDsRequestFieldCodeMark: "repeated string ids = 1 [(validate.rules).repeated.min_items = 1];",
|
||||
listTableByLastIDRequestFieldCodeMark: `string lastID = 1 [(tagger.tags) = "form:\"lastID\""]; // last id`,
|
||||
}
|
||||
|
||||
func adaptedDbType(data tmplData, isWebProto bool, code string) string {
|
||||
switch data.DBDriver {
|
||||
case DBDriverMongodb: // mongodb
|
||||
if isWebProto {
|
||||
code = replaceProtoMessageFieldCode(code, webProtoMessageFieldCodes)
|
||||
} else {
|
||||
code = replaceProtoMessageFieldCode(code, grpcProtoMessageFieldCodes)
|
||||
}
|
||||
default:
|
||||
if isWebProto {
|
||||
code = replaceProtoMessageFieldCode(code, webDefaultProtoMessageFieldCodes)
|
||||
} else {
|
||||
code = replaceProtoMessageFieldCode(code, grpcDefaultProtoMessageFieldCodes)
|
||||
}
|
||||
}
|
||||
|
||||
if data.ProtoSubStructs != "" {
|
||||
code += "\n" + data.ProtoSubStructs
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
func replaceProtoMessageFieldCode(code string, messageFields map[string]string) string {
|
||||
for k, v := range messageFields {
|
||||
code = strings.ReplaceAll(code, k, v)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func getServiceStructCode(data tmplData) (string, error) {
|
||||
builder := strings.Builder{}
|
||||
err := serviceStructTmpl.Execute(&builder, data)
|
||||
@@ -688,6 +880,7 @@ func addCommaToJSON(modelJSONCode string) string {
|
||||
return out
|
||||
}
|
||||
|
||||
// nolint
|
||||
func mysqlToGoType(colTp *types.FieldType, style NullStyle) (name string, path string) {
|
||||
if style == NullInSql {
|
||||
path = "database/sql"
|
||||
@@ -746,6 +939,7 @@ func mysqlToGoType(colTp *types.FieldType, style NullStyle) (name string, path s
|
||||
return name, path
|
||||
}
|
||||
|
||||
// nolint
|
||||
func goTypeToProto(fields []tmplField) []tmplField {
|
||||
var newFields []tmplField
|
||||
for _, field := range fields {
|
||||
@@ -760,7 +954,24 @@ func goTypeToProto(fields []tmplField) []tmplField {
|
||||
field.GoType = "float"
|
||||
case "float64":
|
||||
field.GoType = "double"
|
||||
case goTypeInts, "[]int64":
|
||||
field.GoType = "repeated int64"
|
||||
case "[]int32":
|
||||
field.GoType = "repeated int32"
|
||||
case "[]byte":
|
||||
field.GoType = "string"
|
||||
case goTypeStrings:
|
||||
field.GoType = "repeated string"
|
||||
}
|
||||
|
||||
if field.DBDriver == DBDriverMongodb {
|
||||
if field.GoType[0] == '*' {
|
||||
field.GoType = field.GoType[1:]
|
||||
} else if strings.Contains(field.GoType, "[]*") {
|
||||
field.GoType = "repeated " + strings.ReplaceAll(field.GoType, "[]*", "")
|
||||
}
|
||||
}
|
||||
|
||||
newFields = append(newFields, field)
|
||||
}
|
||||
return newFields
|
||||
|
||||
@@ -11,22 +11,25 @@ import (
|
||||
|
||||
func TestParseSql(t *testing.T) {
|
||||
sql := `CREATE TABLE t_person_info (
|
||||
age INT(11) unsigned NULL,
|
||||
id BIGINT(11) PRIMARY KEY AUTO_INCREMENT NOT NULL COMMENT 'id',
|
||||
age INT(11) unsigned NULL,
|
||||
name VARCHAR(30) NOT NULL DEFAULT 'default_name' COMMENT 'name',
|
||||
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
login_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
sex VARCHAR(2) NULL,
|
||||
gender INT(8) NULL,
|
||||
num INT(11) DEFAULT 3 NULL,
|
||||
comment TEXT
|
||||
) COMMENT="person info";`
|
||||
|
||||
codes, err := ParseSQL(sql, WithTablePrefix("t_"), WithJSONTag(0))
|
||||
codes, err := ParseSQL(sql, WithTablePrefix("t_"), WithJSONTag(0), WithNullStyle(NullDisable))
|
||||
assert.Nil(t, err)
|
||||
for k, v := range codes {
|
||||
assert.NotEmpty(t, k)
|
||||
assert.NotEmpty(t, v)
|
||||
}
|
||||
t.Log(codes[CodeTypeJSON])
|
||||
return
|
||||
//printCode(codes)
|
||||
|
||||
codes, err = ParseSQL(sql, WithTablePrefix("t_"), WithJSONTag(0), WithEmbed())
|
||||
assert.Nil(t, err)
|
||||
@@ -34,6 +37,23 @@ func TestParseSql(t *testing.T) {
|
||||
assert.NotEmpty(t, k)
|
||||
assert.NotEmpty(t, v)
|
||||
}
|
||||
//printCode(codes)
|
||||
|
||||
codes, err = ParseSQL(sql, WithTablePrefix("t_"), WithJSONTag(0), WithWebProto())
|
||||
assert.Nil(t, err)
|
||||
for k, v := range codes {
|
||||
assert.NotEmpty(t, k)
|
||||
assert.NotEmpty(t, v)
|
||||
}
|
||||
//printCode(codes)
|
||||
|
||||
codes, err = ParseSQL(sql, WithTablePrefix("t_"), WithJSONTag(0), WithDBDriver(DBDriverPostgresql))
|
||||
assert.Nil(t, err)
|
||||
for k, v := range codes {
|
||||
assert.NotEmpty(t, k)
|
||||
assert.NotEmpty(t, v)
|
||||
}
|
||||
//printCode(codes)
|
||||
}
|
||||
|
||||
var testData = [][]string{
|
||||
@@ -121,7 +141,7 @@ func Test_parseOption(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_mysqlToGoType(t *testing.T) {
|
||||
testData := []*types.FieldType{
|
||||
fields := []*types.FieldType{
|
||||
{Tp: uint8('n')},
|
||||
{Tp: mysql.TypeTiny},
|
||||
{Tp: mysql.TypeLonglong},
|
||||
@@ -132,7 +152,7 @@ func Test_mysqlToGoType(t *testing.T) {
|
||||
{Tp: mysql.TypeJSON},
|
||||
}
|
||||
var names []string
|
||||
for _, d := range testData {
|
||||
for _, d := range fields {
|
||||
name1, _ := mysqlToGoType(d, NullInSql)
|
||||
name2, _ := mysqlToGoType(d, NullInPointer)
|
||||
names = append(names, name1, name2)
|
||||
@@ -141,12 +161,12 @@ func Test_mysqlToGoType(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_goTypeToProto(t *testing.T) {
|
||||
testData := []tmplField{
|
||||
fields := []tmplField{
|
||||
{GoType: "int"},
|
||||
{GoType: "uint"},
|
||||
{GoType: "time.Time"},
|
||||
}
|
||||
v := goTypeToProto(testData)
|
||||
v := goTypeToProto(fields)
|
||||
assert.NotNil(t, v)
|
||||
}
|
||||
|
||||
@@ -179,8 +199,11 @@ func TestGetMysqlTableInfo(t *testing.T) {
|
||||
|
||||
func TestGetPostgresqlTableInfo(t *testing.T) {
|
||||
fields, err := GetPostgresqlTableInfo("host=192.168.3.37 port=5432 user=root password=123456 dbname=account sslmode=disable", "user_example")
|
||||
t.Log(fields, err)
|
||||
sql, fieldTypes := ConvertToMysqlTable("user_example", fields)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
sql, fieldTypes := ConvertToSQLByPgFields("user_example", fields)
|
||||
t.Log(sql, fieldTypes)
|
||||
}
|
||||
|
||||
@@ -189,13 +212,23 @@ func TestGetSqliteTableInfo(t *testing.T) {
|
||||
t.Log(err, info)
|
||||
}
|
||||
|
||||
func TestConvertToMysqlTable(t *testing.T) {
|
||||
func TestGetMongodbTableInfo(t *testing.T) {
|
||||
fields, err := GetMongodbTableInfo("mongodb://root:123456@192.168.3.37:27017/account", "people")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
sql, fieldTypes := ConvertToSQLByMgoFields("people", fields)
|
||||
t.Log(sql, fieldTypes)
|
||||
}
|
||||
|
||||
func TestConvertToSQLByPgFields(t *testing.T) {
|
||||
fields := []*PGField{
|
||||
{Name: "id", Type: "smallint"},
|
||||
{Name: "name", Type: "character", Lengthvar: 24, Notnull: false},
|
||||
{Name: "age", Type: "smallint", Notnull: true},
|
||||
}
|
||||
sql, tps := ConvertToMysqlTable("foobar", fields)
|
||||
sql, tps := ConvertToSQLByPgFields("foobar", fields)
|
||||
t.Log(sql, tps)
|
||||
}
|
||||
|
||||
@@ -219,3 +252,155 @@ func Test_toMysqlTable(t *testing.T) {
|
||||
t.Log(toMysqlType(field), getType(field))
|
||||
}
|
||||
}
|
||||
|
||||
func printCode(code map[string]string) {
|
||||
for k, v := range code {
|
||||
fmt.Printf("\n\n----------------- %s --------------------\n%s\n", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getMongodbTableFields(t *testing.T) {
|
||||
fields := []*MgoField{
|
||||
{
|
||||
Name: "_id",
|
||||
Type: "primitive.ObjectID",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "age",
|
||||
Type: "int",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "birthday",
|
||||
Type: "time.Time",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "home_address",
|
||||
Type: "HomeAddress",
|
||||
ObjectStr: "type HomeAddress struct { Street string `bson:\"street\" json:\"street\"`; City string `bson:\"city\" json:\"city\"`; State string `bson:\"state\" json:\"state\"`; Zip int `bson:\"zip\" json:\"zip\"` } ",
|
||||
ProtoObjectStr: `message HomeAddress {
|
||||
string street = 1;
|
||||
string city = 2;
|
||||
string state = 3;
|
||||
int32 zip = 4;
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "interests",
|
||||
Type: "[]string",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "is_child",
|
||||
Type: "bool",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "name",
|
||||
Type: "string",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "numbers",
|
||||
Type: "[]int",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "shop_addresses",
|
||||
Type: "[]ShopAddress",
|
||||
ObjectStr: "type ShopAddress struct { CityO string `bson:\"city_o\" json:\"cityO\"`; StateO string `bson:\"state_o\" json:\"stateO\"` }",
|
||||
ProtoObjectStr: `message ShopAddress {
|
||||
string city_o = 1;
|
||||
string state_o = 2;
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "created_at",
|
||||
Type: "time.Time",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "updated_at",
|
||||
Type: "time.Time",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
{
|
||||
Name: "deleted_at",
|
||||
Type: "*time.Time",
|
||||
ObjectStr: "",
|
||||
ProtoObjectStr: "",
|
||||
},
|
||||
}
|
||||
|
||||
goStructs := MgoFieldToGoStruct("foobar", fields)
|
||||
t.Log(goStructs)
|
||||
|
||||
sql, fieldsMap := ConvertToSQLByMgoFields("foobar", fields)
|
||||
t.Log(sql)
|
||||
opts := []Option{
|
||||
WithDBDriver(DBDriverMongodb),
|
||||
WithFieldTypes(fieldsMap),
|
||||
WithJSONTag(1),
|
||||
}
|
||||
codes, err := ParseSQL(sql, opts...)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
_ = codes
|
||||
//printCode(codes)
|
||||
|
||||
sql, fieldsMap = ConvertToSQLByMgoFields("foobar", fields)
|
||||
t.Log(sql)
|
||||
opts = []Option{
|
||||
WithDBDriver(DBDriverMongodb),
|
||||
WithFieldTypes(fieldsMap),
|
||||
WithJSONTag(1),
|
||||
WithWebProto(),
|
||||
}
|
||||
codes, err = ParseSQL(sql, opts...)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
//printCode(codes)
|
||||
}
|
||||
|
||||
func Test_toSingular(t *testing.T) {
|
||||
strs := []string{
|
||||
"users",
|
||||
"address",
|
||||
"addresses",
|
||||
}
|
||||
for _, str := range strs {
|
||||
t.Log(str, toSingular(str))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_embedTimeFields(t *testing.T) {
|
||||
names := []string{"age"}
|
||||
|
||||
fields := embedTimeField(names, []*MgoField{})
|
||||
t.Log(fields)
|
||||
|
||||
names = []string{
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
}
|
||||
fields = embedTimeField(names, []*MgoField{})
|
||||
t.Log(fields)
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ ORDER BY a.attnum;`, tableName)
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
// ConvertToMysqlTable convert to mysql table ddl
|
||||
func ConvertToMysqlTable(tableName string, fields []*PGField) (string, map[string]string) {
|
||||
// ConvertToSQLByPgFields convert to mysql table ddl
|
||||
func ConvertToSQLByPgFields(tableName string, fields []*PGField) (string, map[string]string) {
|
||||
fieldStr := ""
|
||||
pgTypeMap := make(map[string]string) // name:type
|
||||
for _, field := range fields {
|
||||
@@ -71,14 +71,13 @@ func ConvertToMysqlTable(tableName string, fields []*PGField) (string, map[strin
|
||||
return fmt.Sprintf("CREATE TABLE %s (\n%s\n);", tableName, fieldStr), pgTypeMap
|
||||
}
|
||||
|
||||
// nolint
|
||||
func toMysqlType(field *PGField) string {
|
||||
switch field.Type {
|
||||
// 整型
|
||||
case "smallint", "integer", "smallserial", "serial", "int2", "int4":
|
||||
return "int"
|
||||
case "bigint", "bigserial", "int8":
|
||||
return "bigint"
|
||||
// 浮点数
|
||||
case "real":
|
||||
return "float"
|
||||
case "decimal", "numeric":
|
||||
@@ -87,14 +86,12 @@ func toMysqlType(field *PGField) string {
|
||||
return "double"
|
||||
case "money":
|
||||
return "varchar(30)"
|
||||
// 字符串
|
||||
case "character", "character varying", "varchar", "char", "bpchar":
|
||||
if field.Lengthvar > 4 {
|
||||
return fmt.Sprintf("varchar(%d)", field.Lengthvar-4)
|
||||
}
|
||||
case "text":
|
||||
return "text"
|
||||
// 日期时间
|
||||
case "timestamp":
|
||||
return "timestamp"
|
||||
case "date":
|
||||
|
||||
@@ -42,7 +42,7 @@ import (
|
||||
updateFieldTmpl *template.Template
|
||||
updateFieldTmplRaw = `
|
||||
{{- range .Fields}}
|
||||
if table.{{.Name}} {{.ConditionZero}} {
|
||||
if table.{{.Name}}{{.ConditionZero}} {
|
||||
update["{{.ColName}}"] = table.{{.Name}}
|
||||
}
|
||||
{{- end}}`
|
||||
@@ -129,11 +129,11 @@ service {{.TName}} {
|
||||
// protoMessageCreateCode
|
||||
|
||||
message Create{{.TableName}}Reply {
|
||||
uint64 id = 1;
|
||||
// createTableReplyFieldCode
|
||||
}
|
||||
|
||||
message Delete{{.TableName}}ByIDRequest {
|
||||
uint64 id = 1 [(validate.rules).uint64.gt = 0];
|
||||
// deleteTableByIDRequestFieldCode
|
||||
}
|
||||
|
||||
message Delete{{.TableName}}ByIDReply {
|
||||
@@ -141,7 +141,7 @@ message Delete{{.TableName}}ByIDReply {
|
||||
}
|
||||
|
||||
message Delete{{.TableName}}ByIDsRequest {
|
||||
repeated uint64 ids = 1 [(validate.rules).repeated.min_items = 1];
|
||||
// deleteTableByIDsRequestFieldCode
|
||||
}
|
||||
|
||||
message Delete{{.TableName}}ByIDsReply {
|
||||
@@ -157,7 +157,7 @@ message Update{{.TableName}}ByIDReply {
|
||||
// protoMessageDetailCode
|
||||
|
||||
message Get{{.TableName}}ByIDRequest {
|
||||
uint64 id = 1 [(validate.rules).uint64.gt = 0];
|
||||
// getTableByIDRequestFieldCode
|
||||
}
|
||||
|
||||
message Get{{.TableName}}ByIDReply {
|
||||
@@ -173,7 +173,7 @@ message Get{{.TableName}}ByConditionReply {
|
||||
}
|
||||
|
||||
message List{{.TableName}}ByIDsRequest {
|
||||
repeated uint64 ids = 1 [(validate.rules).repeated.min_items = 1];
|
||||
// getTableByIDsRequestFieldCode
|
||||
}
|
||||
|
||||
message List{{.TableName}}ByIDsReply {
|
||||
@@ -181,8 +181,8 @@ message List{{.TableName}}ByIDsReply {
|
||||
}
|
||||
|
||||
message List{{.TableName}}ByLastIDRequest {
|
||||
uint64 lastID = 1; // last id
|
||||
uint32 limit = 2 [(validate.rules).uint32.gt = 0]; // limit size per page
|
||||
// listTableByLastIDRequestFieldCode
|
||||
uint32 limit = 2 [(validate.rules).uint32.gt = 0]; // limit size per page
|
||||
string sort = 3; // sort by column name of table, default is -id, the - sign indicates descending order.
|
||||
}
|
||||
|
||||
@@ -411,11 +411,11 @@ service {{.TName}} {
|
||||
// protoMessageCreateCode
|
||||
|
||||
message Create{{.TableName}}Reply {
|
||||
uint64 id = 1;
|
||||
// createTableReplyFieldCode
|
||||
}
|
||||
|
||||
message Delete{{.TableName}}ByIDRequest {
|
||||
uint64 id =1 [(validate.rules).uint64.gte = 1, (tagger.tags) = "uri:\"id\"" ];
|
||||
// deleteTableByIDRequestFieldCode
|
||||
}
|
||||
|
||||
message Delete{{.TableName}}ByIDReply {
|
||||
@@ -423,7 +423,7 @@ message Delete{{.TableName}}ByIDReply {
|
||||
}
|
||||
|
||||
message Delete{{.TableName}}ByIDsRequest {
|
||||
repeated uint64 ids = 1 [(validate.rules).repeated.min_items = 1];
|
||||
// deleteTableByIDsRequestFieldCode
|
||||
}
|
||||
|
||||
message Delete{{.TableName}}ByIDsReply {
|
||||
@@ -439,7 +439,7 @@ message Update{{.TableName}}ByIDReply {
|
||||
// protoMessageDetailCode
|
||||
|
||||
message Get{{.TableName}}ByIDRequest {
|
||||
uint64 id =1 [(validate.rules).uint64.gte = 1, (tagger.tags) = "uri:\"id\"" ];
|
||||
// getTableByIDRequestFieldCode
|
||||
}
|
||||
|
||||
message Get{{.TableName}}ByIDReply {
|
||||
@@ -455,7 +455,7 @@ message Get{{.TableName}}ByConditionReply {
|
||||
}
|
||||
|
||||
message List{{.TableName}}ByIDsRequest {
|
||||
repeated uint64 ids = 1 [(validate.rules).repeated.min_items = 1];
|
||||
// getTableByIDsRequestFieldCode
|
||||
}
|
||||
|
||||
message List{{.TableName}}ByIDsReply {
|
||||
@@ -463,8 +463,8 @@ message List{{.TableName}}ByIDsReply {
|
||||
}
|
||||
|
||||
message List{{.TableName}}ByLastIDRequest {
|
||||
uint64 lastID = 1 [(tagger.tags) = "form:\"lastID\""]; // last id
|
||||
uint32 limit = 2 [(validate.rules).uint32.gt = 0, (tagger.tags) = "form:\"limit\""]; // limit size per page
|
||||
// listTableByLastIDRequestFieldCode
|
||||
uint32 limit = 2 [(validate.rules).uint32.gt = 0, (tagger.tags) = "form:\"limit\""]; // limit size per page
|
||||
string sort = 3 [(tagger.tags) = "form:\"sort\""]; // sort by column name of table, default is -id, the - sign indicates descending order.
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user