More Roundtrip tests
This commit is contained in:
194
pkg/writers/dctx/roundtrip_test.go
Normal file
194
pkg/writers/dctx/roundtrip_test.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package dctx
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||
dctxreader "git.warky.dev/wdevs/relspecgo/pkg/readers/dctx"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRoundTrip_WriteAndRead(t *testing.T) {
|
||||
// 1. Create a sample schema with relationships
|
||||
schema := models.InitSchema("public")
|
||||
schema.Name = "TestDB"
|
||||
|
||||
// Table 1: users
|
||||
usersTable := models.InitTable("users", "public")
|
||||
usersTable.Comment = "Stores user information"
|
||||
idCol := models.InitColumn("id", "users", "public")
|
||||
idCol.Type = "serial"
|
||||
idCol.IsPrimaryKey = true
|
||||
idCol.NotNull = true
|
||||
usersTable.Columns["id"] = idCol
|
||||
nameCol := models.InitColumn("name", "users", "public")
|
||||
nameCol.Type = "varchar"
|
||||
nameCol.Length = 100
|
||||
usersTable.Columns["name"] = nameCol
|
||||
pkIndex := models.InitIndex("users_pkey", "users", "public")
|
||||
pkIndex.Unique = true
|
||||
pkIndex.Columns = []string{"id"}
|
||||
usersTable.Indexes["users_pkey"] = pkIndex
|
||||
|
||||
pkConstraint := models.InitConstraint("users_pkey", models.PrimaryKeyConstraint)
|
||||
pkConstraint.Table = "users"
|
||||
pkConstraint.Schema = "public"
|
||||
pkConstraint.Columns = []string{"id"}
|
||||
usersTable.Constraints["users_pkey"] = pkConstraint
|
||||
|
||||
schema.Tables = append(schema.Tables, usersTable)
|
||||
|
||||
// Table 2: posts
|
||||
postsTable := models.InitTable("posts", "public")
|
||||
postsTable.Comment = "Stores blog posts"
|
||||
postIDCol := models.InitColumn("id", "posts", "public")
|
||||
postIDCol.Type = "serial"
|
||||
postIDCol.IsPrimaryKey = true
|
||||
postIDCol.NotNull = true
|
||||
postsTable.Columns["id"] = postIDCol
|
||||
titleCol := models.InitColumn("title", "posts", "public")
|
||||
titleCol.Type = "varchar"
|
||||
titleCol.Length = 255
|
||||
postsTable.Columns["title"] = titleCol
|
||||
userIDCol := models.InitColumn("user_id", "posts", "public")
|
||||
userIDCol.Type = "integer"
|
||||
postsTable.Columns["user_id"] = userIDCol
|
||||
postsPKIndex := models.InitIndex("posts_pkey", "posts", "public")
|
||||
postsPKIndex.Unique = true
|
||||
postsPKIndex.Columns = []string{"id"}
|
||||
postsTable.Indexes["posts_pkey"] = postsPKIndex
|
||||
|
||||
fkIndex := models.InitIndex("posts_user_id_idx", "posts", "public")
|
||||
fkIndex.Columns = []string{"user_id"}
|
||||
postsTable.Indexes["posts_user_id_idx"] = fkIndex
|
||||
|
||||
postsPKConstraint := models.InitConstraint("posts_pkey", models.PrimaryKeyConstraint)
|
||||
postsPKConstraint.Table = "posts"
|
||||
postsPKConstraint.Schema = "public"
|
||||
postsPKConstraint.Columns = []string{"id"}
|
||||
postsTable.Constraints["posts_pkey"] = postsPKConstraint
|
||||
|
||||
// Foreign key constraint
|
||||
fkConstraint := models.InitConstraint("fk_posts_users", models.ForeignKeyConstraint)
|
||||
fkConstraint.Table = "posts"
|
||||
fkConstraint.Schema = "public"
|
||||
fkConstraint.Columns = []string{"user_id"}
|
||||
fkConstraint.ReferencedTable = "users"
|
||||
fkConstraint.ReferencedSchema = "public"
|
||||
fkConstraint.ReferencedColumns = []string{"id"}
|
||||
fkConstraint.OnDelete = "CASCADE"
|
||||
fkConstraint.OnUpdate = "NO ACTION"
|
||||
postsTable.Constraints["fk_posts_users"] = fkConstraint
|
||||
|
||||
schema.Tables = append(schema.Tables, postsTable)
|
||||
|
||||
// Relation
|
||||
relation := models.InitRelationship("posts_to_users", models.OneToMany)
|
||||
relation.FromTable = "posts"
|
||||
relation.FromSchema = "public"
|
||||
relation.ToTable = "users"
|
||||
relation.ToSchema = "public"
|
||||
relation.ForeignKey = "fk_posts_users"
|
||||
schema.Relations = append(schema.Relations, relation)
|
||||
|
||||
// 2. Write the schema to DCTX
|
||||
outputPath := filepath.Join(t.TempDir(), "roundtrip.dctx")
|
||||
writerOpts := &writers.WriterOptions{
|
||||
OutputPath: outputPath,
|
||||
}
|
||||
writer := NewWriter(writerOpts)
|
||||
|
||||
err := writer.WriteSchema(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Verify file was created
|
||||
_, err = os.Stat(outputPath)
|
||||
assert.NoError(t, err, "Output file should exist")
|
||||
|
||||
// 3. Read the schema back from DCTX
|
||||
readerOpts := &readers.ReaderOptions{
|
||||
FilePath: outputPath,
|
||||
}
|
||||
reader := dctxreader.NewReader(readerOpts)
|
||||
|
||||
db, err := reader.ReadDatabase()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, db)
|
||||
|
||||
// 4. Verify the schema was read correctly
|
||||
assert.Len(t, db.Schemas, 1, "Should have one schema")
|
||||
readSchema := db.Schemas[0]
|
||||
|
||||
// Verify tables
|
||||
assert.Len(t, readSchema.Tables, 2, "Should have two tables")
|
||||
|
||||
// Find users and posts tables
|
||||
var readUsersTable, readPostsTable *models.Table
|
||||
for _, table := range readSchema.Tables {
|
||||
switch table.Name {
|
||||
case "users":
|
||||
readUsersTable = table
|
||||
case "posts":
|
||||
readPostsTable = table
|
||||
}
|
||||
}
|
||||
|
||||
assert.NotNil(t, readUsersTable, "Users table should exist")
|
||||
assert.NotNil(t, readPostsTable, "Posts table should exist")
|
||||
|
||||
// Verify columns
|
||||
assert.Len(t, readUsersTable.Columns, 2, "Users table should have 2 columns")
|
||||
assert.NotNil(t, readUsersTable.Columns["id"])
|
||||
assert.NotNil(t, readUsersTable.Columns["name"])
|
||||
|
||||
assert.Len(t, readPostsTable.Columns, 3, "Posts table should have 3 columns")
|
||||
assert.NotNil(t, readPostsTable.Columns["id"])
|
||||
assert.NotNil(t, readPostsTable.Columns["title"])
|
||||
assert.NotNil(t, readPostsTable.Columns["user_id"])
|
||||
|
||||
// Verify relationships were preserved
|
||||
// The DCTX reader stores relationships on the foreign table (posts)
|
||||
assert.NotEmpty(t, readPostsTable.Relationships, "Posts table should have relationships")
|
||||
|
||||
// Debug: print all relationships
|
||||
t.Logf("Posts table has %d relationships:", len(readPostsTable.Relationships))
|
||||
for name, rel := range readPostsTable.Relationships {
|
||||
t.Logf(" - %s: from=%s to=%s fk=%s", name, rel.FromTable, rel.ToTable, rel.ForeignKey)
|
||||
}
|
||||
|
||||
// Find the relationship - the reader creates it with FromTable as primary and ToTable as foreign
|
||||
var postsToUsersRel *models.Relationship
|
||||
for _, rel := range readPostsTable.Relationships {
|
||||
// The relationship should have posts as ToTable (foreign) and users as FromTable (primary)
|
||||
if rel.FromTable == "users" && rel.ToTable == "posts" {
|
||||
postsToUsersRel = rel
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.NotNil(t, postsToUsersRel, "Should have relationship from users to posts")
|
||||
if postsToUsersRel != nil {
|
||||
assert.Equal(t, "users", postsToUsersRel.FromTable, "Relationship should come from users (primary) table")
|
||||
assert.Equal(t, "posts", postsToUsersRel.ToTable, "Relationship should point to posts (foreign) table")
|
||||
assert.NotEmpty(t, postsToUsersRel.ForeignKey, "Relationship should have a foreign key")
|
||||
}
|
||||
|
||||
// Verify foreign key constraint
|
||||
fks := readPostsTable.GetForeignKeys()
|
||||
assert.NotEmpty(t, fks, "Posts table should have foreign keys")
|
||||
|
||||
if len(fks) > 0 {
|
||||
fk := fks[0]
|
||||
assert.Equal(t, models.ForeignKeyConstraint, fk.Type)
|
||||
assert.Contains(t, fk.Columns, "user_id")
|
||||
assert.Equal(t, "users", fk.ReferencedTable)
|
||||
assert.Contains(t, fk.ReferencedColumns, "id")
|
||||
assert.Equal(t, "CASCADE", fk.OnDelete)
|
||||
}
|
||||
|
||||
t.Logf("Round-trip test successful: wrote and read back %d tables with relationships", len(readSchema.Tables))
|
||||
}
|
||||
Reference in New Issue
Block a user