hasone hasmany 待完善
This commit is contained in:
parent
a6ee333232
commit
044e55a399
|
@ -1,16 +1,17 @@
|
|||
package model
|
||||
|
||||
type QueryCondition struct {
|
||||
Where ParseWhere
|
||||
From string
|
||||
Fields string
|
||||
Group string
|
||||
Order SqlBuilder
|
||||
Join SqlBuilder
|
||||
Having SqlBuilder
|
||||
Limit int
|
||||
Offset int
|
||||
In [][]any
|
||||
Where ParseWhere
|
||||
From string
|
||||
Fields string
|
||||
Group string
|
||||
Order SqlBuilder
|
||||
Join SqlBuilder
|
||||
Having SqlBuilder
|
||||
Limit int
|
||||
Offset int
|
||||
In [][]any
|
||||
Relation map[string]*QueryCondition
|
||||
}
|
||||
|
||||
func Conditions(fns ...Condition) QueryCondition {
|
||||
|
@ -23,6 +24,16 @@ func Conditions(fns ...Condition) QueryCondition {
|
|||
}
|
||||
return r
|
||||
}
|
||||
func WithConditions(fns ...Condition) *QueryCondition {
|
||||
r := QueryCondition{}
|
||||
for _, fn := range fns {
|
||||
fn(&r)
|
||||
}
|
||||
if r.Fields == "" {
|
||||
r.Fields = "*"
|
||||
}
|
||||
return &r
|
||||
}
|
||||
|
||||
type Condition func(c *QueryCondition)
|
||||
|
||||
|
@ -84,3 +95,12 @@ func In(in ...[]any) Condition {
|
|||
c.In = append(c.In, in...)
|
||||
}
|
||||
}
|
||||
|
||||
func With(tableTag string, q *QueryCondition) Condition {
|
||||
return func(c *QueryCondition) {
|
||||
if c.Relation == nil {
|
||||
c.Relation = map[string]*QueryCondition{}
|
||||
}
|
||||
c.Relation[tableTag] = q
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,10 @@ func pagination[T Model](db dbQuery, ctx context.Context, q QueryCondition, page
|
|||
}
|
||||
if q.Group != "" {
|
||||
qx.Fields = q.Fields
|
||||
sq, in, er := BuildQuerySql[T](qx)
|
||||
if qx.From == "" {
|
||||
qx.From = Table[T]()
|
||||
}
|
||||
sq, in, er := BuildQuerySql(qx)
|
||||
qx.In = [][]any{in}
|
||||
if er != nil {
|
||||
err = er
|
||||
|
@ -91,24 +94,18 @@ func FindOneById[T Model, I constraints.Integer](ctx context.Context, id I) (T,
|
|||
return gets[T](globalBb, ctx, QueryCondition{
|
||||
Fields: "*",
|
||||
Where: SqlBuilder{
|
||||
{PrimaryKey[T](), "=", number.ToString(id), "int"},
|
||||
{PrimaryKey[T](), "=", number.IntToString(id), "int"},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func FirstOne[T Model](ctx context.Context, where ParseWhere, fields string, order SqlBuilder, in ...[]any) (r T, err error) {
|
||||
s, args, err := BuildQuerySql[T](QueryCondition{
|
||||
Where: where,
|
||||
Fields: fields,
|
||||
Order: order,
|
||||
In: in,
|
||||
Limit: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = globalBb.Get(ctx, &r, s, args...)
|
||||
return
|
||||
func FirstOne[T Model](ctx context.Context, where ParseWhere, fields string, order SqlBuilder, in ...[]any) (T, error) {
|
||||
return gets[T](globalBb, ctx, Conditions(
|
||||
Where(where),
|
||||
Fields(fields),
|
||||
Order(order),
|
||||
In(in...),
|
||||
))
|
||||
}
|
||||
|
||||
func LastOne[T Model](ctx context.Context, where ParseWhere, fields string, in ...[]any) (T, error) {
|
||||
|
@ -122,10 +119,11 @@ func LastOne[T Model](ctx context.Context, where ParseWhere, fields string, in .
|
|||
}
|
||||
|
||||
func SimpleFind[T Model](ctx context.Context, where ParseWhere, fields string, in ...[]any) (r []T, err error) {
|
||||
s, args, err := BuildQuerySql[T](QueryCondition{
|
||||
s, args, err := BuildQuerySql(QueryCondition{
|
||||
Where: where,
|
||||
Fields: fields,
|
||||
In: in,
|
||||
From: Table[T](),
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -155,8 +153,9 @@ func Find[T Model](ctx context.Context, where ParseWhere, fields, group string,
|
|||
Having: having,
|
||||
Limit: limit,
|
||||
In: in,
|
||||
From: Table[T](),
|
||||
}
|
||||
s, args, err := BuildQuerySql[T](q)
|
||||
s, args, err := BuildQuerySql(q)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||
"github.com/fthvgb1/wp-go/safety"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
@ -13,29 +14,31 @@ import (
|
|||
)
|
||||
|
||||
type post struct {
|
||||
Id uint64 `gorm:"column:ID" db:"ID" json:"ID" form:"ID"`
|
||||
PostAuthor uint64 `gorm:"column:post_author" db:"post_author" json:"post_author" form:"post_author"`
|
||||
PostDate time.Time `gorm:"column:post_date" db:"post_date" json:"post_date" form:"post_date"`
|
||||
PostDateGmt time.Time `gorm:"column:post_date_gmt" db:"post_date_gmt" json:"post_date_gmt" form:"post_date_gmt"`
|
||||
PostContent string `gorm:"column:post_content" db:"post_content" json:"post_content" form:"post_content"`
|
||||
PostTitle string `gorm:"column:post_title" db:"post_title" json:"post_title" form:"post_title"`
|
||||
PostExcerpt string `gorm:"column:post_excerpt" db:"post_excerpt" json:"post_excerpt" form:"post_excerpt"`
|
||||
PostStatus string `gorm:"column:post_status" db:"post_status" json:"post_status" form:"post_status"`
|
||||
CommentStatus string `gorm:"column:comment_status" db:"comment_status" json:"comment_status" form:"comment_status"`
|
||||
PingStatus string `gorm:"column:ping_status" db:"ping_status" json:"ping_status" form:"ping_status"`
|
||||
PostPassword string `gorm:"column:post_password" db:"post_password" json:"post_password" form:"post_password"`
|
||||
PostName string `gorm:"column:post_name" db:"post_name" json:"post_name" form:"post_name"`
|
||||
ToPing string `gorm:"column:to_ping" db:"to_ping" json:"to_ping" form:"to_ping"`
|
||||
Pinged string `gorm:"column:pinged" db:"pinged" json:"pinged" form:"pinged"`
|
||||
PostModified time.Time `gorm:"column:post_modified" db:"post_modified" json:"post_modified" form:"post_modified"`
|
||||
PostModifiedGmt time.Time `gorm:"column:post_modified_gmt" db:"post_modified_gmt" json:"post_modified_gmt" form:"post_modified_gmt"`
|
||||
PostContentFiltered string `gorm:"column:post_content_filtered" db:"post_content_filtered" json:"post_content_filtered" form:"post_content_filtered"`
|
||||
PostParent uint64 `gorm:"column:post_parent" db:"post_parent" json:"post_parent" form:"post_parent"`
|
||||
Guid string `gorm:"column:guid" db:"guid" json:"guid" form:"guid"`
|
||||
MenuOrder int `gorm:"column:menu_order" db:"menu_order" json:"menu_order" form:"menu_order"`
|
||||
PostType string `gorm:"column:post_type" db:"post_type" json:"post_type" form:"post_type"`
|
||||
PostMimeType string `gorm:"column:post_mime_type" db:"post_mime_type" json:"post_mime_type" form:"post_mime_type"`
|
||||
CommentCount int64 `gorm:"column:comment_count" db:"comment_count" json:"comment_count" form:"comment_count"`
|
||||
Id uint64 `gorm:"column:ID" db:"ID" json:"ID" form:"ID"`
|
||||
PostAuthor uint64 `gorm:"column:post_author" db:"post_author" json:"post_author" form:"post_author"`
|
||||
PostDate time.Time `gorm:"column:post_date" db:"post_date" json:"post_date" form:"post_date"`
|
||||
PostDateGmt time.Time `gorm:"column:post_date_gmt" db:"post_date_gmt" json:"post_date_gmt" form:"post_date_gmt"`
|
||||
PostContent string `gorm:"column:post_content" db:"post_content" json:"post_content" form:"post_content"`
|
||||
PostTitle string `gorm:"column:post_title" db:"post_title" json:"post_title" form:"post_title"`
|
||||
PostExcerpt string `gorm:"column:post_excerpt" db:"post_excerpt" json:"post_excerpt" form:"post_excerpt"`
|
||||
PostStatus string `gorm:"column:post_status" db:"post_status" json:"post_status" form:"post_status"`
|
||||
CommentStatus string `gorm:"column:comment_status" db:"comment_status" json:"comment_status" form:"comment_status"`
|
||||
PingStatus string `gorm:"column:ping_status" db:"ping_status" json:"ping_status" form:"ping_status"`
|
||||
PostPassword string `gorm:"column:post_password" db:"post_password" json:"post_password" form:"post_password"`
|
||||
PostName string `gorm:"column:post_name" db:"post_name" json:"post_name" form:"post_name"`
|
||||
ToPing string `gorm:"column:to_ping" db:"to_ping" json:"to_ping" form:"to_ping"`
|
||||
Pinged string `gorm:"column:pinged" db:"pinged" json:"pinged" form:"pinged"`
|
||||
PostModified time.Time `gorm:"column:post_modified" db:"post_modified" json:"post_modified" form:"post_modified"`
|
||||
PostModifiedGmt time.Time `gorm:"column:post_modified_gmt" db:"post_modified_gmt" json:"post_modified_gmt" form:"post_modified_gmt"`
|
||||
PostContentFiltered string `gorm:"column:post_content_filtered" db:"post_content_filtered" json:"post_content_filtered" form:"post_content_filtered"`
|
||||
PostParent uint64 `gorm:"column:post_parent" db:"post_parent" json:"post_parent" form:"post_parent"`
|
||||
Guid string `gorm:"column:guid" db:"guid" json:"guid" form:"guid"`
|
||||
MenuOrder int `gorm:"column:menu_order" db:"menu_order" json:"menu_order" form:"menu_order"`
|
||||
PostType string `gorm:"column:post_type" db:"post_type" json:"post_type" form:"post_type"`
|
||||
PostMimeType string `gorm:"column:post_mime_type" db:"post_mime_type" json:"post_mime_type" form:"post_mime_type"`
|
||||
CommentCount int64 `gorm:"column:comment_count" db:"comment_count" json:"comment_count" form:"comment_count"`
|
||||
User *user `table:"wp_users user" foreignKey:"ID" local:"post_author" relation:"hasOne"`
|
||||
PostMeta *[]models.PostMeta `table:"wp_postmeta meta" foreignKey:"post_id" local:"ID" relation:"hasMany"`
|
||||
}
|
||||
|
||||
type user struct {
|
||||
|
@ -362,6 +365,18 @@ func TestFirstOne(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := FirstOne[post](ctx, tt.args.where, tt.args.fields, tt.args.order, tt.args.in...)
|
||||
gott, err := Gets[post](ctx, Conditions(
|
||||
Where(SqlBuilder{{"post_status", "publish"}}),
|
||||
Order([][]string{{"ID", "desc"}}),
|
||||
With("user", WithConditions(
|
||||
Fields("ID,user_login,user_pass"),
|
||||
Where(SqlBuilder{
|
||||
{"user.ID", ">", "0", "int"},
|
||||
}),
|
||||
)),
|
||||
With("meta", nil),
|
||||
))
|
||||
_ = gott
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("FirstOne() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
|
|
@ -26,11 +26,13 @@ func FindFromDB[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r [
|
|||
}
|
||||
|
||||
func finds[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r []T, err error) {
|
||||
sq, args, err := BuildQuerySql[T](q)
|
||||
setTable[T](&q)
|
||||
sq, args, err := BuildQuerySql(q)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.Select(ctx, &r, sq, args...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -179,7 +181,8 @@ func GetFieldFromDB[T Model](db dbQuery, ctx context.Context, field string, q Qu
|
|||
}
|
||||
|
||||
func getToStringMap[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r map[string]string, err error) {
|
||||
rawSql, in, err := BuildQuerySql[T](q)
|
||||
setTable[T](&q)
|
||||
rawSql, in, err := BuildQuerySql(q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -193,7 +196,8 @@ func GetToStringMap[T Model](ctx context.Context, q QueryCondition) (r map[strin
|
|||
}
|
||||
|
||||
func findToStringMap[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r []map[string]string, err error) {
|
||||
rawSql, in, err := BuildQuerySql[T](q)
|
||||
setTable[T](&q)
|
||||
rawSql, in, err := BuildQuerySql(q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -217,7 +221,7 @@ func GetToStringMapFromDB[T Model](db dbQuery, ctx context.Context, q QueryCondi
|
|||
return
|
||||
}
|
||||
|
||||
func BuildQuerySql[T Model](q QueryCondition) (r string, args []any, err error) {
|
||||
func BuildQuerySql(q QueryCondition) (r string, args []any, err error) {
|
||||
w := ""
|
||||
if q.Where != nil {
|
||||
w, args, err = q.Where.ParseWhere(&q.In)
|
||||
|
@ -251,10 +255,7 @@ func BuildQuerySql[T Model](q QueryCondition) (r string, args []any, err error)
|
|||
}
|
||||
tp := "select %s from %s %s %s %s %s %s %s"
|
||||
l := ""
|
||||
table := Table[T]()
|
||||
if q.From != "" {
|
||||
table = q.From
|
||||
}
|
||||
table := q.From
|
||||
if q.Limit > 0 {
|
||||
l = fmt.Sprintf(" limit %d", q.Limit)
|
||||
}
|
||||
|
@ -266,7 +267,8 @@ func BuildQuerySql[T Model](q QueryCondition) (r string, args []any, err error)
|
|||
}
|
||||
|
||||
func findScanner[T Model](db dbQuery, ctx context.Context, fn func(T), q QueryCondition) (err error) {
|
||||
s, args, err := BuildQuerySql[T](q)
|
||||
setTable[T](&q)
|
||||
s, args, err := BuildQuerySql(q)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -295,10 +297,17 @@ func GetsFromDB[T Model](db dbQuery, ctx context.Context, q QueryCondition) (T,
|
|||
}
|
||||
|
||||
func gets[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r T, err error) {
|
||||
s, args, err := BuildQuerySql[T](q)
|
||||
setTable[T](&q)
|
||||
s, args, err := BuildQuerySql(q)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.Get(ctx, &r, s, args...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(q.Relation) > 0 {
|
||||
err = Relation[T](db, ctx, &r, &q)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
81
model/relation.go
Normal file
81
model/relation.go
Normal file
|
@ -0,0 +1,81 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func setTable[T Model](q *QueryCondition) {
|
||||
if q.From == "" {
|
||||
q.From = Table[T]()
|
||||
}
|
||||
}
|
||||
|
||||
func Relation[T Model](db dbQuery, ctx context.Context, r *T, q *QueryCondition) (err error) {
|
||||
var rr T
|
||||
t := reflect.TypeOf(rr)
|
||||
v := reflect.ValueOf(r).Elem()
|
||||
for tableTag, relation := range q.Relation {
|
||||
if tableTag == "" {
|
||||
continue
|
||||
}
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
tag := t.Field(i).Tag
|
||||
table, ok := tag.Lookup("table")
|
||||
if !ok || table == "" {
|
||||
continue
|
||||
}
|
||||
tables := strings.Split(table, " ")
|
||||
if tables[len(tables)-1] != tableTag {
|
||||
continue
|
||||
}
|
||||
if relation == nil {
|
||||
relation = &QueryCondition{
|
||||
Fields: "*",
|
||||
}
|
||||
}
|
||||
relation.From = table
|
||||
id := ""
|
||||
j := 0
|
||||
for ; j < t.NumField(); j++ {
|
||||
vvv, ok := t.Field(j).Tag.Lookup("db")
|
||||
if ok && vvv == tag.Get("local") {
|
||||
id = fmt.Sprintf("%v", v.Field(j).Interface())
|
||||
break
|
||||
}
|
||||
}
|
||||
{
|
||||
var w any = relation.Where
|
||||
if w == nil {
|
||||
w = SqlBuilder{}
|
||||
}
|
||||
ww, ok := w.(SqlBuilder)
|
||||
if ok {
|
||||
ww = append(ww, SqlBuilder{{
|
||||
tag.Get("foreignKey"), "=", id, "int",
|
||||
}}...)
|
||||
relation.Where = ww
|
||||
}
|
||||
}
|
||||
sq, args, er := BuildQuerySql(*relation)
|
||||
if er != nil {
|
||||
err = er
|
||||
return
|
||||
}
|
||||
vv := reflect.New(v.Field(i).Type().Elem()).Interface()
|
||||
switch tag.Get("relation") {
|
||||
case "hasOne":
|
||||
err = db.Get(ctx, vv, sq, args...)
|
||||
case "hasMany":
|
||||
err = db.Select(ctx, vv, sq, args...)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
v.Field(i).Set(reflect.ValueOf(vv))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue
Block a user