子句系统模块原理说明

基于1.31 本文档深入解析子句系统模块的设计原理和核心原理,阐述 SQL 组件化构建的理论基础。


一、设计原理

1.1 模块定位

在整体架构中的位置

子句系统是 GORM SQL 构建的核心组件化引擎,位于 Statement 层之下,直接负责将用户意图转换为 SQL 片段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌─────────────────────────────────────────────────────────────┐
│ 用户 API 调用 │
│ db.Where("age > ?", 18).Order("name").Limit(10) │
└────────────────────────┬────────────────────────────────────┘
│ 解析意图

┌─────────────────────────────────────────────────────────────┐
│ Statement 层 │
│ Statement.Clauses["WHERE"] = clause.Where{...} │
│ Statement.Clauses["ORDER BY"] = clause.OrderBy{...} │
└────────────────────────┬────────────────────────────────────┘
│ 构建顺序

┌─────────────────────────────────────────────────────────────┐
│ 子句系统 (本模块) ★ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ SELECT │ │ WHERE │ │ JOIN │ │ ORDER │ │
│ │ 子句 │ │ 子句 │ │ 子句 │ │ BY子句 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└────────────────────────┬────────────────────────────────────┘
│ 拼接 SQL

┌─────────────────────────────────────────────────────────────┐
│ 完整 SQL │
│ SELECT * FROM users WHERE age > 18 ORDER BY name LIMIT 10 │
└─────────────────────────────────────────────────────────────┘

核心价值

子句系统的核心价值在于将复杂的 SQL 语句分解为可组合、可复用的组件:

1
2
3
4
5
6
7
8
9
传统 SQL 构建:
sql := "SELECT * FROM users WHERE age > 18 ORDER BY name"
// 难以复用、难以维护、容易出错

子句系统:
select := clause.Select{Columns: []clause.Column{{Name: "*"}}}
where := clause.Where{Exprs: []clause.Expression{...}}
order := clause.OrderBy{Columns: []clause.OrderByColumn{{Column: "name"}}}
// 可组合、可测试、可扩展

1.2 设计目的

问题 1: 如何将复杂的 SQL 分解为可管理的单元?

  • 挑战: SQL 语句各部分有依赖关系(如 SELECT 后才能用 ORDER BY)
  • 挑战: 不同数据库的语法差异(如 LIMIT 用法)
  • 解决方案: 将每个 SQL 关键字抽象为一个 Clause

问题 2: 如何支持灵活的组合和扩展?

  • 挑战: 用户可能需要组合任意子句
  • 挑战: 需要支持数据库特定的语法
  • 解决方案: 定义统一的 Clause 接口,支持自定义实现

问题 3: 如何保证构建顺序的正确性?

  • 挑战: SQL 子句有严格的语法顺序
  • 挑战: 不同操作的子句需求不同(SELECT vs INSERT)
  • 解决方案: BuildClauses 数组定义构建顺序

1.3 结构安排依据

3 天学习时间的分配逻辑

1
2
3
4
5
6
7
8
9
10
11
Day 1: Clause 接口体系
目标: 理解组件化的设计思想
重点: Interface、Builder、Writer

Day 2: 常用子句分析
目标: 理解各类子句的实现
重点: SELECT、WHERE、JOIN

Day 3: 高级子句实现
目标: 理解复杂子句和自定义
重点: INSERT/UPDATE、自定义子句

由抽象到具体的学习路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
第 1 层: 接口抽象
├─ Clause Interface
├─ Builder Interface
└─ Expression Interface

第 2 层: 基础实现
├─ Select
├─ Where
└─ Order By

第 3 层: 复杂实现
├─ Join
├─ On Conflict
└─ Locking

第 4 层: 自定义扩展
└─ 实现 Clause Interface

1.4 与其他模块的逻辑关系

依赖关系

  • 依赖 Schema: 子句构建需要字段的数据库列名
  • 依赖 Dialector: 占位符、引号等需要数据库特定处理

支撑关系

  • 支撑查询构建: 查询 API 通过添加子句来构建 SQL
  • 支撑回调系统: 回调中可以修改子句来影响 SQL

二、核心原理

2.1 关键概念

概念 1: Clause 接口

定义: Clause 是所有 SQL 子句的抽象接口,定义了子句的核心行为。

1
2
3
4
5
type Interface interface {
Name() string // 子句名称,如 "WHERE"
Build(Builder) // 构建子句 SQL
MergeClause(*Clause) // 合并子句配置
}

设计原理:

1
2
3
4
5
6
7
8
9
10
11
12
接口最小化原则:
┌─────────────────────────────────────┐
│ Clause Interface │
│ ┌──────────┐ ┌──────────┐ │
│ │ Name() │ │ Build() │ │ 核心方法
│ └──────────┘ └──────────┘ │
│ │
│ 子类实现: │
│ ├─ Where.Name() = "WHERE" │
│ ├─ Where.Build() = 构建 WHERE 部分 │
│ └─ OrderBy.Name() = "ORDER BY" │
└─────────────────────────────────────┘

Clause 结构体:

1
2
3
4
5
6
7
8
type Clause struct {
Name string // 子句名称
BeforeExpression Expression // 前置表达式
AfterNameExpression Expression // 名称后表达式
AfterExpression Expression // 后置表达式
Expression Expression // 主表达式
Builder ClauseBuilder // 自定义构建器
}

学习要点:

  • Interface 定义契约,具体实现由各子句类型提供
  • Name() 返回 SQL 关键字(大写)
  • Build() 负责生成 SQL 字符串和参数

Clause 接口完整解析 (clause.go:3-90)

完整定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Interface 子句接口,定义了所有 SQL 子句必须实现的方法
type Interface interface {
Name() string // 返回子句名称,如 "WHERE"、"SELECT"
Build(Builder) // 构建 SQL 子句
MergeClause(*Clause) // 合并子句配置
}

