db.makeDB use text format

This commit is contained in:
Star 2024-07-08 17:27:04 +08:00
parent 1ae9577baf
commit 974e667004
5 changed files with 296 additions and 12 deletions

View File

@ -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
```

View File

@ -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)), "====================")

View File

@ -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
View 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-禁用)

View File

@ -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)