ent: support schema view (#4157)

This commit is contained in:
Ariel Mashraki
2024-07-28 19:00:47 +03:00
committed by GitHub
parent 5cd2ede22d
commit 15bebe8d89
95 changed files with 14608 additions and 32 deletions

View File

@@ -2187,6 +2187,15 @@ type Selector struct {
lock *LockOptions
}
// New returns a new Selector with the same dialect and context.
func (s *Selector) New() *Selector {
c := Dialect(s.dialect).Select()
if s.ctx != nil {
c = c.WithContext(s.ctx)
}
return c
}
// WithContext sets the context into the *Selector.
func (s *Selector) WithContext(ctx context.Context) *Selector {
if ctx == nil {
@@ -2240,6 +2249,11 @@ func (s *Selector) Select(columns ...string) *Selector {
return s
}
// SelectDistinct selects distinct columns.
func (s *Selector) SelectDistinct(columns ...string) *Selector {
return s.Select(columns...).Distinct()
}
// AppendSelect appends additional columns to the SELECT statement.
func (s *Selector) AppendSelect(columns ...string) *Selector {
for i := range columns {
@@ -2626,6 +2640,10 @@ const (
// Union appends the UNION (DISTINCT) clause to the query.
func (s *Selector) Union(t TableView) *Selector {
if s1, ok := t.(*Selector); ok && s == s1 {
s.AddError(errors.New("self UNION is not supported. Create a clone or a new selector instead"))
return s
}
s.setOps = append(s.setOps, setOp{
Type: setOpTypeUnion,
TableView: t,

View File

@@ -572,7 +572,11 @@ func (a *Atlas) StateReader(tables ...*Table) migrate.StateReaderFunc {
if err != nil {
return nil, err
}
return &schema.Realm{Schemas: []*schema.Schema{{Tables: ts}}}, nil
vs, err := a.views(tables)
if err != nil {
return nil, err
}
return &schema.Realm{Schemas: []*schema.Schema{{Tables: ts, Views: vs}}}, nil
}
}
@@ -878,8 +882,14 @@ func (d *db) ExecContext(ctx context.Context, query string, args ...any) (sql.Re
// tables converts an Ent table slice to an atlas table slice
func (a *Atlas) tables(tables []*Table) ([]*schema.Table, error) {
ts := make([]*schema.Table, len(tables))
for i, et := range tables {
var (
byT = make(map[*Table]*schema.Table)
ts = make([]*schema.Table, 0, len(tables))
)
for _, et := range tables {
if et.View {
continue
}
at := schema.NewTable(et.Name)
if et.Comment != "" {
at.SetComment(et.Comment)
@@ -898,10 +908,14 @@ func (a *Atlas) tables(tables []*Table) ([]*schema.Table, error) {
if err := a.aIndexes(et, at); err != nil {
return nil, err
}
ts[i] = at
ts = append(ts, at)
byT[et] = at
}
for i, t1 := range tables {
t2 := ts[i]
for _, t1 := range tables {
if t1.View {
continue
}
t2 := byT[t1]
for _, fk1 := range t1.ForeignKeys {
fk2 := schema.NewForeignKey(fk1.Symbol).
SetTable(t2).
@@ -938,6 +952,30 @@ func (a *Atlas) tables(tables []*Table) ([]*schema.Table, error) {
return ts, nil
}
// tables converts an Ent table slice to an atlas table slice
func (a *Atlas) views(tables []*Table) ([]*schema.View, error) {
vs := make([]*schema.View, 0, len(tables))
for _, et := range tables {
// Not a view, or the view defined externally.
if !et.View || et.Annotation == nil || (et.Annotation.ViewAs == "" && et.Annotation.ViewFor[a.dialect] == "") {
continue
}
def := et.Annotation.ViewFor[a.dialect]
if def == "" {
def = et.Annotation.ViewAs
}
av := schema.NewView(et.Name, def)
if et.Comment != "" {
av.SetComment(et.Comment)
}
if err := a.aVColumns(et, av); err != nil {
return nil, err
}
vs = append(vs, av)
}
return vs, nil
}
func (a *Atlas) aColumns(et *Table, at *schema.Table) error {
for _, c1 := range et.Columns {
c2 := schema.NewColumn(c1.Name).
@@ -965,6 +1003,27 @@ func (a *Atlas) aColumns(et *Table, at *schema.Table) error {
return nil
}
func (a *Atlas) aVColumns(et *Table, at *schema.View) error {
for _, c1 := range et.Columns {
c2 := schema.NewColumn(c1.Name).
SetNull(c1.Nullable)
if c1.Collation != "" {
c2.SetCollation(c1.Collation)
}
if c1.Comment != "" {
c2.SetComment(c1.Comment)
}
if err := a.sqlDialect.atTypeC(c1, c2); err != nil {
return err
}
if err := a.atDefault(c1, c2); err != nil {
return err
}
at.AddColumns(c2)
}
return nil
}
func (a *Atlas) atDefault(c1 *Column, c2 *schema.Column) error {
if c1.Default == nil || !a.sqlDialect.supportsDefault(c1) {
return nil

View File

@@ -38,6 +38,7 @@ type Table struct {
ForeignKeys []*ForeignKey
Annotation *entsql.Annotation
Comment string
View bool // Indicate the table is a view.
}
// NewTable returns a new table with the given name.
@@ -48,6 +49,13 @@ func NewTable(name string) *Table {
}
}
// NewView returns a new view with the given name.
func NewView(name string) *Table {
t := NewTable(name)
t.View = true
return t
}
// SetComment sets the table comment.
func (t *Table) SetComment(c string) *Table {
t.Comment = c