// ClauseBuilder 子句构建器函数类型
// 允许自定义子句的构建逻辑
type ClauseBuilder func(Clause, Builder)

// Writer 写入器接口,提供基础的写入能力
type Writer interface {
WriteByte(byte) error // 写入单个字节
WriteString(string) (int, error) // 写入字符串,返回写入的字节数
}

// Builder 构建器接口,继承 Writer 并添加更多功能
type Builder interface {
Writer // 继承写入接口
WriteQuoted(field interface{}) // 写入带引号的标识符
AddVar(Writer, ...interface{}) // 添加变量到参数列表
AddError(error) error // 添加错误
}

// Clause 子句结构体
type Clause struct {
Name string // 子句名称: "WHERE"
BeforeExpression Expression // 名称前的表达式
AfterNameExpression Expression // 名称后的表达式
AfterExpression Expression // 名称后的表达式
Expression Expression // 主表达式
Builder ClauseBuilder // 自定义构建器函数
}

接口方法说明:

方法 作用 返回值 使用场景
Name() 获取子句名称 string 用于标识和排序子句
Build() 构建 SQL 生成 SQL 字符串和参数
MergeClause() 合并子句 合并多个相同类型的子句

Clause.Build() 完整实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Build 构建子句 SQL
func (c Clause) Build(builder Builder) {
// 1. 如果有自定义构建器,优先使用
if c.Builder != nil {
c.Builder(c, builder) // 调用自定义构建函数
return
}

// 2. 如果有表达式,按标准流程构建
if c.Expression != nil {
// 2.1 构建名称前的表达式
if c.BeforeExpression != nil {
c.BeforeExpression.Build(builder)
builder.WriteByte(' ') // 添加空格
}

// 2.2 写入子句名称
if c.Name != "" {
builder.WriteString(c.Name) // 如 "WHERE"
builder.WriteByte(' ') // 添加空格
}

// 2.3 构建名称后的表达式
if c.AfterNameExpression != nil {
c.AfterNameExpression.Build(builder)
builder.WriteByte(' ')
}

// 2.4 构建主表达式
c.Expression.Build(builder)

// 2.5 构建后置表达式
if c.AfterExpression != nil {
builder.WriteByte(' ')
c.AfterExpression.Build(builder)
}
}
}

Column 和 Table 结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Column 列结构,表示数据库中的列
type Column struct {
Table string // 表名
Name string // 列名
Alias string // 别名
Raw bool // 是否为原始 SQL (不添加引号)
}

// Table 表结构,表示数据库中的表
type Table struct {
Name string // 表名
Alias string // 别名
Raw bool // 是否为原始 SQL (不添加引号)
}

// 特殊常量
const (
PrimaryKey string = "~~~py~~~" // 主键占位符
CurrentTable string = "~~~ct~~~" // 当前表占位符
Associations string = "~~~as~~~" // 关联占位符
)

// 预定义的常用结构
var (
currentTable = Table{Name: CurrentTable} // 当前表引用
PrimaryColumn = Column{Table: CurrentTable, Name: PrimaryKey} // 主键列引用
)

Clause 构建流程图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Clause.Build(builder)


[有自定义构建器?]
Builder != nil?

├─ Yes ──► 调用 c.Builder(c, builder)
│ 返回

└─ No


[有表达式?]
Expression != nil?

├─ No ──► 返回 (无操作)

└─ Yes


[构建 BeforeExpression]
if BeforeExpression != nil

├─► Build(builder)
└─► WriteByte(' ')


[写入子句名称]
if Name != ""

├─► WriteString(Name) // "WHERE"
└─► WriteByte(' ')


[构建 AfterNameExpression]
if AfterNameExpression != nil

├─► Build(builder)
└─► WriteByte(' ')


[构建主表达式]
Expression.Build(builder)


[构建 AfterExpression]
if AfterExpression != nil

├─► WriteByte(' ')
└─► Build(builder)


返回

MergeClause 的作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// MergeClause 合并子句配置
// 当多次调用同一个子句时,需要合并配置而不是覆盖
func (where Where) MergeClause(clause *Clause) {
// 1. 检查是否已存在相同类型的子句
if w, ok := clause.Expression.(Where); ok {
// 2. 合并表达式列表
exprs := make([]Expression, len(w.Exprs)+len(where.Exprs))
copy(exprs, w.Exprs) // 复制原有表达式
copy(exprs[len(w.Exprs):], where.Exprs) // 追加新表达式
where.Exprs = exprs
}

// 3. 更新子句表达式
clause.Expression = where
}

概念 2: Builder 接口

定义: Builder 是 SQL 构建器的抽象,提供写入 SQL 和变量的能力。

1
2
3
4
5
6
7
8
9
10
11
type Builder interface {
Writer // 继承写入接口
WriteQuoted(field interface{}) // 写入带引号的标识符
AddVar(Writer, ...interface{}) // 添加变量
AddError(error) error // 添加错误
}

type Writer interface {
WriteByte(byte) error
WriteString(string) (int, error)
}

设计原理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Builder 的职责分解:

1. Writer (基础写入)
└─ 直接写入字符串到 SQL buffer

2. WriteQuoted (标识符处理)
└─ 根据数据库规则添加引号
└─ MySQL: `column`
└─ PostgreSQL: "column"

3. AddVar (变量处理)
└─ 将变量添加到 Vars 数组
└─ 写入占位符
└─ MySQL: ?
└─ PostgreSQL: $1

实现示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Statement 实现了 Builder 接口
func (stmt *Statement) WriteQuoted(field interface{}) {
switch v := field.(type) {
case clause.Column:
stmt.QuoteTo(&stmt.SQL, v.Name)
case string:
stmt.QuoteTo(&stmt.SQL, v)
}
}

