feat: 新增 SQLite3 虚拟表框架及方言扩展

- 新增 dialect/sqlite3/vtab 包,提供干净的虚拟表接口(Module/Table/Cursor)
- 适配层自动将 BestIndex 约束与 Filter 值绑定(ConstraintInfo.Value),无需手动编解码 IdxStr
- 支持 OpLIMIT/OpOFFSET 约束下推
- 新增 SupportsDistinct 方言选项,控制 SELECT 级和表达式级 DISTINCT 生成
- sqlite3 方言注册 IF() 函数支持
This commit is contained in:
2026-04-18 13:41:41 +08:00
parent 2221ca0ddb
commit ac81f1ff0b
13 changed files with 1443 additions and 9 deletions
+12
View File
@@ -31,6 +31,7 @@ type ColumnOptions struct {
primary bool // Add a primary index
index bool // Add an index
spatialIndex bool // Add a spatial index
hidden bool // SQLite 虚拟表 HIDDEN 列:不出现在 SELECT *,可在 WHERE 中作为参数传入
}
// VirtualAs Create a virtual generated column (MySQL)
@@ -166,3 +167,14 @@ func (c *ColumnDefinition) IsUseCurrent() bool {
func (c *ColumnDefinition) GetRename() string {
return c.rename
}
// Hidden 将列标记为 SQLite 虚拟表 HIDDEN 列。
// HIDDEN 列不出现在 SELECT * 结果中,但可以通过 WHERE col = ? 向虚拟表传递参数。
func (c *ColumnDefinition) Hidden() *ColumnDefinition {
c.hidden = true
return c
}
func (c *ColumnDefinition) IsHidden() bool {
return c.hidden
}
+12 -4
View File
@@ -13,7 +13,7 @@ import (
)
var (
sqlite3DefaultModifiers = []string{"VirtualAs", "StoredAs", "Nullable", "Default", "Increment"}
sqlite3DefaultModifiers = []string{"VirtualAs", "StoredAs", "Hidden", "Nullable", "Default", "Increment"}
sqlite3Serials = []string{"bigInteger", "integer", "mediumInteger", "smallInteger", "tinyInteger"}
)
@@ -178,8 +178,13 @@ func (this Sqlite3) GetColumnModifier(modifier string, bp *schema.Blueprint, col
if v := column.GetStoredAs(); v != "" {
return this.GenerateSQL(" GENERATED ALWAYS AS (?) STORED", db.L(v))
}
case "Hidden":
if column.IsHidden() {
return "HIDDEN"
}
case "Nullable":
if column.GetVirtualAs() == "" && column.GetStoredAs() == "" {
// HIDDEN 列和生成列不加 NULL/NOT NULL
if column.GetVirtualAs() == "" && column.GetStoredAs() == "" && !column.IsHidden() {
if column.IsNullable() {
return "NULL"
}
@@ -267,10 +272,13 @@ func (this Sqlite3) GenerateSQL(sql string, args ...any) string {
}
func init() {
schema.RegisterDialect("sqlite3", func(db *db.Database) schema.Schema {
sc := func(db *db.Database) schema.Schema {
return &Sqlite3{
db: db,
esg: sqlgen.NewExpressionSQLGenerator("sqlite3", sqlite3.DialectOptions()),
}
})
}
schema.RegisterDialect("sqlite3", sc)
schema.RegisterDialect("vtable", sc)
}
+26
View File
@@ -178,6 +178,32 @@ func (t *sqlite3Test) TestCompileDropIfExists() {
t.T().Log(sql)
}
// HIDDEN 列(虚拟表参数列)
func (t *sqlite3Test) TestCompileCreate_HiddenColumn() {
bp := schema.NewBlueprint("api_users")
bp.Create()
bp.BigIncrements("id").AutoIncrement()
bp.String("name", 100).Nullable()
bp.Integer("age")
bp.String("token", 255).Hidden().Nullable()
bp.Integer("page_size").Hidden().Nullable()
sql := t.schema.CompileCreate(bp)
t.Equal([]string{
"CREATE TABLE IF NOT EXISTS `api_users` (\n" +
"`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT\n" +
"`name` varchar(100) NULL\n" +
"`age` INTEGER(0) NOT NULL\n" +
"`token` varchar(255) HIDDEN\n" +
"`page_size` INTEGER(0) HIDDEN\n" +
")",
}, sql)
t.T().Log(sql)
}
// 表重命名
func (t *sqlite3Test) TestCompileRename() {
bp := schema.NewBlueprint("users")