package model import ( "context" "database/sql" "errors" "fmt" "github.com/fthvgb1/wp-go/helper/slice" "strings" ) // Finds 比 Find 多一个offset // // Conditions 中可用 Where Fields Group Having Join Order Offset Limit In 函数 func Finds[T Model](ctx context.Context, q QueryCondition) (r []T, err error) { r, err = finds[T](globalBb, ctx, q) return } // FindFromDB 同 Finds 使用指定 db 查询 // // Conditions 中可用 Where Fields Group Having Join Order Offset Limit In 函数 func FindFromDB[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r []T, err error) { r, err = finds[T](db, ctx, q) return } func finds[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r []T, err error) { setTable[T](&q) sq, args, err := BuildQuerySql(q) if err != nil { return } err = db.Select(ctx, &r, sq, args...) return } 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 { rr, total, err = pagination[T](db, ctx, q, 1, perLimit) } else { q.Offset = offset q.Limit = perLimit rr, err = finds[T](db, ctx, q) } offset += perLimit if (err != nil && err != sql.ErrNoRows) || len(rr) < 1 { return } r = append(r, rr...) if len(r) >= total { break } i++ } return } // ChunkFind 分片查询并直接返回所有结果 // // Conditions 中可用 Where Fields Group Having Join Order Limit In 函数 func ChunkFind[T Model](ctx context.Context, perLimit int, q QueryCondition) (r []T, err error) { r, err = chunkFind[T](globalBb, ctx, perLimit, q) return } // ChunkFindFromDB 同 ChunkFind // // Conditions 中可用 Where Fields Group Having Join Order Limit In 函数 func ChunkFindFromDB[T Model](db dbQuery, ctx context.Context, perLimit int, q QueryCondition) (r []T, err error) { r, err = chunkFind[T](db, ctx, perLimit, q) return } // Chunk 分片查询并函数过虑返回新类型的切片 // // Conditions 中可用 Where Fields Group Having Join Order Limit In 函数 func Chunk[T Model, R any](ctx context.Context, perLimit int, fn func(rows T) (R, bool), q QueryCondition) (r []R, err error) { r, err = chunk(globalBb, ctx, perLimit, fn, q) return } // ChunkFromDB 同 Chunk // // Conditions 中可用 Where Fields Group Having Join Order Limit In 函数 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) { r, err = chunk(db, ctx, perLimit, fn, q) return } 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 { rr, total, err = pagination[T](db, ctx, q, 1, perLimit) } else { q.Offset = offset q.Limit = perLimit 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 } // Pagination 同 // // Condition 中可使用 Where Fields From Group Having Join Order Limit In 函数 func Pagination[T Model](ctx context.Context, q QueryCondition, page, pageSize int) ([]T, int, error) { return pagination[T](globalBb, ctx, q, page, pageSize) } // PaginationFromDB 同 Pagination 方便多个db使用 // // Condition 中可使用 Where Fields Group Having Join Order Limit In 函数 func PaginationFromDB[T Model](db dbQuery, ctx context.Context, q QueryCondition, page, pageSize int) ([]T, int, error) { return pagination[T](db, ctx, q, page, pageSize) } func Column[V Model, T any](ctx context.Context, fn func(V) (T, bool), q QueryCondition) ([]T, error) { return column[V, T](globalBb, ctx, fn, q) } func ColumnFromDB[V Model, T any](db dbQuery, ctx context.Context, fn func(V) (T, bool), q QueryCondition) (r []T, err error) { return column[V, T](db, ctx, fn, q) } func column[V Model, T any](db dbQuery, ctx context.Context, fn func(V) (T, bool), q QueryCondition) (r []T, err error) { res, err := finds[V](db, ctx, q) if err != nil { return nil, err } r = slice.FilterAndMap(res, fn) return } func GetField[T Model](ctx context.Context, field string, q QueryCondition) (r string, err error) { r, err = getField[T](globalBb, ctx, field, q) return } func getField[T Model](db dbQuery, ctx context.Context, field string, q QueryCondition) (r string, err error) { 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 } func GetFieldFromDB[T Model](db dbQuery, ctx context.Context, field string, q QueryCondition) (r string, err error) { return getField[T](db, ctx, field, q) } func getToStringMap[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r map[string]string, err error) { setTable[T](&q) rawSql, in, err := BuildQuerySql(q) if err != nil { return nil, err } ctx = context.WithValue(ctx, "handle=>", "string") err = db.Get(ctx, &r, rawSql, in...) return } func GetToStringMap[T Model](ctx context.Context, q QueryCondition) (r map[string]string, err error) { r, err = getToStringMap[T](globalBb, ctx, q) return } func findToStringMap[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r []map[string]string, err error) { setTable[T](&q) rawSql, in, err := BuildQuerySql(q) if err != nil { return nil, err } ctx = context.WithValue(ctx, "handle=>", "string") err = db.Select(ctx, &r, rawSql, in...) return } func FindToStringMap[T Model](ctx context.Context, q QueryCondition) (r []map[string]string, err error) { r, err = findToStringMap[T](globalBb, ctx, q) return } 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 } 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 } func BuildQuerySql(q QueryCondition) (r string, args []any, err error) { w := "" if q.Where != nil { w, args, err = q.Where.ParseWhere(&q.In) if err != nil { return } } h := "" if q.Having != nil { hh, arg, er := q.Having.ParseWhere(&q.In) if er != nil { err = er return } args = append(args, arg...) h = strings.Replace(hh, " where", " having", 1) } if len(args) == 0 && len(q.In) > 0 { for _, antes := range q.In { args = append(args, antes...) } } j := q.Join.parseJoin() groupBy := "" if q.Group != "" { g := strings.Builder{} g.WriteString(" group by ") g.WriteString(q.Group) groupBy = g.String() } tp := "select %s from %s %s %s %s %s %s %s" l := "" table := q.From if q.Limit > 0 { l = fmt.Sprintf(" limit %d", q.Limit) } if q.Offset > 0 { l = fmt.Sprintf(" %s offset %d", l, q.Offset) } r = fmt.Sprintf(tp, q.Fields, table, j, w, groupBy, h, q.Order.parseOrderBy(), l) return } func findScanner[T Model](db dbQuery, ctx context.Context, fn func(T), q QueryCondition) (err error) { setTable[T](&q) s, args, err := BuildQuerySql(q) 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 } func FindScannerFromDB[T Model](db dbQuery, ctx context.Context, fn func(T), q QueryCondition) error { return findScanner[T](db, ctx, fn, q) } func FindScanner[T Model](ctx context.Context, fn func(T), q QueryCondition) error { return findScanner[T](globalBb, ctx, fn, q) } func Gets[T Model](ctx context.Context, q QueryCondition) (T, error) { return gets[T](globalBb, ctx, q) } func GetsFromDB[T Model](db dbQuery, ctx context.Context, q QueryCondition) (T, error) { return gets[T](db, ctx, q) } func gets[T Model](db dbQuery, ctx context.Context, q QueryCondition) (r T, err error) { setTable[T](&q) s, args, err := BuildQuerySql(q) if err != nil { return } err = db.Get(ctx, &r, s, args...) if err != nil { return } if len(q.Relation) > 0 { err = Relation[T](db, ctx, &r, &q) } return }