func (stmt *Statement) AddVar(writer Writer, vars ...interface{}) {
for _, v := range vars {
switch val := v.(type) {
case clause.Expression:
val.Build(stmt) // 表达式直接构建
default:
stmt.Vars = append(stmt.Vars, val)
stmt.DB.Dialector.BindVarTo(stmt, stmt, val)
}
}
}

概念 3: Expression 表达式

定义: Expression 是 SQL 表达式的抽象,可以是一个值、一个字段、或一个复杂表达式。

1
2
3
type Expression interface {
Build(Builder) // 构建表达式
}

常用表达式类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 1. 原始表达式 (Expr)
type Expr struct {
SQL string // SQL 模板
Vars []interface{} // 变量
}

func (expr Expr) Build(builder Builder) {
// 替换 SQL 中的占位符
// 处理变量绑定
}

// 2. 命名表达式 (NamedExpr)
type NamedExpr struct {
SQL string
Vars []interface{}
}

// 3. 等值表达式 (Eq)
type Eq struct {
Column interface{}
Value interface{}
}

func (eq Eq) Build(builder Builder) {
builder.WriteQuoted(eq.Column)
builder.WriteString(" = ")
builder.AddVar(builder, eq.Value)
}

// 4. 逻辑表达式
type And []Expression
type Or []Expression
type Not Expression

表达式组合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 简单表达式
clause.Eq{"name": "John"}
// SQL: name = 'John'

// 复合表达式
clause.And(
clause.Eq{"age": 18},
clause.Gt{"score": 80},
)
// SQL: (age = 18) AND (score > 80)

// 嵌套表达式
clause.Or(
clause.And(clause.Eq{"age": 18}, clause.Eq{"status": "active"}),
clause.Eq{"vip": true},
)
// SQL: ((age = 18) AND (status = 'active')) OR (vip = true)

Expression 表达式完整解析 (expression.go:10-386)

完整定义:

1
2
3
4
5
6
7
8
9
10
// Expression 表达式接口
type Expression interface {
Build(builder Builder) // 构建表达式
}

// NegationExpressionBuilder 否定表达式构建器接口
// 用于实现 NOT 逻辑
type NegationExpressionBuilder interface {
NegationBuild(builder Builder) // 构建否定表达式
}

Expr 原始表达式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// Expr 原始 SQL 表达式
type Expr struct {
SQL string // SQL 模板字符串
Vars []interface{} // 变量列表
WithoutParentheses bool // 是否不加括号
}

// Build 构建原始表达式
func (expr Expr) Build(builder Builder) {
var (
afterParenthesis bool // 是否在括号后
idx int // 当前变量索引
)

// 1. 遍历 SQL 字符串的每个字节
for _, v := range []byte(expr.SQL) {
if v == '?' && len(expr.Vars) > idx {
// 2. 遇到占位符,替换为变量
if afterParenthesis || expr.WithoutParentheses {
// 2.1 特殊处理:展开切片或处理 Valuer
if _, ok := expr.Vars[idx].(driver.Valuer); ok {
builder.AddVar(builder, expr.Vars[idx])
} else {
switch rv := reflect.ValueOf(expr.Vars[idx]); rv.Kind() {
case reflect.Slice, reflect.Array:
// 2.1.1 展开切片为多个变量
if rv.Len() == 0 {
builder.AddVar(builder, nil)
} else {
for i := 0; i < rv.Len(); i++ {
if i > 0 {
builder.WriteByte(',')
}
builder.AddVar(builder, rv.Index(i).Interface())
}
}
default:
builder.AddVar(builder, expr.Vars[idx])
}
}
} else {
builder.AddVar(builder, expr.Vars[idx])
}
idx++
} else {
// 3. 直接写入字符
if v == '(' {
afterParenthesis = true
} else {
afterParenthesis = false
}
builder.WriteByte(v)
}
}

// 4. 处理剩余的变量
if idx < len(expr.Vars) {
for _, v := range expr.Vars[idx:] {
builder.AddVar(builder, sql.NamedArg{Value: v})
}
}
}

比较表达式类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Eq 等于表达式
type Eq struct {
Column interface{}
Value interface{}
}

func (eq Eq) Build(builder Builder) {
builder.WriteQuoted(eq.Column)

switch eq.Value.(type) {
case []string, []int, []int32, []int64, []uint, []uint32, []uint64, []interface{}:
// 数组值转换为 IN 查询
rv := reflect.ValueOf(eq.Value)
if rv.Len() == 0 {
builder.WriteString(" IN (NULL)")
} else {
builder.WriteString(" IN (")
for i := 0; i < rv.Len(); i++ {
if i > 0 {
builder.WriteByte(',')
}
builder.AddVar(builder, rv.Index(i).Interface())
}
builder.WriteByte(')')
}
default:
if eqNil(eq.Value) {
builder.WriteString(" IS NULL")
} else {
builder.WriteString(" = ")
builder.AddVar(builder, eq.Value)
}
}
}

// Neq 不等于表达式
type Neq Eq

func (neq Neq) Build(builder Builder) {
builder.WriteQuoted(neq.Column)
// 类似 Eq,但生成 <> 或 IS NOT NULL
}

// Gt 大于表达式
type Gt Eq

func (gt Gt) Build(builder Builder) {
builder.WriteQuoted(gt.Column)
builder.WriteString(" > ")
builder.AddVar(builder, gt.Value)
}

// Gte 大于等于表达式
type Gte Eq

func (gte Gte) Build(builder Builder) {
builder.WriteQuoted(gte.Column)
builder.WriteString(" >= ")
builder.AddVar(builder, gte.Value)
}

// Lt 小于表达式
type Lt Eq

func (lt Lt) Build(builder Builder) {
builder.WriteQuoted(lt.Column)
builder.WriteString(" < ")
builder.AddVar(builder, lt.Value)
}

