wp-go/model/querycondition.go

350 lines
9.0 KiB
Go
Raw Normal View History

package model
import (
"context"
"database/sql"
"errors"
"fmt"
2023-02-06 10:34:35 +00:00
"github.com/fthvgb1/wp-go/helper/slice"
"strings"
)
2023-02-02 05:19:43 +00:00
// Finds 比 Find 多一个offset
//
// Conditions 中可用 Where Fields Group Having Join Order Offset Limit In 函数
2023-05-18 14:27:28 +00:00
func Finds[T Model](ctx context.Context, q *QueryCondition) (r []T, err error) {
2023-02-06 09:58:24 +00:00
r, err = finds[T](globalBb, ctx, q)
return
}
2023-02-07 15:05:31 +00:00
// FindFromDB 同 Finds 使用指定 db 查询
2023-02-06 09:58:24 +00:00
//
// Conditions 中可用 Where Fields Group Having Join Order Offset Limit In 函数
2023-05-18 14:27:28 +00:00
func FindFromDB[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []T, err error) {
2023-02-06 09:58:24 +00:00
r, err = finds[T](db, ctx, q)
return
}
2023-05-18 14:27:28 +00:00
func finds[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []T, err error) {
setTable[T](q)
2023-05-19 15:14:58 +00:00
if len(q.RelationFn) < 1 {
sq, args, er := BuildQuerySql(q)
if err != nil {
err = er
return
}
err = db.Select(ctx, &r, sq, args...)
return
}
2023-05-21 11:53:37 +00:00
err = ParseRelation(true, db, ctx, &r, q)
return
}
2023-05-18 14:27:28 +00:00
func chunkFind[T Model](db dbQuery, ctx context.Context, perLimit int, q *QueryCondition) (r []T, err error) {
i := 1
var rr []T
var total int
var offset int
for {
if 1 == i {
2023-02-27 13:34:48 +00:00
rr, total, err = pagination[T](db, ctx, q, 1, perLimit)
} else {
2023-02-25 15:10:42 +00:00
q.Offset = offset
q.Limit = perLimit
2023-02-06 09:58:24 +00:00
rr, err = finds[T](db, ctx, q)
}
offset += perLimit
2023-11-16 14:52:14 +00:00
if (err != nil && !errors.Is(err, sql.ErrNoRows)) || len(rr) < 1 {
return
}
r = append(r, rr...)
if len(r) >= total {
break
}
i++
}
return
}
2023-02-06 09:58:24 +00:00
// ChunkFind 分片查询并直接返回所有结果
//
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
2023-05-18 14:27:28 +00:00
func ChunkFind[T Model](ctx context.Context, perLimit int, q *QueryCondition) (r []T, err error) {
2023-02-06 09:58:24 +00:00
r, err = chunkFind[T](globalBb, ctx, perLimit, q)
return
}
2023-02-07 15:05:31 +00:00
// ChunkFindFromDB 同 ChunkFind
2023-02-06 09:58:24 +00:00
//
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
2023-05-18 14:27:28 +00:00
func ChunkFindFromDB[T Model](db dbQuery, ctx context.Context, perLimit int, q *QueryCondition) (r []T, err error) {
2023-02-06 09:58:24 +00:00
r, err = chunkFind[T](db, ctx, perLimit, q)
return
}
// Chunk 分片查询并函数过虑返回新类型的切片
//
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
2023-05-18 14:27:28 +00:00
func Chunk[T Model, R any](ctx context.Context, perLimit int, fn func(rows T) (R, bool), q *QueryCondition) (r []R, err error) {
2023-02-06 09:58:24 +00:00
r, err = chunk(globalBb, ctx, perLimit, fn, q)
return
}
2023-02-07 15:05:31 +00:00
// ChunkFromDB 同 Chunk
2023-02-06 09:58:24 +00:00
//
// Conditions 中可用 Where Fields Group Having Join Order Limit In 函数
2023-05-18 14:27:28 +00:00
func ChunkFromDB[T Model, R any](db dbQuery, ctx context.Context, perLimit int, fn func(rows T) (R, bool), q *QueryCondition) (r []R, err error) {
2023-02-06 09:58:24 +00:00
r, err = chunk(db, ctx, perLimit, fn, q)
return
}
2023-05-18 14:27:28 +00:00
func chunk[T Model, R any](db dbQuery, ctx context.Context, perLimit int, fn func(rows T) (R, bool), q *QueryCondition) (r []R, err error) {
i := 1
var rr []T
var count int
var total int
var offset int
for {
if 1 == i {
2023-02-27 13:34:48 +00:00
rr, total, err = pagination[T](db, ctx, q, 1, perLimit)
} else {
2023-02-25 15:10:42 +00:00
q.Offset = offset
q.Limit = perLimit
2023-02-06 09:58:24 +00:00
rr, err = finds[T](db, ctx, q)
}
offset += perLimit
if (err != nil && err != sql.ErrNoRows) || len(rr) < 1 {
return
}
for _, t := range rr {
v, ok := fn(t)
if ok {
r = append(r, v)
}
}
count += len(rr)
if count >= total {
break
}
i++
}
return
}
2023-02-02 05:19:43 +00:00
2023-02-25 15:10:42 +00:00
// Pagination 同
2023-02-02 05:19:43 +00:00
//
2023-02-27 13:34:48 +00:00
// Condition 中可使用 Where Fields From Group Having Join Order Limit In 函数
2023-05-18 14:27:28 +00:00
func Pagination[T Model](ctx context.Context, q *QueryCondition, page, pageSize int) ([]T, int, error) {
2023-02-27 13:34:48 +00:00
return pagination[T](globalBb, ctx, q, page, pageSize)
2023-02-02 05:19:43 +00:00
}
2023-02-06 09:58:24 +00:00
2023-02-07 15:05:31 +00:00
// PaginationFromDB 同 Pagination 方便多个db使用
2023-02-06 09:58:24 +00:00
//
2023-02-27 13:34:48 +00:00
// Condition 中可使用 Where Fields Group Having Join Order Limit In 函数
2023-05-18 14:27:28 +00:00
func PaginationFromDB[T Model](db dbQuery, ctx context.Context, q *QueryCondition, page, pageSize int) ([]T, int, error) {
2023-02-27 13:34:48 +00:00
return pagination[T](db, ctx, q, page, pageSize)
2023-02-06 09:58:24 +00:00
}
2023-02-06 10:34:35 +00:00
2023-05-18 14:27:28 +00:00
func Column[V Model, T any](ctx context.Context, fn func(V) (T, bool), q *QueryCondition) ([]T, error) {
2023-02-06 10:42:36 +00:00
return column[V, T](globalBb, ctx, fn, q)
2023-02-06 10:34:35 +00:00
}
2023-05-18 14:27:28 +00:00
func ColumnFromDB[V Model, T any](db dbQuery, ctx context.Context, fn func(V) (T, bool), q *QueryCondition) (r []T, err error) {
2023-02-06 10:42:36 +00:00
return column[V, T](db, ctx, fn, q)
2023-02-06 10:34:35 +00:00
}
2023-05-18 14:27:28 +00:00
func column[V Model, T any](db dbQuery, ctx context.Context, fn func(V) (T, bool), q *QueryCondition) (r []T, err error) {
2023-02-06 10:34:35 +00:00
res, err := finds[V](db, ctx, q)
if err != nil {
return nil, err
}
r = slice.FilterAndMap(res, fn)
return
}
2023-05-18 14:27:28 +00:00
func GetField[T Model](ctx context.Context, field string, q *QueryCondition) (r string, err error) {
r, err = getField[T](globalBb, ctx, field, q)
return
}
2023-05-18 14:27:28 +00:00
func getField[T Model](db dbQuery, ctx context.Context, field string, q *QueryCondition) (r string, err error) {
2023-02-25 15:10:42 +00:00
if q.Fields == "" || q.Fields == "*" {
q.Fields = field
}
res, err := getToStringMap[T](db, ctx, q)
if err != nil {
return
}
f := strings.Split(field, " ")
r, ok := res[f[len(f)-1]]
if !ok {
err = errors.New("not exists")
}
return
}
2023-05-18 14:27:28 +00:00
func GetFieldFromDB[T Model](db dbQuery, ctx context.Context, field string, q *QueryCondition) (r string, err error) {
return getField[T](db, ctx, field, q)
}
2023-05-18 14:27:28 +00:00
func getToStringMap[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r map[string]string, err error) {
setTable[T](q)
2023-05-17 14:22:31 +00:00
rawSql, in, err := BuildQuerySql(q)
if err != nil {
return nil, err
}
2023-02-21 11:49:13 +00:00
ctx = context.WithValue(ctx, "handle=>", "string")
err = db.Get(ctx, &r, rawSql, in...)
return
}
2023-05-18 14:27:28 +00:00
func GetToStringMap[T Model](ctx context.Context, q *QueryCondition) (r map[string]string, err error) {
r, err = getToStringMap[T](globalBb, ctx, q)
return
}
2023-05-18 14:27:28 +00:00
func findToStringMap[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []map[string]string, err error) {
setTable[T](q)
2023-05-17 14:22:31 +00:00
rawSql, in, err := BuildQuerySql(q)
if err != nil {
return nil, err
}
2023-02-21 11:49:13 +00:00
ctx = context.WithValue(ctx, "handle=>", "string")
err = db.Select(ctx, &r, rawSql, in...)
return
}
2023-05-18 14:27:28 +00:00
func FindToStringMap[T Model](ctx context.Context, q *QueryCondition) (r []map[string]string, err error) {
r, err = findToStringMap[T](globalBb, ctx, q)
return
}
2023-05-18 14:27:28 +00:00
func FindToStringMapFromDB[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []map[string]string, err error) {
r, err = findToStringMap[T](db, ctx, q)
return
}
2023-05-18 14:27:28 +00:00
func GetToStringMapFromDB[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r map[string]string, err error) {
r, err = getToStringMap[T](db, ctx, q)
return
}
2023-05-18 14:27:28 +00:00
func BuildQuerySql(q *QueryCondition) (r string, args []any, err error) {
where := ""
2023-02-25 15:10:42 +00:00
if q.Where != nil {
2023-05-18 14:27:28 +00:00
where, args, err = q.Where.ParseWhere(&q.In)
if err != nil {
return
}
}
2023-05-18 14:27:28 +00:00
having := ""
2023-02-25 15:10:42 +00:00
if q.Having != nil {
hh, arg, er := q.Having.ParseWhere(&q.In)
if er != nil {
err = er
return
}
args = append(args, arg...)
2023-05-18 14:27:28 +00:00
having = strings.Replace(hh, " where", " having", 1)
}
2023-02-25 15:10:42 +00:00
if len(args) == 0 && len(q.In) > 0 {
for _, antes := range q.In {
args = append(args, antes...)
}
}
2023-05-18 14:27:28 +00:00
join := ""
if q.Join != nil {
join = q.Join.parseJoin()
}
groupBy := ""
2023-02-25 15:10:42 +00:00
if q.Group != "" {
g := strings.Builder{}
g.WriteString(" group by ")
2023-02-25 15:10:42 +00:00
g.WriteString(q.Group)
groupBy = g.String()
}
tp := "select %s from %s %s %s %s %s %s %s"
l := ""
2023-05-17 14:22:31 +00:00
table := q.From
2023-02-25 15:10:42 +00:00
if q.Limit > 0 {
l = fmt.Sprintf(" limit %d", q.Limit)
}
2023-02-25 15:10:42 +00:00
if q.Offset > 0 {
l = fmt.Sprintf(" %s offset %d", l, q.Offset)
}
2023-05-18 14:27:28 +00:00
order := ""
if q.Order != nil {
order = q.Order.parseOrderBy()
}
r = fmt.Sprintf(tp, q.Fields, table, join, where, groupBy, having, order, l)
return
}
2023-02-21 11:49:13 +00:00
2023-05-18 14:27:28 +00:00
func findScanner[T Model](db dbQuery, ctx context.Context, fn func(T), q *QueryCondition) (err error) {
setTable[T](q)
2023-05-17 14:22:31 +00:00
s, args, err := BuildQuerySql(q)
2023-02-21 11:49:13 +00:00
if err != nil {
return
}
ctx = context.WithValue(ctx, "handle=>", "scanner")
var v T
ctx = context.WithValue(ctx, "fn", func(v any) {
fn(*(v.(*T)))
})
err = db.Select(ctx, &v, s, args...)
return
}
2023-02-21 12:27:29 +00:00
2023-05-18 14:27:28 +00:00
func FindScannerFromDB[T Model](db dbQuery, ctx context.Context, fn func(T), q *QueryCondition) error {
2023-02-21 12:27:29 +00:00
return findScanner[T](db, ctx, fn, q)
}
2023-05-18 14:27:28 +00:00
func FindScanner[T Model](ctx context.Context, fn func(T), q *QueryCondition) error {
2023-02-21 12:27:29 +00:00
return findScanner[T](globalBb, ctx, fn, q)
}
2023-02-21 14:15:35 +00:00
2023-05-18 14:27:28 +00:00
func Gets[T Model](ctx context.Context, q *QueryCondition) (T, error) {
2023-02-21 14:15:35 +00:00
return gets[T](globalBb, ctx, q)
}
2023-05-18 14:27:28 +00:00
func GetsFromDB[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (T, error) {
2023-02-21 14:15:35 +00:00
return gets[T](db, ctx, q)
}
2023-05-18 14:27:28 +00:00
func gets[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r T, err error) {
setTable[T](q)
2023-05-19 15:14:58 +00:00
if len(q.RelationFn) < 1 {
2023-05-18 14:27:28 +00:00
s, args, er := BuildQuerySql(q)
if er != nil {
err = er
return
}
err = db.Get(ctx, &r, s, args...)
return
}
2023-05-21 11:53:37 +00:00
err = ParseRelation(false, db, ctx, &r, q)
2023-05-18 14:27:28 +00:00
return
}
2023-05-21 11:53:37 +00:00
func ParseRelation(isMultiple bool, db dbQuery, ctx context.Context, r any, q *QueryCondition) (err error) {
before, after := Relation(isMultiple, db, ctx, r, q)
for _, fn := range before {
fn()
2023-05-18 14:27:28 +00:00
}
2023-05-17 14:22:31 +00:00
s, args, err := BuildQuerySql(q)
2023-02-21 14:15:35 +00:00
if err != nil {
return
}
2023-05-18 14:27:28 +00:00
if isMultiple {
err = db.Select(ctx, r, s, args...)
} else {
err = db.Get(ctx, r, s, args...)
}
2023-05-17 14:22:31 +00:00
if err != nil {
return
}
2023-05-21 11:53:37 +00:00
for _, fn := range after {
err = fn()
2023-05-18 14:27:28 +00:00
if err != nil {
return
}
2023-05-17 14:22:31 +00:00
}
2023-02-21 14:15:35 +00:00
return
}