Compare commits

...

2 Commits

Author SHA1 Message Date
0827cdc551 优化完善 加注释 2023-05-21 21:30:00 +08:00
7c50f2b1a1 优化完善 2023-05-21 19:53:37 +08:00
9 changed files with 139 additions and 77 deletions

View File

@ -34,7 +34,7 @@ func PostComments(args ...any) ([]uint64, error) {
r, err := model.Finds[models.Comments](ctx, model.Conditions( r, err := model.Finds[models.Comments](ctx, model.Conditions(
model.Where(model.SqlBuilder{ model.Where(model.SqlBuilder{
{"comment_approved", "1"}, {"comment_approved", "1"},
{"comment_post_ID", "=", number.ToString(postId), "int"}, {"comment_post_ID", "=", number.IntToString(postId), "int"},
}), }),
model.Fields("comment_ID"), model.Fields("comment_ID"),
model.Order(model.SqlBuilder{ model.Order(model.SqlBuilder{

View File

@ -5,7 +5,9 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
"github.com/fthvgb1/wp-go/app/pkg/models" "github.com/fthvgb1/wp-go/app/pkg/models"
"github.com/fthvgb1/wp-go/app/pkg/models/relation"
"github.com/fthvgb1/wp-go/app/wpconfig" "github.com/fthvgb1/wp-go/app/wpconfig"
"github.com/fthvgb1/wp-go/helper"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice"
"github.com/fthvgb1/wp-go/model" "github.com/fthvgb1/wp-go/model"
"strings" "strings"
@ -17,7 +19,7 @@ func GetPostsByIds(a ...any) (m map[uint64]models.Posts, err error) {
ctx := a[0].(context.Context) ctx := a[0].(context.Context)
m = make(map[uint64]models.Posts) m = make(map[uint64]models.Posts)
ids := a[1].([]uint64) ids := a[1].([]uint64)
rawPosts, err := model.Finds[models.Posts](ctx, model.Conditions( q := model.Conditions(
model.Where(model.SqlBuilder{{"Id", "in", ""}}), model.Where(model.SqlBuilder{{"Id", "in", ""}}),
model.Join(model.SqlBuilder{ model.Join(model.SqlBuilder{
{"a", "left join", "wp_term_relationships b", "a.Id=b.object_id"}, {"a", "left join", "wp_term_relationships b", "a.Id=b.object_id"},
@ -26,7 +28,11 @@ func GetPostsByIds(a ...any) (m map[uint64]models.Posts, err error) {
}), }),
model.Fields("a.*,ifnull(d.name,'') category_name,ifnull(c.term_id,0) terms_id,ifnull(taxonomy,'') `taxonomy`"), model.Fields("a.*,ifnull(d.name,'') category_name,ifnull(c.term_id,0) terms_id,ifnull(taxonomy,'') `taxonomy`"),
model.In(slice.ToAnySlice(ids)), model.In(slice.ToAnySlice(ids)),
)) )
if helper.GetContextVal(ctx, "getPostAuthor", false) {
q.RelationFn = append(q.RelationFn, model.AddRelationFn(true, false, helper.GetContextVal[*model.QueryCondition](ctx, "postAuthorQueryCondition", nil), relation.PostsWithAuthor))
}
rawPosts, err := model.Finds[models.Posts](ctx, q)
if err != nil { if err != nil {
return m, err return m, err

View File

@ -0,0 +1,23 @@
package relation
import (
"github.com/fthvgb1/wp-go/app/pkg/models"
"github.com/fthvgb1/wp-go/model"
)
var hasUser = model.RelationHasOne(func(m *models.Posts) uint64 {
return m.PostAuthor
}, func(p *models.Users) uint64 {
return p.Id
}, func(m *models.Posts, p *models.Users) {
m.Author = p
}, model.Relationship{
RelationType: model.HasOne,
Table: "wp_users user",
ForeignKey: "ID",
Local: "post_author",
})
func PostsWithAuthor() (func(any) []any, func(any, any), any, any, model.Relationship) {
return hasUser()
}

View File

@ -40,6 +40,7 @@ type Posts struct {
IsSticky bool IsSticky bool
Thumbnail PostThumbnail Thumbnail PostThumbnail
AttachmentMetadata WpAttachmentMetadata AttachmentMetadata WpAttachmentMetadata
Author *Users
} }
type PostThumbnail struct { type PostThumbnail struct {

View File

@ -50,20 +50,20 @@ func (h *Handle) BodyClass() string {
if cate.Slug[0] != '%' { if cate.Slug[0] != '%' {
class = append(class, str.Join("category-", cate.Slug)) class = append(class, str.Join("category-", cate.Slug))
} }
class = append(class, str.Join("category-", number.ToString(cate.Terms.TermId))) class = append(class, str.Join("category-", number.IntToString(cate.Terms.TermId)))
case constraints.Author: case constraints.Author:
class = append(class, "archive", "author") class = append(class, "archive", "author")
author := h.Index.Param.Author author := h.Index.Param.Author
user, _ := cache.GetUserByName(h.C, author) user, _ := cache.GetUserByName(h.C, author)
class = append(class, str.Join("author-", number.ToString(user.Id))) class = append(class, str.Join("author-", number.IntToString(user.Id)))
if user.UserLogin[0] != '%' { if user.UserLogin[0] != '%' {
class = append(class, str.Join("author-", user.UserLogin)) class = append(class, str.Join("author-", user.UserLogin))
} }
case constraints.Detail: case constraints.Detail:
class = append(class, "post-template-default", "single", "single-post") class = append(class, "post-template-default", "single", "single-post")
class = append(class, str.Join("postid-", number.ToString(h.Detail.Post.Id))) class = append(class, str.Join("postid-", number.IntToString(h.Detail.Post.Id)))
if len(h.themeMods.ThemeSupport.PostFormats) > 0 { if len(h.themeMods.ThemeSupport.PostFormats) > 0 {
class = append(class, "single-format-standard") class = append(class, "single-format-standard")
} }

View File

@ -48,7 +48,7 @@ func pagination[T Model](db dbQuery, ctx context.Context, q *QueryCondition, pag
err = er err = er
return return
} }
qx.From = str.Join("( ", sq, " ) ", "table", number.ToString(rand.Int())) qx.From = str.Join("( ", sq, " ) ", "table", number.IntToString(rand.Int()))
qx = QueryCondition{ qx = QueryCondition{
From: qx.From, From: qx.From,
In: qx.In, In: qx.In,

View File

@ -36,7 +36,7 @@ func finds[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []T,
err = db.Select(ctx, &r, sq, args...) err = db.Select(ctx, &r, sq, args...)
return return
} }
err = parseRelation(true, db, ctx, &r, q) err = ParseRelation(true, db, ctx, &r, q)
return return
} }
@ -317,14 +317,14 @@ func gets[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r T, err
err = db.Get(ctx, &r, s, args...) err = db.Get(ctx, &r, s, args...)
return return
} }
err = parseRelation(false, db, ctx, &r, q) err = ParseRelation(false, db, ctx, &r, q)
return return
} }
func parseRelation(isMultiple bool, db dbQuery, ctx context.Context, r any, q *QueryCondition) (err error) { func ParseRelation(isMultiple bool, db dbQuery, ctx context.Context, r any, q *QueryCondition) (err error) {
fn, fns := Relation(isMultiple, db, ctx, r, q) before, after := Relation(isMultiple, db, ctx, r, q)
for _, f := range fn { for _, fn := range before {
f() fn()
} }
s, args, err := BuildQuerySql(q) s, args, err := BuildQuerySql(q)
if err != nil { if err != nil {
@ -339,8 +339,8 @@ func parseRelation(isMultiple bool, db dbQuery, ctx context.Context, r any, q *Q
if err != nil { if err != nil {
return return
} }
for _, f := range fns { for _, fn := range after {
err = f() err = fn()
if err != nil { if err != nil {
return return
} }

View File

@ -16,6 +16,20 @@ func setTable[T Model](q *QueryCondition) {
} }
} }
const (
HasOne = "hasOne"
HasMany = "hasMany"
)
// Relationship join table
//
// # RelationType HasOne| HasMany
//
// eg: hasOne, post has a user. ForeignKey is user's id , Local is post's userId field
//
// eg: hasMany, post has many comments,ForeignKey is comment's postId field, Local is post's id field
//
// On is additional join on conditions
type Relationship struct { type Relationship struct {
RelationType string RelationType string
Table string Table string
@ -24,14 +38,14 @@ type Relationship struct {
On string On string
} }
func Relation(isMultiple 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 fn []func() var beforeFn []func()
var fns []func() error var afterFn []func() error
for _, f := range q.RelationFn { for _, f := range q.RelationFn {
getVal, isJoin, qq, ff := f() getVal, isJoin, qq, relationship := f()
idFn, assignment, rr, rrs, ship := ff() idFn, assignmentFn, rr, rrs, ship := relationship()
if isJoin { if isJoin {
fn = append(fn, func() { beforeFn = append(beforeFn, func() {
tables := strings.Split(ship.Table, " ") tables := strings.Split(ship.Table, " ")
from := strings.Split(q.From, " ") from := strings.Split(q.From, " ")
on := "" on := ""
@ -46,44 +60,45 @@ func Relation(isMultiple bool, db dbQuery, ctx context.Context, r any, q *QueryC
if !getVal { if !getVal {
continue continue
} }
fns = append(fns, func() error { afterFn = append(afterFn, func() error {
ids := idFn(r) ids := idFn(r)
if len(ids) < 1 { if len(ids) < 1 {
return nil return nil
} }
var err error var err error
{ if qq == nil {
if qq == nil { qq = &QueryCondition{
qq = &QueryCondition{ 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 == "" {
qq.From = ship.Table
} }
} }
err = parseRelation(isMultiple || ship.RelationType == "hasMany", db, ctx, helper.Or(isMultiple, rrs, rr), qq) var w any = qq.Where
if err != nil && err != sql.ErrNoRows { if w == nil {
return err w = SqlBuilder{}
} }
assignment(r, helper.Or(isMultiple, rrs, rr)) ww, ok := w.(SqlBuilder)
if ok {
ww = append(ww, SqlBuilder{{
ship.ForeignKey, "in", "",
}}...)
qq.In = [][]any{ids}
qq.Where = ww
}
if qq.From == "" {
qq.From = ship.Table
}
err = ParseRelation(isPlural || ship.RelationType == HasMany, db, ctx, helper.Or(isPlural, rrs, rr), qq)
if err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
return err
}
}
assignmentFn(r, helper.Or(isPlural, rrs, rr))
return err return err
}) })
} }
return fn, fns return beforeFn, afterFn
} }
func GetWithID[T, V any](fn func(*T) V) func(any) []any { func GetWithID[T, V any](fn func(*T) V) func(any) []any {
@ -98,62 +113,82 @@ func GetWithID[T, V any](fn func(*T) V) func(any) []any {
} }
} }
func SetHasOne[T, V any, K comparable](fn func(*T, *V), idFn func(*T) K, iddFn func(*V) K) func(any, any) { // SetHasOne mIdFn is main , pIdFn is part
return func(m, v any) { //
// eg: post has a user. mIdFn is post's userId, iddFn is user's id
func SetHasOne[T, V any, K comparable](assignmentFn func(*T, *V), mIdFn func(*T) K, pIdFn func(*V) K) func(any, any) {
return func(m, p any) {
one, ok := m.(*T) one, ok := m.(*T)
if ok { if ok {
fn(one, v.(*V)) assignmentFn(one, p.(*V))
return return
} }
r := m.(*[]T) mSlice := m.(*[]T)
vv := v.(*[]V) pSLice := p.(*[]V)
mm := slice.SimpleToMap(*vv, func(v V) K { mm := slice.SimpleToMap(*pSLice, func(v V) K {
return iddFn(&v) return pIdFn(&v)
}) })
for i := 0; i < len(*r); i++ { for i := 0; i < len(*mSlice); i++ {
val := &(*r)[i] m := &(*mSlice)[i]
id := idFn(val) id := mIdFn(m)
v, ok := mm[id] p, ok := mm[id]
if ok { if ok {
fn(val, &v) assignmentFn(m, &p)
} }
} }
} }
} }
func SetHasMany[T, V any, K comparable](fn func(*T, *[]V), idFn func(*T) K, iddFn func(*V) K) func(any, any) { // SetHasMany
return func(m, v any) { // eg: post has many comments,pIdFn is comment's postId, mIdFn is post's id
func SetHasMany[T, V any, K comparable](assignmentFn func(*T, *[]V), pIdFn func(*T) K, mIdFn func(*V) K) func(any, any) {
return func(m, p any) {
one, ok := m.(*T) one, ok := m.(*T)
if ok { if ok {
fn(one, v.(*[]V)) assignmentFn(one, p.(*[]V))
return return
} }
r := m.(*[]T) r := m.(*[]T)
vv := v.(*[]V) vv := p.(*[]V)
mm := slice.GroupBy(*vv, func(t V) (K, V) { mm := slice.GroupBy(*vv, func(t V) (K, V) {
return iddFn(&t), t return mIdFn(&t), t
}) })
for i := 0; i < len(*r); i++ { for i := 0; i < len(*r); i++ {
val := &(*r)[i] m := &(*r)[i]
id := idFn(val) id := pIdFn(m)
v, ok := mm[id] p, ok := mm[id]
if ok { if ok {
fn(val, &v) assignmentFn(m, &p)
} }
} }
} }
} }
// RelationHasOne
// 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 | uint64](fId func(*M) I, pId func(*P) I, setVal func(*M, *P), r Relationship) RelationFn {
idFn := GetWithID(fId)
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) {
var s P var s P
var ss []P var ss []P
return GetWithID(fId), SetHasOne(setVal, fId, pId), &s, &ss, r return idFn, setFn, &s, &ss, r
} }
} }
// RelationHasMany
// 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 | uint64](mId func(*M) I, pId func(*P) I, setVal func(*M, *[]P), r Relationship) RelationFn {
idFn := GetWithID(mId)
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) {
var ss []P var ss []P
return GetWithID(mId), SetHasMany(setVal, mId, pId), &ss, &ss, r return idFn, setFn, &ss, &ss, r
}
}
func AddRelationFn(getVal, join bool, q *QueryCondition, r RelationFn) func() (bool, bool, *QueryCondition, RelationFn) {
return func() (bool, bool, *QueryCondition, RelationFn) {
return getVal, join, q, r
} }
} }

View File

@ -17,9 +17,6 @@ func userId(u *user) uint64 {
return u.Id return u.Id
} }
func metaId(m *models.PostMeta) uint64 {
return m.MetaId
}
func metasPostId(m *models.PostMeta) uint64 { func metasPostId(m *models.PostMeta) uint64 {
return m.PostId return m.PostId
} }
@ -39,7 +36,7 @@ func PostAuthor() (func(any) []any, func(any, any), any, any, Relationship) {
}), }),
&u, &uu, &u, &uu,
Relationship{ Relationship{
RelationType: "hasOne", RelationType: HasOne,
Table: "wp_users user", Table: "wp_users user",
ForeignKey: "ID", ForeignKey: "ID",
Local: "post_author", Local: "post_author",
@ -56,7 +53,7 @@ func PostMetas() (func(any) []any, func(any, any), any, any, Relationship) {
}, func(m *models.PostMeta) uint64 { }, func(m *models.PostMeta) uint64 {
return m.PostId return m.PostId
}), &u, &u, Relationship{ }), &u, &u, Relationship{
RelationType: "hasMany", RelationType: HasMany,
Table: "wp_postmeta meta", Table: "wp_postmeta meta",
ForeignKey: "post_id", ForeignKey: "post_id",
Local: "ID", Local: "ID",
@ -75,7 +72,7 @@ func Meta2() RelationFn {
} }
func PostAuthor2() RelationFn { func PostAuthor2() RelationFn {
return RelationHasOne[post, user](postAuthorId, userId, func(p *post, u *user) { return RelationHasOne(postAuthorId, userId, func(p *post, u *user) {
p.User = u p.User = u
}, Relationship{ }, Relationship{
RelationType: "hasOne", RelationType: "hasOne",