entc/gen: allow opening and testing concurrent enttest clients (#2665)

This commit is contained in:
Ariel Mashraki
2022-06-20 08:32:30 +03:00
committed by GitHub
parent abefaa7f24
commit 311d760679
71 changed files with 783 additions and 614 deletions

View File

@@ -104,7 +104,7 @@ func (f CreateFunc) Create(ctx context.Context, tables ...*Table) error {
return f(ctx, tables...)
}
// Migrate runs the migrations logic for the SQL dialects.
// Migrate runs the migration logic for the SQL dialects.
type Migrate struct {
sqlDialect
universalID bool // global unique ids.

View File

@@ -173,6 +173,96 @@ func (t *Table) fk(symbol string) (*ForeignKey, bool) {
return nil, false
}
// CopyTables returns a deep-copy of the given tables. This utility function is
// useful for copying the generated schema tables (i.e. migrate.Tables) before
// running schema migration when there is a need for execute multiple migrations
// concurrently. e.g. running parallel unit-tests using the generated enttest package.
func CopyTables(tables []*Table) ([]*Table, error) {
var (
copyT = make([]*Table, len(tables))
byName = make(map[string]*Table)
)
for i, t := range tables {
copyT[i] = &Table{
Name: t.Name,
Columns: make([]*Column, len(t.Columns)),
Indexes: make([]*Index, len(t.Indexes)),
ForeignKeys: make([]*ForeignKey, len(t.ForeignKeys)),
}
for j, c := range t.Columns {
cc := *c
// SchemaType and Enums are read-only fields.
cc.indexes = nil
cc.foreign = nil
copyT[i].Columns[j] = &cc
}
if at := t.Annotation; at != nil {
cat := *at
copyT[i].Annotation = &cat
}
byName[t.Name] = copyT[i]
}
for i, t := range tables {
ct := copyT[i]
for _, c := range t.PrimaryKey {
cc, ok := ct.column(c.Name)
if !ok {
return nil, fmt.Errorf("sql/schema: missing primary key column %q", c.Name)
}
ct.PrimaryKey = append(ct.PrimaryKey, cc)
}
for j, idx := range t.Indexes {
cidx := &Index{
Name: idx.Name,
Unique: idx.Unique,
Columns: make([]*Column, len(idx.Columns)),
}
if at := idx.Annotation; at != nil {
cat := *at
cidx.Annotation = &cat
}
for k, c := range idx.Columns {
cc, ok := ct.column(c.Name)
if !ok {
return nil, fmt.Errorf("sql/schema: missing index column %q", c.Name)
}
cidx.Columns[k] = cc
}
ct.Indexes[j] = cidx
}
for j, fk := range t.ForeignKeys {
cfk := &ForeignKey{
Symbol: fk.Symbol,
OnUpdate: fk.OnUpdate,
OnDelete: fk.OnDelete,
Columns: make([]*Column, len(fk.Columns)),
RefColumns: make([]*Column, len(fk.RefColumns)),
}
for k, c := range fk.Columns {
cc, ok := ct.column(c.Name)
if !ok {
return nil, fmt.Errorf("sql/schema: missing foreign-key column %q", c.Name)
}
cfk.Columns[k] = cc
}
cref, ok := byName[fk.RefTable.Name]
if !ok {
return nil, fmt.Errorf("sql/schema: missing foreign-key ref-table %q", fk.RefTable.Name)
}
cfk.RefTable = cref
for k, c := range fk.RefColumns {
cc, ok := cref.column(c.Name)
if !ok {
return nil, fmt.Errorf("sql/schema: missing foreign-key ref-column %q", c.Name)
}
cfk.RefColumns[k] = cc
}
ct.ForeignKeys[j] = cfk
}
}
return copyT, nil
}
// Column schema definition for SQL dialects.
type Column struct {
Name string // column name.

View File

@@ -7,6 +7,7 @@ package schema
import (
"testing"
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/schema/field"
"github.com/stretchr/testify/require"
@@ -101,3 +102,50 @@ func TestColumn_ScanDefault(t *testing.T) {
require.NoError(t, c1.ScanDefault("00000000-0000-0000-0000-000000000000"))
require.Equal(t, "00000000-0000-0000-0000-000000000000", c1.Default)
}
func TestCopyTables(t *testing.T) {
users := &Table{
Name: "users",
Columns: []*Column{
{Name: "id", Type: field.TypeInt},
{Name: "name", Type: field.TypeString},
{Name: "spouse_id", Type: field.TypeInt},
},
}
users.PrimaryKey = users.Columns[:1]
users.Indexes = append(users.Indexes, &Index{
Name: "name",
Columns: users.Columns[1:2],
})
users.AddForeignKey(&ForeignKey{
Columns: users.Columns[2:],
RefTable: users,
RefColumns: users.Columns[:1],
OnUpdate: SetNull,
})
users.SetAnnotation(&entsql.Annotation{Table: "Users"})
pets := &Table{
Name: "pets",
Columns: []*Column{
{Name: "id", Type: field.TypeInt},
{Name: "name", Type: field.TypeString},
{Name: "owner_id", Type: field.TypeInt},
},
}
pets.Indexes = append(pets.Indexes, &Index{
Name: "name",
Unique: true,
Columns: pets.Columns[1:2],
Annotation: entsql.Desc(),
})
pets.AddForeignKey(&ForeignKey{
Columns: pets.Columns[2:],
RefTable: users,
RefColumns: users.Columns[:1],
OnDelete: SetDefault,
})
tables := []*Table{users, pets}
copyT, err := CopyTables(tables)
require.NoError(t, err)
require.Equal(t, tables, copyT)
}