has one/many complete
This commit is contained in:
parent
4242d850ff
commit
c95fd7e5da
|
@ -13,9 +13,11 @@ type QueryCondition struct {
|
|||
Limit int
|
||||
Offset int
|
||||
In [][]any
|
||||
RelationFn []func() (bool, bool, *QueryCondition, func() (func(any) []any, func(any, any) error, any, Relationship))
|
||||
RelationFn []func() (bool, bool, *QueryCondition, RelationFn)
|
||||
}
|
||||
|
||||
type RelationFn func() (func(any) []any, func(any, any), any, any, Relationship)
|
||||
|
||||
func Conditions(fns ...Condition) *QueryCondition {
|
||||
r := &QueryCondition{}
|
||||
for _, fn := range fns {
|
||||
|
@ -94,9 +96,9 @@ func WithCtx(ctx *context.Context) Condition {
|
|||
}
|
||||
}
|
||||
|
||||
func WithFn(getVal, isJoin bool, q *QueryCondition, fn func() (func(any) []any, func(any, any) error, any, Relationship)) Condition {
|
||||
func WithFn(getVal, isJoin bool, q *QueryCondition, fn func() (func(any) []any, func(any, any), any, any, Relationship)) Condition {
|
||||
return func(c *QueryCondition) {
|
||||
c.RelationFn = append(c.RelationFn, func() (bool, bool, *QueryCondition, func() (func(any) []any, func(any, any) error, any, Relationship)) {
|
||||
c.RelationFn = append(c.RelationFn, func() (bool, bool, *QueryCondition, RelationFn) {
|
||||
return getVal, isJoin, q, fn
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package model
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||
"github.com/fthvgb1/wp-go/safety"
|
||||
|
@ -42,49 +41,6 @@ type post struct {
|
|||
PostMeta *[]models.PostMeta
|
||||
}
|
||||
|
||||
func PostAuthor() (func(any) []any, func(posts, users any) error, any, Relationship) {
|
||||
var u user
|
||||
return func(a any) []any {
|
||||
return []any{a.(*post).PostAuthor}
|
||||
}, func(posts, users any) error {
|
||||
u := users.(*user)
|
||||
postss, ok := posts.(*post)
|
||||
if !ok {
|
||||
postsss, ok := posts.(*[]post)
|
||||
if !ok {
|
||||
return errors.New("无法识别post的类型")
|
||||
}
|
||||
for i := 0; i < len(*postsss); i++ {
|
||||
(*postsss)[i].User = u
|
||||
}
|
||||
}
|
||||
postss.User = u
|
||||
return nil
|
||||
|
||||
}, &u, Relationship{
|
||||
RelationType: "hasOne",
|
||||
Table: "wp_users user",
|
||||
ForeignKey: "ID",
|
||||
Local: "post_author",
|
||||
}
|
||||
}
|
||||
func PostMetas() (func(any) []any, func(posts, users any) error, any, Relationship) {
|
||||
var u []models.PostMeta
|
||||
return func(a any) []any {
|
||||
return []any{a.(*post).Id}
|
||||
}, func(posts, meta any) error {
|
||||
postss := posts.(*post)
|
||||
u := meta.(*[]models.PostMeta)
|
||||
postss.PostMeta = u
|
||||
return nil
|
||||
}, &u, Relationship{
|
||||
RelationType: "hasMany",
|
||||
Table: "wp_postmeta meta",
|
||||
ForeignKey: "post_id",
|
||||
Local: "ID",
|
||||
}
|
||||
}
|
||||
|
||||
type TermRelationships struct {
|
||||
ObjectID uint64 `db:"object_id"`
|
||||
TermTaxonomyId uint64 `db:"term_taxonomy_id"`
|
||||
|
@ -379,48 +335,6 @@ func TestFindOneById(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGets2(t *testing.T) {
|
||||
t.Run("hasOne", func(t *testing.T) {
|
||||
{
|
||||
q := Conditions(
|
||||
Where(SqlBuilder{{"posts.id = 190"}}),
|
||||
WithCtx(&ctx),
|
||||
WithFn(true, true, Conditions(
|
||||
Fields("ID,user_login,user_pass"),
|
||||
), PostAuthor),
|
||||
Fields("posts.*"),
|
||||
From("wp_posts posts"),
|
||||
WithFn(false, true, nil, PostMetas),
|
||||
)
|
||||
got, err := Gets[post](ctx, q)
|
||||
_ = got
|
||||
if err != nil {
|
||||
t.Errorf("err:%v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("hasOne", func(t *testing.T) {
|
||||
{
|
||||
q := Conditions(
|
||||
Where(SqlBuilder{{"posts.id", "in", ""}}),
|
||||
In([]any{190, 2978}),
|
||||
WithCtx(&ctx),
|
||||
WithFn(true, true, Conditions(
|
||||
Fields("ID,user_login,user_pass"),
|
||||
), PostAuthor),
|
||||
Fields("posts.*"),
|
||||
From("wp_posts posts"),
|
||||
WithFn(false, false, nil, PostMetas),
|
||||
)
|
||||
got, err := Finds[post](ctx, q)
|
||||
_ = got
|
||||
if err != nil {
|
||||
t.Errorf("err:%v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestFirstOne(t *testing.T) {
|
||||
type args struct {
|
||||
where ParseWhere
|
||||
|
|
|
@ -322,7 +322,7 @@ func gets[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r T, err
|
|||
}
|
||||
|
||||
func parseRelation(isMultiple bool, db dbQuery, ctx context.Context, r any, q *QueryCondition) (err error) {
|
||||
fn, fns := Relation(db, ctx, r, q)
|
||||
fn, fns := Relation(isMultiple, db, ctx, r, q)
|
||||
for _, f := range fn {
|
||||
f()
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/fthvgb1/wp-go/helper"
|
||||
"github.com/fthvgb1/wp-go/helper/slice"
|
||||
"golang.org/x/exp/constraints"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -22,12 +24,12 @@ type Relationship struct {
|
|||
On string
|
||||
}
|
||||
|
||||
func Relation(db dbQuery, ctx context.Context, r any, q *QueryCondition) ([]func(), []func() error) {
|
||||
func Relation(isMultiple bool, db dbQuery, ctx context.Context, r any, q *QueryCondition) ([]func(), []func() error) {
|
||||
var fn []func()
|
||||
var fns []func() error
|
||||
for _, f := range q.RelationFn {
|
||||
getVal, isJoin, qq, ff := f()
|
||||
idFn, assignment, rr, ship := ff()
|
||||
idFn, assignment, rr, rrs, ship := ff()
|
||||
if isJoin {
|
||||
fn = append(fn, func() {
|
||||
tables := strings.Split(ship.Table, " ")
|
||||
|
@ -45,6 +47,10 @@ func Relation(db dbQuery, ctx context.Context, r any, q *QueryCondition) ([]func
|
|||
continue
|
||||
}
|
||||
fns = append(fns, func() error {
|
||||
ids := idFn(r)
|
||||
if len(ids) < 1 {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
{
|
||||
if qq == nil {
|
||||
|
@ -61,26 +67,93 @@ func Relation(db dbQuery, ctx context.Context, r any, q *QueryCondition) ([]func
|
|||
ww = append(ww, SqlBuilder{{
|
||||
ship.ForeignKey, "in", "",
|
||||
}}...)
|
||||
qq.In = [][]any{idFn(r)}
|
||||
qq.In = [][]any{ids}
|
||||
qq.Where = ww
|
||||
}
|
||||
if qq.From == "" {
|
||||
qq.From = ship.Table
|
||||
}
|
||||
}
|
||||
// todo finds的情况
|
||||
switch ship.RelationType {
|
||||
case "hasOne":
|
||||
err = parseRelation(false, db, ctx, rr, qq)
|
||||
case "hasMany":
|
||||
err = parseRelation(true, db, ctx, rr, qq)
|
||||
}
|
||||
err = parseRelation(isMultiple || ship.RelationType == "hasMany", db, ctx, helper.Or(isMultiple, rrs, rr), qq)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
err = assignment(r, rr)
|
||||
assignment(r, helper.Or(isMultiple, rrs, rr))
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
return fn, fns
|
||||
}
|
||||
|
||||
func GetWithID[T, V any](fn func(*T) V) func(any) []any {
|
||||
return func(a any) []any {
|
||||
one, ok := a.(*T)
|
||||
if ok {
|
||||
return []any{fn(one)}
|
||||
}
|
||||
return slice.ToAnySlice(slice.Unique(slice.Map(*a.(*[]T), func(t T) any {
|
||||
return fn(&t)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
func SetHasOne[T, V any, K comparable](fn func(*T, *V), idFn func(*T) K, iddFn func(*V) K) func(any, any) {
|
||||
return func(m, v any) {
|
||||
one, ok := m.(*T)
|
||||
if ok {
|
||||
fn(one, v.(*V))
|
||||
return
|
||||
}
|
||||
r := m.(*[]T)
|
||||
vv := v.(*[]V)
|
||||
mm := slice.SimpleToMap(*vv, func(v V) K {
|
||||
return iddFn(&v)
|
||||
})
|
||||
for i := 0; i < len(*r); i++ {
|
||||
val := &(*r)[i]
|
||||
id := idFn(val)
|
||||
v, ok := mm[id]
|
||||
if ok {
|
||||
fn(val, &v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetHasMany[T, V any, K comparable](fn func(*T, *[]V), idFn func(*T) K, iddFn func(*V) K) func(any, any) {
|
||||
return func(m, v any) {
|
||||
one, ok := m.(*T)
|
||||
if ok {
|
||||
fn(one, v.(*[]V))
|
||||
return
|
||||
}
|
||||
r := m.(*[]T)
|
||||
vv := v.(*[]V)
|
||||
mm := slice.GroupBy(*vv, func(t V) (K, V) {
|
||||
return iddFn(&t), t
|
||||
})
|
||||
for i := 0; i < len(*r); i++ {
|
||||
val := &(*r)[i]
|
||||
id := idFn(val)
|
||||
v, ok := mm[id]
|
||||
if ok {
|
||||
fn(val, &v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RelationHasOne[M, P any, I constraints.Integer | uint64](fId func(*M) I, pId func(*P) I, setVal func(*M, *P), r Relationship) RelationFn {
|
||||
return func() (func(any) []any, func(any, any), any, any, Relationship) {
|
||||
var s P
|
||||
var ss []P
|
||||
return GetWithID(fId), SetHasOne(setVal, fId, pId), &s, &ss, r
|
||||
}
|
||||
}
|
||||
func RelationHasMany[M, P any, I constraints.Integer | uint64](mId func(*M) I, pId func(*P) I, setVal func(*M, *[]P), r Relationship) RelationFn {
|
||||
return func() (func(any) []any, func(any, any), any, any, Relationship) {
|
||||
var ss []P
|
||||
return GetWithID(mId), SetHasMany(setVal, mId, pId), &ss, &ss, r
|
||||
}
|
||||
}
|
||||
|
|
128
model/relation_test.go
Normal file
128
model/relation_test.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/fthvgb1/wp-go/app/pkg/models"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func postAuthorId(p *post) uint64 {
|
||||
return p.PostAuthor
|
||||
}
|
||||
|
||||
func postId(p *post) uint64 {
|
||||
return p.Id
|
||||
}
|
||||
|
||||
func userId(u *user) uint64 {
|
||||
return u.Id
|
||||
}
|
||||
|
||||
func metaId(m *models.PostMeta) uint64 {
|
||||
return m.MetaId
|
||||
}
|
||||
func metasPostId(m *models.PostMeta) uint64 {
|
||||
return m.PostId
|
||||
}
|
||||
|
||||
func PostAuthor() (func(any) []any, func(any, any), any, any, Relationship) {
|
||||
var u user
|
||||
var uu []user
|
||||
return GetWithID[post](func(t *post) uint64 {
|
||||
return t.PostAuthor
|
||||
}),
|
||||
SetHasOne(func(p *post, u *user) {
|
||||
p.User = u
|
||||
}, func(t *post) uint64 {
|
||||
return t.PostAuthor
|
||||
}, func(u *user) uint64 {
|
||||
return u.Id
|
||||
}),
|
||||
&u, &uu,
|
||||
Relationship{
|
||||
RelationType: "hasOne",
|
||||
Table: "wp_users user",
|
||||
ForeignKey: "ID",
|
||||
Local: "post_author",
|
||||
}
|
||||
}
|
||||
func PostMetas() (func(any) []any, func(any, any), any, any, Relationship) {
|
||||
var u []models.PostMeta
|
||||
return GetWithID(func(t *post) any {
|
||||
return t.Id
|
||||
}), SetHasMany(func(t *post, v *[]models.PostMeta) {
|
||||
t.PostMeta = v
|
||||
}, func(t *post) uint64 {
|
||||
return t.Id
|
||||
}, func(m *models.PostMeta) uint64 {
|
||||
return m.PostId
|
||||
}), &u, &u, Relationship{
|
||||
RelationType: "hasMany",
|
||||
Table: "wp_postmeta meta",
|
||||
ForeignKey: "post_id",
|
||||
Local: "ID",
|
||||
}
|
||||
}
|
||||
|
||||
func Meta2() RelationFn {
|
||||
return RelationHasMany(postId, metasPostId, func(m *post, i *[]models.PostMeta) {
|
||||
m.PostMeta = i
|
||||
}, Relationship{
|
||||
RelationType: "hasMany",
|
||||
Table: "wp_postmeta meta",
|
||||
ForeignKey: "post_id",
|
||||
Local: "ID",
|
||||
})
|
||||
}
|
||||
|
||||
func PostAuthor2() RelationFn {
|
||||
return RelationHasOne[post, user](postAuthorId, userId, func(p *post, u *user) {
|
||||
p.User = u
|
||||
}, Relationship{
|
||||
RelationType: "hasOne",
|
||||
Table: "wp_users user",
|
||||
ForeignKey: "ID",
|
||||
Local: "post_author",
|
||||
})
|
||||
}
|
||||
|
||||
func TestGets2(t *testing.T) {
|
||||
t.Run("one", func(t *testing.T) {
|
||||
{
|
||||
q := Conditions(
|
||||
Where(SqlBuilder{{"posts.id = 190"}}),
|
||||
WithCtx(&ctx),
|
||||
WithFn(true, true, Conditions(
|
||||
Fields("ID,user_login,user_pass"),
|
||||
), PostAuthor2()),
|
||||
Fields("posts.*"),
|
||||
From("wp_posts posts"),
|
||||
WithFn(true, true, nil, Meta2()),
|
||||
)
|
||||
got, err := Gets[post](ctx, q)
|
||||
_ = got
|
||||
if err != nil {
|
||||
t.Errorf("err:%v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("many", func(t *testing.T) {
|
||||
{
|
||||
q := Conditions(
|
||||
Where(SqlBuilder{{"posts.id", "in", ""}}),
|
||||
In([]any{190, 3022}),
|
||||
WithCtx(&ctx),
|
||||
WithFn(true, false, Conditions(
|
||||
Fields("ID,user_login,user_pass"),
|
||||
), PostAuthor2()),
|
||||
Fields("posts.*"),
|
||||
From("wp_posts posts"),
|
||||
WithFn(true, false, nil, Meta2()),
|
||||
)
|
||||
got, err := Finds[post](ctx, q)
|
||||
_ = got
|
||||
if err != nil {
|
||||
t.Errorf("err:%v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user