2022-04-30 15:53:56 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
|
|
|
|
package gdb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
2022-05-07 15:11:31 +08:00
|
|
|
// WhereBuilder holds multiple where conditions in a group.
|
2022-04-30 15:53:56 +08:00
|
|
|
type WhereBuilder struct {
|
2022-05-06 22:21:43 +08:00
|
|
|
model *Model // A WhereBuilder should be bound to certain Model.
|
2022-04-30 15:53:56 +08:00
|
|
|
whereHolder []WhereHolder // Condition strings for where operation.
|
|
|
|
}
|
|
|
|
|
|
|
|
// WhereHolder is the holder for where condition preparing.
|
|
|
|
type WhereHolder struct {
|
|
|
|
Type string // Type of this holder.
|
|
|
|
Operator int // Operator for this holder.
|
|
|
|
Where interface{} // Where parameter, which can commonly be type of string/map/struct.
|
|
|
|
Args []interface{} // Arguments for where parameter.
|
|
|
|
Prefix string // Field prefix, eg: "user.", "order.".
|
|
|
|
}
|
|
|
|
|
2023-03-28 09:23:08 +08:00
|
|
|
// Builder creates and returns a WhereBuilder. Please note that the builder is chain-safe.
|
2022-04-30 15:53:56 +08:00
|
|
|
func (m *Model) Builder() *WhereBuilder {
|
|
|
|
b := &WhereBuilder{
|
|
|
|
model: m,
|
|
|
|
whereHolder: make([]WhereHolder, 0),
|
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2023-03-28 09:23:08 +08:00
|
|
|
// getBuilder creates and returns a cloned WhereBuilder of current WhereBuilder
|
2022-04-30 15:53:56 +08:00
|
|
|
func (b *WhereBuilder) getBuilder() *WhereBuilder {
|
2022-05-25 21:52:08 +08:00
|
|
|
return b.Clone()
|
2022-04-30 15:53:56 +08:00
|
|
|
}
|
|
|
|
|
2022-05-07 15:11:31 +08:00
|
|
|
// Clone clones and returns a WhereBuilder that is a copy of current one.
|
2022-05-07 14:26:56 +08:00
|
|
|
func (b *WhereBuilder) Clone() *WhereBuilder {
|
2022-04-30 15:53:56 +08:00
|
|
|
newBuilder := b.model.Builder()
|
|
|
|
newBuilder.whereHolder = make([]WhereHolder, len(b.whereHolder))
|
|
|
|
copy(newBuilder.whereHolder, b.whereHolder)
|
|
|
|
return newBuilder
|
|
|
|
}
|
|
|
|
|
2022-05-07 15:11:31 +08:00
|
|
|
// Build builds current WhereBuilder and returns the condition string and parameters.
|
2022-04-30 15:53:56 +08:00
|
|
|
func (b *WhereBuilder) Build() (conditionWhere string, conditionArgs []interface{}) {
|
|
|
|
var (
|
|
|
|
ctx = b.model.GetCtx()
|
|
|
|
autoPrefix = b.model.getAutoPrefix()
|
|
|
|
tableForMappingAndFiltering = b.model.tables
|
|
|
|
)
|
|
|
|
if len(b.whereHolder) > 0 {
|
|
|
|
for _, holder := range b.whereHolder {
|
|
|
|
if holder.Prefix == "" {
|
|
|
|
holder.Prefix = autoPrefix
|
|
|
|
}
|
|
|
|
switch holder.Operator {
|
2022-05-06 22:21:43 +08:00
|
|
|
case whereHolderOperatorWhere, whereHolderOperatorAnd:
|
2022-04-30 15:53:56 +08:00
|
|
|
newWhere, newArgs := formatWhereHolder(ctx, b.model.db, formatWhereHolderInput{
|
|
|
|
WhereHolder: holder,
|
|
|
|
OmitNil: b.model.option&optionOmitNilWhere > 0,
|
|
|
|
OmitEmpty: b.model.option&optionOmitEmptyWhere > 0,
|
|
|
|
Schema: b.model.schema,
|
|
|
|
Table: tableForMappingAndFiltering,
|
|
|
|
})
|
|
|
|
if len(newWhere) > 0 {
|
|
|
|
if len(conditionWhere) == 0 {
|
|
|
|
conditionWhere = newWhere
|
|
|
|
} else if conditionWhere[0] == '(' {
|
|
|
|
conditionWhere = fmt.Sprintf(`%s AND (%s)`, conditionWhere, newWhere)
|
|
|
|
} else {
|
|
|
|
conditionWhere = fmt.Sprintf(`(%s) AND (%s)`, conditionWhere, newWhere)
|
|
|
|
}
|
|
|
|
conditionArgs = append(conditionArgs, newArgs...)
|
|
|
|
}
|
|
|
|
|
|
|
|
case whereHolderOperatorOr:
|
|
|
|
newWhere, newArgs := formatWhereHolder(ctx, b.model.db, formatWhereHolderInput{
|
|
|
|
WhereHolder: holder,
|
|
|
|
OmitNil: b.model.option&optionOmitNilWhere > 0,
|
|
|
|
OmitEmpty: b.model.option&optionOmitEmptyWhere > 0,
|
|
|
|
Schema: b.model.schema,
|
|
|
|
Table: tableForMappingAndFiltering,
|
|
|
|
})
|
|
|
|
if len(newWhere) > 0 {
|
|
|
|
if len(conditionWhere) == 0 {
|
|
|
|
conditionWhere = newWhere
|
|
|
|
} else if conditionWhere[0] == '(' {
|
|
|
|
conditionWhere = fmt.Sprintf(`%s OR (%s)`, conditionWhere, newWhere)
|
|
|
|
} else {
|
|
|
|
conditionWhere = fmt.Sprintf(`(%s) OR (%s)`, conditionWhere, newWhere)
|
|
|
|
}
|
|
|
|
conditionArgs = append(conditionArgs, newArgs...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2022-05-07 14:26:56 +08:00
|
|
|
|
2022-05-07 15:11:31 +08:00
|
|
|
// convertWhereBuilder converts parameter `where` to condition string and parameters if `where` is also a WhereBuilder.
|
|
|
|
func (b *WhereBuilder) convertWhereBuilder(where interface{}, args []interface{}) (newWhere interface{}, newArgs []interface{}) {
|
2022-05-07 14:26:56 +08:00
|
|
|
var builder *WhereBuilder
|
|
|
|
switch v := where.(type) {
|
|
|
|
case WhereBuilder:
|
|
|
|
builder = &v
|
2022-05-25 21:52:08 +08:00
|
|
|
|
2022-05-07 14:26:56 +08:00
|
|
|
case *WhereBuilder:
|
|
|
|
builder = v
|
|
|
|
}
|
|
|
|
if builder != nil {
|
|
|
|
conditionWhere, conditionArgs := builder.Build()
|
2023-07-25 20:13:17 +08:00
|
|
|
if conditionWhere != "" && (len(b.whereHolder) == 0 || len(builder.whereHolder) > 1) {
|
2022-05-07 14:26:56 +08:00
|
|
|
conditionWhere = "(" + conditionWhere + ")"
|
|
|
|
}
|
|
|
|
return conditionWhere, conditionArgs
|
|
|
|
}
|
|
|
|
return where, args
|
|
|
|
}
|