// Lte 小于等于表达式
type Lte Eq

func (lte Lte) Build(builder Builder) {
builder.WriteQuoted(lte.Column)
builder.WriteString(" <= ")
builder.AddVar(builder, lte.Value)
}

// Like 模糊匹配表达式
type Like Eq

func (like Like) Build(builder Builder) {
builder.WriteQuoted(like.Column)
builder.WriteString(" LIKE ")
builder.AddVar(builder, like.Value)
}

// IN 表达式
type IN struct {
Column interface{}
Values []interface{}
}

func (in IN) Build(builder Builder) {
builder.WriteQuoted(in.Column)

switch len(in.Values) {
case 0:
builder.WriteString(" IN (NULL)")
case 1:
// 单个值转换为 =
if _, ok := in.Values[0].([]interface{}); !ok {
builder.WriteString(" = ")
builder.AddVar(builder, in.Values[0])
break
}
fallthrough
default:
builder.WriteString(" IN (")
builder.AddVar(builder, in.Values...)
builder.WriteByte(')')
}
}

逻辑表达式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// And 逻辑与表达式
func And(exprs ...Expression) Expression {
if len(exprs) == 0 {
return nil
}
if len(exprs) == 1 {
if _, ok := exprs[0].(OrConditions); !ok {
return exprs[0]
}
}
return AndConditions{Exprs: exprs}
}

type AndConditions struct {
Exprs []Expression
}

func (and AndConditions) Build(builder Builder) {
if len(and.Exprs) > 1 {
builder.WriteByte('(')
buildExprs(and.Exprs, builder, " AND ")
builder.WriteByte(')')
} else {
buildExprs(and.Exprs, builder, " AND ")
}
}

// Or 逻辑或表达式
func Or(exprs ...Expression) Expression {
if len(exprs) == 0 {
return nil
}
return OrConditions{Exprs: exprs}
}

type OrConditions struct {
Exprs []Expression
}

func (or OrConditions) Build(builder Builder) {
if len(or.Exprs) > 1 {
builder.WriteByte('(')
buildExprs(or.Exprs, builder, " OR ")
builder.WriteByte(')')
} else {
buildExprs(or.Exprs, builder, " OR ")
}
}

// Not 逻辑非表达式
func Not(exprs ...Expression) Expression {
if len(exprs) == 0 {
return nil
}
if len(exprs) == 1 {
if andCondition, ok := exprs[0].(AndConditions); ok {
exprs = andCondition.Exprs
}
}
return NotConditions{Exprs: exprs}
}

type NotConditions struct {
Exprs []Expression
}

func (not NotConditions) Build(builder Builder) {
// 检查是否有实现了 NegationBuild 的表达式
anyNegationBuilder := false
for _, c := range not.Exprs {
if _, ok := c.(NegationExpressionBuilder); ok {
anyNegationBuilder = true
break
}
}

if anyNegationBuilder {
// 使用 NegationBuild
if len(not.Exprs) > 1 {
builder.WriteByte('(')
}
for idx, c := range not.Exprs {
if idx > 0 {
builder.WriteString(" AND ")
}
if negationBuilder, ok := c.(NegationExpressionBuilder); ok {
negationBuilder.NegationBuild(builder)
} else {
builder.WriteString("NOT ")
c.Build(builder)
}
}
if len(not.Exprs) > 1 {
builder.WriteByte(')')
}
} else {
// 使用 NOT 前缀
builder.WriteString("NOT ")
if len(not.Exprs) > 1 {
builder.WriteByte('(')
}
for idx, c := range not.Exprs {
if idx > 0 {
switch c.(type) {
case OrConditions:
builder.WriteString(" OR ")
default:
builder.WriteString(" AND ")
}
}
c.Build(builder)
}
if len(not.Exprs) > 1 {
builder.WriteByte(')')
}
}
}

表达式构建流程图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
表达式构建流程

Expression.Build(builder)


[表达式类型判断]

├─► Expr (原始 SQL)
│ │
│ └─► 遍历 SQL 字符串
│ ├─► 遇到 '?' ──► AddVar(vars[idx++])
│ └─► 其他字符 ──► WriteByte(c)

├─► Eq (等于)
│ │
│ ├─► WriteQuoted(Column)
│ ├─► 检查 Value 类型
│ │ ├─► 切片 ──► IN (...)
│ │ ├─► nil ──► IS NULL
│ │ └─► 其他 ──► = ?
│ └─► AddVar(Value)

├─► AndConditions (逻辑与)
│ │
│ ├─► 多个表达式? ──Yes──► WriteByte('(')
│ │ │
│ │ └─► 遍历 Exprs
│ │ ├─► Build(expr)
│ │ ├─► i > 0? ──► WriteString(" AND ")
│ │ └─► i++
│ │
│ └─► 多个表达式? ──Yes──► WriteByte(')')

├─► OrConditions (逻辑或)
│ │ (类似 And,但使用 " OR ")

└─► NotConditions (逻辑非)
│ (见上述详细流程)

Where 子句完整解析 (where.go:12-246)

完整定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Where WHERE 子句
type Where struct {
Exprs []Expression // 条件表达式列表
}

// Name 返回子句名称
func (where Where) Name() string {
return "WHERE"
}

// Build 构建 WHERE 子句
func (where Where) Build(builder Builder) {
// 1. 如果只有一个表达式且是 AndConditions,展开它
if len(where.Exprs) == 1 {
if andCondition, ok := where.Exprs[0].(AndConditions); ok {
where.Exprs = andCondition.Exprs
}
}

// 2. 调整位置:如果是单个 Or 条件,移到前面
for idx, expr := range where.Exprs {
if v, ok := expr.(OrConditions); !ok || len(v.Exprs) > 1 {
if idx != 0 {
where.Exprs[0], where.Exprs[idx] = where.Exprs[idx], where.Exprs[0]
}
break
}
}

// 3. 构建表达式列表
buildExprs(where.Exprs, builder, " AND ")
}

