func (cs ChangeSet) Reverse(old *DBSchema) Change {
	var result = make(ChangeSet, len(cs))
	for i, c := range cs {
		result[i] = c.Reverse(old)
	}
	return result
}
Reverse returns the change that will revert the current change set.
package generator
import (
	"bytes"
	"encoding"
	"encoding/json"
	"fmt"
	"strings"
)
type Migration struct {
	Up ChangeSet
	Down ChangeSet
	Lock *DBSchema
}
func NewMigration(old, new *DBSchema) (*Migration, error) {
	var (
		migration = &Migration{}
		err       error
		oldTables = old.index()
		newTables = new.index()
	)
	migration.Up, err = SchemaDiff(old, new).
		sorted(oldTables, newTables)
	if err != nil {
		return nil, err
	}
	migration.Down, err = migration.Up.
		ReverseChangeSet(old).
		sorted(newTables, oldTables)
	if err != nil {
		return nil, err
	}
	migration.Lock = new
	return migration, nil
}
type DBSchema struct {
	Tables []*TableSchema
}
func SchemaFromPackages(pkgs ...*Package) (*DBSchema, error) {
	t := newPackageTransformer()
	return t.transform(pkgs...)
}
func (s *DBSchema) MarshalText() ([]byte, error) {
	schema := struct {
		Tables []*TableSchema
	}{s.Tables}
	return json.MarshalIndent(schema, "", "  ")
}
func (s *DBSchema) Table(name string) *TableSchema {
	for _, t := range s.Tables {
		if t.Name == name {
			return t
		}
	}
	return nil
}
func (s *DBSchema) index() map[string]*TableSchema {
	var result = make(map[string]*TableSchema)
	for _, t := range s.Tables {
		result[t.Name] = t
	}
	return result
}
type TableSchema struct {
	Name string
	Columns []*ColumnSchema
}
type relationship struct {
	name    string
	inverse bool
}
func (s *TableSchema) relationships() []relationship {
	var rels = make(map[string]struct{})
	var result []relationship
	for _, c := range s.Columns {
		if c.Reference != nil {
			if _, ok := rels[c.Reference.Table]; !ok {
				result = append(result, relationship{c.Reference.Table, c.Reference.inverse})
				rels[c.Reference.Table] = struct{}{}
			}
		}
	}
	return result
}
func (s *TableSchema) String() string {
	var buf bytes.Buffer
	buf.WriteString(fmt.Sprintf("CREATE TABLE %s (\n", s.Name))
	for i, c := range s.Columns {
		buf.WriteRune('\t')
		buf.WriteString(c.String())
		if i < len(s.Columns)-1 {
			buf.WriteString(",\n")
		} else {
			buf.WriteRune('\n')
		}
	}
	buf.WriteString(");\n\n")
	return buf.String()
}
func (s *TableSchema) Column(name string) *ColumnSchema {
	for _, c := range s.Columns {
		if c.Name == name {
			return c
		}
	}
	return nil
}
func (s *TableSchema) Equals(s2 *TableSchema) bool {
	if s.Name != s2.Name || len(s.Columns) != len(s2.Columns) {
		return false
	}
	for i, c := range s.Columns {
		if !c.Equals(s2.Columns[i]) {
			return false
		}
	}
	return true
}
type ColumnSchema struct {
	Name string
	Type ColumnType
	PrimaryKey bool
	Reference *Reference
	NotNull bool
	Unique bool
}
func (s *ColumnSchema) Equals(s2 *ColumnSchema) bool {
	return s.Name == s2.Name &&
		s.Type == s2.Type &&
		s.PrimaryKey == s2.PrimaryKey &&
		s.NotNull == s2.NotNull &&
		s.Unique == s2.Unique &&
		s.Reference.Equals(s2.Reference)
}
func (s *ColumnSchema) String() string {
	var buf bytes.Buffer
	buf.WriteString(s.Name)
	buf.WriteRune(' ')
	buf.WriteString(string(s.Type))
	if s.NotNull {
		buf.WriteString(" NOT NULL")
	}
	if s.Unique {
		buf.WriteString(" UNIQUE")
	}
	if s.PrimaryKey {
		buf.WriteString(" PRIMARY KEY")
	}
	if s.Reference != nil {
		buf.WriteString(" REFERENCES ")
		buf.WriteString(s.Reference.String())
	}
	return buf.String()
}
type ColumnType string
const (
	ByteaColumn       ColumnType = "bytea"
	SmallIntColumn    ColumnType = "smallint"
	IntegerColumn     ColumnType = "integer"
	BigIntColumn      ColumnType = "bigint"
	RealColumn        ColumnType = "real"
	DoubleColumn      ColumnType = "double precision"
	SmallSerialColumn ColumnType = "smallserial"
	SerialColumn      ColumnType = "serial"
	BigSerialColumn   ColumnType = "bigserial"
	TimestamptzColumn ColumnType = "timestamptz"
	TextColumn        ColumnType = "text"
	JSONBColumn       ColumnType = "jsonb"
	BooleanColumn     ColumnType = "boolean"
	UUIDColumn        ColumnType = "uuid"
)
func NumericColumn(precision int) ColumnType {
	return ColumnType(fmt.Sprintf("numeric(%d)", precision))
}
func DecimalColumn(precision, scale int) ColumnType {
	return ColumnType(fmt.Sprintf("decimal(%d, %d)", precision, scale))
}
func ArrayColumn(typ ColumnType) ColumnType {
	if strings.HasSuffix(string(typ), "[]") {
		return typ
	}
	return typ + "[]"
}
type Reference struct {
	Table string
	Column  string
	inverse bool
}
func (r *Reference) Equals(r2 *Reference) bool {
	if r == nil && r2 == nil {
		return true
	} else if r == nil || r2 == nil {
		return false
	}
	return r.Table == r2.Table &&
		r.Column == r2.Column
}
func (r *Reference) String() string {
	return fmt.Sprintf("%s(%s)", r.Table, r.Column)
}
type ChangeSet []Change
func (cs ChangeSet) sorted(dropIndex, createIndex map[string]*TableSchema) (ChangeSet, error) {
	var (
		createTables = make(map[string]Change)
		dropTables   = make(map[string]Change)
		createGraph  = newGraph()
		dropGraph    = newGraph()
		others       ChangeSet
		result       ChangeSet
	)
	for _, c := range cs {
		switch c := c.(type) {
		case *CreateTable:
			createTables[c.Name] = c
			if rels := createIndex[c.Name].relationships(); len(rels) > 0 {
				for _, r := range rels {
					if r.name == c.Name {
						continue
					}
					createGraph.dependsOn(r.name, c.Name)
				}
			} else {
				createGraph.add(c.Name)
			}
		case *DropTable:
			dropTables[c.Name] = c
			if rels := dropIndex[c.Name].relationships(); len(rels) > 0 {
				for _, r := range rels {
					if r.name == c.Name {
						continue
					}
					dropGraph.dependsOn(r.name, c.Name)
				}
			} else {
				dropGraph.add(c.Name)
			}
		default:
			others = append(others, c)
		}
	}
	creates, err := createGraph.resolve()
	if err != nil {
		return nil, err
	}
	for _, c := range creates {
		if change, ok := createTables[c]; ok {
			result = append(result, change)
		}
	}
	drops, err := dropGraph.resolve()
	if err != nil {
		return nil, err
	}
	drops = reverse(drops)
	for _, d := range drops {
		if change, ok := dropTables[d]; ok {
			result = append(result, change)
		}
	}
	result = append(result, others...)
	return result, nil
}
func (cs ChangeSet) MarshalText() ([]byte, error) {
	var buf bytes.Buffer
	buf.WriteString("BEGIN;\n\n")
	for _, c := range cs {
		bytes, err := c.MarshalText()
		if err != nil {
			return nil, err
		}
		buf.Write(bytes)
		buf.WriteRune('\n')
	}
	buf.WriteString("COMMIT;\n")
	return buf.Bytes(), nil
}
func (cs ChangeSet) String() string {
	var buf bytes.Buffer
	for _, c := range cs {
		buf.WriteString(fmt.Sprintf("- %s", c))
	}
	return buf.String()
}