From d5a546c01a09484070cd3334d4059915651dd538 Mon Sep 17 00:00:00 2001 From: xing Date: Wed, 24 May 2023 20:41:24 +0800 Subject: [PATCH 1/4] db middle table --- model/parse.go | 1 + model/query_test.go | 1 + model/relation.go | 120 +++++++++++++++++++++++++++++++++-------- model/relation_test.go | 25 ++++++++- 4 files changed, 122 insertions(+), 25 deletions(-) diff --git a/model/parse.go b/model/parse.go index 67ded99..fedf647 100644 --- a/model/parse.go +++ b/model/parse.go @@ -88,6 +88,7 @@ func (w SqlBuilder) ParseWhere(in *[][]any) (string, []any, error) { args = append(args, ss[1]) case 3, 4: w.parseWhereField(ss, &s) + s.WriteString(" ") s.WriteString(ss[1]) if w.parseIn(ss, &s, &c, &args, in) { s.WriteString(" and ") diff --git a/model/query_test.go b/model/query_test.go index ff633a6..f3fcced 100644 --- a/model/query_test.go +++ b/model/query_test.go @@ -39,6 +39,7 @@ type post struct { CommentCount int64 `gorm:"column:comment_count" db:"comment_count" json:"comment_count" form:"comment_count"` User *user PostMeta *[]models.PostMeta + TermTaxonomy *[]models.TermTaxonomy } type TermRelationships struct { diff --git a/model/relation.go b/model/relation.go index cca14dd..c00afff 100644 --- a/model/relation.go +++ b/model/relation.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/fthvgb1/wp-go/helper" "github.com/fthvgb1/wp-go/helper/slice" + str "github.com/fthvgb1/wp-go/helper/strings" "golang.org/x/exp/constraints" "strings" ) @@ -36,25 +37,88 @@ type Relationship struct { ForeignKey string Local 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) { var beforeFn []func() var afterFn []func() error + qx := helper.GetContextVal(ctx, "ancestorsQueryCondition", q) + for _, f := range q.RelationFn { getVal, isJoin, qq, relationship := f() idFn, assignmentFn, rr, rrs, ship := relationship() if isJoin { beforeFn = append(beforeFn, func() { - tables := strings.Split(ship.Table, " ") - 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)}) + parseBeforeJoin(qx, ship) }) } if !getVal { @@ -71,21 +135,27 @@ func Relation(isPlural bool, db dbQuery, ctx context.Context, r any, q *QueryCon 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 } + 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) if err != nil { if err == sql.ErrNoRows { @@ -166,7 +236,9 @@ func SetHasMany[T, V any, K comparable](assignmentFn func(*T, *[]V), pIdFn func( // 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 | constraints.Unsigned]( + 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) { @@ -178,7 +250,9 @@ func RelationHasOne[M, P any, I constraints.Integer | uint64](fId func(*M) I, pI // 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 | constraints.Unsigned]( + 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) { diff --git a/model/relation_test.go b/model/relation_test.go index 618a683..8d11bc7 100644 --- a/model/relation_test.go +++ b/model/relation_test.go @@ -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 { return RelationHasMany(postId, metasPostId, func(m *post, i *[]models.PostMeta) { m.PostMeta = i @@ -93,7 +112,8 @@ func TestGets2(t *testing.T) { ), PostAuthor2()), Fields("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 @@ -106,7 +126,7 @@ func TestGets2(t *testing.T) { { q := Conditions( Where(SqlBuilder{{"posts.id", "in", ""}}), - In([]any{190, 3022}), + In([]any{190, 3022, 291}), WithCtx(&ctx), WithFn(true, false, Conditions( Fields("ID,user_login,user_pass"), @@ -114,6 +134,7 @@ func TestGets2(t *testing.T) { Fields("posts.*"), From("wp_posts posts"), WithFn(true, false, nil, Meta2()), + WithFn(true, false, nil, term), ) got, err := Finds[post](ctx, q) _ = got From 95e3298b7e6d8c263d71f91bae0c591c1cbd5c00 Mon Sep 17 00:00:00 2001 From: xing Date: Wed, 24 May 2023 21:33:30 +0800 Subject: [PATCH 2/4] db middle table --- model/query_test.go | 4 ++- model/relation.go | 11 ++---- model/relation_test.go | 77 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/model/query_test.go b/model/query_test.go index f3fcced..6ce4967 100644 --- a/model/query_test.go +++ b/model/query_test.go @@ -38,14 +38,16 @@ type post struct { 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 + Ships *[]TermRelationships PostMeta *[]models.PostMeta - TermTaxonomy *[]models.TermTaxonomy + TermTaxonomy *[]TermTaxonomy } type TermRelationships struct { ObjectID uint64 `db:"object_id"` TermTaxonomyId uint64 `db:"term_taxonomy_id"` TermOrder int64 `db:"term_order"` + TermTaxonomy *[]TermTaxonomy } type user struct { diff --git a/model/relation.go b/model/relation.go index c00afff..70a8dd6 100644 --- a/model/relation.go +++ b/model/relation.go @@ -44,19 +44,12 @@ 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 - } } + foreignKey = ship.ForeignKey + local = ship.Local tables := strings.Split(ship.Table, " ") from := strings.Split(fromTable, " ") on := "" diff --git a/model/relation_test.go b/model/relation_test.go index 8d11bc7..93d7841 100644 --- a/model/relation_test.go +++ b/model/relation_test.go @@ -5,6 +5,63 @@ import ( "testing" ) +type TermTaxonomy struct { + TermTaxonomyId uint64 `gorm:"column:term_taxonomy_id" db:"term_taxonomy_id" json:"term_taxonomy_id" form:"term_taxonomy_id"` + TermId uint64 `gorm:"column:term_id" db:"term_id" json:"term_id" form:"term_id"` + Taxonomy string `gorm:"column:taxonomy" db:"taxonomy" json:"taxonomy" form:"taxonomy"` + Description string `gorm:"column:description" db:"description" json:"description" form:"description"` + Parent uint64 `gorm:"column:parent" db:"parent" json:"parent" form:"parent"` + Count int64 `gorm:"column:count" db:"count" json:"count" form:"count"` + Term *models.Terms +} + +var termMyHasOneTerm = RelationHasOne(func(m *TermTaxonomy) uint64 { + return m.TermTaxonomyId +}, func(p *models.Terms) uint64 { + return p.TermId +}, func(m *TermTaxonomy, p *models.Terms) { + m.Term = p +}, Relationship{ + RelationType: HasOne, + Table: "wp_terms", + ForeignKey: "term_id", + Local: "term_id", +}) + +var postHasManyShip = RelationHasMany(func(m *post) uint64 { + return m.Id +}, func(p *TermRelationships) uint64 { + return p.ObjectID +}, func(m *post, i *[]TermRelationships) { + m.Ships = i +}, Relationship{ + RelationType: HasMany, + Table: "wp_term_relationships", + ForeignKey: "object_id", + Local: "ID", +}) + +var shipHasManyTermMy = RelationHasMany(func(m *TermRelationships) uint64 { + return m.TermTaxonomyId +}, func(p *TermTaxonomy) uint64 { + return p.TermTaxonomyId +}, func(m *TermRelationships, i *[]TermTaxonomy) { + m.TermTaxonomy = i +}, Relationship{ + RelationType: HasMany, + Table: "wp_term_taxonomy", + ForeignKey: "term_taxonomy_id", + Local: "term_taxonomy_id", +}) + +func (w TermTaxonomy) PrimaryKey() string { + return "term_taxonomy_id" +} + +func (w TermTaxonomy) Table() string { + return "wp_term_taxonomy" +} + func postAuthorId(p *post) uint64 { return p.PostAuthor } @@ -62,9 +119,9 @@ 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 { +}, func(p *TermTaxonomy) uint64 { return p.TermTaxonomyId -}, func(m *post, i *[]models.TermTaxonomy) { +}, func(m *post, i *[]TermTaxonomy) { m.TermTaxonomy = i }, Relationship{ RelationType: HasOne, @@ -112,8 +169,13 @@ func TestGets2(t *testing.T) { ), PostAuthor2()), Fields("posts.*"), From("wp_posts posts"), - WithFn(true, false, nil, Meta2()), - WithFn(true, false, nil, term), + WithFn(true, true, nil, Meta2()), + WithFn(true, false, Conditions( + WithFn(true, false, Conditions( + WithFn(true, false, nil, termMyHasOneTerm), + ), shipHasManyTermMy), + ), postHasManyShip), + //WithFn(true, false, nil, term), ) got, err := Gets[post](ctx, q) _ = got @@ -134,7 +196,12 @@ func TestGets2(t *testing.T) { Fields("posts.*"), From("wp_posts posts"), WithFn(true, false, nil, Meta2()), - WithFn(true, false, nil, term), + WithFn(true, false, Conditions( + WithFn(true, false, Conditions( + WithFn(true, false, nil, termMyHasOneTerm), + ), shipHasManyTermMy), + ), postHasManyShip), + //WithFn(true, false, nil, term), ) got, err := Finds[post](ctx, q) _ = got From 1c33665e34fe1552678f1891fcd816c096c15f04 Mon Sep 17 00:00:00 2001 From: xing Date: Sat, 27 May 2023 14:42:14 +0800 Subject: [PATCH 3/4] query remote relation model --- model/query_test.go | 1 + model/relation.go | 20 ++++++++--------- model/relation_test.go | 51 +++++++++++++++++++++++++++++------------- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/model/query_test.go b/model/query_test.go index 6ce4967..0b14e93 100644 --- a/model/query_test.go +++ b/model/query_test.go @@ -41,6 +41,7 @@ type post struct { Ships *[]TermRelationships PostMeta *[]models.PostMeta TermTaxonomy *[]TermTaxonomy + Terms *[]models.Terms } type TermRelationships struct { diff --git a/model/relation.go b/model/relation.go index 70a8dd6..8823afa 100644 --- a/model/relation.go +++ b/model/relation.go @@ -45,6 +45,7 @@ func parseBeforeJoin(qq *QueryCondition, ship Relationship) { if ship.Middle != nil { parseBeforeJoin(qq, *ship.Middle) local = ship.Local + fromTable = ship.Middle.Table } else { fromTable = qq.From } @@ -64,37 +65,34 @@ func parseBeforeJoin(qq *QueryCondition, ship Relationship) { } -func parseAfterJoin(ids [][]any, qq *QueryCondition, ship Relationship) bool { +func parseAfterJoin(fromTable string, ids [][]any, qq *QueryCondition, ship Relationship) bool { tables := strings.Split(ship.Middle.Table, " ") - from := strings.Split(qq.From, " ") + from := strings.Split(fromTable, " ") 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) + if ship.Middle != nil && ship.Middle.Middle != nil { + return parseAfterJoin(tables[len(tables)-1], ids, qq, *ship.Middle) } else { + from := strings.Split(qq.From, " ") ww, ok := qq.Where.(SqlBuilder) if ok { ww = append(ww, []string{fmt.Sprintf("%s.%s", - tables[len(tables)-1], ship.Middle.Local), "in", ""}, + tables[len(tables)-1], ship.Middle.ForeignKey), "in", ""}, ) qq.Where = ww } if qq.Fields == "" || qq.Fields == "*" { - qq.Fields = str.Join(from[len(from)-1], ".", "*") + qq.Fields = str.Join(from[len(from)-1], ".", "*", ",", tables[len(tables)-1], ".", ship.Middle.ForeignKey) } qq.In = ids return ship.Middle.RelationType == HasMany @@ -139,7 +137,7 @@ func Relation(isPlural bool, db dbQuery, ctx context.Context, r any, q *QueryCon in := [][]any{ids} if ok { if ship.Middle != nil { - isPlural = parseAfterJoin(in, qq, ship) + isPlural = parseAfterJoin(qq.From, in, qq, ship) } else { ww = append(ww, SqlBuilder{{ ship.ForeignKey, "in", "", diff --git a/model/relation_test.go b/model/relation_test.go index 93d7841..d0b9023 100644 --- a/model/relation_test.go +++ b/model/relation_test.go @@ -2,6 +2,7 @@ package model import ( "github.com/fthvgb1/wp-go/app/pkg/models" + "github.com/fthvgb1/wp-go/helper/slice" "testing" ) @@ -117,22 +118,40 @@ func PostMetas() (func(any) []any, func(any, any), any, any, Relationship) { } } -var term = RelationHasMany(func(m *post) uint64 { +var postHaveManyTerms = RelationHasMany(func(m *post) uint64 { return m.Id -}, func(p *TermTaxonomy) uint64 { - return p.TermTaxonomyId -}, func(m *post, i *[]TermTaxonomy) { - m.TermTaxonomy = i +}, func(p *struct { + ObjectId uint64 `db:"object_id"` + models.Terms +}) uint64 { + return p.ObjectId +}, func(m *post, i *[]struct { + ObjectId uint64 `db:"object_id"` + models.Terms +}) { + v := slice.Map(*i, func(t struct { + ObjectId uint64 `db:"object_id"` + models.Terms + }) models.Terms { + return t.Terms + }) + m.Terms = &v }, Relationship{ RelationType: HasOne, - Table: "wp_term_taxonomy taxonomy", - ForeignKey: "term_taxonomy_id", - Local: "term_taxonomy_id", + Table: "wp_terms", + ForeignKey: "term_id", + Local: "term_id", Middle: &Relationship{ - RelationType: HasMany, - Table: "wp_term_relationships", - ForeignKey: "ID", - Local: "object_id", + RelationType: HasOne, + Table: "wp_term_taxonomy taxonomy", + ForeignKey: "term_taxonomy_id", + Local: "term_taxonomy_id", + Middle: &Relationship{ + RelationType: HasMany, + Table: "wp_term_relationships", + ForeignKey: "object_id", + Local: "ID", + }, }, }) @@ -175,7 +194,7 @@ func TestGets2(t *testing.T) { WithFn(true, false, nil, termMyHasOneTerm), ), shipHasManyTermMy), ), postHasManyShip), - //WithFn(true, false, nil, term), + WithFn(true, false, nil, postHaveManyTerms), ) got, err := Gets[post](ctx, q) _ = got @@ -196,12 +215,12 @@ func TestGets2(t *testing.T) { Fields("posts.*"), From("wp_posts posts"), WithFn(true, false, nil, Meta2()), - WithFn(true, false, Conditions( + /*WithFn(true, false, Conditions( WithFn(true, false, Conditions( WithFn(true, false, nil, termMyHasOneTerm), ), shipHasManyTermMy), - ), postHasManyShip), - //WithFn(true, false, nil, term), + ), postHasManyShip),*/ + WithFn(true, false, nil, postHaveManyTerms), ) got, err := Finds[post](ctx, q) _ = got From fe9ac0d126aa1f9e721a123095c7c1453e4a71bf Mon Sep 17 00:00:00 2001 From: xing Date: Mon, 29 May 2023 19:40:11 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/query_test.go | 1 + model/relation_test.go | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/model/query_test.go b/model/query_test.go index 0b14e93..a691c34 100644 --- a/model/query_test.go +++ b/model/query_test.go @@ -42,6 +42,7 @@ type post struct { PostMeta *[]models.PostMeta TermTaxonomy *[]TermTaxonomy Terms *[]models.Terms + CommentMetas *[]CommentMeta } type TermRelationships struct { diff --git a/model/relation_test.go b/model/relation_test.go index d0b9023..dd51587 100644 --- a/model/relation_test.go +++ b/model/relation_test.go @@ -16,6 +16,13 @@ type TermTaxonomy struct { Term *models.Terms } +type CommentMeta struct { + MetaId uint64 `db:"meta_id"` + CommentId uint64 `db:"comment_id"` + MetaKey string `db:"meta_key"` + MetaValue string `db:"meta_value"` +} + var termMyHasOneTerm = RelationHasOne(func(m *TermTaxonomy) uint64 { return m.TermTaxonomyId }, func(p *models.Terms) uint64 { @@ -155,6 +162,34 @@ var postHaveManyTerms = RelationHasMany(func(m *post) uint64 { }, }) +var postHaveManyCommentMetas = func() RelationFn { + type metas struct { + CommentPostID uint64 `db:"comment_post_ID"` + CommentMeta + } + return RelationHasMany(func(m *post) uint64 { + return m.Id + }, func(p *metas) uint64 { + return p.CommentPostID + }, func(m *post, i *[]metas) { + v := slice.Map(*i, func(t metas) CommentMeta { + return t.CommentMeta + }) + m.CommentMetas = &v + }, Relationship{ + RelationType: HasOne, + Table: "wp_commentmeta", + ForeignKey: "comment_id", + Local: "comment_ID", + Middle: &Relationship{ + RelationType: HasMany, + Table: "wp_comments comments", + ForeignKey: "comment_post_ID", + Local: "ID", + }, + }) +}() + func Meta2() RelationFn { return RelationHasMany(postId, metasPostId, func(m *post, i *[]models.PostMeta) { m.PostMeta = i @@ -207,7 +242,7 @@ func TestGets2(t *testing.T) { { q := Conditions( Where(SqlBuilder{{"posts.id", "in", ""}}), - In([]any{190, 3022, 291}), + In([]any{190, 3022, 291, 2858}), WithCtx(&ctx), WithFn(true, false, Conditions( Fields("ID,user_login,user_pass"), @@ -221,6 +256,7 @@ func TestGets2(t *testing.T) { ), shipHasManyTermMy), ), postHasManyShip),*/ WithFn(true, false, nil, postHaveManyTerms), + WithFn(true, false, nil, postHaveManyCommentMetas), ) got, err := Finds[post](ctx, q) _ = got