buildExprs 辅助函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// buildExprs 构建表达式列表
func buildExprs(exprs []Expression, builder Builder, joinCond string) {
wrapInParentheses := false // 是否需要括号

for idx, expr := range exprs {
// 1. 添加连接符
if idx > 0 {
if v, ok := expr.(OrConditions); ok && len(v.Exprs) == 1 {
builder.WriteString(" OR ")
} else {
builder.WriteString(joinCond) // 通常是 " AND "
}
}

// 2. 判断是否需要括号
if len(exprs) > 1 {
switch v := expr.(type) {
case OrConditions:
if len(v.Exprs) == 1 {
if e, ok := v.Exprs[0].(Expr); ok {
sql := strings.ToUpper(e.SQL)
wrapInParentheses = strings.Contains(sql, " AND ") ||
strings.Contains(sql, " OR ")
}
}
case AndConditions:
if len(v.Exprs) == 1 {
if e, ok := v.Exprs[0].(Expr); ok {
sql := strings.ToUpper(e.SQL)
wrapInParentheses = strings.Contains(sql, " AND ") ||
strings.Contains(sql, " OR ")
}
}
case Expr:
sql := strings.ToUpper(v.SQL)
wrapInParentheses = strings.Contains(sql, " AND ") ||
strings.Contains(sql, " OR ")
case NamedExpr:
sql := strings.ToUpper(v.SQL)
wrapInParentheses = strings.Contains(sql, " AND ") ||
strings.Contains(sql, " OR ")
}
}

// 3. 构建表达式
if wrapInParentheses {
builder.WriteByte('(')
expr.Build(builder)
builder.WriteByte(')')
wrapInParentheses = false
} else {
expr.Build(builder)
}
}
}

Where 子句构建示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 示例 1: 简单条件
where := clause.Where{
Exprs: []clause.Expression{
clause.Eq{"age": 18},
},
}
// SQL: WHERE age = 18

// 示例 2: AND 条件
where := clause.Where{
Exprs: []clause.Expression{
clause.Eq{"status": "active"},
clause.Gt{"score": 80},
},
}
// SQL: WHERE status = 'active' AND score > 80

// 示例 3: OR 条件
where := clause.Where{
Exprs: []clause.Expression{
clause.Or(
clause.Eq{"status": "active"},
clause.Eq{"vip": true},
),
},
}
// SQL: WHERE (status = 'active' OR vip = true)

// 示例 4: 复合条件
where := clause.Where{
Exprs: []clause.Expression{
clause.And(
clause.Eq{"age": 18},
clause.Gt{"score": 80},
),
clause.Eq{"status": "active"},
},
}
// SQL: WHERE (age = 18 AND score > 80) AND status = 'active'

MergeClause 完整实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// MergeClause 合并 WHERE 子句
func (where Where) MergeClause(clause *Clause) {
// 1. 检查是否已存在 WHERE 子句
if w, ok := clause.Expression.(Where); ok {
// 2. 合并表达式列表
exprs := make([]Expression, len(w.Exprs)+len(where.Exprs))
copy(exprs, w.Exprs) // 复制原有表达式
copy(exprs[len(w.Exprs):], where.Exprs) // 追加新表达式
where.Exprs = exprs
}

// 3. 更新子句表达式
clause.Expression = where
}

WHERE 子句流程图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Where.Build(builder)


[只有一个表达式?]
len(Exprs) == 1?

├─ Yes ──► 是 AndConditions? ──Yes──► 展开为多个表达式


[调整 Or 位置]
将单个 Or 条件移到前面


[调用 buildExprs]

├─► 遍历表达式
│ │
│ ├─► 添加连接符 (AND/OR)
│ │
│ ├─► 检查是否需要括号
│ │ └─► 表达式包含 AND/OR ──► wrapInParentheses = true
│ │
│ └─► 构建表达式
│ ├─► wrapInParentheses? ──Yes──► ( expr )
│ └─► No ──► expr


返回

2.2 理论基础

理论 1: 组合模式在子句系统中的应用

模式定义: 将对象组合成树形结构以表示”部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性。

在子句系统中的体现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Expression 的组合层次:

Expression (接口)

├─ Expr (叶子)
│ └─ "age > ?"

├─ And (组合)
│ ├─ Eq{"age": 18}
│ └─ Gt{"score": 80}

└─ Or (组合)
├─ And{...}
└─ Eq{"vip": true}

构建时的递归处理:
Build(Or) {
Write("(")
Build(And) // 递归
Write(") OR (")
Build(Eq) // 递归
Write(")")
}

优势:

  • 可以无限嵌套
  • 统一的 Build 接口
  • 类型安全的组合

理论 2: 访问者模式在构建中的应用

模式定义: 在不改变集合元素的前提下,为一个对象集合上的元素定义新的操作。

在子句构建中的体现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Builder 作为访问者:
┌──────────────────────────────────────┐
│ Builder (访问者) │
│ ┌────────────────────────────────┐ │
│ │ Visit(Clause) → Build() │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────┘
│ 访问

┌──────────────────────────────────────┐
│ Clause (元素) │
│ Accept(Builder) { │
│ Build(Builder) │
│ } │
└──────────────────────────────────────┘

代码体现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Builder 遍历所有子句
for _, name := range stmt.BuildClauses {
if c, ok := stmt.Clauses[name]; ok {
c.Build(stmt) // 调用子句的 Build 方法
}
}

// 每个 Clause 实现自己的 Build 逻辑
func (where Where) Build(builder Builder) {
builder.WriteString("WHERE ")
for _, expr := range where.Exprs {
expr.Build(builder) // 表达式也实现 Build
}
}

