db middle table
This commit is contained in:
parent
9580678b55
commit
d5a546c01a
@ -88,6 +88,7 @@ func (w SqlBuilder) ParseWhere(in *[][]any) (string, []any, error) {
|
|||||||
args = append(args, ss[1])
|
args = append(args, ss[1])
|
||||||
case 3, 4:
|
case 3, 4:
|
||||||
w.parseWhereField(ss, &s)
|
w.parseWhereField(ss, &s)
|
||||||
|
s.WriteString(" ")
|
||||||
s.WriteString(ss[1])
|
s.WriteString(ss[1])
|
||||||
if w.parseIn(ss, &s, &c, &args, in) {
|
if w.parseIn(ss, &s, &c, &args, in) {
|
||||||
s.WriteString(" and ")
|
s.WriteString(" and ")
|
||||||
|
@ -39,6 +39,7 @@ type post struct {
|
|||||||
CommentCount int64 `gorm:"column:comment_count" db:"comment_count" json:"comment_count" form:"comment_count"`
|
CommentCount int64 `gorm:"column:comment_count" db:"comment_count" json:"comment_count" form:"comment_count"`
|
||||||
User *user
|
User *user
|
||||||
PostMeta *[]models.PostMeta
|
PostMeta *[]models.PostMeta
|
||||||
|
TermTaxonomy *[]models.TermTaxonomy
|
||||||
}
|
}
|
||||||
|
|
||||||
type TermRelationships struct {
|
type TermRelationships struct {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fthvgb1/wp-go/helper"
|
"github.com/fthvgb1/wp-go/helper"
|
||||||
"github.com/fthvgb1/wp-go/helper/slice"
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -36,25 +37,88 @@ type Relationship struct {
|
|||||||
ForeignKey string
|
ForeignKey string
|
||||||
Local string
|
Local string
|
||||||
On string
|
On string
|
||||||
|
Middle *Relationship
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBeforeJoin(qq *QueryCondition, ship Relationship) {
|
||||||
|
var fromTable, foreignKey, local string
|
||||||
|
if ship.Middle != nil {
|
||||||
|
parseBeforeJoin(qq, *ship.Middle)
|
||||||
|
fromTable = ship.Middle.Table
|
||||||
|
foreignKey = ship.ForeignKey
|
||||||
|
local = ship.Local
|
||||||
|
} else {
|
||||||
|
fromTable = qq.From
|
||||||
|
if ship.RelationType == HasMany {
|
||||||
|
foreignKey = ship.Local
|
||||||
|
local = ship.ForeignKey
|
||||||
|
} else {
|
||||||
|
foreignKey = ship.ForeignKey
|
||||||
|
local = ship.Local
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tables := strings.Split(ship.Table, " ")
|
||||||
|
from := strings.Split(fromTable, " ")
|
||||||
|
on := ""
|
||||||
|
if ship.On != "" {
|
||||||
|
on = fmt.Sprintf("and %s", on)
|
||||||
|
}
|
||||||
|
qq.Join = append(qq.Join, []string{
|
||||||
|
"left join", ship.Table,
|
||||||
|
fmt.Sprintf("%s.%s=%s.%s %s",
|
||||||
|
tables[len(tables)-1], foreignKey, from[len(from)-1], local, on,
|
||||||
|
)})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseAfterJoin(ids [][]any, qq *QueryCondition, ship Relationship) bool {
|
||||||
|
tables := strings.Split(ship.Middle.Table, " ")
|
||||||
|
from := strings.Split(qq.From, " ")
|
||||||
|
on := ""
|
||||||
|
if ship.On != "" {
|
||||||
|
on = fmt.Sprintf("and %s", on)
|
||||||
|
}
|
||||||
|
foreignKey := ship.ForeignKey
|
||||||
|
local := ship.Local
|
||||||
|
if ship.RelationType == HasMany {
|
||||||
|
foreignKey = ship.Local
|
||||||
|
local = ship.ForeignKey
|
||||||
|
}
|
||||||
|
qq.Join = append(qq.Join, []string{
|
||||||
|
"left join", ship.Middle.Table,
|
||||||
|
fmt.Sprintf("%s.%s=%s.%s %s",
|
||||||
|
tables[len(tables)-1], foreignKey, from[len(from)-1], local, on,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
if ship.Middle.Middle != nil {
|
||||||
|
return parseAfterJoin(ids, qq, *ship.Middle.Middle)
|
||||||
|
} else {
|
||||||
|
ww, ok := qq.Where.(SqlBuilder)
|
||||||
|
if ok {
|
||||||
|
ww = append(ww, []string{fmt.Sprintf("%s.%s",
|
||||||
|
tables[len(tables)-1], ship.Middle.Local), "in", ""},
|
||||||
|
)
|
||||||
|
qq.Where = ww
|
||||||
|
}
|
||||||
|
if qq.Fields == "" || qq.Fields == "*" {
|
||||||
|
qq.Fields = str.Join(from[len(from)-1], ".", "*")
|
||||||
|
}
|
||||||
|
qq.In = ids
|
||||||
|
return ship.Middle.RelationType == HasMany
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Relation(isPlural bool, db dbQuery, ctx context.Context, r any, q *QueryCondition) ([]func(), []func() error) {
|
func Relation(isPlural bool, db dbQuery, ctx context.Context, r any, q *QueryCondition) ([]func(), []func() error) {
|
||||||
var beforeFn []func()
|
var beforeFn []func()
|
||||||
var afterFn []func() error
|
var afterFn []func() error
|
||||||
|
qx := helper.GetContextVal(ctx, "ancestorsQueryCondition", q)
|
||||||
|
|
||||||
for _, f := range q.RelationFn {
|
for _, f := range q.RelationFn {
|
||||||
getVal, isJoin, qq, relationship := f()
|
getVal, isJoin, qq, relationship := f()
|
||||||
idFn, assignmentFn, rr, rrs, ship := relationship()
|
idFn, assignmentFn, rr, rrs, ship := relationship()
|
||||||
if isJoin {
|
if isJoin {
|
||||||
beforeFn = append(beforeFn, func() {
|
beforeFn = append(beforeFn, func() {
|
||||||
tables := strings.Split(ship.Table, " ")
|
parseBeforeJoin(qx, ship)
|
||||||
from := strings.Split(q.From, " ")
|
|
||||||
on := ""
|
|
||||||
if ship.On != "" {
|
|
||||||
on = fmt.Sprintf("and %s", on)
|
|
||||||
}
|
|
||||||
qq := helper.GetContextVal(ctx, "ancestorsQueryCondition", q)
|
|
||||||
qq.Join = append(qq.Join, []string{
|
|
||||||
"left join", ship.Table, fmt.Sprintf("%s.%s=%s.%s %s", tables[len(tables)-1], ship.ForeignKey, from[len(from)-1], ship.Local, on)})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if !getVal {
|
if !getVal {
|
||||||
@ -71,21 +135,27 @@ func Relation(isPlural bool, db dbQuery, ctx context.Context, r any, q *QueryCon
|
|||||||
Fields: "*",
|
Fields: "*",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var w any = qq.Where
|
|
||||||
if w == nil {
|
|
||||||
w = SqlBuilder{}
|
|
||||||
}
|
|
||||||
ww, ok := w.(SqlBuilder)
|
|
||||||
if ok {
|
|
||||||
ww = append(ww, SqlBuilder{{
|
|
||||||
ship.ForeignKey, "in", "",
|
|
||||||
}}...)
|
|
||||||
qq.In = [][]any{ids}
|
|
||||||
qq.Where = ww
|
|
||||||
}
|
|
||||||
if qq.From == "" {
|
if qq.From == "" {
|
||||||
qq.From = ship.Table
|
qq.From = ship.Table
|
||||||
}
|
}
|
||||||
|
var w any = qq.Where
|
||||||
|
if w == nil {
|
||||||
|
qq.Where = SqlBuilder{}
|
||||||
|
}
|
||||||
|
ww, ok := qq.Where.(SqlBuilder)
|
||||||
|
in := [][]any{ids}
|
||||||
|
if ok {
|
||||||
|
if ship.Middle != nil {
|
||||||
|
isPlural = parseAfterJoin(in, qq, ship)
|
||||||
|
} else {
|
||||||
|
ww = append(ww, SqlBuilder{{
|
||||||
|
ship.ForeignKey, "in", "",
|
||||||
|
}}...)
|
||||||
|
qq.In = in
|
||||||
|
qq.Where = ww
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = ParseRelation(isPlural || ship.RelationType == HasMany, db, ctx, helper.Or(isPlural, rrs, rr), qq)
|
err = ParseRelation(isPlural || ship.RelationType == HasMany, db, ctx, helper.Or(isPlural, rrs, rr), qq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
@ -166,7 +236,9 @@ func SetHasMany[T, V any, K comparable](assignmentFn func(*T, *[]V), pIdFn func(
|
|||||||
|
|
||||||
// RelationHasOne
|
// RelationHasOne
|
||||||
// eg: post has a user. fId is post's userId, pId is user's id
|
// eg: post has a user. fId is post's userId, pId is user's id
|
||||||
func RelationHasOne[M, P any, I constraints.Integer | uint64](fId func(*M) I, pId func(*P) I, setVal func(*M, *P), r Relationship) RelationFn {
|
func RelationHasOne[M, P any, I constraints.Integer | constraints.Unsigned](
|
||||||
|
fId func(*M) I, pId func(*P) I, setVal func(*M, *P), r Relationship) RelationFn {
|
||||||
|
|
||||||
idFn := GetWithID(fId)
|
idFn := GetWithID(fId)
|
||||||
setFn := SetHasOne(setVal, fId, pId)
|
setFn := SetHasOne(setVal, fId, pId)
|
||||||
return func() (func(any) []any, func(any, any), any, any, Relationship) {
|
return func() (func(any) []any, func(any, any), any, any, Relationship) {
|
||||||
@ -178,7 +250,9 @@ func RelationHasOne[M, P any, I constraints.Integer | uint64](fId func(*M) I, pI
|
|||||||
|
|
||||||
// RelationHasMany
|
// RelationHasMany
|
||||||
// eg: post has many comments,mId is comment's postId, pId is post's id
|
// eg: post has many comments,mId is comment's postId, pId is post's id
|
||||||
func RelationHasMany[M, P any, I constraints.Integer | uint64](mId func(*M) I, pId func(*P) I, setVal func(*M, *[]P), r Relationship) RelationFn {
|
func RelationHasMany[M, P any, I constraints.Integer | constraints.Unsigned](
|
||||||
|
mId func(*M) I, pId func(*P) I, setVal func(*M, *[]P), r Relationship) RelationFn {
|
||||||
|
|
||||||
idFn := GetWithID(mId)
|
idFn := GetWithID(mId)
|
||||||
setFn := SetHasMany(setVal, mId, pId)
|
setFn := SetHasMany(setVal, mId, pId)
|
||||||
return func() (func(any) []any, func(any, any), any, any, Relationship) {
|
return func() (func(any) []any, func(any, any), any, any, Relationship) {
|
||||||
|
@ -60,6 +60,25 @@ func PostMetas() (func(any) []any, func(any, any), any, any, Relationship) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var term = RelationHasMany(func(m *post) uint64 {
|
||||||
|
return m.Id
|
||||||
|
}, func(p *models.TermTaxonomy) uint64 {
|
||||||
|
return p.TermTaxonomyId
|
||||||
|
}, func(m *post, i *[]models.TermTaxonomy) {
|
||||||
|
m.TermTaxonomy = i
|
||||||
|
}, Relationship{
|
||||||
|
RelationType: HasOne,
|
||||||
|
Table: "wp_term_taxonomy taxonomy",
|
||||||
|
ForeignKey: "term_taxonomy_id",
|
||||||
|
Local: "term_taxonomy_id",
|
||||||
|
Middle: &Relationship{
|
||||||
|
RelationType: HasMany,
|
||||||
|
Table: "wp_term_relationships",
|
||||||
|
ForeignKey: "ID",
|
||||||
|
Local: "object_id",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
func Meta2() RelationFn {
|
func Meta2() RelationFn {
|
||||||
return RelationHasMany(postId, metasPostId, func(m *post, i *[]models.PostMeta) {
|
return RelationHasMany(postId, metasPostId, func(m *post, i *[]models.PostMeta) {
|
||||||
m.PostMeta = i
|
m.PostMeta = i
|
||||||
@ -93,7 +112,8 @@ func TestGets2(t *testing.T) {
|
|||||||
), PostAuthor2()),
|
), PostAuthor2()),
|
||||||
Fields("posts.*"),
|
Fields("posts.*"),
|
||||||
From("wp_posts posts"),
|
From("wp_posts posts"),
|
||||||
WithFn(true, true, nil, Meta2()),
|
WithFn(true, false, nil, Meta2()),
|
||||||
|
WithFn(true, false, nil, term),
|
||||||
)
|
)
|
||||||
got, err := Gets[post](ctx, q)
|
got, err := Gets[post](ctx, q)
|
||||||
_ = got
|
_ = got
|
||||||
@ -106,7 +126,7 @@ func TestGets2(t *testing.T) {
|
|||||||
{
|
{
|
||||||
q := Conditions(
|
q := Conditions(
|
||||||
Where(SqlBuilder{{"posts.id", "in", ""}}),
|
Where(SqlBuilder{{"posts.id", "in", ""}}),
|
||||||
In([]any{190, 3022}),
|
In([]any{190, 3022, 291}),
|
||||||
WithCtx(&ctx),
|
WithCtx(&ctx),
|
||||||
WithFn(true, false, Conditions(
|
WithFn(true, false, Conditions(
|
||||||
Fields("ID,user_login,user_pass"),
|
Fields("ID,user_login,user_pass"),
|
||||||
@ -114,6 +134,7 @@ func TestGets2(t *testing.T) {
|
|||||||
Fields("posts.*"),
|
Fields("posts.*"),
|
||||||
From("wp_posts posts"),
|
From("wp_posts posts"),
|
||||||
WithFn(true, false, nil, Meta2()),
|
WithFn(true, false, nil, Meta2()),
|
||||||
|
WithFn(true, false, nil, term),
|
||||||
)
|
)
|
||||||
got, err := Finds[post](ctx, q)
|
got, err := Finds[post](ctx, q)
|
||||||
_ = got
|
_ = got
|
||||||
|
Loading…
Reference in New Issue
Block a user