fix(bun): support extra generated model fields

This commit is contained in:
Hermes Agent
2026-07-09 05:50:33 +02:00
parent 7805d9b6f0
commit 47b77763cb
7 changed files with 359 additions and 2 deletions
+160
View File
@@ -855,6 +855,166 @@ func TestTypeMapper_BuildBunTag_StdlibArrayHasArrayTag(t *testing.T) {
}
}
func TestExtraFields_LoadFromMetadata(t *testing.T) {
tests := []struct {
name string
metadata map[string]interface{}
expected int
}{
{
name: "nil metadata",
metadata: nil,
expected: 0,
},
{
name: "no extra_fields key",
metadata: map[string]interface{}{
"generate_table_name": true,
},
expected: 0,
},
{
name: "empty array",
metadata: map[string]interface{}{
"extra_fields": []interface{}{},
},
expected: 0,
},
{
name: "JSON string format",
metadata: map[string]interface{}{
"extra_fields": `[{"name":"ThoughtCount","type":"int64","bun_tag":"thought_count,scanonly","json_tag":"thought_count"}]`,
},
expected: 1,
},
{
name: "structured format",
metadata: map[string]interface{}{
"extra_fields": []interface{}{
map[string]interface{}{
"name": "ThoughtCount",
"type": "int64",
"bun_tag": "thought_count,scanonly",
"json_tag": "thought_count",
},
},
},
expected: 1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fields := LoadExtraFieldsFromMetadata(tt.metadata)
if len(fields) != tt.expected {
t.Errorf("expected %d fields, got %d", tt.expected, len(fields))
}
})
}
}
func TestExtraFields_InSingleFile(t *testing.T) {
table := models.InitTable("projects", "public")
table.Columns["id"] = &models.Column{
Name: "id",
Type: "bigint",
NotNull: true,
IsPrimaryKey: true,
}
table.Columns["name"] = &models.Column{
Name: "name",
Type: "varchar",
Length: 255,
Sequence: 1,
}
opts := &writers.WriterOptions{
PackageName: "models",
OutputPath: t.TempDir() + "/test.go",
Metadata: map[string]interface{}{
"extra_fields": `[{"name":"ThoughtCount","type":"int64","bun_tag":"thought_count,scanonly","json_tag":"thought_count"}]`,
},
}
writer := NewWriter(opts)
err := writer.WriteTable(table)
if err != nil {
t.Fatalf("WriteTable failed: %v", err)
}
content, _ := os.ReadFile(opts.OutputPath)
generated := string(content)
// Verify extra field is present with separator comment
expectations := []string{
"// --- Custom fields (managed by relspecgo generator config, issue #4) ---",
"ThoughtCount int64 `bun:\"thought_count,scanonly\" json:\"thought_count\"`",
}
for _, expected := range expectations {
if !strings.Contains(generated, expected) {
t.Errorf("Generated code missing: %q\nGenerated:\n%s", expected, generated)
}
}
}
func TestExtraFields_InMultiFile(t *testing.T) {
db := models.InitDatabase("testdb")
schema := models.InitSchema("public")
users := models.InitTable("users", "public")
users.Columns["id"] = &models.Column{
Name: "id",
Type: "bigint",
NotNull: true,
IsPrimaryKey: true,
}
schema.Tables = append(schema.Tables, users)
posts := models.InitTable("posts", "public")
posts.Columns["id"] = &models.Column{
Name: "id",
Type: "bigint",
NotNull: true,
IsPrimaryKey: true,
}
schema.Tables = append(schema.Tables, posts)
db.Schemas = append(db.Schemas, schema)
tmpDir := t.TempDir()
opts := &writers.WriterOptions{
PackageName: "models",
OutputPath: tmpDir,
Metadata: map[string]interface{}{
"multi_file": true,
"extra_fields": `[{"target_table":"users","name":"PostCount","type":"int64","bun_tag":"post_count,scanonly","json_tag":"post_count"}]`,
},
}
writer := NewWriter(opts)
err := writer.WriteDatabase(db)
if err != nil {
t.Fatalf("WriteDatabase failed: %v", err)
}
// Check users file has the extra field (matched by table name "users")
usersContent, _ := os.ReadFile(tmpDir + "/sql_public_users.go")
usersStr := string(usersContent)
if !strings.Contains(usersStr, "PostCount int64 `bun:\"post_count,scanonly\"") {
t.Errorf("Extra field not found in users file:\n%s", usersStr)
}
// Posts file should NOT have the extra field (name mismatch)
postsContent, _ := os.ReadFile(tmpDir + "/sql_public_posts.go")
postsStr := string(postsContent)
if strings.Contains(postsStr, "PostCount") {
t.Errorf("Extra field should not be in posts file:\n%s", postsStr)
}
}
func TestTypeMapper_BuildBunTag_PreservesExplicitTypeModifiers(t *testing.T) {
mapper := NewTypeMapper("")