理论 3: 模板方法模式

模式定义: 在父类中定义算法的骨架,将某些步骤延迟到子类实现。

在 Clause.Build 中的体现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Clause 的 Build 定义了构建框架
func (c Clause) Build(builder Builder) {
if c.Builder != nil {
c.Builder(c, builder) // 自定义构建器优先
} else if c.Expression != nil {
// 标准构建流程
if c.BeforeExpression != nil {
c.BeforeExpression.Build(builder)
builder.WriteByte(' ')
}

if c.Name != "" {
builder.WriteString(c.Name)
builder.WriteByte(' ')
}

c.Expression.Build(builder)

if c.AfterExpression != nil {
builder.WriteByte(' ')
c.AfterExpression.Build(builder)
}
}
}

优势:

  • 统一的构建流程
  • 支持自定义扩展
  • 灵活的位置控制

2.3 学习方法

方法 1: 逆向工程法

步骤:

  1. 从一个完整的 SQL 开始
  2. 分解为子句
  3. 找到对应的 Clause 实现
  4. 追踪 Build 过程

示例:

1
2
-- 目标 SQL
SELECT id, name FROM users WHERE age > 18 ORDER BY name DESC LIMIT 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
-- 分解为子句
stmt.Clauses = map[string]clause.Clause{
"SELECT": {
Name: "SELECT",
Expression: clause.Select{
Columns: []clause.Column{
{Name: "id"},
{Name: "name"},
},
},
},
"FROM": {
Name: "FROM",
Expression: clause.From{Tables: []clause.Table{{Name: "users"}}},
},
"WHERE": {
Name: "WHERE",
Expression: clause.Where{
Exprs: []clause.Expression{
clause.Expr{SQL: "age > ?", Vars: []interface{}{18}},
},
},
},
"ORDER BY": {
Name: "ORDER BY",
Expression: clause.OrderBy{
Columns: []clause.OrderByColumn{
{Column: clause.Column{Name: "name"}, Desc: true},
},
},
},
"LIMIT": {
Name: "LIMIT",
Expression: clause.Limit{Limit: 10},
},
}

方法 2: 对比分析法

对比不同子句的构建方式:

子句 结构 关键字段 Build 特点
SELECT Select{Columns} Columns 逗号分隔列名
WHERE Where{Exprs} Exprs AND 连接表达式
JOIN Join{Table, ON} Table, ON 复杂的 ON 条件
ORDER BY OrderBy{Columns} Columns 支持 ASC/DESC
LIMIT Limit{Limit, Offset} Limit, Offset 简单数值

对比不同数据库的差异:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// MySQL 的 LIMIT
LIMIT 10 OFFSET 20

// PostgreSQL 的 LIMIT
LIMIT 10 OFFSET 20
-- 或
LIMIT 10 OFFSET 20

// SQL Server 的 LIMIT (TOP)
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY

// Oracle 的 LIMIT (ROWNUM)
-- 或 FETCH FIRST
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY

方法 3: 实验验证法

实验 1: 追踪 Build 过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 自定义 Builder 记录构建过程
type TracingBuilder struct {
gorm.Statement
trace []string
}

func (b *TracingBuilder) WriteString(str string) (int, error) {
b.trace = append(b.trace, fmt.Sprintf("WriteString: %q", str))
return b.Statement.WriteString(str)
}

func (b *TracingBuilder) AddVar(writer Writer, vars ...interface{}) {
b.trace = append(b.trace, fmt.Sprintf("AddVar: %v", vars))
b.Statement.AddVar(writer, vars...)
}

// 使用
stmt := &TracingBuilder{...}
stmt.Clauses["WHERE"].Build(stmt)

// 查看追踪
for _, entry := range stmt.trace {
fmt.Println(entry)
}

实验 2: 自定义子句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 实现 TOP 子句 (SQL Server)
type Top struct {
N int
}

func (t Top) Name() string {
return "TOP"
}

func (t Top) Build(builder Builder) {
builder.WriteString(fmt.Sprintf("TOP (%d) ", t.N))
}

func (t Top) MergeClause(c *Clause) {
c.Expression = t
}

// 使用
db.Clauses(clause.Top{N: 10}).Find(&users)
// 生成: SELECT TOP (10) * FROM users

2.4 实施策略

策略 1: 分层学习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
第 1 层: 接口层 (Day 1)
目标: 理解接口设计
内容:
- Clause Interface
- Builder Interface
- Expression Interface

第 2 层: 实现层 (Day 2)
目标: 理解具体实现
内容:
- 基础子句 (SELECT, WHERE)
- 复杂子句 (JOIN, ON CONFLICT)
- 对比不同实现

第 3 层: 扩展层 (Day 3)
目标: 掌握自定义扩展
内容:
- 实现自定义子句
- 实现自定义表达式
- 集成到查询流程

策略 2: 问题驱动

问题序列:

  1. 为什么需要子句系统?

    • 对比字符串拼接和子句系统
    • 理解组件化的价值
  2. 子句如何组合?

    • 测试不同子句的组合
    • 观察构建顺序的影响
  3. 如何自定义子句?

    • 实现一个简单子句
    • 测试与现有子句的协作

策略 3: 验证反馈

验证点 1: 理解验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func TestClauseBuild(t *testing.T) {
stmt := &gorm.Statement{...}

// 构建 WHERE 子句
where := clause.Where{
Exprs: []clause.Expression{
clause.Expr{SQL: "age > ?", Vars: []interface{}{18}},
},
}
where.Build(stmt)

assert.Equal(t, "WHERE age > ?", stmt.SQL.String())
assert.Equal(t, []interface{}{18}, stmt.Vars)
}

验证点 2: 组合验证

