db.makeDB use text format
This commit is contained in:
parent
1ae9577baf
commit
974e667004
87
README.md
87
README.md
@ -1,2 +1,89 @@
|
|||||||
# plugins
|
# plugins
|
||||||
|
|
||||||
|
## db.makeDB 根据简化的数据结构描述自动生成数据库表结构(自动比对,增量更新)
|
||||||
|
|
||||||
|
```
|
||||||
|
// Account 账号
|
||||||
|
|
||||||
|
User // 用户
|
||||||
|
id c12 PK // 用户ID
|
||||||
|
phone v20 U // 手机号
|
||||||
|
password v80 n // 密码
|
||||||
|
salt v50 // 随机密码
|
||||||
|
name v100 n // 名称
|
||||||
|
serverKey v200 // 服务密钥
|
||||||
|
isValid b // 是否有效
|
||||||
|
|
||||||
|
Device // 设备
|
||||||
|
id v30 PK // 设备ID
|
||||||
|
userId c12 // 当前用户
|
||||||
|
salt v50 // 随机密码
|
||||||
|
secretTime dt // 密钥生成时间
|
||||||
|
|
||||||
|
// Log 日志
|
||||||
|
|
||||||
|
LoginLog // 登录日志
|
||||||
|
id ubi AI // 登录ID
|
||||||
|
way v20 // 登录途径(verifyCode/autoLogin/oneClickLogin)
|
||||||
|
userId c12 I // 当前用户
|
||||||
|
deviceId v30 I // 设备ID
|
||||||
|
time dt I // 登录时间
|
||||||
|
userAgent v200 // 设备信息
|
||||||
|
requestId v20 // 请求ID
|
||||||
|
sessionId v20 // 会话ID
|
||||||
|
successful b // 是否成功
|
||||||
|
message v1024 // 登录处理失败的信息
|
||||||
|
```
|
||||||
|
|
||||||
|
## db.makeDB 缩写对照表
|
||||||
|
|
||||||
|
### types
|
||||||
|
|
||||||
|
```
|
||||||
|
c => char
|
||||||
|
v => varchar
|
||||||
|
dt => datetime
|
||||||
|
d => date
|
||||||
|
tm => time
|
||||||
|
i => int
|
||||||
|
ui => int unsigned
|
||||||
|
ti => tinyint
|
||||||
|
uti => tinyint unsigned
|
||||||
|
b => tinyint unsigned
|
||||||
|
bi => bigint
|
||||||
|
ubi => bigint unsigned
|
||||||
|
f => float
|
||||||
|
uf => float unsigned
|
||||||
|
ff => double
|
||||||
|
uff => double unsigned
|
||||||
|
si => smallint
|
||||||
|
usi => smallint unsigned
|
||||||
|
mi => middleint
|
||||||
|
umi => middleint unsigned
|
||||||
|
t => text
|
||||||
|
bb => blob
|
||||||
|
```
|
||||||
|
|
||||||
|
### indexes
|
||||||
|
|
||||||
|
```
|
||||||
|
PK => PRIMARY KEY NOT NULL
|
||||||
|
AI => PRIMARY KEY AUTOINCREMENT NOT NULL
|
||||||
|
I => index
|
||||||
|
U => unique
|
||||||
|
TI => fulltext
|
||||||
|
```
|
||||||
|
|
||||||
|
### defaults
|
||||||
|
|
||||||
|
```
|
||||||
|
ct => CURRENT_TIMESTAMP
|
||||||
|
ctu => CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
```
|
||||||
|
|
||||||
|
### null set
|
||||||
|
|
||||||
|
```
|
||||||
|
n => NULL
|
||||||
|
nn => NOT NULL
|
||||||
|
```
|
||||||
|
163
db/MakeTable.go
163
db/MakeTable.go
@ -180,6 +180,169 @@ func MakeER(groups []ERGroup, outputFile *string, tplFile *string, ctx *plugin.C
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ConvertTextToER(text string) []ERGroup {
|
||||||
|
tablesByGroup := make([]ERGroup, 0)
|
||||||
|
var lastGroup *ERGroup
|
||||||
|
lastTableName := ""
|
||||||
|
var lastTable *TableStruct
|
||||||
|
lastTableComment := ""
|
||||||
|
splitter := regexp.MustCompile(`\s+`)
|
||||||
|
wnMatcher := regexp.MustCompile(`^([a-zA-Z]+)([0-9]+)$`)
|
||||||
|
for _, line := range strings.Split(text, "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
lc := strings.SplitN(line, "//", 2)
|
||||||
|
comment := ""
|
||||||
|
if len(lc) == 2 {
|
||||||
|
line = strings.TrimSpace(lc[0])
|
||||||
|
comment = strings.TrimSpace(lc[1])
|
||||||
|
}
|
||||||
|
if line == "" {
|
||||||
|
if comment != "" {
|
||||||
|
commentA := strings.SplitN(comment, " ", 2)
|
||||||
|
if len(commentA) == 1 {
|
||||||
|
commentA = append(commentA, "")
|
||||||
|
}
|
||||||
|
//lastGroupName = comment
|
||||||
|
lastGroup = &ERGroup{
|
||||||
|
Group: commentA[0],
|
||||||
|
Comment: commentA[1],
|
||||||
|
Tables: make([]TableStruct, 0),
|
||||||
|
}
|
||||||
|
tablesByGroup = append(tablesByGroup, *lastGroup)
|
||||||
|
lastGroup = &tablesByGroup[len(tablesByGroup)-1]
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
a := splitter.Split(line, 10)
|
||||||
|
if len(a) == 1 {
|
||||||
|
lastTableName = a[0]
|
||||||
|
lastTableComment = comment
|
||||||
|
lastTable = &TableStruct{
|
||||||
|
Name: lastTableName,
|
||||||
|
Comment: lastTableComment,
|
||||||
|
Fields: make([]TableField, 0),
|
||||||
|
}
|
||||||
|
if lastGroup == nil {
|
||||||
|
lastGroup = &ERGroup{
|
||||||
|
Group: "Default",
|
||||||
|
Tables: make([]TableStruct, 0),
|
||||||
|
}
|
||||||
|
tablesByGroup = append(tablesByGroup, *lastGroup)
|
||||||
|
lastGroup = &tablesByGroup[len(tablesByGroup)-1]
|
||||||
|
}
|
||||||
|
lastGroup.Tables = append(lastGroup.Tables, *lastTable)
|
||||||
|
lastTable = &lastGroup.Tables[len(lastGroup.Tables)-1]
|
||||||
|
} else if lastTableName != "" {
|
||||||
|
field := TableField{
|
||||||
|
Name: a[0],
|
||||||
|
Type: "",
|
||||||
|
Index: "",
|
||||||
|
IndexGroup: "",
|
||||||
|
Default: "",
|
||||||
|
Comment: comment,
|
||||||
|
Null: "NOT NULL",
|
||||||
|
Extra: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < len(a); i++ {
|
||||||
|
wn := wnMatcher.FindStringSubmatch(a[i])
|
||||||
|
tag := a[i]
|
||||||
|
size := 0
|
||||||
|
if wn != nil {
|
||||||
|
tag = wn[1]
|
||||||
|
size = u.Int(wn[2])
|
||||||
|
}
|
||||||
|
switch tag {
|
||||||
|
case "PK":
|
||||||
|
field.Index = "pk"
|
||||||
|
field.Null = "NOT NULL"
|
||||||
|
case "I":
|
||||||
|
field.Index = "index"
|
||||||
|
case "AI":
|
||||||
|
field.Extra = "AUTO_INCREMENT"
|
||||||
|
field.Index = "pk"
|
||||||
|
case "TI":
|
||||||
|
field.Index = "fulltext"
|
||||||
|
case "U":
|
||||||
|
field.Index = "unique"
|
||||||
|
case "ct":
|
||||||
|
field.Default = "CURRENT_TIMESTAMP"
|
||||||
|
case "ctu":
|
||||||
|
field.Default = "CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
|
||||||
|
case "n":
|
||||||
|
field.Null = "NULL"
|
||||||
|
case "nn":
|
||||||
|
field.Null = "NOT NULL"
|
||||||
|
case "c":
|
||||||
|
field.Type = "char"
|
||||||
|
case "v":
|
||||||
|
field.Type = "varchar"
|
||||||
|
case "dt":
|
||||||
|
field.Type = "datetime"
|
||||||
|
case "d":
|
||||||
|
field.Type = "date"
|
||||||
|
case "tm":
|
||||||
|
field.Type = "time"
|
||||||
|
case "i":
|
||||||
|
field.Type = "int"
|
||||||
|
case "ui":
|
||||||
|
field.Type = "int unsigned"
|
||||||
|
case "ti":
|
||||||
|
field.Type = "tinyint"
|
||||||
|
case "uti":
|
||||||
|
field.Type = "tinyint unsigned"
|
||||||
|
case "b":
|
||||||
|
field.Type = "tinyint unsigned"
|
||||||
|
case "bi":
|
||||||
|
field.Type = "bigint"
|
||||||
|
case "ubi":
|
||||||
|
field.Type = "bigint unsigned"
|
||||||
|
case "f":
|
||||||
|
field.Type = "float"
|
||||||
|
case "uf":
|
||||||
|
field.Type = "float unsigned"
|
||||||
|
case "ff":
|
||||||
|
field.Type = "double"
|
||||||
|
case "uff":
|
||||||
|
field.Type = "double unsigned"
|
||||||
|
case "si":
|
||||||
|
field.Type = "smallint"
|
||||||
|
case "usi":
|
||||||
|
field.Type = "smallint unsigned"
|
||||||
|
case "mi":
|
||||||
|
field.Type = "middleint"
|
||||||
|
case "umi":
|
||||||
|
field.Type = "middleint unsigned"
|
||||||
|
case "t":
|
||||||
|
field.Type = "text"
|
||||||
|
case "bb":
|
||||||
|
field.Type = "blob"
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if size > 0 {
|
||||||
|
switch tag {
|
||||||
|
case "I":
|
||||||
|
// 索引分组
|
||||||
|
field.Index = "index"
|
||||||
|
field.IndexGroup = u.String(size)
|
||||||
|
case "U":
|
||||||
|
// 唯一索引分组
|
||||||
|
field.Index = "unique"
|
||||||
|
field.IndexGroup = u.String(size)
|
||||||
|
default:
|
||||||
|
// 带长度的类型
|
||||||
|
field.Type += fmt.Sprintf("(%d)", size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastTable.Fields = append(lastTable.Fields, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tablesByGroup
|
||||||
|
}
|
||||||
|
|
||||||
func MakeTable(conn *db.DB, table *TableStruct, ctx *plugin.Context) ([]string, error) {
|
func MakeTable(conn *db.DB, table *TableStruct, ctx *plugin.Context) ([]string, error) {
|
||||||
logger := ctx.GetInject("*log.Logger").(*log.Logger)
|
logger := ctx.GetInject("*log.Logger").(*log.Logger)
|
||||||
//fmt.Println(u.JsonP(ddlKeyMatcher.FindAllStringSubmatch("(`key`,id, `name` )", 100)), "====================")
|
//fmt.Println(u.JsonP(ddlKeyMatcher.FindAllStringSubmatch("(`key`,id, `name` )", 100)), "====================")
|
||||||
|
39
db/db.go
39
db/db.go
@ -73,9 +73,11 @@ configs:
|
|||||||
"destroy": DefaultDestroy,
|
"destroy": DefaultDestroy,
|
||||||
"exec": DefaultExec,
|
"exec": DefaultExec,
|
||||||
"insert": DefaultInsert,
|
"insert": DefaultInsert,
|
||||||
"make": DefaultMake,
|
"makeDB": DefaultMakeDBByText,
|
||||||
|
"makeDBBy": DefaultMakeDBByObject,
|
||||||
"makeDao": DefaultMakeDao,
|
"makeDao": DefaultMakeDao,
|
||||||
"makeER": DefaultMakeER,
|
"makeER": DefaultMakeERByText,
|
||||||
|
"makeERBy": DefaultMakeERByObject,
|
||||||
"makeId": DefaultMakeId,
|
"makeId": DefaultMakeId,
|
||||||
"query": DefaultQuery,
|
"query": DefaultQuery,
|
||||||
"query1": DefaultQuery1,
|
"query1": DefaultQuery1,
|
||||||
@ -125,9 +127,15 @@ func InKeys(numArgs int) string {
|
|||||||
return fmt.Sprintf("(%s)", strings.Join(a, ","))
|
return fmt.Sprintf("(%s)", strings.Join(a, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make 创建表格,如果表格已经存在则更新表结构
|
// MakeDB 创建或更新数据库
|
||||||
// Make return 已执行的SQL列表
|
// MakeDB return 已执行的SQL列表
|
||||||
func (db *DB) Make(groups []ERGroup, ctx *plugin.Context) ([]string, error) {
|
func (db *DB) MakeDB(dbDesc string, ctx *plugin.Context) ([]string, error) {
|
||||||
|
return db.MakeDBBy(ConvertTextToER(dbDesc), ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeDBBy 创建或更新数据库
|
||||||
|
// MakeDBBy return 已执行的SQL列表
|
||||||
|
func (db *DB) MakeDBBy(groups []ERGroup, ctx *plugin.Context) ([]string, error) {
|
||||||
outSql := make([]string, 0)
|
outSql := make([]string, 0)
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
for _, table := range group.Tables {
|
for _, table := range group.Tables {
|
||||||
@ -143,7 +151,12 @@ func (db *DB) Make(groups []ERGroup, ctx *plugin.Context) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeER 创建ER图
|
// MakeER 创建ER图
|
||||||
func (db *DB) MakeER(groups []ERGroup, outputFile *string, tplFile *string, ctx *plugin.Context) error {
|
func (db *DB) MakeER(dbDesc string, outputFile *string, tplFile *string, ctx *plugin.Context) error {
|
||||||
|
return MakeER(ConvertTextToER(dbDesc), outputFile, tplFile, ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeERBy 创建ER图
|
||||||
|
func (db *DB) MakeERBy(groups []ERGroup, outputFile *string, tplFile *string, ctx *plugin.Context) error {
|
||||||
return MakeER(groups, outputFile, tplFile, ctx)
|
return MakeER(groups, outputFile, tplFile, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,14 +475,20 @@ func DefaultReplace(ctx *plugin.Context, table string, data map[string]interface
|
|||||||
func DefaultUpdate(ctx *plugin.Context, table string, data map[string]interface{}, wheres string, args ...interface{}) (ExecResult, error) {
|
func DefaultUpdate(ctx *plugin.Context, table string, data map[string]interface{}, wheres string, args ...interface{}) (ExecResult, error) {
|
||||||
return GetDB(ctx, nil).Update(table, data, wheres, args...)
|
return GetDB(ctx, nil).Update(table, data, wheres, args...)
|
||||||
}
|
}
|
||||||
func DefaultMake(ctx *plugin.Context, groups []ERGroup) ([]string, error) {
|
func DefaultMakeDBByText(ctx *plugin.Context, dbDesc string) ([]string, error) {
|
||||||
return GetDB(ctx, nil).Make(groups, ctx)
|
return GetDB(ctx, nil).MakeDB(dbDesc, ctx)
|
||||||
|
}
|
||||||
|
func DefaultMakeDBByObject(ctx *plugin.Context, groups []ERGroup) ([]string, error) {
|
||||||
|
return GetDB(ctx, nil).MakeDBBy(groups, ctx)
|
||||||
}
|
}
|
||||||
func DefaultMakeDao(ctx *plugin.Context, outputPath *string, conf *DaoConfig) error {
|
func DefaultMakeDao(ctx *plugin.Context, outputPath *string, conf *DaoConfig) error {
|
||||||
return GetDB(ctx, nil).MakeDao(outputPath, conf, ctx)
|
return GetDB(ctx, nil).MakeDao(outputPath, conf, ctx)
|
||||||
}
|
}
|
||||||
func DefaultMakeER(ctx *plugin.Context, groups []ERGroup, outputFile *string, tplFile *string) error {
|
func DefaultMakeERByText(ctx *plugin.Context, dbDesc string, outputFile *string, tplFile *string) error {
|
||||||
return GetDB(ctx, nil).MakeER(groups, outputFile, tplFile, ctx)
|
return GetDB(ctx, nil).MakeER(dbDesc, outputFile, tplFile, ctx)
|
||||||
|
}
|
||||||
|
func DefaultMakeERByObject(ctx *plugin.Context, groups []ERGroup, outputFile *string, tplFile *string) error {
|
||||||
|
return GetDB(ctx, nil).MakeERBy(groups, outputFile, tplFile, ctx)
|
||||||
}
|
}
|
||||||
func DefaultMakeId(ctx *plugin.Context, table string, idField string, idSize uint) (string, error) {
|
func DefaultMakeId(ctx *plugin.Context, table string, idField string, idSize uint) (string, error) {
|
||||||
return GetDB(ctx, nil).MakeId(table, idField, idSize)
|
return GetDB(ctx, nil).MakeId(table, idField, idSize)
|
||||||
|
9
tests/TestDB.txt
Normal file
9
tests/TestDB.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// account 账号相关
|
||||||
|
|
||||||
|
user // 用户表
|
||||||
|
id i AI // 用户编号
|
||||||
|
name v30 // 姓名
|
||||||
|
phone v20 U // 手机号
|
||||||
|
addDate dt I // 创建时间
|
||||||
|
version i I // 数据版本号
|
||||||
|
isValid i // 是否有效(1-启用,0-禁用)
|
@ -1,7 +1,13 @@
|
|||||||
import db from "apigo.cc/apigo/plugins/db"
|
import db from "apigo.cc/apigo/plugins/db"
|
||||||
import file from "apigo.cc/apigo/plugins/file"
|
import file from "apigo.cc/apigo/plugins/file"
|
||||||
|
|
||||||
let testDBDesc = file.loadYaml('./TestDB.yml')
|
let testDBDesc = file.read('./TestDB.txt')
|
||||||
db.make(testDBDesc)
|
db.makeDB(testDBDesc)
|
||||||
db.makeDao("db_tests")
|
db.makeDao("db_tests")
|
||||||
db.makeER(testDBDesc)
|
db.makeER(testDBDesc)
|
||||||
|
|
||||||
|
// let testDBDesc = file.loadYaml('./TestDB.yml')
|
||||||
|
// console.info(db.makeDBBy(testDBDesc))
|
||||||
|
// db.makeDao("db_tests")
|
||||||
|
// db.makeERBy(testDBDesc)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user