feat: Oracle 驱动完整化——回调体系、版本感知、驱动抽象层与测试套件
- 新增驱动抽象层 driver_adapter(go-ora/godror 双驱动切换) - 新增 Update/Delete/Query 回调,完善 RETURNING INTO 子句 - 修复 create.go 事务悬挂行 BUG、批量 RowsAffected、主键 WHERE 注入 - 版本感知体系:分页/自增/序列默认值/BOOLEAN/32k VARCHAR2 分级能力判定 - 11g 序列+触发器自增、ON UPDATE 触发器、默认值智能转换 - 升级 go-ora v2.8.19 → v2.9.0 - 单元测试+模块测试+集成测试共 96 个,真实 Oracle 11g 全绿 - 测试 DSN 密码移除,改为 ORACLE_DSN 环境变量注入
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package clauses
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
func TestWhenNotMatchedName(t *testing.T) {
|
||||
var w WhenNotMatched
|
||||
if got := w.Name(); got != "WHEN NOT MATCHED" {
|
||||
t.Errorf("WhenNotMatched.Name() = %q, want %q", got, "WHEN NOT MATCHED")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWhenNotMatchedBuild(t *testing.T) {
|
||||
w := WhenNotMatched{
|
||||
Values: clause.Values{
|
||||
Columns: []clause.Column{{Name: "name"}, {Name: "age"}},
|
||||
Values: [][]interface{}{{"x", 1}},
|
||||
},
|
||||
}
|
||||
|
||||
sql := buildClauseSQL(t, "WHEN NOT MATCHED", w)
|
||||
// 期望: WHEN NOT MATCHED THEN INSERT (name,age) VALUES (:1,:2)
|
||||
for _, want := range []string{
|
||||
"WHEN NOT MATCHED",
|
||||
"THEN INSERT",
|
||||
"(name,age)", // 列名
|
||||
"VALUES (:1,:2)", // VALUES 绑定参数
|
||||
} {
|
||||
if !strings.Contains(sql, want) {
|
||||
t.Errorf("WhenNotMatched SQL %q does not contain %q", sql, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWhenNotMatchedBuildWithWhere(t *testing.T) {
|
||||
w := WhenNotMatched{
|
||||
Values: clause.Values{
|
||||
Columns: []clause.Column{{Name: "name"}},
|
||||
Values: [][]interface{}{{"x"}},
|
||||
},
|
||||
Where: clause.Where{Exprs: []clause.Expression{
|
||||
clause.Eq{Column: clause.Column{Name: "deleted"}, Value: 0},
|
||||
}},
|
||||
}
|
||||
|
||||
sql := buildSQL(t, w)
|
||||
for _, want := range []string{
|
||||
"THEN INSERT",
|
||||
"(name)",
|
||||
"VALUES (:1)",
|
||||
"WHERE deleted = :2",
|
||||
} {
|
||||
if !strings.Contains(sql, want) {
|
||||
t.Errorf("WhenNotMatched SQL %q does not contain %q", sql, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWhenNotMatchedBuildEmpty(t *testing.T) {
|
||||
var w WhenNotMatched
|
||||
|
||||
sql := buildSQL(t, w)
|
||||
if sql != "" {
|
||||
t.Errorf("WhenNotMatched with empty Columns should generate no SQL, got %q", sql)
|
||||
}
|
||||
}
|
||||
|
||||
// TestWhenNotMatchedBuildPanicsOnMultipleRows 验证多行插入时按 Oracle 限制 panic。
|
||||
func TestWhenNotMatchedBuildPanicsOnMultipleRows(t *testing.T) {
|
||||
w := WhenNotMatched{
|
||||
Values: clause.Values{
|
||||
Columns: []clause.Column{{Name: "name"}},
|
||||
Values: [][]interface{}{{"x"}, {"y"}},
|
||||
},
|
||||
}
|
||||
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
t.Fatal("expected panic for multiple insert rows")
|
||||
}
|
||||
msg, ok := r.(string)
|
||||
if !ok || !strings.Contains(msg, "cannot insert more than one rows") {
|
||||
t.Errorf("unexpected panic message: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
buildSQL(t, w)
|
||||
}
|
||||
Reference in New Issue
Block a user