1
2
3
4
5
6
7
8
9
10
11
12
13
func TestClauseComposition(t *testing.T) {
stmt := &gorm.Statement{...}

// 组合多个表达式
expr := clause.And(
clause.Eq{"status": "active"},
clause.Gt{"score": 80},
)
expr.Build(stmt)

expected := "(status = 'active') AND (score > 80)"
assert.Equal(t, expected, stmt.SQL.String())
}

三、学习路径建议

3.1 前置知识检查

知识点 要求 检验方式
SQL 语法 熟悉 DML、DDL 能写出复杂查询
接口设计 理解接口组合 能设计简单接口
设计模式 了解组合模式 能识别应用场景
字符串处理 理解 Builder 模式 能实现简单 Builder

3.2 学习时间分配

内容 理论 实践 产出
Day 1: 接口体系 2h 1.5h 接口图
Day 2: 子句实现 1.5h 2h 对比表
Day 3: 自定义扩展 1.5h 2h 自定义子句

3.3 学习成果验收

理论验收:

  • 能解释 Clause 接口的设计
  • 能说明 Builder 的职责
  • 能区分不同的 Expression 类型

实践验收:

  • 能使用子句构建查询
  • 能实现自定义表达式
  • 能实现自定义子句

四、实战代码示例

4.1 基础子句使用示例

示例 1: SELECT 子句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package main

import (
"fmt"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)

type User struct {
ID uint
Name string
Email string
Age int
}

func main() {
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})

// 1. 查询所有列
var users1 []User
db.Find(&users1)
// SQL: SELECT * FROM users

// 2. 指定列
var users2 []User
db.Select("id", "name").Find(&users2)
// SQL: SELECT id, name FROM users

// 3. 使用子句结构
var users3 []User
db.Clauses(clause.Select{
Columns: []clause.Column{
{Name: "id"},
{Name: "name"},
},
}).Find(&users3)
// SQL: SELECT id, name FROM users

// 4. DISTINCT 查询
var ages []int
db.Distinct("age").Pluck("age", &ages)
// SQL: SELECT DISTINCT age FROM users

// 5. 带别名的列
var users4 []User
db.Select("id as user_id", "name").Find(&users4)
// SQL: SELECT id as user_id, name FROM users
}

示例 2: WHERE 子句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 1. 简单条件
db.Where("age > ?", 18).Find(&users)
// SQL: SELECT * FROM users WHERE age > 18

// 2. 使用 Eq 表达式
db.Where(clause.Eq{"status": "active"}).Find(&users)
// SQL: SELECT * FROM users WHERE status = 'active'

// 3. 多个条件 (AND)
db.Where(
clause.And(
clause.Eq{"status": "active"},
clause.Gt{"age": 18},
),
).Find(&users)
// SQL: SELECT * FROM users WHERE (status = 'active' AND age > 18)

// 4. OR 条件
db.Where(
clause.Or(
clause.Eq{"status": "active"},
clause.Eq{"vip": true},
),
).Find(&users)
// SQL: SELECT * FROM users WHERE (status = 'active' OR vip = true)

// 5. 复杂条件
db.Where(
clause.Or(
clause.And(
clause.Eq{"age": 18},
clause.Eq{"status": "active"},
),
clause.Eq{"vip": true},
),
).Find(&users)
// SQL: SELECT * FROM users WHERE ((age = 18 AND status = 'active') OR vip = true)

// 6. NOT 条件
db.Where(
clause.Not(
clause.Eq{"status": "deleted"},
),
).Find(&users)
// SQL: SELECT * FROM users WHERE NOT (status = 'deleted')

示例 3: ORDER BY 子句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1. 单列升序
db.Order("name").Find(&users)
// SQL: SELECT * FROM users ORDER BY name

// 2. 单列降序
db.Order("name desc").Find(&users)
// SQL: SELECT * FROM users ORDER BY name DESC

// 3. 使用子句结构
db.Clauses(clause.OrderBy{
Columns: []clause.OrderByColumn{
{Column: clause.Column{Name: "age"}, Desc: true},
},
}).Find(&users)
// SQL: SELECT * FROM users ORDER BY age DESC

// 4. 多列排序
db.Order("age desc").Order("name asc").Find(&users)
// SQL: SELECT * FROM users ORDER BY age DESC, name ASC

4.2 高级子句示例

示例 4: JOIN 子句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 1. 内连接
db.Table("users").
Joins("JOIN profiles ON profiles.user_id = users.id").
Find(&users)
// SQL: SELECT * FROM users JOIN profiles ON profiles.user_id = users.id

// 2. 使用子句结构
db.Table("users").
Clauses(clause.Join{
Type: "LEFT",
Table: clause.Table{Name: "profiles"},
ON: clause.Where{
Exprs: []clause.Expression{
clause.Eq{
Column: clause.Column{Table: "profiles", Name: "user_id"},
Value: clause.Column{Table: "users", Name: "id"},
},
},
},
}).
Find(&users)
// SQL: SELECT * FROM users LEFT JOIN profiles ON profiles.user_id = users.id

示例 5: LIMIT 和 OFFSET

1
2
3
4
5
6
7
8
9
10
// 1. 分页查询
db.Limit(10).Offset(20).Find(&users)
// SQL: SELECT * FROM users LIMIT 10 OFFSET 20

// 2. 使用子句结构
db.Clauses(clause.Limit{
Limit: 10,
Offset: 20,
}).Find(&users)
// SQL: SELECT * FROM users LIMIT 10 OFFSET 20

示例 6: IN 查询

1
2
3
4
5
6
7
8
9
10
11
// 1. 使用切片
ids := []uint{1, 2, 3}
db.Where("id IN ?", ids).Find(&users)
// SQL: SELECT * FROM users WHERE id IN (1, 2, 3)

