feat(merge): 🎉 Add support for constraints and indexes in merge results
All checks were successful
CI / Test (1.24) (push) Successful in -26m24s
CI / Test (1.25) (push) Successful in -26m10s
CI / Lint (push) Successful in -26m33s
CI / Build (push) Successful in -26m40s
Release / Build and Release (push) Successful in -26m23s
Integration Tests / Integration Tests (push) Successful in -25m53s
All checks were successful
CI / Test (1.24) (push) Successful in -26m24s
CI / Test (1.25) (push) Successful in -26m10s
CI / Lint (push) Successful in -26m33s
CI / Build (push) Successful in -26m40s
Release / Build and Release (push) Successful in -26m23s
Integration Tests / Integration Tests (push) Successful in -25m53s
* Enhance MergeResult to track added constraints and indexes. * Update merge logic to increment counters for added constraints and indexes. * Modify GetMergeSummary to include constraints and indexes in the output. * Add comprehensive tests for merging constraints and indexes.
This commit is contained in:
@@ -15,6 +15,8 @@ type MergeResult struct {
|
|||||||
SchemasAdded int
|
SchemasAdded int
|
||||||
TablesAdded int
|
TablesAdded int
|
||||||
ColumnsAdded int
|
ColumnsAdded int
|
||||||
|
ConstraintsAdded int
|
||||||
|
IndexesAdded int
|
||||||
RelationsAdded int
|
RelationsAdded int
|
||||||
DomainsAdded int
|
DomainsAdded int
|
||||||
EnumsAdded int
|
EnumsAdded int
|
||||||
@@ -171,6 +173,7 @@ func (r *MergeResult) mergeConstraints(table *models.Table, srcTable *models.Tab
|
|||||||
// Constraint doesn't exist, add it
|
// Constraint doesn't exist, add it
|
||||||
newConst := cloneConstraint(srcConst)
|
newConst := cloneConstraint(srcConst)
|
||||||
table.Constraints[constName] = newConst
|
table.Constraints[constName] = newConst
|
||||||
|
r.ConstraintsAdded++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,6 +196,7 @@ func (r *MergeResult) mergeIndexes(table *models.Table, srcTable *models.Table)
|
|||||||
// Index doesn't exist, add it
|
// Index doesn't exist, add it
|
||||||
newIdx := cloneIndex(srcIdx)
|
newIdx := cloneIndex(srcIdx)
|
||||||
table.Indexes[idxName] = newIdx
|
table.Indexes[idxName] = newIdx
|
||||||
|
r.IndexesAdded++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -598,6 +602,8 @@ func GetMergeSummary(result *MergeResult) string {
|
|||||||
fmt.Sprintf("Schemas added: %d", result.SchemasAdded),
|
fmt.Sprintf("Schemas added: %d", result.SchemasAdded),
|
||||||
fmt.Sprintf("Tables added: %d", result.TablesAdded),
|
fmt.Sprintf("Tables added: %d", result.TablesAdded),
|
||||||
fmt.Sprintf("Columns added: %d", result.ColumnsAdded),
|
fmt.Sprintf("Columns added: %d", result.ColumnsAdded),
|
||||||
|
fmt.Sprintf("Constraints added: %d", result.ConstraintsAdded),
|
||||||
|
fmt.Sprintf("Indexes added: %d", result.IndexesAdded),
|
||||||
fmt.Sprintf("Views added: %d", result.ViewsAdded),
|
fmt.Sprintf("Views added: %d", result.ViewsAdded),
|
||||||
fmt.Sprintf("Sequences added: %d", result.SequencesAdded),
|
fmt.Sprintf("Sequences added: %d", result.SequencesAdded),
|
||||||
fmt.Sprintf("Enums added: %d", result.EnumsAdded),
|
fmt.Sprintf("Enums added: %d", result.EnumsAdded),
|
||||||
@@ -606,6 +612,7 @@ func GetMergeSummary(result *MergeResult) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
totalAdded := result.SchemasAdded + result.TablesAdded + result.ColumnsAdded +
|
totalAdded := result.SchemasAdded + result.TablesAdded + result.ColumnsAdded +
|
||||||
|
result.ConstraintsAdded + result.IndexesAdded +
|
||||||
result.ViewsAdded + result.SequencesAdded + result.EnumsAdded +
|
result.ViewsAdded + result.SequencesAdded + result.EnumsAdded +
|
||||||
result.RelationsAdded + result.DomainsAdded
|
result.RelationsAdded + result.DomainsAdded
|
||||||
|
|
||||||
|
|||||||
617
pkg/merge/merge_test.go
Normal file
617
pkg/merge/merge_test.go
Normal file
@@ -0,0 +1,617 @@
|
|||||||
|
package merge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMergeDatabases_NilInputs(t *testing.T) {
|
||||||
|
result := MergeDatabases(nil, nil, nil)
|
||||||
|
if result == nil {
|
||||||
|
t.Fatal("Expected non-nil result")
|
||||||
|
}
|
||||||
|
if result.SchemasAdded != 0 {
|
||||||
|
t.Errorf("Expected 0 schemas added, got %d", result.SchemasAdded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeDatabases_NewSchema(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{Name: "public"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{Name: "auth"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.SchemasAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 schema added, got %d", result.SchemasAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas) != 2 {
|
||||||
|
t.Errorf("Expected 2 schemas in target, got %d", len(target.Schemas))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeDatabases_ExistingSchema(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{Name: "public"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{Name: "public"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.SchemasAdded != 0 {
|
||||||
|
t.Errorf("Expected 0 schemas added, got %d", result.SchemasAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas) != 1 {
|
||||||
|
t.Errorf("Expected 1 schema in target, got %d", len(target.Schemas))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeTables_NewTable(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "posts",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.TablesAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 table added, got %d", result.TablesAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Tables) != 2 {
|
||||||
|
t.Errorf("Expected 2 tables in target schema, got %d", len(target.Schemas[0].Tables))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeColumns_NewColumn(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{
|
||||||
|
"id": {Name: "id", Type: "int"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{
|
||||||
|
"email": {Name: "email", Type: "varchar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.ColumnsAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 column added, got %d", result.ColumnsAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Tables[0].Columns) != 2 {
|
||||||
|
t.Errorf("Expected 2 columns in target table, got %d", len(target.Schemas[0].Tables[0].Columns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeConstraints_NewConstraint(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
Constraints: map[string]*models.Constraint{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
Constraints: map[string]*models.Constraint{
|
||||||
|
"ukey_users_email": {
|
||||||
|
Type: models.UniqueConstraint,
|
||||||
|
Columns: []string{"email"},
|
||||||
|
Name: "ukey_users_email",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.ConstraintsAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 constraint added, got %d", result.ConstraintsAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Tables[0].Constraints) != 1 {
|
||||||
|
t.Errorf("Expected 1 constraint in target table, got %d", len(target.Schemas[0].Tables[0].Constraints))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeConstraints_NilConstraintsMap(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
Constraints: nil, // Nil map
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
Constraints: map[string]*models.Constraint{
|
||||||
|
"ukey_users_email": {
|
||||||
|
Type: models.UniqueConstraint,
|
||||||
|
Columns: []string{"email"},
|
||||||
|
Name: "ukey_users_email",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.ConstraintsAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 constraint added, got %d", result.ConstraintsAdded)
|
||||||
|
}
|
||||||
|
if target.Schemas[0].Tables[0].Constraints == nil {
|
||||||
|
t.Error("Expected constraints map to be initialized")
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Tables[0].Constraints) != 1 {
|
||||||
|
t.Errorf("Expected 1 constraint in target table, got %d", len(target.Schemas[0].Tables[0].Constraints))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeIndexes_NewIndex(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
Indexes: map[string]*models.Index{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
Indexes: map[string]*models.Index{
|
||||||
|
"idx_users_email": {
|
||||||
|
Name: "idx_users_email",
|
||||||
|
Columns: []string{"email"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.IndexesAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 index added, got %d", result.IndexesAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Tables[0].Indexes) != 1 {
|
||||||
|
t.Errorf("Expected 1 index in target table, got %d", len(target.Schemas[0].Tables[0].Indexes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeIndexes_NilIndexesMap(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
Indexes: nil, // Nil map
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
Indexes: map[string]*models.Index{
|
||||||
|
"idx_users_email": {
|
||||||
|
Name: "idx_users_email",
|
||||||
|
Columns: []string{"email"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.IndexesAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 index added, got %d", result.IndexesAdded)
|
||||||
|
}
|
||||||
|
if target.Schemas[0].Tables[0].Indexes == nil {
|
||||||
|
t.Error("Expected indexes map to be initialized")
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Tables[0].Indexes) != 1 {
|
||||||
|
t.Errorf("Expected 1 index in target table, got %d", len(target.Schemas[0].Tables[0].Indexes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeOptions_SkipTableNames(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "migrations",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &MergeOptions{
|
||||||
|
SkipTableNames: map[string]bool{
|
||||||
|
"migrations": true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, opts)
|
||||||
|
if result.TablesAdded != 0 {
|
||||||
|
t.Errorf("Expected 0 tables added (skipped), got %d", result.TablesAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Tables) != 1 {
|
||||||
|
t.Errorf("Expected 1 table in target schema, got %d", len(target.Schemas[0].Tables))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeViews_NewView(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Views: []*models.View{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Views: []*models.View{
|
||||||
|
{
|
||||||
|
Name: "user_summary",
|
||||||
|
Schema: "public",
|
||||||
|
Definition: "SELECT * FROM users",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.ViewsAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 view added, got %d", result.ViewsAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Views) != 1 {
|
||||||
|
t.Errorf("Expected 1 view in target schema, got %d", len(target.Schemas[0].Views))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeEnums_NewEnum(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Enums: []*models.Enum{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Enums: []*models.Enum{
|
||||||
|
{
|
||||||
|
Name: "user_role",
|
||||||
|
Schema: "public",
|
||||||
|
Values: []string{"admin", "user"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.EnumsAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 enum added, got %d", result.EnumsAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Enums) != 1 {
|
||||||
|
t.Errorf("Expected 1 enum in target schema, got %d", len(target.Schemas[0].Enums))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeDomains_NewDomain(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Domains: []*models.Domain{},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Domains: []*models.Domain{
|
||||||
|
{
|
||||||
|
Name: "auth",
|
||||||
|
Description: "Authentication domain",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.DomainsAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 domain added, got %d", result.DomainsAdded)
|
||||||
|
}
|
||||||
|
if len(target.Domains) != 1 {
|
||||||
|
t.Errorf("Expected 1 domain in target, got %d", len(target.Domains))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeRelations_NewRelation(t *testing.T) {
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Relations: []*models.Relationship{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Relations: []*models.Relationship{
|
||||||
|
{
|
||||||
|
Name: "fk_posts_user",
|
||||||
|
Type: models.OneToMany,
|
||||||
|
FromTable: "posts",
|
||||||
|
FromColumns: []string{"user_id"},
|
||||||
|
ToTable: "users",
|
||||||
|
ToColumns: []string{"id"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
if result.RelationsAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 relation added, got %d", result.RelationsAdded)
|
||||||
|
}
|
||||||
|
if len(target.Schemas[0].Relations) != 1 {
|
||||||
|
t.Errorf("Expected 1 relation in target schema, got %d", len(target.Schemas[0].Relations))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetMergeSummary(t *testing.T) {
|
||||||
|
result := &MergeResult{
|
||||||
|
SchemasAdded: 1,
|
||||||
|
TablesAdded: 2,
|
||||||
|
ColumnsAdded: 5,
|
||||||
|
ConstraintsAdded: 3,
|
||||||
|
IndexesAdded: 2,
|
||||||
|
ViewsAdded: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
summary := GetMergeSummary(result)
|
||||||
|
if summary == "" {
|
||||||
|
t.Error("Expected non-empty summary")
|
||||||
|
}
|
||||||
|
if len(summary) < 50 {
|
||||||
|
t.Errorf("Summary seems too short: %s", summary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetMergeSummary_Nil(t *testing.T) {
|
||||||
|
summary := GetMergeSummary(nil)
|
||||||
|
if summary == "" {
|
||||||
|
t.Error("Expected non-empty summary for nil result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComplexMerge(t *testing.T) {
|
||||||
|
// Target with existing structure
|
||||||
|
target := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{
|
||||||
|
"id": {Name: "id", Type: "int"},
|
||||||
|
},
|
||||||
|
Constraints: map[string]*models.Constraint{},
|
||||||
|
Indexes: map[string]*models.Index{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source with new columns, constraints, and indexes
|
||||||
|
source := &models.Database{
|
||||||
|
Schemas: []*models.Schema{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
Tables: []*models.Table{
|
||||||
|
{
|
||||||
|
Name: "users",
|
||||||
|
Schema: "public",
|
||||||
|
Columns: map[string]*models.Column{
|
||||||
|
"email": {Name: "email", Type: "varchar"},
|
||||||
|
"guid": {Name: "guid", Type: "uuid"},
|
||||||
|
},
|
||||||
|
Constraints: map[string]*models.Constraint{
|
||||||
|
"ukey_users_email": {
|
||||||
|
Type: models.UniqueConstraint,
|
||||||
|
Columns: []string{"email"},
|
||||||
|
Name: "ukey_users_email",
|
||||||
|
},
|
||||||
|
"ukey_users_guid": {
|
||||||
|
Type: models.UniqueConstraint,
|
||||||
|
Columns: []string{"guid"},
|
||||||
|
Name: "ukey_users_guid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Indexes: map[string]*models.Index{
|
||||||
|
"idx_users_email": {
|
||||||
|
Name: "idx_users_email",
|
||||||
|
Columns: []string{"email"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := MergeDatabases(target, source, nil)
|
||||||
|
|
||||||
|
// Verify counts
|
||||||
|
if result.ColumnsAdded != 2 {
|
||||||
|
t.Errorf("Expected 2 columns added, got %d", result.ColumnsAdded)
|
||||||
|
}
|
||||||
|
if result.ConstraintsAdded != 2 {
|
||||||
|
t.Errorf("Expected 2 constraints added, got %d", result.ConstraintsAdded)
|
||||||
|
}
|
||||||
|
if result.IndexesAdded != 1 {
|
||||||
|
t.Errorf("Expected 1 index added, got %d", result.IndexesAdded)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify target has merged data
|
||||||
|
table := target.Schemas[0].Tables[0]
|
||||||
|
if len(table.Columns) != 3 {
|
||||||
|
t.Errorf("Expected 3 columns in merged table, got %d", len(table.Columns))
|
||||||
|
}
|
||||||
|
if len(table.Constraints) != 2 {
|
||||||
|
t.Errorf("Expected 2 constraints in merged table, got %d", len(table.Constraints))
|
||||||
|
}
|
||||||
|
if len(table.Indexes) != 1 {
|
||||||
|
t.Errorf("Expected 1 index in merged table, got %d", len(table.Indexes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify specific constraint
|
||||||
|
if _, exists := table.Constraints["ukey_users_guid"]; !exists {
|
||||||
|
t.Error("Expected ukey_users_guid constraint to exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user