Files
relspecgo/pkg/writers/bun/writer_test.go
Hein 5d60bc3b2c
Some checks are pending
CI / Test (1.23) (push) Waiting to run
CI / Test (1.24) (push) Waiting to run
CI / Test (1.25) (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Build (push) Waiting to run
Bugs Fixed
1. pkg/models/models.go:184 - Fixed typo in ForeignKeyConstraint constant from "foreign_Key" to "foreign_key"
  2. pkg/readers/drawdb/reader.go:62-68 - Fixed ReadSchema() to properly detect schema name from tables instead of hardcoding "default"
  3. pkg/writers/dbml/writer.go:128 - Changed primary key attribute from "primary key" to DBML standard "pk"
  4. pkg/writers/dbml/writer.go:208-221 - Fixed foreign key reference format to use "table.column" syntax for single columns instead of "table.(column)"

  Test Results

  All reader and writer tests are now passing:

  Readers:
  - DBML: 74.4% coverage (2 tests skipped due to missing parser features for Ref statements)
  - DCTX: 77.6% coverage
  - DrawDB: 83.6% coverage
  - JSON: 82.1% coverage
  - YAML: 82.1% coverage

  Writers:
  - Bun: 68.5% coverage
  - DBML: 91.5% coverage
  - DCTX: 100.0% coverage
  - DrawDB: 83.8% coverage
  - GORM: 69.2% coverage
  - JSON: 82.4% coverage
  - YAML: 82.4% coverage
2025-12-16 21:43:45 +02:00

268 lines
6.3 KiB
Go

package bun
import (
"os"
"path/filepath"
"strings"
"testing"
"git.warky.dev/wdevs/relspecgo/pkg/models"
"git.warky.dev/wdevs/relspecgo/pkg/writers"
)
func TestWriter_WriteTable(t *testing.T) {
// Create a simple table
table := models.InitTable("users", "public")
table.Columns["id"] = &models.Column{
Name: "id",
Type: "bigint",
NotNull: true,
IsPrimaryKey: true,
AutoIncrement: true,
Sequence: 1,
}
table.Columns["email"] = &models.Column{
Name: "email",
Type: "varchar",
Length: 255,
NotNull: false,
Sequence: 2,
}
table.Columns["created_at"] = &models.Column{
Name: "created_at",
Type: "timestamp",
NotNull: true,
Sequence: 3,
}
// Create writer
opts := &writers.WriterOptions{
PackageName: "models",
Metadata: map[string]interface{}{
"generate_table_name": true,
"generate_get_id": true,
},
}
writer := NewWriter(opts)
// Write to temporary file
tmpDir := t.TempDir()
opts.OutputPath = filepath.Join(tmpDir, "test.go")
err := writer.WriteTable(table)
if err != nil {
t.Fatalf("WriteTable failed: %v", err)
}
// Read the generated file
content, err := os.ReadFile(opts.OutputPath)
if err != nil {
t.Fatalf("Failed to read generated file: %v", err)
}
generated := string(content)
// Verify key elements are present
expectations := []string{
"package models",
"type ModelUser struct",
"bun.BaseModel",
"table:public.users",
"alias:users",
"ID",
"int64",
"Email",
"resolvespec_common.SqlString",
"CreatedAt",
"resolvespec_common.SqlTime",
"bun:\"id",
"bun:\"email",
"func (m ModelUser) TableName() string",
"return \"public.users\"",
"func (m ModelUser) GetID() int64",
}
for _, expected := range expectations {
if !strings.Contains(generated, expected) {
t.Errorf("Generated code missing expected content: %q\nGenerated:\n%s", expected, generated)
}
}
// Verify Bun-specific elements
if !strings.Contains(generated, "bun:\"id,type:bigint,pk,") {
t.Errorf("Missing Bun-style primary key tag")
}
}
func TestWriter_WriteDatabase_MultiFile(t *testing.T) {
// Create a database with two tables
db := models.InitDatabase("testdb")
schema := models.InitSchema("public")
// Table 1: users
users := models.InitTable("users", "public")
users.Columns["id"] = &models.Column{
Name: "id",
Type: "bigint",
NotNull: true,
IsPrimaryKey: true,
}
schema.Tables = append(schema.Tables, users)
// Table 2: posts
posts := models.InitTable("posts", "public")
posts.Columns["id"] = &models.Column{
Name: "id",
Type: "bigint",
NotNull: true,
IsPrimaryKey: true,
}
posts.Columns["user_id"] = &models.Column{
Name: "user_id",
Type: "bigint",
NotNull: true,
}
posts.Constraints["fk_user"] = &models.Constraint{
Name: "fk_user",
Type: models.ForeignKeyConstraint,
Columns: []string{"user_id"},
ReferencedTable: "users",
ReferencedSchema: "public",
ReferencedColumns: []string{"id"},
OnDelete: "CASCADE",
}
schema.Tables = append(schema.Tables, posts)
db.Schemas = append(db.Schemas, schema)
// Create writer with multi-file mode
tmpDir := t.TempDir()
opts := &writers.WriterOptions{
PackageName: "models",
OutputPath: tmpDir,
Metadata: map[string]interface{}{
"multi_file": true,
},
}
writer := NewWriter(opts)
err := writer.WriteDatabase(db)
if err != nil {
t.Fatalf("WriteDatabase failed: %v", err)
}
// Verify two files were created
expectedFiles := []string{
"sql_public_users.go",
"sql_public_posts.go",
}
for _, filename := range expectedFiles {
filepath := filepath.Join(tmpDir, filename)
if _, err := os.Stat(filepath); os.IsNotExist(err) {
t.Errorf("Expected file not created: %s", filename)
}
}
// Check posts file contains relationship
postsContent, err := os.ReadFile(filepath.Join(tmpDir, "sql_public_posts.go"))
if err != nil {
t.Fatalf("Failed to read posts file: %v", err)
}
postsStr := string(postsContent)
// Verify relationship is present with Bun format
if !strings.Contains(postsStr, "USE") {
t.Errorf("Missing relationship field USE")
}
if !strings.Contains(postsStr, "rel:has-one") {
t.Errorf("Missing Bun relationship tag: %s", postsStr)
}
}
func TestTypeMapper_SQLTypeToGoType_Bun(t *testing.T) {
mapper := NewTypeMapper()
tests := []struct {
sqlType string
notNull bool
want string
}{
{"bigint", true, "int64"},
{"bigint", false, "resolvespec_common.SqlInt64"},
{"varchar", true, "resolvespec_common.SqlString"}, // Bun uses sql types even for NOT NULL strings
{"varchar", false, "resolvespec_common.SqlString"},
{"timestamp", true, "resolvespec_common.SqlTime"},
{"timestamp", false, "resolvespec_common.SqlTime"},
{"date", false, "resolvespec_common.SqlDate"},
{"boolean", true, "bool"},
{"boolean", false, "resolvespec_common.SqlBool"},
{"uuid", false, "resolvespec_common.SqlUUID"},
{"jsonb", false, "resolvespec_common.SqlJSONB"},
}
for _, tt := range tests {
t.Run(tt.sqlType, func(t *testing.T) {
result := mapper.SQLTypeToGoType(tt.sqlType, tt.notNull)
if result != tt.want {
t.Errorf("SQLTypeToGoType(%q, %v) = %q, want %q", tt.sqlType, tt.notNull, result, tt.want)
}
})
}
}
func TestTypeMapper_BuildBunTag(t *testing.T) {
mapper := NewTypeMapper()
tests := []struct {
name string
column *models.Column
want []string // Parts that should be in the tag
}{
{
name: "primary key",
column: &models.Column{
Name: "id",
Type: "bigint",
IsPrimaryKey: true,
NotNull: true,
},
want: []string{"id,", "type:bigint,", "pk,"},
},
{
name: "nullable varchar",
column: &models.Column{
Name: "email",
Type: "varchar",
Length: 255,
NotNull: false,
},
want: []string{"email,", "type:varchar(255),", "nullzero,"},
},
{
name: "with default",
column: &models.Column{
Name: "status",
Type: "text",
NotNull: true,
Default: "active",
},
want: []string{"status,", "type:text,", "default:active,"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := mapper.BuildBunTag(tt.column, nil)
for _, part := range tt.want {
if !strings.Contains(result, part) {
t.Errorf("BuildBunTag() = %q, missing %q", result, part)
}
}
})
}
}