// 2. 使用 IN 表达式
db.Where(clause.IN{
Column: "id",
Values: []interface{}{1, 2, 3},
}).Find(&users)
// SQL: SELECT * FROM users WHERE id IN (1, 2, 3)

4.3 自定义子句示例

示例 7: 实现 FOR UPDATE 子句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 定义 FOR UPDATE 子句
type ForUpdate struct {
Tables []string
Wait bool
SkipLocked bool
NoWait bool
}

func (f ForUpdate) Name() string {
return "FOR UPDATE"
}

func (f ForUpdate) Build(builder Builder) {
builder.WriteString("FOR UPDATE")

if len(f.Tables) > 0 {
builder.WriteString(" OF ")
for i, table := range f.Tables {
if i > 0 {
builder.WriteByte(',')
}
builder.WriteString(table)
}
}

if f.NoWait {
builder.WriteString(" NOWAIT")
} else if f.SkipLocked {
builder.WriteString(" SKIP LOCKED")
} else if f.Wait {
builder.WriteString(" WAIT")
}
}

func (f ForUpdate) MergeClause(c *Clause) {
c.Expression = f
}

// 使用
db.Clauses(ForUpdate{SkipLocked: true}).Find(&user)
// SQL: SELECT * FROM users WHERE id = 1 FOR UPDATE SKIP LOCKED

五、最佳实践与故障排查

5.1 子句使用最佳实践

1. 使用类型安全的表达式

1
2
3
4
5
6
7
8
9
10
// 推荐:使用类型安全的表达式
db.Where(
clause.And(
clause.Eq{"status": "active"},
clause.Gt{"age": 18},
),
).Find(&users)

// 不推荐:使用字符串拼接
db.Where("status = ? AND age > ?", "active", 18).Find(&users)

2. 合理使用子句合并

1
2
3
4
// 子句会自动合并
query := db.Where("age > ?", 18)
query = query.Where("status = ?", "active")
// 最终 SQL: WHERE age > 18 AND status = 'active'

3. 使用 Distinct 去重

1
2
3
4
// 查询不重复的值
var uniqueAges []int
db.Model(&User{}).Distinct("age").Pluck("age", &uniqueAges)
// SQL: SELECT DISTINCT age FROM users

5.2 常见问题与解决方案

问题 1: 表达式括号不正确

症状:

1
2
// 期望: WHERE (age = 18 AND status = 'active') OR vip = true
//实际: WHERE age = 18 AND status = 'active' OR vip = true

解决方案:

1
2
3
4
5
6
7
8
9
10
// 使用 Or 和 And 明确分组
db.Where(
clause.Or(
clause.And(
clause.Eq{"age": 18},
clause.Eq{"status": "active"},
),
clause.Eq{"vip": true},
),
).Find(&users)

问题 2: IN 查询为空

症状: 当传入空切片时,IN 查询语法错误

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 检查切片是否为空
ids := []uint{}
if len(ids) > 0 {
db.Where("id IN ?", ids).Find(&users)
} else {
db.Find(&users)
}

// 或使用条件构建
query := db.Where("1 = 1")
if len(ids) > 0 {
query = query.Where("id IN ?", ids)
}

问题 3: ORDER BY 方向错误

症状: 排序结果与预期相反

解决方案:

1
2
3
4
5
6
7
8
9
// 明确指定排序方向
db.Order("age DESC").Find(&users)

// 或使用子句结构
db.Clauses(clause.OrderBy{
Columns: []clause.OrderByColumn{
{Column: clause.Column{Name: "age"}, Desc: true},
},
}).Find(&users)

六、学习验证

6.1 知识自测

基础题

  1. Clause 接口必须实现哪些方法?

    • A. Name() 和 Build()
    • B. Name()、Build() 和 MergeClause()
    • C. Build() 和 MergeClause()
    • D. 只有 Build()
  2. 以下哪个是正确的 WHERE 子句构建方式?

    • db.Where("age > 18").Where("status = 'active'")
    • db.Where("age > 18 AND status = 'active'")
    • 以上都可以
  3. Expression 接口的 Build 方法接收什么参数?

    • A. *Statement
    • B. Builder
    • C. *DB
    • D. Writer

进阶题

  1. 如何实现自定义子句?

    • 实现 Clause 接口
    • 实现 Expression 接口
    • 直接嵌入 Clause 结构体
    • 继承现有子句
  2. 以下代码生成的 SQL 是什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    db.Where(
    clause.Or(
    clause.And(
    clause.Eq{"age": 18},
    clause.Eq{"status": "active"},
    ),
    clause.Eq{"vip": true},
    ),
    ).Find(&users)
    • WHERE age = 18 AND status = 'active' OR vip = true
    • WHERE ((age = 18 AND status = 'active') OR vip = true)
    • WHERE (age = 18 AND status = 'active') OR (vip = true)

6.2 实践练习

练习 1: 实现自定义表达式

实现一个 Between 表达式,用于生成 BETWEEN SQL:

1
2
3
4
5
6
7
8
9
10
11
12
13
type Between struct {
Column interface{}
Min interface{}
Max interface{}
}

func (b Between) Build(builder Builder) {
// TODO: 实现 Build 方法
}

// 目标输出:
// db.Where(clause.Between{"age": 18, 60}).Find(&users)
// SQL: WHERE age BETWEEN 18 AND 60

练习 2: 实现 FULL OUTER JOIN

为不支持 FULL OUTER JOIN 的数据库(如 MySQL)实现等价查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
// MySQL 不支持 FULL OUTER JOIN
// 需要使用 UNION 来模拟

type FullJoin struct {
LeftTable string
RightTable string
OnClause string
}

func (f FullJoin) Build(builder Builder) {
// TODO: 实现 FULL OUTER JOIN 的等价查询
// 使用 LEFT JOIN UNION RIGHT JOIN
}