mirror of
https://github.com/go-home-admin/toolset.git
synced 2025-12-24 13:37:52 +08:00
feat: 表关联
This commit is contained in:
24
config/database/README.md
Normal file
24
config/database/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
* 该目录存放表关联配置文件,
|
||||
* 创建以database.yaml的connection名对应的```connection名.json```文件
|
||||
* json结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"表名": [
|
||||
...Relationship结构
|
||||
]
|
||||
}
|
||||
```
|
||||
* Relationship Go的结构说明:
|
||||
```go
|
||||
type Relationship struct {
|
||||
Type string `json:"type"` //关联类型:belongs_to、has_one、has_many、many2many
|
||||
Table string `json:"table"` //关联表名
|
||||
Alias string `json:"alias"` //别名(可不声明,默认用表名)
|
||||
ForeignKey string `json:"foreign_key"` //外键(可不声明,默认为'id'或'表名_id')
|
||||
ReferenceKey string `json:"reference_key"` //引用键(可不声明,默认为'id'或'表名_id')
|
||||
RelationshipTable string `json:"relationship_table"` //当many2many时,连接表名
|
||||
JoinForeignKey string `json:"join_foreign_key"` //当many2many时,本表在连接表的外键
|
||||
JoinTargetKey string `json:"join_target_key"` //当many2many时,关联表在连接表的外键
|
||||
}
|
||||
```
|
||||
@@ -3,6 +3,7 @@ package orm
|
||||
import (
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-home-admin/home/bootstrap/services"
|
||||
"github.com/go-home-admin/toolset/parser"
|
||||
@@ -22,6 +23,17 @@ func IsExist(f string) bool {
|
||||
|
||||
type Conf map[interface{}]interface{}
|
||||
|
||||
type Relationship struct {
|
||||
Type string `json:"type"` //关联类型:belongs_to、has_one、has_many、many2many
|
||||
Table string `json:"table"` //关联表名
|
||||
Alias string `json:"alias"` //别名(可不声明,默认用表名)
|
||||
ForeignKey string `json:"foreign_key"` //外键(可不声明,默认为'id'或'表名_id')
|
||||
ReferenceKey string `json:"reference_key"` //引用键(可不声明,默认为'id'或'表名_id')
|
||||
RelationshipTable string `json:"relationship_table"` //当many2many时,连接表名
|
||||
JoinForeignKey string `json:"join_foreign_key"` //当many2many时,本表在连接表的外键
|
||||
JoinTargetKey string `json:"join_target_key"` //当many2many时,关联表在连接表的外键
|
||||
}
|
||||
|
||||
func GenMysql(name string, conf Conf, out string) {
|
||||
if !IsExist(out) {
|
||||
os.MkdirAll(out, 0766)
|
||||
@@ -30,6 +42,16 @@ func GenMysql(name string, conf Conf, out string) {
|
||||
db := NewDb(conf)
|
||||
tableColumns := db.tableColumns()
|
||||
|
||||
root, _ := os.Getwd()
|
||||
file, err := os.ReadFile(root + "/config/database/" + name + ".json")
|
||||
var relationship map[string][]*Relationship
|
||||
if err == nil {
|
||||
err = json.Unmarshal(file, &relationship)
|
||||
if err != nil {
|
||||
panic("表关系JSON文件配置出错:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 计算import
|
||||
imports := getImports(tableColumns)
|
||||
for table, columns := range tableColumns {
|
||||
@@ -38,7 +60,7 @@ func GenMysql(name string, conf Conf, out string) {
|
||||
|
||||
str := "package " + name
|
||||
str += "\nimport (" + imports[table] + "\n)"
|
||||
str += "\n" + genOrmStruct(table, columns, conf)
|
||||
str += "\n" + genOrmStruct(table, columns, conf, relationship[table])
|
||||
|
||||
baseFunStr := baseMysqlFuncStr
|
||||
for old, newStr := range map[string]string{
|
||||
@@ -222,10 +244,12 @@ func getImports(tableColumns map[string][]tableColumn) map[string]string {
|
||||
for table, columns := range tableColumns {
|
||||
// 初始引入
|
||||
tm := map[string]string{
|
||||
"strings": "",
|
||||
"gorm.io/gorm": "gorm",
|
||||
"github.com/go-home-admin/home/bootstrap/providers": "providers",
|
||||
"github.com/sirupsen/logrus": "logrus",
|
||||
"database/sql": "sql",
|
||||
"github.com/go-home-admin/home/app": "home",
|
||||
}
|
||||
for _, column := range columns {
|
||||
index := strings.Index(column.GoType, ".")
|
||||
@@ -241,7 +265,7 @@ func getImports(tableColumns map[string][]tableColumn) map[string]string {
|
||||
return got
|
||||
}
|
||||
|
||||
func genOrmStruct(table string, columns []tableColumn, conf Conf) string {
|
||||
func genOrmStruct(table string, columns []tableColumn, conf Conf, relationships []*Relationship) string {
|
||||
TableName := parser.StringToHump(table)
|
||||
|
||||
hasField := make(map[string]bool)
|
||||
@@ -255,27 +279,44 @@ func genOrmStruct(table string, columns []tableColumn, conf Conf) string {
|
||||
fieldName := parser.StringToHump(column.COLUMN_NAME)
|
||||
str += fmt.Sprintf("\n\t%v %v%v`%v` // %v", fieldName, p, column.GoType, genGormTag(column), strings.ReplaceAll(column.COLUMN_COMMENT, "\n", " "))
|
||||
}
|
||||
// 表依赖
|
||||
if helper, ok := conf["helper"]; ok {
|
||||
helperConf := helper.(map[interface{}]interface{})
|
||||
tableConfig, ok := helperConf[table].([]interface{})
|
||||
if ok {
|
||||
for _, c := range tableConfig {
|
||||
cf := c.(map[interface{}]interface{})
|
||||
with := cf["with"]
|
||||
tbName := parser.StringToHump(cf["table"].(string))
|
||||
switch with {
|
||||
case "belongs_to":
|
||||
str += fmt.Sprintf("\n\t%v *%v `gorm:\"%v\"`", parser.StringToHump(cf["alias"].(string)), tbName, cf["gorm"])
|
||||
case "has_one":
|
||||
str += fmt.Sprintf("\n\t%v *%v `gorm:\"%v\"`", parser.StringToHump(cf["alias"].(string)), tbName, cf["gorm"])
|
||||
case "has_many":
|
||||
str += fmt.Sprintf("\n\t%v []%v `gorm:\"%v\"`", parser.StringToHump(cf["alias"].(string)), tbName, cf["gorm"])
|
||||
case "many2many":
|
||||
str += fmt.Sprintf("\n\t%v []%v `gorm:\"%v\"`", parser.StringToHump(cf["alias"].(string)), tbName, cf["gorm"])
|
||||
default:
|
||||
panic("with: belongs_to,has_one,has_many,many2many")
|
||||
// 表关系
|
||||
if len(relationships) > 0 {
|
||||
for _, relationship := range relationships {
|
||||
switch relationship.Type {
|
||||
case "belongs_to", "has_one", "has_many", "many2many":
|
||||
default:
|
||||
panic("with: belongs_to,has_one,has_many,many2many")
|
||||
}
|
||||
tbName := "*" + parser.StringToHump(relationship.Table)
|
||||
if relationship.Type == "has_many" || relationship.Type == "many2many" {
|
||||
tbName = "[]" + tbName
|
||||
}
|
||||
fieldName := parser.StringToHump(relationship.Table)
|
||||
if relationship.Alias != "" {
|
||||
fieldName = parser.StringToHump(relationship.Alias)
|
||||
}
|
||||
str += fmt.Sprintf("\n\t%v %v", fieldName, tbName)
|
||||
if relationship.ForeignKey != "" || relationship.ReferenceKey != "" || relationship.Type == "many2many" {
|
||||
str += " `gorm:\""
|
||||
if relationship.Type == "many2many" {
|
||||
if relationship.RelationshipTable == "" {
|
||||
panic("表" + relationship.Table + "的many2many必须声明连接表")
|
||||
}
|
||||
str += "many2many:" + relationship.RelationshipTable + ";"
|
||||
if relationship.JoinForeignKey != "" {
|
||||
str += "joinForeignKey:" + relationship.JoinForeignKey + ";"
|
||||
}
|
||||
if relationship.JoinTargetKey != "" {
|
||||
str += "joinReferences:" + relationship.JoinTargetKey + ";"
|
||||
}
|
||||
}
|
||||
if relationship.ForeignKey != "" {
|
||||
str += "foreignKey:" + relationship.ForeignKey + ";"
|
||||
}
|
||||
if relationship.ReferenceKey != "" {
|
||||
str += "references:" + relationship.ReferenceKey + ";"
|
||||
}
|
||||
str += "\"`"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,3 +241,22 @@ func (orm *OrmMysqlTableName) Or(fuc func(orm *OrmMysqlTableName)) *OrmMysqlTabl
|
||||
orm.db.Or(ormOr.db)
|
||||
return orm
|
||||
}
|
||||
|
||||
// Preload preload associations with given conditions
|
||||
// db.Preload("Orders|orders", "state NOT IN (?)", "cancelled").Find(&users)
|
||||
func (orm *OrmMysqlTableName) Preload(query string, args ...interface{}) *OrmMysqlTableName {
|
||||
orm.db.Preload(home.StringToHump(query), args...)
|
||||
return orm
|
||||
}
|
||||
|
||||
// Joins specify Joins conditions
|
||||
// db.Joins("Account|account").Find(&user)
|
||||
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
|
||||
// db.Joins("Account", DB.Select("id").Where("user_id = users.id AND name = ?", "someName").Model(&Account{}))
|
||||
func (orm *OrmMysqlTableName) Joins(query string, args ...interface{}) *OrmMysqlTableName {
|
||||
if !strings.Contains(query, " ") {
|
||||
query = home.StringToHump(query)
|
||||
}
|
||||
orm.db.Joins(query, args...)
|
||||
return orm
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ package pgorm
|
||||
import (
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-home-admin/home/bootstrap/services"
|
||||
"github.com/go-home-admin/toolset/console/commands/orm"
|
||||
"github.com/go-home-admin/toolset/parser"
|
||||
_ "github.com/lib/pq"
|
||||
"log"
|
||||
@@ -30,6 +32,16 @@ func GenSql(name string, conf Conf, out string) {
|
||||
db := NewDb(conf)
|
||||
tableColumns := db.tableColumns()
|
||||
|
||||
root, _ := os.Getwd()
|
||||
file, err := os.ReadFile(root + "/config/database/" + name + ".json")
|
||||
var relationship map[string][]*orm.Relationship
|
||||
if err == nil {
|
||||
err = json.Unmarshal(file, &relationship)
|
||||
if err != nil {
|
||||
panic("表关系JSON文件配置出错:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 计算import
|
||||
imports := getImports(tableColumns)
|
||||
for table, columns := range tableColumns {
|
||||
@@ -38,7 +50,7 @@ func GenSql(name string, conf Conf, out string) {
|
||||
|
||||
str := "package " + name
|
||||
str += "\nimport (" + imports[table] + "\n)"
|
||||
str += "\n" + genOrmStruct(table, columns, conf)
|
||||
str += "\n" + genOrmStruct(table, columns, conf, relationship[table])
|
||||
|
||||
baseFunStr := baseMysqlFuncStr
|
||||
for old, newStr := range map[string]string{
|
||||
@@ -223,10 +235,12 @@ func getImports(tableColumns map[string][]tableColumn) map[string]string {
|
||||
for table, columns := range tableColumns {
|
||||
// 初始引入
|
||||
tm := map[string]string{
|
||||
"strings": "",
|
||||
"gorm.io/gorm": "gorm",
|
||||
"github.com/go-home-admin/home/bootstrap/providers": "providers",
|
||||
"github.com/sirupsen/logrus": "logrus",
|
||||
"database/sql": "sql",
|
||||
"github.com/go-home-admin/home/app": "home",
|
||||
}
|
||||
for _, column := range columns {
|
||||
index := strings.Index(column.GoType, ".")
|
||||
@@ -242,7 +256,7 @@ func getImports(tableColumns map[string][]tableColumn) map[string]string {
|
||||
return got
|
||||
}
|
||||
|
||||
func genOrmStruct(table string, columns []tableColumn, conf Conf) string {
|
||||
func genOrmStruct(table string, columns []tableColumn, conf Conf, relationships []*orm.Relationship) string {
|
||||
TableName := parser.StringToHump(table)
|
||||
|
||||
hasField := make(map[string]bool)
|
||||
@@ -256,27 +270,44 @@ func genOrmStruct(table string, columns []tableColumn, conf Conf) string {
|
||||
fieldName := parser.StringToHump(column.ColumnName)
|
||||
str += fmt.Sprintf("\n\t%v %v%v`%v` // %v", fieldName, p, column.GoType, genGormTag(column), strings.ReplaceAll(column.Comment, "\n", " "))
|
||||
}
|
||||
// 表依赖
|
||||
if helper, ok := conf["helper"]; ok {
|
||||
helperConf := helper.(map[interface{}]interface{})
|
||||
tableConfig, ok := helperConf[table].([]interface{})
|
||||
if ok {
|
||||
for _, c := range tableConfig {
|
||||
cf := c.(map[interface{}]interface{})
|
||||
with := cf["with"]
|
||||
tbName := parser.StringToHump(cf["table"].(string))
|
||||
switch with {
|
||||
case "belongs_to":
|
||||
str += fmt.Sprintf("\n\t%v *%v `gorm:\"%v\"`", parser.StringToHump(cf["alias"].(string)), tbName, cf["gorm"])
|
||||
case "has_one":
|
||||
str += fmt.Sprintf("\n\t%v *%v `gorm:\"%v\"`", parser.StringToHump(cf["alias"].(string)), tbName, cf["gorm"])
|
||||
case "has_many":
|
||||
str += fmt.Sprintf("\n\t%v []%v `gorm:\"%v\"`", parser.StringToHump(cf["alias"].(string)), tbName, cf["gorm"])
|
||||
case "many2many":
|
||||
str += fmt.Sprintf("\n\t%v []%v `gorm:\"%v\"`", parser.StringToHump(cf["alias"].(string)), tbName, cf["gorm"])
|
||||
default:
|
||||
panic("with: belongs_to,has_one,has_many,many2many")
|
||||
// 表关系
|
||||
if len(relationships) > 0 {
|
||||
for _, relationship := range relationships {
|
||||
switch relationship.Type {
|
||||
case "belongs_to", "has_one", "has_many", "many2many":
|
||||
default:
|
||||
panic("with: belongs_to,has_one,has_many,many2many")
|
||||
}
|
||||
tbName := "*" + parser.StringToHump(relationship.Table)
|
||||
if relationship.Type == "has_many" || relationship.Type == "many2many" {
|
||||
tbName = "[]" + tbName
|
||||
}
|
||||
fieldName := parser.StringToHump(relationship.Table)
|
||||
if relationship.Alias != "" {
|
||||
fieldName = parser.StringToHump(relationship.Alias)
|
||||
}
|
||||
str += fmt.Sprintf("\n\t%v %v", fieldName, tbName)
|
||||
if relationship.ForeignKey != "" || relationship.ReferenceKey != "" || relationship.Type == "many2many" {
|
||||
str += " `gorm:\""
|
||||
if relationship.Type == "many2many" {
|
||||
if relationship.RelationshipTable == "" {
|
||||
panic("表" + relationship.Table + "的many2many必须声明连接表")
|
||||
}
|
||||
str += "many2many:" + relationship.RelationshipTable + ";"
|
||||
if relationship.JoinForeignKey != "" {
|
||||
str += "joinForeignKey:" + relationship.JoinForeignKey + ";"
|
||||
}
|
||||
if relationship.JoinTargetKey != "" {
|
||||
str += "joinReferences:" + relationship.JoinTargetKey + ";"
|
||||
}
|
||||
}
|
||||
if relationship.ForeignKey != "" {
|
||||
str += "foreignKey:" + relationship.ForeignKey + ";"
|
||||
}
|
||||
if relationship.ReferenceKey != "" {
|
||||
str += "references:" + relationship.ReferenceKey + ";"
|
||||
}
|
||||
str += "\"`"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,3 +241,22 @@ func (orm *Orm{orm_table_name}) Or(fuc func(orm *Orm{orm_table_name})) *Orm{orm_
|
||||
orm.db.Or(ormOr.db)
|
||||
return orm
|
||||
}
|
||||
|
||||
// Preload preload associations with given conditions
|
||||
// db.Preload("Orders|orders", "state NOT IN (?)", "cancelled").Find(&users)
|
||||
func (orm *OrmMysqlTableName) Preload(query string, args ...interface{}) *OrmMysqlTableName {
|
||||
orm.db.Preload(home.StringToHump(query), args...)
|
||||
return orm
|
||||
}
|
||||
|
||||
// Joins specify Joins conditions
|
||||
// db.Joins("Account|account").Find(&user)
|
||||
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
|
||||
// db.Joins("Account", DB.Select("id").Where("user_id = users.id AND name = ?", "someName").Model(&Account{}))
|
||||
func (orm *OrmMysqlTableName) Joins(query string, args ...interface{}) *OrmMysqlTableName {
|
||||
if !strings.Contains(query, " ") {
|
||||
query = home.StringToHump(query)
|
||||
}
|
||||
orm.db.Joins(query, args...)
|
||||
return orm
|
||||
}
|
||||
|
||||
4
go.mod
4
go.mod
@@ -4,12 +4,12 @@ go 1.16
|
||||
|
||||
require (
|
||||
github.com/ctfang/command v1.0.1
|
||||
github.com/go-home-admin/home v0.3.6
|
||||
github.com/go-home-admin/home v0.4.14
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/joho/godotenv v1.4.0
|
||||
github.com/lib/pq v1.10.6
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gorm.io/gorm v1.23.5 // indirect
|
||||
gorm.io/gorm v1.23.5
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
4
go.sum
4
go.sum
@@ -20,8 +20,8 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||
github.com/gin-gonic/gin v1.8.0 h1:4WFH5yycBMA3za5Hnl425yd9ymdw1XPm4666oab+hv4=
|
||||
github.com/gin-gonic/gin v1.8.0/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||
github.com/go-home-admin/home v0.3.6 h1:tk56T1DgdqTWcuOdT07N/SLojrAW5BhqSC02kdlNiVI=
|
||||
github.com/go-home-admin/home v0.3.6/go.mod h1:51swp6MVnaZVT1ZfZlSWMGGTT7zuqI7NMd0mX6EEenw=
|
||||
github.com/go-home-admin/home v0.4.14 h1:Ta2D4Wys1pSH78lYNJP+PF8XwOkLy+IH75KkaWGDJ0I=
|
||||
github.com/go-home-admin/home v0.4.14/go.mod h1:51swp6MVnaZVT1ZfZlSWMGGTT7zuqI7NMd0mX6EEenw=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
|
||||
Reference in New Issue
Block a user