mirror of
https://github.com/gohouse/gorose.git
synced 2025-09-26 20:01:15 +08:00
调整目录结构,更适合拆分驱动
This commit is contained in:
40
builder/builder.go
Normal file
40
builder/builder.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package builder
|
||||
|
||||
type IBuilder interface {
|
||||
ToSql() (sql4prepare string, binds []any, err error)
|
||||
ToSqlSelect() (sql4prepare string, binds []any)
|
||||
ToSqlTable() (sql4prepare string, values []any, err error)
|
||||
ToSqlJoin() (sql4prepare string, binds []any, err error)
|
||||
ToSqlWhere() (sql4prepare string, values []any, err error)
|
||||
ToSqlOrderBy() (sql4prepare string)
|
||||
ToSqlLimitOffset() (sqlSegment string, binds []any)
|
||||
ToSqlInsert(obj any, args ...TypeToSqlInsertCase) (sqlSegment string, binds []any, err error)
|
||||
ToSqlDelete(obj any, mustColumn ...string) (sqlSegment string, binds []any, err error)
|
||||
ToSqlUpdate(obj any, mustColumn ...string) (sqlSegment string, binds []any, err error)
|
||||
ToSqlIncDec(symbol string, data map[string]any) (sql4prepare string, values []any, err error)
|
||||
}
|
||||
|
||||
// LimitOffsetClause 存储LIMIT和OFFSET信息。
|
||||
type LimitOffsetClause struct {
|
||||
Limit int
|
||||
Offset int
|
||||
Page int
|
||||
}
|
||||
|
||||
type TypeToSqlUpdateCase struct {
|
||||
BindOrData any
|
||||
MustColumn []string
|
||||
}
|
||||
|
||||
type TypeToSqlIncDecCase struct {
|
||||
Symbol string
|
||||
Data map[string]any
|
||||
}
|
||||
|
||||
type TypeToSqlInsertCase struct {
|
||||
IsReplace bool
|
||||
IsIgnoreCase bool
|
||||
OnDuplicateKeys []string
|
||||
UpdateFields []string
|
||||
MustColumn []string
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package gorose
|
||||
package builder
|
||||
|
||||
type Context struct {
|
||||
TableClause TableClause
|
@@ -1,4 +1,4 @@
|
||||
package gorose
|
||||
package builder
|
||||
|
||||
type TypeGroupItem struct {
|
||||
Column string
|
@@ -1,4 +1,4 @@
|
||||
package gorose
|
||||
package builder
|
||||
|
||||
// HavingClause 类似于WhereClause,但应用于HAVING子句。
|
||||
type HavingClause struct {
|
30
builder/helper.go
Normal file
30
builder/helper.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func IsExpression(obj any) (b bool) {
|
||||
rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
if rfv.Kind() == reflect.String && strings.Contains(rfv.String(), "?") {
|
||||
b = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ToSlice(arg any) []any {
|
||||
ref := reflect.Indirect(reflect.ValueOf(arg))
|
||||
var res []any
|
||||
switch ref.Kind() {
|
||||
case reflect.Slice:
|
||||
l := ref.Len()
|
||||
v := ref.Slice(0, l)
|
||||
for i := 0; i < l; i++ {
|
||||
res = append(res, v.Index(i).Interface())
|
||||
}
|
||||
default:
|
||||
res = append(res, ref.Interface())
|
||||
}
|
||||
return res
|
||||
}
|
@@ -8,9 +8,11 @@
|
||||
// db.xxx.LeftJoin(xxx, <same as before>)
|
||||
// db.Table(gorose.As("users", "a")).Join(gorose.As("card", "b"), "a.id", "b.uid")
|
||||
|
||||
package gorose
|
||||
package builder
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type IJoinOn interface {
|
||||
On(column string, args ...string) IJoinOn
|
@@ -1,4 +1,4 @@
|
||||
package gorose
|
||||
package builder
|
||||
|
||||
type OrderByItem struct {
|
||||
Column string
|
||||
@@ -22,6 +22,8 @@ func (db *OrderByClause) OrderBy(column string, directions ...string) {
|
||||
Direction: direction,
|
||||
})
|
||||
}
|
||||
|
||||
// OrderByRaw adds a Raw ORDER BY clause to the query.
|
||||
func (db *OrderByClause) OrderByRaw(column string) {
|
||||
db.Columns = append(db.Columns, OrderByItem{
|
||||
Column: column,
|
@@ -1,4 +1,4 @@
|
||||
package gorose
|
||||
package builder
|
||||
|
||||
import "strings"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package gorose
|
||||
package builder
|
||||
|
||||
// TableClause table clause
|
||||
type TableClause struct {
|
||||
@@ -6,13 +6,6 @@ type TableClause struct {
|
||||
Alias string
|
||||
}
|
||||
|
||||
func As(table any, alias string) TableClause {
|
||||
return TableClause{
|
||||
Tables: table,
|
||||
Alias: alias,
|
||||
}
|
||||
}
|
||||
|
||||
// Table sets the table name for the query.
|
||||
func (db *TableClause) Table(table any, alias ...string) {
|
||||
var as string
|
@@ -1,4 +1,4 @@
|
||||
package gorose
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -389,6 +389,10 @@ func (w *WhereClause) WhereNot(column any, args ...any) IWhere {
|
||||
w.Not = true
|
||||
return w.Where(column, args...)
|
||||
}
|
||||
func (w *WhereClause) OrWhereNot(column any, args ...any) IWhere {
|
||||
w.Not = true
|
||||
return w.OrWhere(column, args...)
|
||||
}
|
||||
|
||||
func (w *WhereClause) addTypeWhereRaw(boolean string, value string, bindings []any) *WhereClause {
|
||||
w.Conditions = append(w.Conditions, TypeWhereRaw{LogicalOp: boolean, Column: value, Bindings: bindings})
|
44
database.go
44
database.go
@@ -3,34 +3,22 @@ package gorose
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gohouse/gorose/v3/builder"
|
||||
"github.com/gohouse/gorose/v3/driver"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type IBuilder interface {
|
||||
ToSql() (sql4prepare string, binds []any, err error)
|
||||
ToSqlSelect() (sql4prepare string, binds []any)
|
||||
ToSqlTable() (sql4prepare string, values []any, err error)
|
||||
ToSqlJoin() (sql4prepare string, binds []any, err error)
|
||||
ToSqlWhere() (sql4prepare string, values []any, err error)
|
||||
ToSqlOrderBy() (sql4prepare string)
|
||||
ToSqlLimitOffset() (sqlSegment string, binds []any)
|
||||
ToSqlInsert(obj any, args ...TypeToSqlInsertCase) (sqlSegment string, binds []any, err error)
|
||||
ToSqlDelete(obj any, mustColumn ...string) (sqlSegment string, binds []any, err error)
|
||||
ToSqlUpdate(obj any, mustColumn ...string) (sqlSegment string, binds []any, err error)
|
||||
ToSqlIncDec(symbol string, data map[string]any) (sql4prepare string, values []any, err error)
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
*Engin
|
||||
Driver IDriver
|
||||
Context *Context
|
||||
Driver driver.IDriver
|
||||
Context *builder.Context
|
||||
}
|
||||
|
||||
func NewDatabase(g *GoRose) *Database {
|
||||
return &Database{
|
||||
Driver: GetDriver(g.driver),
|
||||
Driver: driver.GetDriver(g.driver),
|
||||
Engin: NewEngin(g),
|
||||
Context: NewContext(g.prefix),
|
||||
Context: builder.NewContext(g.prefix),
|
||||
}
|
||||
}
|
||||
func (db *Database) Table(table any, alias ...string) *Database {
|
||||
@@ -228,7 +216,7 @@ func (db *Database) queryToBindResult(bind any, query string, args ...any) (err
|
||||
return db.Engin.QueryTo(bind, query, args...)
|
||||
}
|
||||
|
||||
func (db *Database) insert(obj any, arg TypeToSqlInsertCase) (res sql.Result, err error) {
|
||||
func (db *Database) insert(obj any, arg builder.TypeToSqlInsertCase) (res sql.Result, err error) {
|
||||
//segment, binds, err := db.ToSqlInsert(obj, ignoreCase, onDuplicateKeys, mustColumn...)
|
||||
segment, binds, err := db.ToSqlInsert(obj, arg)
|
||||
if err != nil {
|
||||
@@ -237,7 +225,7 @@ func (db *Database) insert(obj any, arg TypeToSqlInsertCase) (res sql.Result, er
|
||||
return db.Engin.Exec(segment, binds...)
|
||||
}
|
||||
func (db *Database) Insert(obj any, mustColumn ...string) (affectedRows int64, err error) {
|
||||
result, err := db.insert(obj, TypeToSqlInsertCase{MustColumn: mustColumn})
|
||||
result, err := db.insert(obj, builder.TypeToSqlInsertCase{MustColumn: mustColumn})
|
||||
if err != nil {
|
||||
return affectedRows, err
|
||||
}
|
||||
@@ -248,7 +236,7 @@ func (db *Database) Insert(obj any, mustColumn ...string) (affectedRows int64, e
|
||||
//
|
||||
// 参考 https://laravel.com/docs/10.x/queries#auto-incrementing-ids
|
||||
func (db *Database) InsertGetId(obj any, mustColumn ...string) (lastInsertId int64, err error) {
|
||||
result, err := db.insert(obj, TypeToSqlInsertCase{MustColumn: mustColumn})
|
||||
result, err := db.insert(obj, builder.TypeToSqlInsertCase{MustColumn: mustColumn})
|
||||
if err != nil {
|
||||
return lastInsertId, err
|
||||
}
|
||||
@@ -259,7 +247,7 @@ func (db *Database) InsertGetId(obj any, mustColumn ...string) (lastInsertId int
|
||||
//
|
||||
// 参考 https://laravel.com/docs/10.x/queries#insert-statements
|
||||
func (db *Database) InsertOrIgnore(obj any, mustColumn ...string) (affectedRows int64, err error) {
|
||||
result, err := db.insert(obj, TypeToSqlInsertCase{IsIgnoreCase: true, MustColumn: mustColumn})
|
||||
result, err := db.insert(obj, builder.TypeToSqlInsertCase{IsIgnoreCase: true, MustColumn: mustColumn})
|
||||
if err != nil {
|
||||
return affectedRows, err
|
||||
}
|
||||
@@ -273,7 +261,7 @@ func (db *Database) InsertOrIgnore(obj any, mustColumn ...string) (affectedRows
|
||||
//
|
||||
// eg: Upsert(obj, []string{"id"}, []string{"age"}, "id", "name")
|
||||
func (db *Database) Upsert(obj any, onDuplicateKeys, updateFields []string, mustColumn ...string) (affectedRows int64, err error) {
|
||||
result, err := db.insert(obj, TypeToSqlInsertCase{OnDuplicateKeys: onDuplicateKeys, UpdateFields: updateFields, MustColumn: mustColumn})
|
||||
result, err := db.insert(obj, builder.TypeToSqlInsertCase{OnDuplicateKeys: onDuplicateKeys, UpdateFields: updateFields, MustColumn: mustColumn})
|
||||
if err != nil {
|
||||
return affectedRows, err
|
||||
}
|
||||
@@ -284,7 +272,7 @@ func (db *Database) Upsert(obj any, onDuplicateKeys, updateFields []string, must
|
||||
//
|
||||
// 参考 mysql replace into 用法
|
||||
func (db *Database) Replace(obj any, mustColumn ...string) (affectedRows int64, err error) {
|
||||
result, err := db.insert(obj, TypeToSqlInsertCase{IsReplace: true, MustColumn: mustColumn})
|
||||
result, err := db.insert(obj, builder.TypeToSqlInsertCase{IsReplace: true, MustColumn: mustColumn})
|
||||
if err != nil {
|
||||
return affectedRows, err
|
||||
}
|
||||
@@ -421,7 +409,7 @@ func (db *Database) DoesntExist(bind ...any) (b bool, err error) {
|
||||
b, err = db.Exists(bind...)
|
||||
return !b, err
|
||||
}
|
||||
func (db *Database) Union(b IBuilder, unionAll ...bool) (res []map[string]any, err error) {
|
||||
func (db *Database) Union(b builder.IBuilder, unionAll ...bool) (res []map[string]any, err error) {
|
||||
prepare, values, err := db.ToSql()
|
||||
if err != nil {
|
||||
return res, err
|
||||
@@ -437,7 +425,7 @@ func (db *Database) Union(b IBuilder, unionAll ...bool) (res []map[string]any, e
|
||||
err = db.queryToBindResult(&res, fmt.Sprintf("%s %s %s", prepare, union, sql4prepare), append(values, binds...))
|
||||
return
|
||||
}
|
||||
func (db *Database) UnionAll(b IBuilder) (res []map[string]any, err error) {
|
||||
func (db *Database) UnionAll(b builder.IBuilder) (res []map[string]any, err error) {
|
||||
return db.Union(b, true)
|
||||
}
|
||||
|
||||
@@ -451,14 +439,14 @@ func (db *Database) Truncate(obj ...any) (affectedRows int64, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.Engin.execute(fmt.Sprintf("TRUNCATE TABLE %s", BackQuotes(table)))
|
||||
return db.Engin.execute(fmt.Sprintf("TRUNCATE TABLE %s", table))
|
||||
}
|
||||
|
||||
type TxHandler func() *Database
|
||||
|
||||
func (db *Database) Begin() (tx TxHandler, err error) {
|
||||
return func() *Database {
|
||||
db.Context = NewContext(db.prefix)
|
||||
db.Context = builder.NewContext(db.prefix)
|
||||
return db
|
||||
}, db.Engin.Begin()
|
||||
}
|
||||
|
43
driver.go
43
driver.go
@@ -1,43 +0,0 @@
|
||||
package gorose
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type IDriver interface {
|
||||
ToSqlSelect(c *Context) (sql4prepare string, binds []any)
|
||||
ToSqlTable(c *Context) (sql4prepare string, values []any, err error)
|
||||
ToSqlJoin(c *Context) (sql4prepare string, binds []any, err error)
|
||||
ToSqlWhere(c *Context) (sql4prepare string, values []any, err error)
|
||||
ToSqlOrderBy(c *Context) (sql4prepare string)
|
||||
ToSqlLimitOffset(c *Context) (sqlSegment string, binds []any)
|
||||
|
||||
ToSql(c *Context) (sql4prepare string, binds []any, err error)
|
||||
ToSqlInsert(c *Context, obj any, args ...TypeToSqlInsertCase) (sqlSegment string, binds []any, err error)
|
||||
ToSqlUpdate(c *Context, arg any) (sqlSegment string, binds []any, err error)
|
||||
ToSqlDelete(c *Context, obj any, mustColumn ...string) (sqlSegment string, binds []any, err error)
|
||||
}
|
||||
|
||||
var driverMap = map[string]IDriver{}
|
||||
var driverLock sync.RWMutex
|
||||
|
||||
func Register(driver string, parser IDriver) {
|
||||
driverLock.Lock()
|
||||
defer driverLock.Unlock()
|
||||
driverMap[driver] = parser
|
||||
}
|
||||
|
||||
func GetDriver(driver string) IDriver {
|
||||
driverLock.RLock()
|
||||
defer driverLock.RUnlock()
|
||||
return driverMap[driver]
|
||||
}
|
||||
|
||||
func DriverList() (dr []string) {
|
||||
driverLock.RLock()
|
||||
defer driverLock.RUnlock()
|
||||
for d := range driverMap {
|
||||
dr = append(dr, d)
|
||||
}
|
||||
return
|
||||
}
|
44
driver/driver.go
Normal file
44
driver/driver.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package driver
|
||||
|
||||
import (
|
||||
"github.com/gohouse/gorose/v3/builder"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type IDriver interface {
|
||||
ToSqlSelect(c *builder.Context) (sql4prepare string, binds []any)
|
||||
ToSqlTable(c *builder.Context) (sql4prepare string, values []any, err error)
|
||||
ToSqlJoin(c *builder.Context) (sql4prepare string, binds []any, err error)
|
||||
ToSqlWhere(c *builder.Context) (sql4prepare string, values []any, err error)
|
||||
ToSqlOrderBy(c *builder.Context) (sql4prepare string)
|
||||
ToSqlLimitOffset(c *builder.Context) (sqlSegment string, binds []any)
|
||||
|
||||
ToSql(c *builder.Context) (sql4prepare string, binds []any, err error)
|
||||
ToSqlInsert(c *builder.Context, obj any, args ...builder.TypeToSqlInsertCase) (sqlSegment string, binds []any, err error)
|
||||
ToSqlUpdate(c *builder.Context, arg any) (sqlSegment string, binds []any, err error)
|
||||
ToSqlDelete(c *builder.Context, obj any, mustColumn ...string) (sqlSegment string, binds []any, err error)
|
||||
}
|
||||
|
||||
var driverMap = map[string]IDriver{}
|
||||
var driverLock sync.RWMutex
|
||||
|
||||
func Register(driver string, parser IDriver) {
|
||||
driverLock.Lock()
|
||||
defer driverLock.Unlock()
|
||||
driverMap[driver] = parser
|
||||
}
|
||||
|
||||
func GetDriver(driver string) IDriver {
|
||||
driverLock.RLock()
|
||||
defer driverLock.RUnlock()
|
||||
return driverMap[driver]
|
||||
}
|
||||
|
||||
func DriverList() (dr []string) {
|
||||
driverLock.RLock()
|
||||
defer driverLock.RUnlock()
|
||||
for d := range driverMap {
|
||||
dr = append(dr, d)
|
||||
}
|
||||
return
|
||||
}
|
@@ -3,8 +3,11 @@ package mysql
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/gohouse/gorose/v3"
|
||||
"github.com/gohouse/gorose/v3/builder"
|
||||
"github.com/gohouse/gorose/v3/parser"
|
||||
|
||||
//_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/gohouse/gorose/v3/driver"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
@@ -16,10 +19,10 @@ type Builder struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
gorose.Register(DriverName, &Builder{})
|
||||
driver.Register(DriverName, &Builder{})
|
||||
}
|
||||
|
||||
func (b Builder) ToSql(c *gorose.Context) (sql4prepare string, binds []any, err error) {
|
||||
func (b Builder) ToSql(c *builder.Context) (sql4prepare string, binds []any, err error) {
|
||||
selects, anies := b.ToSqlSelect(c)
|
||||
table, binds2, err := b.ToSqlTable(c)
|
||||
if err != nil {
|
||||
@@ -49,7 +52,7 @@ func (b Builder) ToSql(c *gorose.Context) (sql4prepare string, binds []any, err
|
||||
return
|
||||
}
|
||||
|
||||
func (Builder) ToSqlSelect(c *gorose.Context) (sql4prepare string, binds []any) {
|
||||
func (Builder) ToSqlSelect(c *builder.Context) (sql4prepare string, binds []any) {
|
||||
var cols []string
|
||||
for _, col := range c.SelectClause.Columns {
|
||||
if col.IsRaw {
|
||||
@@ -74,12 +77,12 @@ func (Builder) ToSqlSelect(c *gorose.Context) (sql4prepare string, binds []any)
|
||||
return
|
||||
}
|
||||
|
||||
func (b Builder) ToSqlTable(c *gorose.Context) (sql4prepare string, binds []any, err error) {
|
||||
func (b Builder) ToSqlTable(c *builder.Context) (sql4prepare string, binds []any, err error) {
|
||||
return b.buildSqlTable(c.TableClause, c.Prefix)
|
||||
}
|
||||
|
||||
func (b Builder) buildSqlTable(tab gorose.TableClause, prefix string) (sql4prepare string, binds []any, err error) {
|
||||
if v, ok := tab.Tables.(gorose.IBuilder); ok {
|
||||
func (b Builder) buildSqlTable(tab builder.TableClause, prefix string) (sql4prepare string, binds []any, err error) {
|
||||
if v, ok := tab.Tables.(builder.IBuilder); ok {
|
||||
sql4prepare, binds, err = v.ToSql()
|
||||
if tab.Alias != "" {
|
||||
sql4prepare = fmt.Sprintf("(%s) %s", sql4prepare, BackQuotes(tab.Alias))
|
||||
@@ -106,34 +109,29 @@ func (b Builder) buildSqlTable(tab gorose.TableClause, prefix string) (sql4prepa
|
||||
return strings.TrimSpace(fmt.Sprintf("%s %s", sql4prepare, BackQuotes(tab.Alias))), binds, err
|
||||
}
|
||||
|
||||
func (b Builder) toSqlWhere(c *gorose.Context, wc gorose.WhereClause) (sql4prepare string, binds []any, err error) {
|
||||
func (b Builder) toSqlWhere(c *builder.Context, wc builder.WhereClause) (sql4prepare string, binds []any, err error) {
|
||||
if len(wc.Conditions) == 0 {
|
||||
return
|
||||
}
|
||||
var sql4prepareArr []string
|
||||
for _, v := range wc.Conditions {
|
||||
switch item := v.(type) {
|
||||
case gorose.TypeWhereRaw:
|
||||
//item := v.(gorose.TypeWhereRaw)
|
||||
case builder.TypeWhereRaw:
|
||||
sql4prepareArr = append(sql4prepareArr, fmt.Sprintf("%s %s", item.LogicalOp, item.Column))
|
||||
binds = append(binds, item.Bindings...)
|
||||
case gorose.TypeWhereStandard:
|
||||
//item := v.(gorose.TypeWhereStandard)
|
||||
case builder.TypeWhereStandard:
|
||||
sql4prepareArr = append(sql4prepareArr, fmt.Sprintf("%s %s %s ?", item.LogicalOp, BackQuotes(item.Column), item.Operator))
|
||||
binds = append(binds, item.Value)
|
||||
case gorose.TypeWhereIn:
|
||||
//item := v.(gorose.TypeWhereIn)
|
||||
case builder.TypeWhereIn:
|
||||
values := ToSlice(item.Value)
|
||||
sql4prepareArr = append(sql4prepareArr, fmt.Sprintf("%s %s %s (%s)", item.LogicalOp, BackQuotes(item.Column), item.Operator, strings.Repeat("?,", len(values)-1)+"?"))
|
||||
binds = append(binds, values...)
|
||||
case gorose.TypeWhereBetween:
|
||||
//item := v.(gorose.TypeWhereBetween)
|
||||
case builder.TypeWhereBetween:
|
||||
values := ToSlice(item.Value)
|
||||
sql4prepareArr = append(sql4prepareArr, fmt.Sprintf("%s %s %s ? AND ?", item.LogicalOp, BackQuotes(item.Column), item.Operator))
|
||||
binds = append(binds, values...)
|
||||
case gorose.TypeWhereNested:
|
||||
//item := v.(gorose.TypeWhereNested)
|
||||
var tmp = gorose.Context{}
|
||||
case builder.TypeWhereNested:
|
||||
var tmp = builder.Context{}
|
||||
item.WhereNested(&tmp.WhereClause)
|
||||
prepare, anies, err := b.ToSqlWhere(&tmp)
|
||||
if err != nil {
|
||||
@@ -141,17 +139,15 @@ func (b Builder) toSqlWhere(c *gorose.Context, wc gorose.WhereClause) (sql4prepa
|
||||
}
|
||||
sql4prepareArr = append(sql4prepareArr, fmt.Sprintf("%s (%s)", item.LogicalOp, strings.TrimPrefix(prepare, "WHERE ")))
|
||||
binds = append(binds, anies...)
|
||||
case gorose.TypeWhereSubQuery:
|
||||
//item := v.(gorose.TypeWhereSubQuery)
|
||||
case builder.TypeWhereSubQuery:
|
||||
query, anies, err := item.SubQuery.ToSql()
|
||||
if err != nil {
|
||||
return sql4prepare, binds, err
|
||||
}
|
||||
sql4prepareArr = append(sql4prepareArr, fmt.Sprintf("%s %s %s (%s)", item.LogicalOp, BackQuotes(item.Column), item.Operator, query))
|
||||
binds = append(binds, anies...)
|
||||
case gorose.TypeWhereSubHandler:
|
||||
//item := v.(gorose.TypeWhereSubQuery)
|
||||
var ctx = gorose.NewContext(c.Prefix)
|
||||
case builder.TypeWhereSubHandler:
|
||||
var ctx = builder.NewContext(c.Prefix)
|
||||
item.Sub(ctx)
|
||||
query, anies, err := b.ToSql(ctx)
|
||||
if err != nil {
|
||||
@@ -166,7 +162,7 @@ func (b Builder) toSqlWhere(c *gorose.Context, wc gorose.WhereClause) (sql4prepa
|
||||
}
|
||||
return
|
||||
}
|
||||
func (b Builder) ToSqlWhere(c *gorose.Context) (sql4prepare string, binds []any, err error) {
|
||||
func (b Builder) ToSqlWhere(c *builder.Context) (sql4prepare string, binds []any, err error) {
|
||||
sql4prepare, binds, err = b.toSqlWhere(c, c.WhereClause)
|
||||
if sql4prepare != "" {
|
||||
if c.WhereClause.Not {
|
||||
@@ -177,7 +173,7 @@ func (b Builder) ToSqlWhere(c *gorose.Context) (sql4prepare string, binds []any,
|
||||
return
|
||||
}
|
||||
|
||||
func (b Builder) ToSqlJoin(c *gorose.Context) (sql4prepare string, binds []any, err error) {
|
||||
func (b Builder) ToSqlJoin(c *builder.Context) (sql4prepare string, binds []any, err error) {
|
||||
if c.JoinClause.Err != nil {
|
||||
return sql4prepare, binds, c.JoinClause.Err
|
||||
}
|
||||
@@ -189,19 +185,19 @@ func (b Builder) ToSqlJoin(c *gorose.Context) (sql4prepare string, binds []any,
|
||||
var sql4 string
|
||||
var bind []any
|
||||
switch item := v.(type) {
|
||||
case gorose.TypeJoinStandard:
|
||||
case builder.TypeJoinStandard:
|
||||
prepare, bind, err = b.buildSqlTable(item.TableClause, c.Prefix)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sql4 = fmt.Sprintf("%s %s ON %s %s %s", item.Type, prepare, BackQuotes(item.Column1), item.Operator, BackQuotes(item.Column2))
|
||||
case gorose.TypeJoinSub:
|
||||
case builder.TypeJoinSub:
|
||||
sql4, bind, err = item.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case gorose.TypeJoinOn:
|
||||
var tjo gorose.TypeJoinOnCondition
|
||||
case builder.TypeJoinOn:
|
||||
var tjo builder.TypeJoinOnCondition
|
||||
item.OnClause(&tjo)
|
||||
if len(tjo.Conditions) == 0 {
|
||||
return
|
||||
@@ -219,7 +215,7 @@ func (b Builder) ToSqlJoin(c *gorose.Context) (sql4prepare string, binds []any,
|
||||
return
|
||||
}
|
||||
|
||||
func (b Builder) ToSqlGroupBy(c *gorose.Context) (sql4prepare string) {
|
||||
func (b Builder) ToSqlGroupBy(c *builder.Context) (sql4prepare string) {
|
||||
if len(c.GroupClause.Groups) > 0 {
|
||||
var tmp []string
|
||||
for _, col := range c.GroupClause.Groups {
|
||||
@@ -233,14 +229,14 @@ func (b Builder) ToSqlGroupBy(c *gorose.Context) (sql4prepare string) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (b Builder) ToSqlHaving(c *gorose.Context) (sql4prepare string, binds []any, err error) {
|
||||
func (b Builder) ToSqlHaving(c *builder.Context) (sql4prepare string, binds []any, err error) {
|
||||
sql4prepare, binds, err = b.toSqlWhere(c, c.HavingClause.WhereClause)
|
||||
if sql4prepare != "" {
|
||||
sql4prepare = fmt.Sprintf("HAVING %s", sql4prepare)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (b Builder) ToSqlOrderBy(c *gorose.Context) (sql4prepare string) {
|
||||
func (b Builder) ToSqlOrderBy(c *builder.Context) (sql4prepare string) {
|
||||
if len(c.OrderByClause.Columns) == 0 {
|
||||
return
|
||||
}
|
||||
@@ -260,7 +256,7 @@ func (b Builder) ToSqlOrderBy(c *gorose.Context) (sql4prepare string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (b Builder) ToSqlLimitOffset(c *gorose.Context) (sqlSegment string, binds []any) {
|
||||
func (b Builder) ToSqlLimitOffset(c *builder.Context) (sqlSegment string, binds []any) {
|
||||
var offset int
|
||||
if c.LimitOffsetClause.Offset > 0 {
|
||||
offset = c.LimitOffsetClause.Offset
|
||||
@@ -279,11 +275,9 @@ func (b Builder) ToSqlLimitOffset(c *gorose.Context) (sqlSegment string, binds [
|
||||
return
|
||||
}
|
||||
|
||||
//func (b Builder) ToSqlInsert(c *gorose.Context, obj any, ignoreCase string, onDuplicateKeys []string, mustColumn ...string) (sqlSegment string, binds []any, err error) {
|
||||
|
||||
// ToSqlInsert insert
|
||||
func (b Builder) ToSqlInsert(c *gorose.Context, obj any, args ...gorose.TypeToSqlInsertCase) (sqlSegment string, binds []any, err error) {
|
||||
var arg gorose.TypeToSqlInsertCase
|
||||
func (b Builder) ToSqlInsert(c *builder.Context, obj any, args ...builder.TypeToSqlInsertCase) (sqlSegment string, binds []any, err error) {
|
||||
var arg builder.TypeToSqlInsertCase
|
||||
if len(args) > 0 {
|
||||
arg = args[0]
|
||||
}
|
||||
@@ -292,7 +286,7 @@ func (b Builder) ToSqlInsert(c *gorose.Context, obj any, args ...gorose.TypeToSq
|
||||
switch rfv.Kind() {
|
||||
case reflect.Struct:
|
||||
var datas []map[string]any
|
||||
datas, err = gorose.StructsToInsert(obj, arg.MustColumn...)
|
||||
datas, err = parser.StructsToInsert(obj, arg.MustColumn...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -303,7 +297,7 @@ func (b Builder) ToSqlInsert(c *gorose.Context, obj any, args ...gorose.TypeToSq
|
||||
case reflect.Struct:
|
||||
c.TableClause.Table(obj)
|
||||
var datas []map[string]any
|
||||
datas, err = gorose.StructsToInsert(obj, arg.MustColumn...)
|
||||
datas, err = parser.StructsToInsert(obj, arg.MustColumn...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -316,12 +310,12 @@ func (b Builder) ToSqlInsert(c *gorose.Context, obj any, args ...gorose.TypeToSq
|
||||
}
|
||||
}
|
||||
|
||||
func (b Builder) ToSqlDelete(c *gorose.Context, obj any, mustColumn ...string) (sqlSegment string, binds []any, err error) {
|
||||
func (b Builder) ToSqlDelete(c *builder.Context, obj any, mustColumn ...string) (sqlSegment string, binds []any, err error) {
|
||||
var ctx = *c
|
||||
rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
switch rfv.Kind() {
|
||||
case reflect.Struct:
|
||||
data, err := gorose.StructToDelete(obj, mustColumn...)
|
||||
data, err := parser.StructToDelete(obj, mustColumn...)
|
||||
if err != nil {
|
||||
return sqlSegment, binds, err
|
||||
}
|
||||
@@ -337,22 +331,22 @@ func (b Builder) ToSqlDelete(c *gorose.Context, obj any, mustColumn ...string) (
|
||||
return
|
||||
}
|
||||
|
||||
func (b Builder) ToSqlUpdate(c *gorose.Context, arg any) (sqlSegment string, binds []any, err error) {
|
||||
func (b Builder) ToSqlUpdate(c *builder.Context, arg any) (sqlSegment string, binds []any, err error) {
|
||||
switch v := arg.(type) {
|
||||
case gorose.TypeToSqlUpdateCase:
|
||||
case builder.TypeToSqlUpdateCase:
|
||||
return b.toSqlUpdate(c, v.BindOrData, v.MustColumn...)
|
||||
case gorose.TypeToSqlIncDecCase:
|
||||
case builder.TypeToSqlIncDecCase:
|
||||
return b.toSqlIncDec(c, v.Symbol, v.Data)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (b Builder) toSqlUpdate(c *gorose.Context, obj any, mustColumn ...string) (sqlSegment string, binds []any, err error) {
|
||||
func (b Builder) toSqlUpdate(c *builder.Context, obj any, mustColumn ...string) (sqlSegment string, binds []any, err error) {
|
||||
rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
switch rfv.Kind() {
|
||||
case reflect.Struct:
|
||||
dataMap, pk, pkValue, err := gorose.StructToUpdate(obj, mustColumn...)
|
||||
dataMap, pk, pkValue, err := parser.StructToUpdate(obj, mustColumn...)
|
||||
if err != nil {
|
||||
return sqlSegment, binds, err
|
||||
}
|
||||
@@ -370,7 +364,7 @@ func (b Builder) toSqlUpdate(c *gorose.Context, obj any, mustColumn ...string) (
|
||||
}
|
||||
}
|
||||
|
||||
func (b Builder) toSqlIncDec(c *gorose.Context, symbol string, data map[string]any) (sql4prepare string, values []any, err error) {
|
||||
func (b Builder) toSqlIncDec(c *builder.Context, symbol string, data map[string]any) (sql4prepare string, values []any, err error) {
|
||||
prepare, anies, err := b.ToSqlTable(c)
|
||||
if err != nil {
|
||||
return sql4prepare, values, err
|
@@ -3,18 +3,19 @@ package mysql
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gohouse/gorose/v3"
|
||||
"github.com/gohouse/gorose/v3/builder"
|
||||
"github.com/gohouse/gorose/v3/parser"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (b Builder) buildTableName(rft reflect.Type, prefix string) (tab string) {
|
||||
return BackQuotes(fmt.Sprintf("%s%s", prefix, gorose.StructsToTableName(rft)))
|
||||
return BackQuotes(fmt.Sprintf("%s%s", prefix, parser.StructsToTableName(rft)))
|
||||
}
|
||||
|
||||
// func (b Builder) toSqlInsert(c *gorose.Context, data any, ignoreCase string, onDuplicateKeys []string) (sql4prepare string, values []any, err error) {
|
||||
func (b Builder) toSqlInsert(c *gorose.Context, data any, insertCase gorose.TypeToSqlInsertCase) (sql4prepare string, values []any, err error) {
|
||||
func (b Builder) toSqlInsert(c *builder.Context, data any, insertCase builder.TypeToSqlInsertCase) (sql4prepare string, values []any, err error) {
|
||||
rfv := reflect.Indirect(reflect.ValueOf(data))
|
||||
var fields []string
|
||||
var valuesPlaceholderArr []string
|
||||
@@ -90,7 +91,7 @@ func (b Builder) toSqlInsert(c *gorose.Context, data any, insertCase gorose.Type
|
||||
return
|
||||
}
|
||||
|
||||
func (b Builder) toSqlUpdateReal(c *gorose.Context, data any) (sql4prepare string, values []any, err error) {
|
||||
func (b Builder) toSqlUpdateReal(c *builder.Context, data any) (sql4prepare string, values []any, err error) {
|
||||
rfv := reflect.Indirect(reflect.ValueOf(data))
|
||||
var updates []string
|
||||
switch rfv.Kind() {
|
||||
@@ -123,7 +124,7 @@ func (b Builder) toSqlUpdateReal(c *gorose.Context, data any) (sql4prepare strin
|
||||
return
|
||||
}
|
||||
|
||||
func (b Builder) toSqlDelete(c *gorose.Context) (sql4prepare string, values []any, err error) {
|
||||
func (b Builder) toSqlDelete(c *builder.Context) (sql4prepare string, values []any, err error) {
|
||||
var tables string
|
||||
tables, _, err = b.ToSqlTable(c)
|
||||
if err != nil {
|
11
engin.go
11
engin.go
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"github.com/gohouse/gorose/v3/parser"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
)
|
||||
@@ -154,7 +155,7 @@ func (s *Engin) rowsToBind(rows *sql.Rows, bind any) (err error) {
|
||||
|
||||
func (s *Engin) rowsToStruct(rows *sql.Rows, rfv reflect.Value) error {
|
||||
//FieldTag, FieldStruct, _ := structsParse(rfv)
|
||||
FieldTag, FieldStruct, _ := structsTypeParse(rfv.Type())
|
||||
FieldTag, FieldStruct, _ := parser.StructsTypeParse(rfv.Type())
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
@@ -167,14 +168,6 @@ func (s *Engin) rowsToStruct(rows *sql.Rows, rfv reflect.Value) error {
|
||||
count := len(columns)
|
||||
|
||||
for rows.Next() {
|
||||
// 要先扫描到map, 再做字段比对, 因为这里不确定具体字段数量
|
||||
// 主要针对 select * 或者直接sql语句
|
||||
//todo 如果是由struct转换而来, 可以新开一个方法, 不需要做转换比对过程
|
||||
//entry, err := s.rowsToMapSingle(rows, columns, count)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
if rfv.Kind() == reflect.Slice {
|
||||
rfvItem := reflect.Indirect(reflect.New(rfv.Type().Elem()))
|
||||
err = s.scanStructRow(rfvItem, rows, count, FieldTag, FieldStruct, columns)
|
||||
|
@@ -2,7 +2,8 @@ package gorose
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"math"
|
||||
"github.com/gohouse/gorose/v3/builder"
|
||||
_ "github.com/gohouse/gorose/v3/driver/mysql"
|
||||
)
|
||||
|
||||
type GoRose struct {
|
||||
@@ -14,10 +15,10 @@ type GoRose struct {
|
||||
handlers HandlersChain
|
||||
}
|
||||
|
||||
type HandlerFunc func(*Context)
|
||||
type HandlerFunc func(*builder.Context)
|
||||
type HandlersChain []HandlerFunc
|
||||
|
||||
const abortIndex int8 = math.MaxInt8 >> 1
|
||||
//const abortIndex int8 = math.MaxInt8 >> 1
|
||||
|
||||
//type handlers struct {
|
||||
// handlers HandlersChain
|
||||
@@ -44,6 +45,7 @@ func (g *GoRose) Use(h ...HandlerFunc) *GoRose {
|
||||
// examples
|
||||
//
|
||||
// Open("mysql", "root:root@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=true")
|
||||
// Open(&Config{...})
|
||||
// Open(&ConfigCluster{...})
|
||||
func Open(conf ...any) *GoRose {
|
||||
var g = GoRose{}
|
||||
|
@@ -1,58 +0,0 @@
|
||||
package gorose
|
||||
|
||||
import "math"
|
||||
|
||||
// LimitOffsetClause 存储LIMIT和OFFSET信息。
|
||||
type LimitOffsetClause struct {
|
||||
Limit int
|
||||
Offset int
|
||||
Page int
|
||||
}
|
||||
|
||||
// Pagination 是用于分页查询结果的结构体,包含当前页数据及分页信息。
|
||||
type Pagination struct {
|
||||
Limit int `json:"limit"`
|
||||
Pages int `json:"pages"`
|
||||
CurrentPage int `json:"currentPage"`
|
||||
PrevPage int `json:"prevPage"`
|
||||
NextPage int `json:"nextPage"`
|
||||
Total int64 `json:"total"`
|
||||
Data []map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
func (db *Database) Paginate(obj ...any) (result Pagination, err error) {
|
||||
if len(obj) > 0 {
|
||||
db.Table(obj[0])
|
||||
}
|
||||
var count int64
|
||||
count, err = db.Count()
|
||||
if err != nil || count == 0 {
|
||||
return
|
||||
}
|
||||
if db.Context.LimitOffsetClause.Limit == 0 {
|
||||
db.Limit(15)
|
||||
}
|
||||
if db.Context.LimitOffsetClause.Page == 0 {
|
||||
db.Page(1)
|
||||
}
|
||||
|
||||
res, err := db.Get()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
result.Total = count
|
||||
result.Data = res
|
||||
result.Limit = db.Context.LimitOffsetClause.Limit
|
||||
result.Pages = int(math.Ceil(float64(count) / float64(db.Context.LimitOffsetClause.Limit)))
|
||||
result.CurrentPage = db.Context.LimitOffsetClause.Page
|
||||
result.PrevPage = db.Context.LimitOffsetClause.Page - 1
|
||||
result.NextPage = db.Context.LimitOffsetClause.Page + 1
|
||||
if db.Context.LimitOffsetClause.Page == 1 {
|
||||
result.PrevPage = 1
|
||||
}
|
||||
if db.Context.LimitOffsetClause.Page == result.Pages {
|
||||
result.NextPage = result.Pages
|
||||
}
|
||||
return
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package gorose
|
||||
package parser
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
@@ -28,20 +28,20 @@ func StructsParse(obj any) (FieldTag []string, FieldStruct []string, pkField str
|
||||
rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
switch rfv.Kind() {
|
||||
case reflect.Struct:
|
||||
return structsTypeParse(rfv.Type())
|
||||
return StructsTypeParse(rfv.Type())
|
||||
case reflect.Slice:
|
||||
return structsTypeParse(rfv.Type())
|
||||
return StructsTypeParse(rfv.Type())
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func structsTypeParse(rft reflect.Type) (fieldTag []string, fieldStruct []string, pkField string) {
|
||||
func StructsTypeParse(rft reflect.Type) (fieldTag []string, fieldStruct []string, pkField string) {
|
||||
//rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
if rft.Kind() == reflect.Slice {
|
||||
rft2 := rft.Elem()
|
||||
if rft2.Kind() == reflect.Struct {
|
||||
return structsTypeParse(rft2)
|
||||
return StructsTypeParse(rft2)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < rft.NumField(); i++ {
|
||||
@@ -89,7 +89,7 @@ func structsTypeParse(rft reflect.Type) (fieldTag []string, fieldStruct []string
|
||||
// }
|
||||
//}
|
||||
|
||||
func structDataToMap(rfv reflect.Value, tags, fieldStruct []string, mustColumn ...string) (data map[string]any, err error) {
|
||||
func StructDataToMap(rfv reflect.Value, tags, fieldStruct []string, mustColumn ...string) (data map[string]any, err error) {
|
||||
data = make(map[string]any)
|
||||
for i, fieldName := range fieldStruct {
|
||||
field := rfv.FieldByName(fieldName)
|
||||
@@ -136,8 +136,8 @@ func structUpdateDataToMap(rfv reflect.Value, tags, fieldStruct []string, pkFiel
|
||||
func StructToDelete(obj any, mustColumn ...string) (data map[string]any, err error) {
|
||||
rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
if rfv.Kind() == reflect.Struct {
|
||||
tag, fieldStruct, _ := structsTypeParse(rfv.Type())
|
||||
data, err = structDataToMap(rfv, tag, fieldStruct, mustColumn...)
|
||||
tag, fieldStruct, _ := StructsTypeParse(rfv.Type())
|
||||
data, err = StructDataToMap(rfv, tag, fieldStruct, mustColumn...)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -146,18 +146,18 @@ func StructsToInsert(obj any, mustColumn ...string) (datas []map[string]any, err
|
||||
rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
switch rfv.Kind() {
|
||||
case reflect.Struct:
|
||||
fieldTag, fieldStruct, _ := structsTypeParse(rfv.Type())
|
||||
fieldTag, fieldStruct, _ := StructsTypeParse(rfv.Type())
|
||||
var data = make(map[string]any)
|
||||
data, err = structDataToMap(rfv, fieldTag, fieldStruct, mustColumn...)
|
||||
data, err = StructDataToMap(rfv, fieldTag, fieldStruct, mustColumn...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
datas = append(datas, data)
|
||||
case reflect.Slice:
|
||||
tag, fieldStruct, _ := structsTypeParse(rfv.Type())
|
||||
tag, fieldStruct, _ := StructsTypeParse(rfv.Type())
|
||||
for i := 0; i < rfv.Len(); i++ {
|
||||
var data = make(map[string]any)
|
||||
data, err = structDataToMap(rfv.Index(i), tag, fieldStruct, mustColumn...)
|
||||
data, err = StructDataToMap(rfv.Index(i), tag, fieldStruct, mustColumn...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
161
sugar.go
161
sugar.go
@@ -1,108 +1,153 @@
|
||||
package gorose
|
||||
|
||||
//func (db *Database) MustFirst(columns ...string) (res map[string]any) {
|
||||
// res, db.Context.Err = db.First(columns...)
|
||||
// return
|
||||
//}
|
||||
//func (db *Database) MustGet(columns ...string) (res []map[string]any) {
|
||||
// res, db.Context.Err = db.Get(columns...)
|
||||
// return
|
||||
//}
|
||||
import (
|
||||
"github.com/gohouse/gorose/v3/builder"
|
||||
"math"
|
||||
)
|
||||
|
||||
func (db *Database) WhereSub(column string, operation string, sub WhereSubHandler) *Database {
|
||||
// Pagination 是用于分页查询结果的结构体,包含当前页数据及分页信息。
|
||||
type Pagination struct {
|
||||
Limit int `json:"limit"`
|
||||
Pages int `json:"pages"`
|
||||
CurrentPage int `json:"currentPage"`
|
||||
PrevPage int `json:"prevPage"`
|
||||
NextPage int `json:"nextPage"`
|
||||
Total int64 `json:"total"`
|
||||
Data []map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
func (db *Database) Paginate(obj ...any) (result Pagination, err error) {
|
||||
if len(obj) > 0 {
|
||||
db.Table(obj[0])
|
||||
}
|
||||
var count int64
|
||||
count, err = db.Count()
|
||||
if err != nil || count == 0 {
|
||||
return
|
||||
}
|
||||
if db.Context.LimitOffsetClause.Limit == 0 {
|
||||
db.Limit(15)
|
||||
}
|
||||
if db.Context.LimitOffsetClause.Page == 0 {
|
||||
db.Page(1)
|
||||
}
|
||||
|
||||
res, err := db.Get()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
result.Total = count
|
||||
result.Data = res
|
||||
result.Limit = db.Context.LimitOffsetClause.Limit
|
||||
result.Pages = int(math.Ceil(float64(count) / float64(db.Context.LimitOffsetClause.Limit)))
|
||||
result.CurrentPage = db.Context.LimitOffsetClause.Page
|
||||
result.PrevPage = db.Context.LimitOffsetClause.Page - 1
|
||||
result.NextPage = db.Context.LimitOffsetClause.Page + 1
|
||||
if db.Context.LimitOffsetClause.Page == 1 {
|
||||
result.PrevPage = 1
|
||||
}
|
||||
if db.Context.LimitOffsetClause.Page == result.Pages {
|
||||
result.NextPage = result.Pages
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func (db *Database) WhereSub(column string, operation string, sub builder.WhereSubHandler) *Database {
|
||||
db.Context.WhereClause.WhereSub(column, operation, sub)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereSub(column string, operation string, sub WhereSubHandler) *Database {
|
||||
func (db *Database) OrWhereSub(column string, operation string, sub builder.WhereSubHandler) *Database {
|
||||
db.Context.WhereClause.OrWhereSub(column, operation, sub)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereBuilder(column string, operation string, sub IBuilder) *Database {
|
||||
func (db *Database) WhereBuilder(column string, operation string, sub builder.IBuilder) *Database {
|
||||
db.Context.WhereClause.WhereBuilder(column, operation, sub)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereBuilder(column string, operation string, sub IBuilder) *Database {
|
||||
func (db *Database) OrWhereBuilder(column string, operation string, sub builder.IBuilder) *Database {
|
||||
db.Context.WhereClause.OrWhereBuilder(column, operation, sub)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereNested(handler WhereNestedHandler) *Database {
|
||||
func (db *Database) WhereNested(handler builder.WhereNestedHandler) *Database {
|
||||
db.Context.WhereClause.WhereNested(handler)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereNested(handler WhereNestedHandler) *Database {
|
||||
func (db *Database) OrWhereNested(handler builder.WhereNestedHandler) *Database {
|
||||
db.Context.WhereClause.OrWhereNested(handler)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereIn(column string, value any) *Database {
|
||||
db.Context.WhereClause.whereIn("AND", column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereNotIn(column string, value any) *Database {
|
||||
db.Context.WhereClause.whereIn("AND", column, value, true)
|
||||
db.Context.WhereClause.WhereIn(column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereIn(column string, value any) *Database {
|
||||
db.Context.WhereClause.whereIn("OR", column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereNotIn(column string, value any) *Database {
|
||||
db.Context.WhereClause.whereIn("OR", column, value, true)
|
||||
db.Context.WhereClause.WhereIn(column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereNull(column string) *Database {
|
||||
db.Context.WhereClause.whereNull("AND", column)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereNotNull(column string) *Database {
|
||||
db.Context.WhereClause.whereNull("AND", column, true)
|
||||
db.Context.WhereClause.WhereNull(column)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereNull(column string) *Database {
|
||||
db.Context.WhereClause.whereNull("OR", column)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereNotNull(column string) *Database {
|
||||
db.Context.WhereClause.whereNull("OR", column, true)
|
||||
db.Context.WhereClause.WhereNull(column)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereBetween(column string, value any) *Database {
|
||||
db.Context.WhereClause.whereBetween("AND", column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereNotBetween(column string, value any) *Database {
|
||||
db.Context.WhereClause.whereBetween("AND", column, value, true)
|
||||
db.Context.WhereClause.WhereBetween(column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereBetween(column string, value any) *Database {
|
||||
db.Context.WhereClause.whereBetween("OR", column, value)
|
||||
db.Context.WhereClause.WhereBetween(column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereNotBetween(column string, value any) *Database {
|
||||
db.Context.WhereClause.whereBetween("OR", column, value, true)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereExists(clause IBuilder) {
|
||||
func (db *Database) WhereExists(clause builder.IBuilder) {
|
||||
db.Context.WhereClause.WhereExists(clause)
|
||||
}
|
||||
func (db *Database) WhereNotExists(clause IBuilder) {
|
||||
db.Context.WhereClause.WhereNotExists(clause)
|
||||
}
|
||||
func (db *Database) WhereLike(column, value string) *Database {
|
||||
db.Context.WhereClause.whereLike("AND", column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) WhereNotLike(column, value string) *Database {
|
||||
db.Context.WhereClause.whereLike("AND", column, value, true)
|
||||
db.Context.WhereClause.WhereLike(column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereLike(column, value string) *Database {
|
||||
db.Context.WhereClause.whereLike("OR", column, value)
|
||||
return db
|
||||
}
|
||||
func (db *Database) OrWhereNotLike(column, value string) *Database {
|
||||
db.Context.WhereClause.whereLike("OR", column, value, true)
|
||||
db.Context.WhereClause.OrWhereLike(column, value)
|
||||
return db
|
||||
}
|
||||
//func (db *Database) WhereNotIn(column string, value any) *Database {
|
||||
// db.Context.WhereClause.WhereNotIn(column, value)
|
||||
// return db
|
||||
//}
|
||||
//func (db *Database) OrWhereNotIn(column string, value any) *Database {
|
||||
// db.Context.WhereClause.WhereNotIn(column, value)
|
||||
// return db
|
||||
//}
|
||||
//func (db *Database) WhereNotNull(column string) *Database {
|
||||
// db.Context.WhereClause.whereNull("AND", column, true)
|
||||
// return db
|
||||
//}
|
||||
//func (db *Database) OrWhereNotNull(column string) *Database {
|
||||
// db.Context.WhereClause.whereNull("OR", column, true)
|
||||
// return db
|
||||
//}
|
||||
//func (db *Database) WhereNotBetween(column string, value any) *Database {
|
||||
// db.Context.WhereClause.whereBetween("AND", column, value, true)
|
||||
// return db
|
||||
//}
|
||||
//func (db *Database) OrWhereNotBetween(column string, value any) *Database {
|
||||
// db.Context.WhereClause.whereBetween("OR", column, value, true)
|
||||
// return db
|
||||
//}
|
||||
//func (db *Database) WhereNotExists(clause IBuilder) {
|
||||
// db.Context.WhereClause.WhereNotExists(clause)
|
||||
//}
|
||||
//func (db *Database) WhereNotLike(column, value string) *Database {
|
||||
// db.Context.WhereClause.whereLike("AND", column, value, true)
|
||||
// return db
|
||||
//}
|
||||
//func (db *Database) OrWhereNotLike(column, value string) *Database {
|
||||
// db.Context.WhereClause.whereLike("OR", column, value, true)
|
||||
// return db
|
||||
//}
|
||||
func (db *Database) WhereNot(column any, args ...any) *Database {
|
||||
db.Context.WhereClause.WhereNot(column, args...)
|
||||
return db
|
||||
|
46
toSql.go
46
toSql.go
@@ -3,41 +3,11 @@ package gorose
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gohouse/gorose/v3/builder"
|
||||
"github.com/gohouse/gorose/v3/parser"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
//type TypeToSqlExists struct {
|
||||
// Bindings []any
|
||||
//}
|
||||
//type TypeToSqlPessimisticLocking struct {
|
||||
// LockType string
|
||||
//}
|
||||
//type TypeToSqlAggregate struct {
|
||||
// CallFunc, Column string
|
||||
//}
|
||||
|
||||
type TypeToSqlUpdateCase struct {
|
||||
BindOrData any
|
||||
MustColumn []string
|
||||
}
|
||||
|
||||
//type TypeToSqlDeleteCase struct {
|
||||
// Bind any
|
||||
// MustColumn []string
|
||||
//}
|
||||
|
||||
type TypeToSqlIncDecCase struct {
|
||||
Symbol string
|
||||
Data map[string]any
|
||||
}
|
||||
type TypeToSqlInsertCase struct {
|
||||
IsReplace bool
|
||||
IsIgnoreCase bool
|
||||
OnDuplicateKeys []string
|
||||
UpdateFields []string
|
||||
MustColumn []string
|
||||
}
|
||||
|
||||
func (db *Database) ToSqlSelect() (sql4prepare string, binds []any) {
|
||||
return db.Driver.ToSqlSelect(db.Context)
|
||||
}
|
||||
@@ -79,7 +49,7 @@ func (db *Database) ToSqlExists(bind ...any) (sql4prepare string, values []any,
|
||||
|
||||
func (db *Database) ToSqlAggregate(function, column string) (sql4prepare string, values []any, err error) {
|
||||
var ctx = *db.Context
|
||||
ctx.SelectClause.Columns = append(ctx.SelectClause.Columns, Column{
|
||||
ctx.SelectClause.Columns = append(ctx.SelectClause.Columns, builder.Column{
|
||||
Name: fmt.Sprintf("%s(%s)", function, column),
|
||||
Alias: function,
|
||||
IsRaw: true,
|
||||
@@ -90,11 +60,11 @@ func (db *Database) ToSqlAggregate(function, column string) (sql4prepare string,
|
||||
|
||||
func (db *Database) ToSqlTo(obj any, mustColumn ...string) (sql4prepare string, binds []any, err error) {
|
||||
rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
columns, fieldStruct, _ := StructsParse(obj)
|
||||
columns, fieldStruct, _ := parser.StructsParse(obj)
|
||||
switch rfv.Kind() {
|
||||
case reflect.Struct:
|
||||
var data = make(map[string]any)
|
||||
data, err = structDataToMap(rfv, columns, fieldStruct, mustColumn...)
|
||||
data, err = parser.StructDataToMap(rfv, columns, fieldStruct, mustColumn...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -109,7 +79,7 @@ func (db *Database) ToSqlTo(obj any, mustColumn ...string) (sql4prepare string,
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) ToSqlInsert(obj any, args ...TypeToSqlInsertCase) (sqlSegment string, binds []any, err error) {
|
||||
func (db *Database) ToSqlInsert(obj any, args ...builder.TypeToSqlInsertCase) (sqlSegment string, binds []any, err error) {
|
||||
return db.Driver.ToSqlInsert(db.Context, obj, args...)
|
||||
}
|
||||
func (db *Database) ToSqlDelete(obj any, mustColumn ...string) (sqlSegment string, binds []any, err error) {
|
||||
@@ -117,9 +87,9 @@ func (db *Database) ToSqlDelete(obj any, mustColumn ...string) (sqlSegment strin
|
||||
}
|
||||
|
||||
func (db *Database) ToSqlUpdate(obj any, mustColumn ...string) (sqlSegment string, binds []any, err error) {
|
||||
return db.Driver.ToSqlUpdate(db.Context, TypeToSqlUpdateCase{obj, mustColumn})
|
||||
return db.Driver.ToSqlUpdate(db.Context, builder.TypeToSqlUpdateCase{obj, mustColumn})
|
||||
}
|
||||
func (db *Database) ToSqlIncDec(symbol string, data map[string]any) (sql4prepare string, values []any, err error) {
|
||||
//return db.Driver.ToSqlIncDec(db.Context, symbol, data)
|
||||
return db.Driver.ToSqlUpdate(db.Context, TypeToSqlIncDecCase{symbol, data})
|
||||
return db.Driver.ToSqlUpdate(db.Context, builder.TypeToSqlIncDecCase{symbol, data})
|
||||
}
|
||||
|
158
util.go
158
util.go
@@ -3,10 +3,9 @@ package gorose
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gohouse/gorose/v3/builder"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -14,6 +13,13 @@ import (
|
||||
func init() {
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
}
|
||||
|
||||
func As(table any, alias string) builder.TableClause {
|
||||
return builder.TableClause{
|
||||
Tables: table,
|
||||
Alias: alias,
|
||||
}
|
||||
}
|
||||
func GetRandomInt(num int) int {
|
||||
return rand.Intn(num)
|
||||
}
|
||||
@@ -46,158 +52,16 @@ func GetRandomWeightedIndex(weights []int) int {
|
||||
|
||||
//////////// struct field ptr 4 orm helpers ////////////
|
||||
|
||||
// PtrBool helper
|
||||
func PtrBool(arg bool) *bool {
|
||||
return &arg
|
||||
}
|
||||
|
||||
// PtrString helper
|
||||
func PtrString(arg string) *string {
|
||||
return &arg
|
||||
}
|
||||
|
||||
// PtrInt helper
|
||||
func PtrInt(arg int) *int {
|
||||
return &arg
|
||||
}
|
||||
|
||||
// PtrInt8 helper
|
||||
func PtrInt8(arg int8) *int8 {
|
||||
return &arg
|
||||
}
|
||||
|
||||
// PtrInt16 helper
|
||||
func PtrInt16(arg int16) *int16 {
|
||||
return &arg
|
||||
}
|
||||
|
||||
// PtrInt64 helper
|
||||
func PtrInt64(arg int64) *int64 {
|
||||
return &arg
|
||||
}
|
||||
|
||||
// PtrFloat64 helper
|
||||
func PtrFloat64(arg float64) *float64 {
|
||||
return &arg
|
||||
}
|
||||
|
||||
// PtrTime helper
|
||||
func PtrTime(arg time.Time) *time.Time {
|
||||
func Ptr[T any](arg T) *T {
|
||||
return &arg
|
||||
}
|
||||
|
||||
//////////// sql.Null* type helpers ////////////
|
||||
|
||||
// NullInt64From helper
|
||||
func NullInt64From(arg int64) sql.NullInt64 { return sql.NullInt64{Int64: arg, Valid: true} }
|
||||
|
||||
// NullInt32From helper
|
||||
func NullInt32From(arg int32) sql.NullInt32 { return sql.NullInt32{Int32: arg, Valid: true} }
|
||||
|
||||
// NullInt16From helper
|
||||
func NullInt16From(arg int16) sql.NullInt16 { return sql.NullInt16{Int16: arg, Valid: true} }
|
||||
|
||||
// NullByteFrom helper
|
||||
func NullByteFrom(arg byte) sql.NullByte { return sql.NullByte{Byte: arg, Valid: true} }
|
||||
|
||||
// NullFloat64From helper
|
||||
func NullFloat64From(arg float64) sql.NullFloat64 { return sql.NullFloat64{Float64: arg, Valid: true} }
|
||||
|
||||
// NullBoolFrom helper
|
||||
func NullBoolFrom(arg bool) sql.NullBool { return sql.NullBool{Bool: arg, Valid: true} }
|
||||
|
||||
// NullTimeFrom helper
|
||||
func NullTimeFrom(arg time.Time) sql.NullTime { return sql.NullTime{Time: arg, Valid: true} }
|
||||
|
||||
func ToSlice(arg any) []any {
|
||||
ref := reflect.Indirect(reflect.ValueOf(arg))
|
||||
var res []any
|
||||
switch ref.Kind() {
|
||||
case reflect.Slice:
|
||||
l := ref.Len()
|
||||
v := ref.Slice(0, l)
|
||||
for i := 0; i < l; i++ {
|
||||
res = append(res, v.Index(i).Interface())
|
||||
}
|
||||
default:
|
||||
res = append(res, ref.Interface())
|
||||
}
|
||||
return res
|
||||
}
|
||||
func ToSliceAddressable(arg any) []any {
|
||||
ref := reflect.Indirect(reflect.ValueOf(arg))
|
||||
var res []any
|
||||
switch ref.Kind() {
|
||||
case reflect.Slice:
|
||||
l := ref.Len()
|
||||
v := ref.Slice(0, l)
|
||||
for i := 0; i < l; i++ {
|
||||
res = append(res, v.Index(i).Addr().Interface())
|
||||
}
|
||||
default:
|
||||
res = append(res, ref.Addr().Interface())
|
||||
}
|
||||
return res
|
||||
}
|
||||
func SliceContains(haystack []string, needle string) bool {
|
||||
for _, v := range haystack {
|
||||
if v == needle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func Map[E any, T any](data []E, mapper func(E) T) []T {
|
||||
results := make([]T, 0, len(data))
|
||||
for _, v := range data {
|
||||
results = append(results, mapper(v))
|
||||
}
|
||||
return results
|
||||
func Null[T any](arg T) sql.Null[T] {
|
||||
return sql.Null[T]{V: arg, Valid: true}
|
||||
}
|
||||
|
||||
func NamedSprintf(format string, a ...any) string {
|
||||
return strings.TrimSpace(regexp.MustCompile(`\s{2,}`).ReplaceAllString(fmt.Sprintf(regexp.MustCompile(`:\w+`).ReplaceAllString(format, "%s"), a...), " "))
|
||||
}
|
||||
|
||||
func BackQuotes(arg any) string {
|
||||
var tmp []string
|
||||
if v, ok := arg.(string); ok {
|
||||
split := strings.Split(v, " ")
|
||||
split2 := strings.Split(split[0], ".")
|
||||
if len(split2) > 1 {
|
||||
if split2[1] == "*" {
|
||||
tmp = append(tmp, fmt.Sprintf("`%s`.%s", split2[0], split2[1]))
|
||||
} else {
|
||||
tmp = append(tmp, fmt.Sprintf("`%s`.`%s`", split2[0], split2[1]))
|
||||
}
|
||||
} else {
|
||||
tmp = append(tmp, fmt.Sprintf("`%s`", split2[len(split2)-1]))
|
||||
}
|
||||
tmp = append(tmp, split[1:]...)
|
||||
}
|
||||
return strings.Join(tmp, " ")
|
||||
}
|
||||
|
||||
func SortedMapKeys(data any) (cols []string) {
|
||||
// 从 map 中获取所有的键,并转换为切片
|
||||
keys := reflect.ValueOf(data).MapKeys()
|
||||
|
||||
// 对切片进行排序
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return keys[i].String() < keys[j].String()
|
||||
})
|
||||
|
||||
// 输出排序后的结果
|
||||
for _, key := range keys {
|
||||
cols = append(cols, key.String())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func IsExpression(obj any) (b bool) {
|
||||
rfv := reflect.Indirect(reflect.ValueOf(obj))
|
||||
if rfv.Kind() == reflect.String && strings.Contains(rfv.String(), "?") {
|
||||
b = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
Reference in New Issue
Block a user