测试:完善和优化测试用例
- 优化 schema 测试用例,增加边界条件测试 - 完善 table、index、database 等模块的测试 - 改进测试数据清理和错误处理 - 更新示例程序以使用最新 API - 增强测试覆盖率和可靠性
This commit is contained in:
@@ -20,9 +20,12 @@ func TestCompactionBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "value", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建 VersionSet
|
||||
versionSet, err := NewVersionSet(manifestDir)
|
||||
@@ -222,9 +225,12 @@ func TestCompactionMerge(t *testing.T) {
|
||||
}
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "value", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建 VersionSet
|
||||
versionSet, err := NewVersionSet(manifestDir)
|
||||
@@ -343,9 +349,12 @@ func BenchmarkCompaction(b *testing.B) {
|
||||
}
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "value", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建 VersionSet
|
||||
versionSet, err := NewVersionSet(manifestDir)
|
||||
@@ -429,12 +438,15 @@ func TestCompactionQueryOrder(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// 创建 Schema - 包含多个字段以增加数据大小
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "data", Type: FieldTypeString},
|
||||
{Name: "timestamp", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 打开 Table (使用较小的 MemTable 触发频繁 flush)
|
||||
table, err := OpenTable(&TableOptions{
|
||||
|
||||
@@ -40,10 +40,13 @@ func TestCreateTable(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
// 创建 Schema
|
||||
userSchema := NewSchema("users", []Field{
|
||||
userSchema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建表
|
||||
usersTable, err := db.CreateTable("users", userSchema)
|
||||
@@ -76,15 +79,21 @@ func TestMultipleTables(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
// 创建多个表
|
||||
userSchema := NewSchema("users", []Field{
|
||||
userSchema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
orderSchema := NewSchema("orders", []Field{
|
||||
orderSchema, err := NewSchema("orders", []Field{
|
||||
{Name: "order_id", Type: FieldTypeString, Indexed: true, Comment: "订单ID"},
|
||||
{Name: "amount", Type: FieldTypeInt64, Indexed: true, Comment: "金额"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = db.CreateTable("users", userSchema)
|
||||
if err != nil {
|
||||
@@ -117,10 +126,13 @@ func TestTableOperations(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
// 创建表
|
||||
userSchema := NewSchema("users", []Field{
|
||||
userSchema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
usersTable, err := db.CreateTable("users", userSchema)
|
||||
if err != nil {
|
||||
@@ -179,9 +191,12 @@ func TestDropTable(t *testing.T) {
|
||||
defer db.Close()
|
||||
|
||||
// 创建表
|
||||
userSchema := NewSchema("users", []Field{
|
||||
userSchema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = db.CreateTable("users", userSchema)
|
||||
if err != nil {
|
||||
@@ -214,10 +229,13 @@ func TestDatabaseRecover(t *testing.T) {
|
||||
t.Fatalf("Open failed: %v", err)
|
||||
}
|
||||
|
||||
userSchema := NewSchema("users", []Field{
|
||||
userSchema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
usersTable, err := db1.CreateTable("users", userSchema)
|
||||
if err != nil {
|
||||
@@ -272,10 +290,13 @@ func TestDatabaseClean(t *testing.T) {
|
||||
|
||||
// 2. 创建多个表并插入数据
|
||||
// 表 1: users
|
||||
usersSchema := NewSchema("users", []Field{
|
||||
usersSchema, err := NewSchema("users", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: true, Comment: "User ID"},
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "Name"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
usersTable, err := db.CreateTable("users", usersSchema)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -289,10 +310,13 @@ func TestDatabaseClean(t *testing.T) {
|
||||
}
|
||||
|
||||
// 表 2: orders
|
||||
ordersSchema := NewSchema("orders", []Field{
|
||||
ordersSchema, err := NewSchema("orders", []Field{
|
||||
{Name: "order_id", Type: FieldTypeInt64, Indexed: true, Comment: "Order ID"},
|
||||
{Name: "amount", Type: FieldTypeInt64, Indexed: false, Comment: "Amount"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ordersTable, err := db.CreateTable("orders", ordersSchema)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -367,9 +391,12 @@ func TestDatabaseDestroy(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
table, err := db.CreateTable("test", schema)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -420,10 +447,13 @@ func TestDatabaseCleanMultipleTables(t *testing.T) {
|
||||
// 创建 5 个表
|
||||
for i := range 5 {
|
||||
tableName := fmt.Sprintf("table%d", i)
|
||||
schema := NewSchema(tableName, []Field{
|
||||
schema, err := NewSchema(tableName, []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
|
||||
{Name: "value", Type: FieldTypeString, Indexed: false, Comment: "Value"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := db.CreateTable(tableName, schema)
|
||||
if err != nil {
|
||||
@@ -493,9 +523,12 @@ func TestDatabaseCleanAndReopen(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
table, err := db.CreateTable("test", schema)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -560,10 +593,13 @@ func TestDatabaseCleanTable(t *testing.T) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "Name"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := db.CreateTable("users", schema)
|
||||
if err != nil {
|
||||
@@ -629,9 +665,12 @@ func TestDatabaseDestroyTable(t *testing.T) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := db.CreateTable("test", schema)
|
||||
if err != nil {
|
||||
@@ -681,9 +720,12 @@ func TestDatabaseDestroyTableMultiple(t *testing.T) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建 3 个表
|
||||
for i := 1; i <= 3; i++ {
|
||||
|
||||
@@ -26,7 +26,7 @@ type Product struct {
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== SRDB 批量插入示例 ===\n")
|
||||
fmt.Println("=== SRDB 批量插入示例 ===")
|
||||
|
||||
// 清理旧数据
|
||||
os.RemoveAll("./data")
|
||||
@@ -55,10 +55,13 @@ func main() {
|
||||
func example1() {
|
||||
fmt.Println("=== 示例 1: 插入单个 map ===")
|
||||
|
||||
schema := srdb.NewSchema("users", []srdb.Field{
|
||||
schema, err := srdb.NewSchema("users", []srdb.Field{
|
||||
{Name: "name", Type: srdb.FieldTypeString, Comment: "用户名"},
|
||||
{Name: "age", Type: srdb.FieldTypeInt64, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := srdb.OpenTable(&srdb.TableOptions{
|
||||
Dir: "./data/example1",
|
||||
@@ -89,11 +92,14 @@ func example1() {
|
||||
func example2() {
|
||||
fmt.Println("=== 示例 2: 批量插入 map 切片 ===")
|
||||
|
||||
schema := srdb.NewSchema("users", []srdb.Field{
|
||||
schema, err := srdb.NewSchema("users", []srdb.Field{
|
||||
{Name: "name", Type: srdb.FieldTypeString},
|
||||
{Name: "age", Type: srdb.FieldTypeInt64},
|
||||
{Name: "email", Type: srdb.FieldTypeString, Indexed: true},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := srdb.OpenTable(&srdb.TableOptions{
|
||||
Dir: "./data/example2",
|
||||
@@ -134,12 +140,15 @@ func example2() {
|
||||
func example3() {
|
||||
fmt.Println("=== 示例 3: 插入单个结构体 ===")
|
||||
|
||||
schema := srdb.NewSchema("users", []srdb.Field{
|
||||
schema, err := srdb.NewSchema("users", []srdb.Field{
|
||||
{Name: "name", Type: srdb.FieldTypeString},
|
||||
{Name: "age", Type: srdb.FieldTypeInt64},
|
||||
{Name: "email", Type: srdb.FieldTypeString},
|
||||
{Name: "is_active", Type: srdb.FieldTypeBool},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := srdb.OpenTable(&srdb.TableOptions{
|
||||
Dir: "./data/example3",
|
||||
@@ -175,12 +184,15 @@ func example3() {
|
||||
func example4() {
|
||||
fmt.Println("=== 示例 4: 批量插入结构体切片 ===")
|
||||
|
||||
schema := srdb.NewSchema("users", []srdb.Field{
|
||||
schema, err := srdb.NewSchema("users", []srdb.Field{
|
||||
{Name: "name", Type: srdb.FieldTypeString},
|
||||
{Name: "age", Type: srdb.FieldTypeInt64},
|
||||
{Name: "email", Type: srdb.FieldTypeString},
|
||||
{Name: "is_active", Type: srdb.FieldTypeBool},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := srdb.OpenTable(&srdb.TableOptions{
|
||||
Dir: "./data/example4",
|
||||
@@ -222,12 +234,15 @@ func example4() {
|
||||
func example5() {
|
||||
fmt.Println("=== 示例 5: 批量插入结构体指针切片 ===")
|
||||
|
||||
schema := srdb.NewSchema("users", []srdb.Field{
|
||||
schema, err := srdb.NewSchema("users", []srdb.Field{
|
||||
{Name: "name", Type: srdb.FieldTypeString},
|
||||
{Name: "age", Type: srdb.FieldTypeInt64},
|
||||
{Name: "email", Type: srdb.FieldTypeString},
|
||||
{Name: "is_active", Type: srdb.FieldTypeBool},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := srdb.OpenTable(&srdb.TableOptions{
|
||||
Dir: "./data/example5",
|
||||
@@ -262,12 +277,15 @@ func example5() {
|
||||
func example6() {
|
||||
fmt.Println("=== 示例 6: 使用 snake_case 自动转换 ===")
|
||||
|
||||
schema := srdb.NewSchema("products", []srdb.Field{
|
||||
schema, err := srdb.NewSchema("products", []srdb.Field{
|
||||
{Name: "product_id", Type: srdb.FieldTypeString, Comment: "产品ID"},
|
||||
{Name: "product_name", Type: srdb.FieldTypeString, Comment: "产品名称"},
|
||||
{Name: "price", Type: srdb.FieldTypeFloat, Comment: "价格"},
|
||||
{Name: "in_stock", Type: srdb.FieldTypeBool, Comment: "是否有货"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := srdb.OpenTable(&srdb.TableOptions{
|
||||
Dir: "./data/example6",
|
||||
|
||||
@@ -93,6 +93,9 @@ func main() {
|
||||
}
|
||||
|
||||
// 创建 Schema
|
||||
schema := srdb.NewSchema("demo", fields)
|
||||
schema, err := srdb.NewSchema("demo", fields)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("\n✅ 成功创建 Schema,包含 %d 个字段\n", len(schema.Fields))
|
||||
}
|
||||
|
||||
@@ -38,7 +38,10 @@ func main() {
|
||||
}
|
||||
|
||||
// 创建 Schema
|
||||
schema := srdb.NewSchema("users", fields)
|
||||
schema, err := srdb.NewSchema("users", fields)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 打印 Schema 信息
|
||||
fmt.Printf("Schema 名称: %s\n", schema.Name)
|
||||
|
||||
@@ -23,19 +23,25 @@ func StartWebUI(dbPath string, addr string) {
|
||||
defer db.Close()
|
||||
|
||||
// 创建示例 Schema
|
||||
userSchema := srdb.NewSchema("users", []srdb.Field{
|
||||
userSchema, err := srdb.NewSchema("users", []srdb.Field{
|
||||
{Name: "name", Type: srdb.FieldTypeString, Indexed: true, Comment: "User name"},
|
||||
{Name: "email", Type: srdb.FieldTypeString, Indexed: false, Comment: "Email address"},
|
||||
{Name: "age", Type: srdb.FieldTypeInt64, Indexed: false, Comment: "Age"},
|
||||
{Name: "city", Type: srdb.FieldTypeString, Indexed: false, Comment: "City"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
productSchema := srdb.NewSchema("products", []srdb.Field{
|
||||
productSchema, err := srdb.NewSchema("products", []srdb.Field{
|
||||
{Name: "product_name", Type: srdb.FieldTypeString, Indexed: true, Comment: "Product name"},
|
||||
{Name: "price", Type: srdb.FieldTypeFloat, Indexed: false, Comment: "Price"},
|
||||
{Name: "quantity", Type: srdb.FieldTypeInt64, Indexed: false, Comment: "Quantity"},
|
||||
{Name: "category", Type: srdb.FieldTypeString, Indexed: false, Comment: "Category"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建表(如果不存在)
|
||||
tables := db.ListTables()
|
||||
@@ -133,14 +139,16 @@ func autoInsertData(db *srdb.Database) {
|
||||
hasLogs := slices.Contains(tables, "logs")
|
||||
|
||||
if !hasLogs {
|
||||
logsSchema := srdb.NewSchema("logs", []srdb.Field{
|
||||
logsSchema, err := srdb.NewSchema("logs", []srdb.Field{
|
||||
{Name: "group", Type: srdb.FieldTypeString, Indexed: true, Comment: "Log group (A-E)"},
|
||||
{Name: "timestamp", Type: srdb.FieldTypeString, Indexed: false, Comment: "Timestamp"},
|
||||
{Name: "data", Type: srdb.FieldTypeString, Indexed: false, Comment: "Random data"},
|
||||
{Name: "size_bytes", Type: srdb.FieldTypeInt64, Indexed: false, Comment: "Data size in bytes"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var err error
|
||||
logsTable, err = db.CreateTable("logs", logsSchema)
|
||||
if err != nil {
|
||||
log.Printf("Failed to create logs table: %v", err)
|
||||
|
||||
@@ -12,18 +12,21 @@ func TestIndexBTreeBasic(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "city", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建索引管理器
|
||||
mgr := NewIndexManager(tmpDir, schema)
|
||||
defer mgr.Close()
|
||||
|
||||
// 创建索引
|
||||
err := mgr.CreateIndex("city")
|
||||
err = mgr.CreateIndex("city")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create index: %v", err)
|
||||
}
|
||||
@@ -126,17 +129,20 @@ func TestIndexBTreeLargeDataset(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "category", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建索引管理器
|
||||
mgr := NewIndexManager(tmpDir, schema)
|
||||
defer mgr.Close()
|
||||
|
||||
// 创建索引
|
||||
err := mgr.CreateIndex("category")
|
||||
err = mgr.CreateIndex("category")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create index: %v", err)
|
||||
}
|
||||
@@ -211,16 +217,19 @@ func TestIndexBTreeBackwardCompatibility(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "status", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 创建索引管理器并用旧方式(通过先禁用新格式)创建索引
|
||||
mgr := NewIndexManager(tmpDir, schema)
|
||||
|
||||
// 创建索引
|
||||
err := mgr.CreateIndex("status")
|
||||
err = mgr.CreateIndex("status")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create index: %v", err)
|
||||
}
|
||||
@@ -286,17 +295,20 @@ func TestIndexBTreeIncrementalUpdate(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "tag", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建索引管理器
|
||||
mgr := NewIndexManager(tmpDir, schema)
|
||||
defer mgr.Close()
|
||||
|
||||
// 创建索引
|
||||
err := mgr.CreateIndex("tag")
|
||||
err = mgr.CreateIndex("tag")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create index: %v", err)
|
||||
}
|
||||
|
||||
@@ -11,9 +11,12 @@ func TestIndexVersionControl(t *testing.T) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
testSchema := NewSchema("test", []Field{
|
||||
testSchema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 创建索引管理器
|
||||
mgr := NewIndexManager(dir, testSchema)
|
||||
@@ -72,9 +75,12 @@ func TestIncrementalUpdate(t *testing.T) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
testSchema := NewSchema("test", []Field{
|
||||
testSchema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 创建索引并添加初始数据
|
||||
mgr := NewIndexManager(dir, testSchema)
|
||||
@@ -103,7 +109,7 @@ func TestIncrementalUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
// 3. 增量更新
|
||||
err := idx.IncrementalUpdate(getData, 3, 5)
|
||||
err = idx.IncrementalUpdate(getData, 3, 5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -143,9 +149,12 @@ func TestNeedsUpdate(t *testing.T) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
testSchema := NewSchema("test", []Field{
|
||||
testSchema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mgr := NewIndexManager(dir, testSchema)
|
||||
mgr.CreateIndex("name")
|
||||
@@ -174,16 +183,19 @@ func TestIndexPersistence(t *testing.T) {
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// 创建 Schema
|
||||
testSchema := NewSchema("test", []Field{
|
||||
testSchema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 创建索引管理器
|
||||
mgr := NewIndexManager(dir, testSchema)
|
||||
|
||||
// 2. 创建索引
|
||||
err := mgr.CreateIndex("name")
|
||||
err = mgr.CreateIndex("name")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -253,9 +265,12 @@ func TestIndexDropWithFile(t *testing.T) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
testSchema := NewSchema("test", []Field{
|
||||
testSchema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mgr := NewIndexManager(dir, testSchema)
|
||||
|
||||
@@ -272,7 +287,7 @@ func TestIndexDropWithFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// 删除索引
|
||||
err := mgr.DropIndex("name")
|
||||
err = mgr.DropIndex("name")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -290,11 +305,14 @@ func TestIndexQueryIntegration(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// 1. 创建带索引字段的 Schema
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false},
|
||||
{Name: "email", Type: FieldTypeString, Indexed: true}, // email 字段有索引
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 2. 打开表
|
||||
table, err := OpenTable(&TableOptions{
|
||||
@@ -450,11 +468,14 @@ func TestIndexPersistenceAcrossRestart(t *testing.T) {
|
||||
|
||||
// 1. 第一次打开:创建数据和索引
|
||||
{
|
||||
schema := NewSchema("products", []Field{
|
||||
schema, err := NewSchema("products", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false},
|
||||
{Name: "category", Type: FieldTypeString, Indexed: true},
|
||||
{Name: "price", Type: FieldTypeInt64, Indexed: false},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
|
||||
@@ -11,10 +11,13 @@ func TestLazyLoadingBasic(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestLazyLoadingBasic")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -67,10 +70,13 @@ func TestLazyLoadingVsEagerLoading(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestLazyLoadingVsEagerLoading")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -144,11 +150,14 @@ func TestIndexQueryIsEager(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestIndexQueryIsEager")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "email", Type: FieldTypeString, Indexed: true},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -226,11 +235,14 @@ func TestLazyLoadingWithConditions(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestLazyLoadingWithConditions")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
{Name: "active", Type: FieldTypeBool},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -301,10 +313,13 @@ func TestFirstDoesNotLoadAll(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestFirstDoesNotLoadAll")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
|
||||
33
schema.go
33
schema.go
@@ -50,11 +50,40 @@ type Schema struct {
|
||||
}
|
||||
|
||||
// NewSchema 创建 Schema
|
||||
func NewSchema(name string, fields []Field) *Schema {
|
||||
// 参数:
|
||||
// - name: Schema 名称,不能为空
|
||||
// - fields: 字段列表,至少需要 1 个字段
|
||||
//
|
||||
// 返回:
|
||||
// - *Schema: Schema 实例
|
||||
// - error: 错误信息
|
||||
func NewSchema(name string, fields []Field) (*Schema, error) {
|
||||
// 验证 name
|
||||
if name == "" {
|
||||
return nil, NewError(ErrCodeSchemaInvalid, fmt.Errorf("schema name cannot be empty"))
|
||||
}
|
||||
|
||||
// 验证 fields 数量
|
||||
if len(fields) == 0 {
|
||||
return nil, NewError(ErrCodeSchemaInvalid, fmt.Errorf("schema must have at least one field"))
|
||||
}
|
||||
|
||||
// 验证字段名不能为空且不能重复
|
||||
fieldNames := make(map[string]bool)
|
||||
for i, field := range fields {
|
||||
if field.Name == "" {
|
||||
return nil, NewError(ErrCodeSchemaInvalid, fmt.Errorf("field at index %d has empty name", i))
|
||||
}
|
||||
if fieldNames[field.Name] {
|
||||
return nil, NewError(ErrCodeSchemaInvalid, fmt.Errorf("duplicate field name: %s", field.Name))
|
||||
}
|
||||
fieldNames[field.Name] = true
|
||||
}
|
||||
|
||||
return &Schema{
|
||||
Name: name,
|
||||
Fields: fields,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StructToFields 从 Go 结构体生成 Field 列表
|
||||
|
||||
484
schema_test.go
484
schema_test.go
@@ -1,41 +1,65 @@
|
||||
package srdb
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// UserSchema 用户表 Schema
|
||||
var UserSchema = NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
{Name: "email", Type: FieldTypeString, Indexed: true, Comment: "邮箱"},
|
||||
{Name: "description", Type: FieldTypeString, Indexed: false, Comment: "描述"},
|
||||
})
|
||||
// Package-level test schemas
|
||||
var (
|
||||
UserSchema *Schema
|
||||
LogSchema *Schema
|
||||
OrderSchema *Schema
|
||||
)
|
||||
|
||||
// LogSchema 日志表 Schema
|
||||
var LogSchema = NewSchema("logs", []Field{
|
||||
{Name: "level", Type: FieldTypeString, Indexed: true, Comment: "日志级别"},
|
||||
{Name: "message", Type: FieldTypeString, Indexed: false, Comment: "日志消息"},
|
||||
{Name: "source", Type: FieldTypeString, Indexed: true, Comment: "来源"},
|
||||
{Name: "error_code", Type: FieldTypeInt64, Indexed: true, Comment: "错误码"},
|
||||
})
|
||||
func init() {
|
||||
var err error
|
||||
|
||||
// OrderSchema 订单表 Schema
|
||||
var OrderSchema = NewSchema("orders", []Field{
|
||||
{Name: "order_id", Type: FieldTypeString, Indexed: true, Comment: "订单ID"},
|
||||
{Name: "user_id", Type: FieldTypeInt64, Indexed: true, Comment: "用户ID"},
|
||||
{Name: "amount", Type: FieldTypeFloat, Indexed: true, Comment: "金额"},
|
||||
{Name: "status", Type: FieldTypeString, Indexed: true, Comment: "状态"},
|
||||
{Name: "paid", Type: FieldTypeBool, Indexed: true, Comment: "是否支付"},
|
||||
})
|
||||
// UserSchema 用户表 Schema
|
||||
UserSchema, err = NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
{Name: "email", Type: FieldTypeString, Indexed: true, Comment: "邮箱"},
|
||||
{Name: "description", Type: FieldTypeString, Indexed: false, Comment: "描述"},
|
||||
})
|
||||
if err != nil {
|
||||
panic("Failed to create UserSchema: " + err.Error())
|
||||
}
|
||||
|
||||
// LogSchema 日志表 Schema
|
||||
LogSchema, err = NewSchema("logs", []Field{
|
||||
{Name: "level", Type: FieldTypeString, Indexed: true, Comment: "日志级别"},
|
||||
{Name: "message", Type: FieldTypeString, Indexed: false, Comment: "日志消息"},
|
||||
{Name: "source", Type: FieldTypeString, Indexed: true, Comment: "来源"},
|
||||
{Name: "error_code", Type: FieldTypeInt64, Indexed: true, Comment: "错误码"},
|
||||
})
|
||||
if err != nil {
|
||||
panic("Failed to create LogSchema: " + err.Error())
|
||||
}
|
||||
|
||||
// OrderSchema 订单表 Schema
|
||||
OrderSchema, err = NewSchema("orders", []Field{
|
||||
{Name: "order_id", Type: FieldTypeString, Indexed: true, Comment: "订单ID"},
|
||||
{Name: "user_id", Type: FieldTypeInt64, Indexed: true, Comment: "用户ID"},
|
||||
{Name: "amount", Type: FieldTypeFloat, Indexed: true, Comment: "金额"},
|
||||
{Name: "status", Type: FieldTypeString, Indexed: true, Comment: "状态"},
|
||||
{Name: "paid", Type: FieldTypeBool, Indexed: true, Comment: "是否支付"},
|
||||
})
|
||||
if err != nil {
|
||||
panic("Failed to create OrderSchema: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSchema(t *testing.T) {
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
{Name: "score", Type: FieldTypeFloat, Indexed: false, Comment: "分数"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 测试数据
|
||||
data := map[string]any{
|
||||
@@ -45,7 +69,7 @@ func TestSchema(t *testing.T) {
|
||||
}
|
||||
|
||||
// 验证
|
||||
err := schema.Validate(data)
|
||||
err = schema.Validate(data)
|
||||
if err != nil {
|
||||
t.Errorf("Validation failed: %v", err)
|
||||
}
|
||||
@@ -60,10 +84,13 @@ func TestSchema(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSchemaValidation(t *testing.T) {
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 正确的数据
|
||||
validData := map[string]any{
|
||||
@@ -71,7 +98,7 @@ func TestSchemaValidation(t *testing.T) {
|
||||
"age": 30,
|
||||
}
|
||||
|
||||
err := schema.Validate(validData)
|
||||
err = schema.Validate(validData)
|
||||
if err != nil {
|
||||
t.Errorf("Valid data failed validation: %v", err)
|
||||
}
|
||||
@@ -90,11 +117,361 @@ func TestSchemaValidation(t *testing.T) {
|
||||
t.Log("Schema validation test passed!")
|
||||
}
|
||||
|
||||
// TestNewSchemaValidation 测试 NewSchema 的各种验证场景
|
||||
func TestNewSchemaValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
schemaName string
|
||||
fields []Field
|
||||
shouldError bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "Valid schema",
|
||||
schemaName: "users",
|
||||
fields: []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "Empty schema name",
|
||||
schemaName: "",
|
||||
fields: []Field{{Name: "id", Type: FieldTypeInt64}},
|
||||
shouldError: true,
|
||||
errorMsg: "schema name cannot be empty",
|
||||
},
|
||||
{
|
||||
name: "Empty fields array",
|
||||
schemaName: "users",
|
||||
fields: []Field{},
|
||||
shouldError: true,
|
||||
errorMsg: "schema must have at least one field",
|
||||
},
|
||||
{
|
||||
name: "Nil fields array",
|
||||
schemaName: "users",
|
||||
fields: nil,
|
||||
shouldError: true,
|
||||
errorMsg: "schema must have at least one field",
|
||||
},
|
||||
{
|
||||
name: "Empty field name at index 0",
|
||||
schemaName: "users",
|
||||
fields: []Field{
|
||||
{Name: "", Type: FieldTypeInt64},
|
||||
},
|
||||
shouldError: true,
|
||||
errorMsg: "field at index 0 has empty name",
|
||||
},
|
||||
{
|
||||
name: "Empty field name at index 1",
|
||||
schemaName: "users",
|
||||
fields: []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "", Type: FieldTypeString},
|
||||
},
|
||||
shouldError: true,
|
||||
errorMsg: "field at index 1 has empty name",
|
||||
},
|
||||
{
|
||||
name: "Duplicate field name",
|
||||
schemaName: "users",
|
||||
fields: []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "id", Type: FieldTypeString}, // Duplicate
|
||||
},
|
||||
shouldError: true,
|
||||
errorMsg: "duplicate field name: id",
|
||||
},
|
||||
{
|
||||
name: "Valid schema with single field",
|
||||
schemaName: "logs",
|
||||
fields: []Field{
|
||||
{Name: "message", Type: FieldTypeString},
|
||||
},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "Valid schema with indexed field",
|
||||
schemaName: "users",
|
||||
fields: []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: true},
|
||||
{Name: "email", Type: FieldTypeString, Indexed: true},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "Valid schema with comments",
|
||||
schemaName: "products",
|
||||
fields: []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Comment: "产品ID"},
|
||||
{Name: "name", Type: FieldTypeString, Comment: "产品名称"},
|
||||
{Name: "price", Type: FieldTypeFloat, Comment: "价格"},
|
||||
},
|
||||
shouldError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
schema, err := NewSchema(tt.schemaName, tt.fields)
|
||||
|
||||
if tt.shouldError {
|
||||
if err == nil {
|
||||
t.Errorf("Expected error but got none")
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), tt.errorMsg) {
|
||||
t.Errorf("Expected error to contain %q, got %q", tt.errorMsg, err.Error())
|
||||
}
|
||||
|
||||
// 验证错误码是 ErrCodeSchemaInvalid
|
||||
if GetErrorCode(err) != ErrCodeSchemaInvalid {
|
||||
t.Errorf("Expected error code %d, got %d", ErrCodeSchemaInvalid, GetErrorCode(err))
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error but got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证返回的 schema 是正确的
|
||||
if schema == nil {
|
||||
t.Errorf("Expected schema, got nil")
|
||||
return
|
||||
}
|
||||
if schema.Name != tt.schemaName {
|
||||
t.Errorf("Expected schema name %q, got %q", tt.schemaName, schema.Name)
|
||||
}
|
||||
if len(schema.Fields) != len(tt.fields) {
|
||||
t.Errorf("Expected %d fields, got %d", len(tt.fields), len(schema.Fields))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewSchemaFieldValidation 测试字段级别的验证
|
||||
func TestNewSchemaFieldValidation(t *testing.T) {
|
||||
t.Run("Multiple duplicate field names", func(t *testing.T) {
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "id", Type: FieldTypeString}, // First duplicate
|
||||
{Name: "name", Type: FieldTypeString}, // Second duplicate
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for duplicate field names")
|
||||
return
|
||||
}
|
||||
|
||||
// 应该在第一个重复处就停止
|
||||
if !strings.Contains(err.Error(), "duplicate field name: id") {
|
||||
t.Errorf("Expected error about duplicate field 'id', got: %v", err)
|
||||
}
|
||||
|
||||
if schema != nil {
|
||||
t.Errorf("Expected nil schema on error, got %+v", schema)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Case sensitive field names", func(t *testing.T) {
|
||||
// 大小写敏感,ID 和 id 应该是不同的字段
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
{Name: "ID", Type: FieldTypeInt64},
|
||||
{Name: "Id", Type: FieldTypeInt64},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error for case-sensitive field names, got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(schema.Fields) != 3 {
|
||||
t.Errorf("Expected 3 fields (case sensitive), got %d", len(schema.Fields))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Fields with all types", func(t *testing.T) {
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "int_field", Type: FieldTypeInt64},
|
||||
{Name: "string_field", Type: FieldTypeString},
|
||||
{Name: "float_field", Type: FieldTypeFloat},
|
||||
{Name: "bool_field", Type: FieldTypeBool},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(schema.Fields) != 4 {
|
||||
t.Errorf("Expected 4 fields, got %d", len(schema.Fields))
|
||||
}
|
||||
|
||||
// 验证每个字段的类型
|
||||
expectedTypes := map[string]FieldType{
|
||||
"int_field": FieldTypeInt64,
|
||||
"string_field": FieldTypeString,
|
||||
"float_field": FieldTypeFloat,
|
||||
"bool_field": FieldTypeBool,
|
||||
}
|
||||
|
||||
for _, field := range schema.Fields {
|
||||
expectedType, exists := expectedTypes[field.Name]
|
||||
if !exists {
|
||||
t.Errorf("Unexpected field name: %s", field.Name)
|
||||
continue
|
||||
}
|
||||
if field.Type != expectedType {
|
||||
t.Errorf("Field %s: expected type %v, got %v", field.Name, expectedType, field.Type)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestNewSchemaEdgeCases 测试边界情况
|
||||
func TestNewSchemaEdgeCases(t *testing.T) {
|
||||
t.Run("Very long schema name", func(t *testing.T) {
|
||||
longName := strings.Repeat("a", 1000)
|
||||
schema, err := NewSchema(longName, []Field{
|
||||
{Name: "id", Type: FieldTypeInt64},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error for long schema name, got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if schema.Name != longName {
|
||||
t.Errorf("Expected schema name to be preserved")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Very long field name", func(t *testing.T) {
|
||||
longFieldName := strings.Repeat("b", 1000)
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: longFieldName, Type: FieldTypeInt64},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error for long field name, got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if schema.Fields[0].Name != longFieldName {
|
||||
t.Errorf("Expected field name to be preserved")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Many fields", func(t *testing.T) {
|
||||
fields := make([]Field, 100)
|
||||
for i := 0; i < 100; i++ {
|
||||
fields[i] = Field{
|
||||
Name: strings.Repeat("field", 1) + string(rune('a'+i)),
|
||||
Type: FieldTypeInt64,
|
||||
}
|
||||
}
|
||||
|
||||
schema, err := NewSchema("test", fields)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error for many fields, got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(schema.Fields) != 100 {
|
||||
t.Errorf("Expected 100 fields, got %d", len(schema.Fields))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Field with special characters", func(t *testing.T) {
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "field_with_underscore", Type: FieldTypeInt64},
|
||||
{Name: "field123", Type: FieldTypeInt64},
|
||||
{Name: "字段名", Type: FieldTypeString}, // 中文字段名
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error for special characters, got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(schema.Fields) != 3 {
|
||||
t.Errorf("Expected 3 fields with special characters, got %d", len(schema.Fields))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestNewSchemaConsistency 测试创建后的一致性
|
||||
func TestNewSchemaConsistency(t *testing.T) {
|
||||
t.Run("Field order preserved", func(t *testing.T) {
|
||||
fields := []Field{
|
||||
{Name: "zebra", Type: FieldTypeString},
|
||||
{Name: "alpha", Type: FieldTypeInt64},
|
||||
{Name: "beta", Type: FieldTypeFloat},
|
||||
}
|
||||
|
||||
schema, err := NewSchema("test", fields)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 字段顺序应该保持不变
|
||||
for i, field := range schema.Fields {
|
||||
if field.Name != fields[i].Name {
|
||||
t.Errorf("Field order not preserved at index %d: expected %s, got %s",
|
||||
i, fields[i].Name, field.Name)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Field properties preserved", func(t *testing.T) {
|
||||
fields := []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: true, Comment: "Primary key"},
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "User name"},
|
||||
}
|
||||
|
||||
schema, err := NewSchema("users", fields)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证所有属性都被保留
|
||||
if schema.Fields[0].Indexed != true {
|
||||
t.Errorf("Expected field 0 to be indexed")
|
||||
}
|
||||
if schema.Fields[1].Indexed != false {
|
||||
t.Errorf("Expected field 1 to not be indexed")
|
||||
}
|
||||
if schema.Fields[0].Comment != "Primary key" {
|
||||
t.Errorf("Expected field 0 comment to be preserved")
|
||||
}
|
||||
if schema.Fields[1].Comment != "User name" {
|
||||
t.Errorf("Expected field 1 comment to be preserved")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestExtractIndexValue(t *testing.T) {
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data := map[string]any{
|
||||
"name": "David",
|
||||
@@ -156,15 +533,21 @@ func TestPredefinedSchemas(t *testing.T) {
|
||||
func TestChecksumDeterminism(t *testing.T) {
|
||||
// 创建相同的 Schema 多次
|
||||
for i := range 10 {
|
||||
s1 := NewSchema("users", []Field{
|
||||
s1, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s2 := NewSchema("users", []Field{
|
||||
s2, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
checksum1, err := s1.ComputeChecksum()
|
||||
if err != nil {
|
||||
@@ -186,15 +569,21 @@ func TestChecksumDeterminism(t *testing.T) {
|
||||
|
||||
// TestChecksumFieldOrderIndependent 测试字段顺序不影响 checksum
|
||||
func TestChecksumFieldOrderIndependent(t *testing.T) {
|
||||
s1 := NewSchema("users", []Field{
|
||||
s1, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s2 := NewSchema("users", []Field{
|
||||
s2, err := NewSchema("users", []Field{
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
checksum1, _ := s1.ComputeChecksum()
|
||||
checksum2, _ := s2.ComputeChecksum()
|
||||
@@ -209,13 +598,19 @@ func TestChecksumFieldOrderIndependent(t *testing.T) {
|
||||
|
||||
// TestChecksumDifferentData 测试不同 Schema 的 checksum 应该不同
|
||||
func TestChecksumDifferentData(t *testing.T) {
|
||||
s1 := NewSchema("users", []Field{
|
||||
s1, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s2 := NewSchema("users", []Field{
|
||||
s2, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"}, // Indexed 不同
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
checksum1, _ := s1.ComputeChecksum()
|
||||
checksum2, _ := s2.ComputeChecksum()
|
||||
@@ -236,12 +631,20 @@ func TestChecksumMultipleFieldOrders(t *testing.T) {
|
||||
fieldD := Field{Name: "email", Type: FieldTypeString, Indexed: true, Comment: "邮箱"}
|
||||
|
||||
// 创建不同顺序的 Schema
|
||||
mustNewSchema := func(name string, fields []Field) *Schema {
|
||||
s, err := NewSchema(name, fields)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create schema: %v", err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
schemas := []*Schema{
|
||||
NewSchema("test", []Field{fieldA, fieldB, fieldC, fieldD}), // 原始顺序
|
||||
NewSchema("test", []Field{fieldD, fieldC, fieldB, fieldA}), // 完全反转
|
||||
NewSchema("test", []Field{fieldB, fieldD, fieldA, fieldC}), // 随机顺序 1
|
||||
NewSchema("test", []Field{fieldC, fieldA, fieldD, fieldB}), // 随机顺序 2
|
||||
NewSchema("test", []Field{fieldD, fieldA, fieldC, fieldB}), // 随机顺序 3
|
||||
mustNewSchema("test", []Field{fieldA, fieldB, fieldC, fieldD}), // 原始顺序
|
||||
mustNewSchema("test", []Field{fieldD, fieldC, fieldB, fieldA}), // 完全反转
|
||||
mustNewSchema("test", []Field{fieldB, fieldD, fieldA, fieldC}), // 随机顺序 1
|
||||
mustNewSchema("test", []Field{fieldC, fieldA, fieldD, fieldB}), // 随机顺序 2
|
||||
mustNewSchema("test", []Field{fieldD, fieldA, fieldC, fieldB}), // 随机顺序 3
|
||||
}
|
||||
|
||||
// 计算所有 checksum
|
||||
@@ -478,7 +881,10 @@ func TestStructToFieldsWithSchema(t *testing.T) {
|
||||
}
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("customers", fields)
|
||||
schema, err := NewSchema("customers", fields)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 验证 Schema
|
||||
if schema.Name != "customers" {
|
||||
|
||||
@@ -16,10 +16,13 @@ func TestSSTable(t *testing.T) {
|
||||
defer os.Remove("test.sst")
|
||||
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 2. 写入数据
|
||||
writer := NewSSTableWriter(file, schema)
|
||||
@@ -164,9 +167,12 @@ func TestSSTableHeaderSerialization(t *testing.T) {
|
||||
|
||||
func BenchmarkSSTableGet(b *testing.B) {
|
||||
// 创建 Schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "value", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建测试文件
|
||||
file, _ := os.Create("bench.sst")
|
||||
|
||||
5
table.go
5
table.go
@@ -80,7 +80,10 @@ func OpenTable(opts *TableOptions) (*Table, error) {
|
||||
var sch *Schema
|
||||
if opts.Name != "" && len(opts.Fields) > 0 {
|
||||
// 从 Name 和 Fields 创建 Schema
|
||||
sch = NewSchema(opts.Name, opts.Fields)
|
||||
sch, err = NewSchema(opts.Name, opts.Fields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create schema: %w", err)
|
||||
}
|
||||
// 保存到磁盘(带校验和)
|
||||
schemaPath := filepath.Join(opts.Dir, "schema.json")
|
||||
schemaFile, err := NewSchemaFile(sch)
|
||||
|
||||
170
table_test.go
170
table_test.go
@@ -18,10 +18,13 @@ func TestTable(t *testing.T) {
|
||||
os.RemoveAll(dir)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: dir,
|
||||
@@ -80,9 +83,12 @@ func TestTableRecover(t *testing.T) {
|
||||
os.RemoveAll(dir)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "value", Type: FieldTypeInt64, Indexed: false, Comment: "值"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 创建引擎并插入数据
|
||||
table, err := OpenTable(&TableOptions{
|
||||
@@ -143,9 +149,12 @@ func TestTableFlush(t *testing.T) {
|
||||
os.RemoveAll(dir)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "data", Type: FieldTypeString, Indexed: false, Comment: "数据"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: dir,
|
||||
@@ -193,9 +202,12 @@ func BenchmarkTableInsert(b *testing.B) {
|
||||
os.RemoveAll(dir)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "value", Type: FieldTypeInt64, Indexed: false, Comment: "值"},
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
table, _ := OpenTable(&TableOptions{
|
||||
Dir: dir,
|
||||
@@ -219,9 +231,12 @@ func BenchmarkTableGet(b *testing.B) {
|
||||
os.RemoveAll(dir)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "value", Type: FieldTypeInt64, Indexed: false, Comment: "值"},
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
table, _ := OpenTable(&TableOptions{
|
||||
Dir: dir,
|
||||
@@ -251,9 +266,12 @@ func TestHighConcurrencyWrite(t *testing.T) {
|
||||
|
||||
// Note: This test uses []byte payload - we create a minimal schema
|
||||
// Schema validation accepts []byte as it gets JSON-marshaled
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "worker_id", Type: FieldTypeInt64, Indexed: false, Comment: "Worker ID"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -366,9 +384,12 @@ func TestConcurrentReadWrite(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Note: This test uses []byte data - we create a minimal schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "writer_id", Type: FieldTypeInt64, Indexed: false, Comment: "Writer ID"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -485,9 +506,12 @@ func TestPowerFailureRecovery(t *testing.T) {
|
||||
t.Log("=== 阶段 1: 写入数据 ===")
|
||||
|
||||
// Note: This test uses []byte data - we create a minimal schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "batch", Type: FieldTypeInt64, Indexed: false, Comment: "Batch number"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -621,9 +645,12 @@ func TestCrashDuringCompaction(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Note: This test uses []byte data - we create a minimal schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "Index"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -721,9 +748,12 @@ func TestLargeDataIntegrity(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Note: This test uses []byte data - we create a minimal schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "size", Type: FieldTypeInt64, Indexed: false, Comment: "Size"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -832,9 +862,12 @@ func BenchmarkConcurrentWrites(b *testing.B) {
|
||||
tmpDir := b.TempDir()
|
||||
|
||||
// Note: This benchmark uses []byte data - we create a minimal schema
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "timestamp", Type: FieldTypeInt64, Indexed: false, Comment: "Timestamp"},
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -883,11 +916,14 @@ func TestTableWithCompaction(t *testing.T) {
|
||||
// 创建临时目录
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "batch", Type: FieldTypeInt64, Indexed: false, Comment: "批次"},
|
||||
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "索引"},
|
||||
{Name: "value", Type: FieldTypeString, Indexed: false, Comment: "值"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 打开 Table
|
||||
opts := &TableOptions{
|
||||
@@ -1009,11 +1045,14 @@ func TestTableWithCompaction(t *testing.T) {
|
||||
func TestTableCompactionMerge(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "batch", Type: FieldTypeInt64, Indexed: false, Comment: "批次"},
|
||||
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "索引"},
|
||||
{Name: "value", Type: FieldTypeString, Indexed: false, Comment: "值"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -1114,10 +1153,13 @@ func TestTableBackgroundCompaction(t *testing.T) {
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "batch", Type: FieldTypeInt64, Indexed: false, Comment: "批次"},
|
||||
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "索引"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -1201,10 +1243,13 @@ func TestTableBackgroundCompaction(t *testing.T) {
|
||||
func BenchmarkTableWithCompaction(b *testing.B) {
|
||||
tmpDir := b.TempDir()
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "索引"},
|
||||
{Name: "value", Type: FieldTypeString, Indexed: false, Comment: "值"},
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
opts := &TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -1253,11 +1298,14 @@ func TestTableSchemaRecover(t *testing.T) {
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// 创建 Schema
|
||||
s := NewSchema("users", []Field{
|
||||
s, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
{Name: "email", Type: FieldTypeString, Indexed: false, Comment: "邮箱"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 创建引擎并插入数据(带 Schema)
|
||||
table, err := OpenTable(&TableOptions{
|
||||
@@ -1325,10 +1373,13 @@ func TestTableSchemaRecoverInvalid(t *testing.T) {
|
||||
os.RemoveAll(dir)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeString, Indexed: false, Comment: "年龄字符串"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 先不带 Schema 插入一些数据
|
||||
table, err := OpenTable(&TableOptions{
|
||||
@@ -1369,10 +1420,13 @@ func TestTableSchemaRecoverInvalid(t *testing.T) {
|
||||
}
|
||||
|
||||
// 3. 创建 Schema,age 字段要求 int64
|
||||
s := NewSchema("users", []Field{
|
||||
s, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 4. 尝试用 Schema 打开引擎,应该失败
|
||||
table2, err := OpenTable(&TableOptions{
|
||||
@@ -1400,10 +1454,13 @@ func TestTableAutoRecoverSchema(t *testing.T) {
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// 创建 Schema
|
||||
s := NewSchema("users", []Field{
|
||||
s, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 创建引擎并提供 Schema(会保存到磁盘)
|
||||
table1, err := OpenTable(&TableOptions{
|
||||
@@ -1492,10 +1549,13 @@ func TestTableSchemaTamperDetection(t *testing.T) {
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// 创建 Schema
|
||||
s := NewSchema("users", []Field{
|
||||
s, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
|
||||
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 1. 创建引擎并保存 Schema
|
||||
table1, err := OpenTable(&TableOptions{
|
||||
@@ -1554,10 +1614,13 @@ func TestTableClean(t *testing.T) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: true, Comment: "ID"},
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "Name"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := db.CreateTable("users", schema)
|
||||
if err != nil {
|
||||
@@ -1623,9 +1686,12 @@ func TestTableDestroy(t *testing.T) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := db.CreateTable("test", schema)
|
||||
if err != nil {
|
||||
@@ -1679,11 +1745,14 @@ func TestTableCleanWithIndex(t *testing.T) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: true, Comment: "ID"},
|
||||
{Name: "email", Type: FieldTypeString, Indexed: true, Comment: "Email"},
|
||||
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "Name"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := db.CreateTable("users", schema)
|
||||
if err != nil {
|
||||
@@ -1765,10 +1834,13 @@ func TestTableCleanAndQuery(t *testing.T) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schema := NewSchema("test", []Field{
|
||||
schema, err := NewSchema("test", []Field{
|
||||
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
|
||||
{Name: "status", Type: FieldTypeString, Indexed: false, Comment: "Status"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := db.CreateTable("test", schema)
|
||||
if err != nil {
|
||||
@@ -1850,10 +1922,13 @@ func TestInsertMap(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestInsertMap")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -1892,10 +1967,13 @@ func TestInsertMapSlice(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestInsertMapSlice")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -1940,11 +2018,14 @@ func TestInsertStruct(t *testing.T) {
|
||||
Email string `srdb:"email"`
|
||||
}
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
{Name: "email", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -1995,11 +2076,14 @@ func TestInsertStructPointer(t *testing.T) {
|
||||
Email string `srdb:"email"`
|
||||
}
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
{Name: "email", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -2046,10 +2130,13 @@ func TestInsertStructSlice(t *testing.T) {
|
||||
Age int64 `srdb:"age"`
|
||||
}
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -2095,10 +2182,13 @@ func TestInsertStructPointerSlice(t *testing.T) {
|
||||
Age int64 `srdb:"age"`
|
||||
}
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -2146,11 +2236,14 @@ func TestInsertWithSnakeCase(t *testing.T) {
|
||||
IsActive bool // 应该自动转为 is_active
|
||||
}
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "user_name", Type: FieldTypeString, Comment: "用户名"},
|
||||
{Name: "email_address", Type: FieldTypeString},
|
||||
{Name: "is_active", Type: FieldTypeBool},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -2198,9 +2291,12 @@ func TestInsertInvalidType(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestInsertInvalidType")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -2236,9 +2332,12 @@ func TestInsertEmptySlice(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestInsertEmptySlice")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
@@ -2270,10 +2369,13 @@ func TestBatchInsertPerformance(t *testing.T) {
|
||||
tmpDir, _ := os.MkdirTemp("", "TestBatchInsertPerformance")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schema := NewSchema("users", []Field{
|
||||
schema, err := NewSchema("users", []Field{
|
||||
{Name: "name", Type: FieldTypeString},
|
||||
{Name: "age", Type: FieldTypeInt64},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
table, err := OpenTable(&TableOptions{
|
||||
Dir: tmpDir,
|
||||
|
||||
Reference in New Issue
Block a user