Fixed bug/gorm indexes
Some checks are pending
CI / Build (push) Waiting to run
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

This commit is contained in:
2025-12-18 19:15:22 +02:00
parent b7950057eb
commit d93a4b6f08
4 changed files with 622 additions and 142 deletions

View File

@@ -14,18 +14,135 @@ import (
bunwriter "git.warky.dev/wdevs/relspecgo/pkg/writers/bun"
gormwriter "git.warky.dev/wdevs/relspecgo/pkg/writers/gorm"
yamlwriter "git.warky.dev/wdevs/relspecgo/pkg/writers/yaml"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)
// ComparisonResults holds the results of database comparison
type ComparisonResults struct {
Schemas int
Tables int
Columns int
OriginalIndexes int
RoundtripIndexes int
OriginalConstraints int
RoundtripConstraints int
}
// countDatabaseStats counts tables, indexes, and constraints in a database
func countDatabaseStats(db *models.Database) (tables, indexes, constraints int) {
for _, schema := range db.Schemas {
tables += len(schema.Tables)
for _, table := range schema.Tables {
indexes += len(table.Indexes)
constraints += len(table.Constraints)
}
}
return
}
// compareDatabases performs comprehensive comparison between two databases
func compareDatabases(t *testing.T, db1, db2 *models.Database, ormName string) ComparisonResults {
t.Helper()
results := ComparisonResults{}
// Compare high-level structure
t.Log(" Comparing high-level structure...")
require.Equal(t, len(db1.Schemas), len(db2.Schemas), "Schema count should match")
results.Schemas = len(db1.Schemas)
// Count totals
tables1, indexes1, constraints1 := countDatabaseStats(db1)
_, indexes2, constraints2 := countDatabaseStats(db2)
results.OriginalIndexes = indexes1
results.RoundtripIndexes = indexes2
results.OriginalConstraints = constraints1
results.RoundtripConstraints = constraints2
// Compare schemas and tables
for i, schema1 := range db1.Schemas {
if i >= len(db2.Schemas) {
t.Errorf("Schema index %d out of bounds in second database", i)
continue
}
schema2 := db2.Schemas[i]
require.Equal(t, schema1.Name, schema2.Name, "Schema names should match")
require.Equal(t, len(schema1.Tables), len(schema2.Tables),
"Table count in schema '%s' should match", schema1.Name)
// Compare tables
for j, table1 := range schema1.Tables {
if j >= len(schema2.Tables) {
t.Errorf("Table index %d out of bounds in schema '%s'", j, schema1.Name)
continue
}
table2 := schema2.Tables[j]
require.Equal(t, table1.Name, table2.Name,
"Table names should match in schema '%s'", schema1.Name)
// Compare column count
require.Equal(t, len(table1.Columns), len(table2.Columns),
"Column count in table '%s.%s' should match", schema1.Name, table1.Name)
results.Columns += len(table1.Columns)
// Compare each column
for colName, col1 := range table1.Columns {
col2, ok := table2.Columns[colName]
if !ok {
t.Errorf("Column '%s' missing from roundtrip table '%s.%s'",
colName, schema1.Name, table1.Name)
continue
}
// Compare key column properties
require.Equal(t, col1.Name, col2.Name,
"Column name mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
require.Equal(t, col1.Type, col2.Type,
"Column type mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
require.Equal(t, col1.Length, col2.Length,
"Column length mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
require.Equal(t, col1.IsPrimaryKey, col2.IsPrimaryKey,
"Primary key mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
require.Equal(t, col1.NotNull, col2.NotNull,
"NotNull mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
// Log defaults that don't match (these can vary in representation)
if col1.Default != col2.Default {
t.Logf(" Default value differs for '%s.%s.%s': '%v' vs '%v'",
schema1.Name, table1.Name, colName, col1.Default, col2.Default)
}
}
// Log index and constraint differences (ORM readers may not capture all of these)
if len(table1.Indexes) != len(table2.Indexes) {
t.Logf(" Index count differs for table '%s.%s': %d vs %d",
schema1.Name, table1.Name, len(table1.Indexes), len(table2.Indexes))
}
if len(table1.Constraints) != len(table2.Constraints) {
t.Logf(" Constraint count differs for table '%s.%s': %d vs %d",
schema1.Name, table1.Name, len(table1.Constraints), len(table2.Constraints))
}
}
}
results.Tables = tables1
t.Logf(" ✓ Validated %d schemas, %d tables, %d columns", results.Schemas, results.Tables, results.Columns)
return results
}
// TestYAMLToBunRoundTrip tests YAML → Bun Go → YAML roundtrip
func TestYAMLToBunRoundTrip(t *testing.T) {
testDir := t.TempDir()
// Step 1: Read YAML file
t.Log("Step 1: Reading YAML file...")
yamlPath := filepath.Join("..", "assets", "yaml", "database.yaml")
yamlPath := filepath.Join("..", "assets", "yaml", "complex_database.yaml")
yamlReaderOpts := &readers.ReaderOptions{
FilePath: yamlPath,
}
@@ -36,6 +153,10 @@ func TestYAMLToBunRoundTrip(t *testing.T) {
require.NotNil(t, dbFromYAML, "Database from YAML should not be nil")
t.Logf(" ✓ Read database '%s' with %d schemas", dbFromYAML.Name, len(dbFromYAML.Schemas))
// Log initial stats
totalTables, totalIndexes, totalConstraints := countDatabaseStats(dbFromYAML)
t.Logf(" ✓ Original: %d tables, %d indexes, %d constraints", totalTables, totalIndexes, totalConstraints)
// Step 2: Write to Bun Go code
t.Log("Step 2: Writing to Bun Go code...")
bunGoPath := filepath.Join(testDir, "models_bun.go")
@@ -103,67 +224,24 @@ func TestYAMLToBunRoundTrip(t *testing.T) {
err = yaml.Unmarshal(yaml2Data, &db2)
require.NoError(t, err, "Failed to parse second YAML")
// Compare high-level structure
t.Log(" Comparing high-level structure...")
assert.Equal(t, len(db1.Schemas), len(db2.Schemas), "Schema count should match")
// Compare schemas and tables
for i, schema1 := range db1.Schemas {
if i >= len(db2.Schemas) {
t.Errorf("Schema index %d out of bounds in second database", i)
continue
}
schema2 := db2.Schemas[i]
assert.Equal(t, schema1.Name, schema2.Name, "Schema names should match")
assert.Equal(t, len(schema1.Tables), len(schema2.Tables),
"Table count in schema '%s' should match", schema1.Name)
// Compare tables
for j, table1 := range schema1.Tables {
if j >= len(schema2.Tables) {
t.Errorf("Table index %d out of bounds in schema '%s'", j, schema1.Name)
continue
}
table2 := schema2.Tables[j]
assert.Equal(t, table1.Name, table2.Name,
"Table names should match in schema '%s'", schema1.Name)
// Compare column count
assert.Equal(t, len(table1.Columns), len(table2.Columns),
"Column count in table '%s.%s' should match", schema1.Name, table1.Name)
// Compare each column
for colName, col1 := range table1.Columns {
col2, ok := table2.Columns[colName]
if !ok {
t.Errorf("Column '%s' missing from roundtrip table '%s.%s'",
colName, schema1.Name, table1.Name)
continue
}
// Compare key column properties
assert.Equal(t, col1.Name, col2.Name,
"Column name mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
assert.Equal(t, col1.Type, col2.Type,
"Column type mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
assert.Equal(t, col1.IsPrimaryKey, col2.IsPrimaryKey,
"Primary key mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
}
}
}
// Comprehensive comparison
compareResults := compareDatabases(t, &db1, &db2, "Bun")
// Summary
t.Log("Summary:")
t.Logf(" ✓ Round-trip completed: YAML → Bun → YAML")
t.Logf(" ✓ Schemas match: %d", len(db1.Schemas))
t.Logf(" ✓ Schemas: %d", compareResults.Schemas)
t.Logf(" ✓ Tables: %d", compareResults.Tables)
t.Logf(" ✓ Columns: %d", compareResults.Columns)
t.Logf(" ✓ Indexes: %d (original), %d (roundtrip)", compareResults.OriginalIndexes, compareResults.RoundtripIndexes)
t.Logf(" ✓ Constraints: %d (original), %d (roundtrip)", compareResults.OriginalConstraints, compareResults.RoundtripConstraints)
totalTables := 0
for _, schema := range db1.Schemas {
totalTables += len(schema.Tables)
if compareResults.OriginalIndexes != compareResults.RoundtripIndexes {
t.Logf(" ⚠ Note: Index counts differ - Bun reader may not parse all index information from Go code")
}
if compareResults.OriginalConstraints != compareResults.RoundtripConstraints {
t.Logf(" ⚠ Note: Constraint counts differ - Bun reader may not parse all constraint information from Go code")
}
t.Logf(" ✓ Total tables: %d", totalTables)
}
// TestYAMLToGORMRoundTrip tests YAML → GORM Go → YAML roundtrip
@@ -172,7 +250,7 @@ func TestYAMLToGORMRoundTrip(t *testing.T) {
// Step 1: Read YAML file
t.Log("Step 1: Reading YAML file...")
yamlPath := filepath.Join("..", "assets", "yaml", "database.yaml")
yamlPath := filepath.Join("..", "assets", "yaml", "complex_database.yaml")
yamlReaderOpts := &readers.ReaderOptions{
FilePath: yamlPath,
}
@@ -183,6 +261,10 @@ func TestYAMLToGORMRoundTrip(t *testing.T) {
require.NotNil(t, dbFromYAML, "Database from YAML should not be nil")
t.Logf(" ✓ Read database '%s' with %d schemas", dbFromYAML.Name, len(dbFromYAML.Schemas))
// Log initial stats
totalTables, totalIndexes, totalConstraints := countDatabaseStats(dbFromYAML)
t.Logf(" ✓ Original: %d tables, %d indexes, %d constraints", totalTables, totalIndexes, totalConstraints)
// Step 2: Write to GORM Go code
t.Log("Step 2: Writing to GORM Go code...")
gormGoPath := filepath.Join(testDir, "models_gorm.go")
@@ -250,65 +332,22 @@ func TestYAMLToGORMRoundTrip(t *testing.T) {
err = yaml.Unmarshal(yaml2Data, &db2)
require.NoError(t, err, "Failed to parse second YAML")
// Compare high-level structure
t.Log(" Comparing high-level structure...")
assert.Equal(t, len(db1.Schemas), len(db2.Schemas), "Schema count should match")
// Compare schemas and tables
for i, schema1 := range db1.Schemas {
if i >= len(db2.Schemas) {
t.Errorf("Schema index %d out of bounds in second database", i)
continue
}
schema2 := db2.Schemas[i]
assert.Equal(t, schema1.Name, schema2.Name, "Schema names should match")
assert.Equal(t, len(schema1.Tables), len(schema2.Tables),
"Table count in schema '%s' should match", schema1.Name)
// Compare tables
for j, table1 := range schema1.Tables {
if j >= len(schema2.Tables) {
t.Errorf("Table index %d out of bounds in schema '%s'", j, schema1.Name)
continue
}
table2 := schema2.Tables[j]
assert.Equal(t, table1.Name, table2.Name,
"Table names should match in schema '%s'", schema1.Name)
// Compare column count
assert.Equal(t, len(table1.Columns), len(table2.Columns),
"Column count in table '%s.%s' should match", schema1.Name, table1.Name)
// Compare each column
for colName, col1 := range table1.Columns {
col2, ok := table2.Columns[colName]
if !ok {
t.Errorf("Column '%s' missing from roundtrip table '%s.%s'",
colName, schema1.Name, table1.Name)
continue
}
// Compare key column properties
assert.Equal(t, col1.Name, col2.Name,
"Column name mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
assert.Equal(t, col1.Type, col2.Type,
"Column type mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
assert.Equal(t, col1.IsPrimaryKey, col2.IsPrimaryKey,
"Primary key mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
}
}
}
// Comprehensive comparison
compareResults := compareDatabases(t, &db1, &db2, "GORM")
// Summary
t.Log("Summary:")
t.Logf(" ✓ Round-trip completed: YAML → GORM → YAML")
t.Logf(" ✓ Schemas match: %d", len(db1.Schemas))
t.Logf(" ✓ Schemas: %d", compareResults.Schemas)
t.Logf(" ✓ Tables: %d", compareResults.Tables)
t.Logf(" ✓ Columns: %d", compareResults.Columns)
t.Logf(" ✓ Indexes: %d (original), %d (roundtrip)", compareResults.OriginalIndexes, compareResults.RoundtripIndexes)
t.Logf(" ✓ Constraints: %d (original), %d (roundtrip)", compareResults.OriginalConstraints, compareResults.RoundtripConstraints)
totalTables := 0
for _, schema := range db1.Schemas {
totalTables += len(schema.Tables)
if compareResults.OriginalIndexes != compareResults.RoundtripIndexes {
t.Logf(" ⚠ Note: Index counts differ - GORM reader may not parse all index information from Go code")
}
if compareResults.OriginalConstraints != compareResults.RoundtripConstraints {
t.Logf(" ⚠ Note: Constraint counts differ - GORM reader may not parse all constraint information from Go code")
}
t.Logf(" ✓ Total tables: %d", totalTables)
}