Skip to content

Commit 3e04d16

Browse files
committed
some improves
1 parent 414739f commit 3e04d16

6 files changed

Lines changed: 540 additions & 39 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Migration of the following objects is currently supported:
2525
- Tables
2626
- Columns
2727
- Indexes
28+
- Constraints and Foreign Keys
2829
- Views
2930

3031
This set covers 99% of PostgreSQL usecases in Golang services.

drivers/postgres/postgres.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ func (p *Postgres) Analyze(s *schema.Schema) error {
168168
constraint.OnDelete = strings.TrimSpace(ss[5])
169169
}
170170
relation := &schema.Relation{
171+
Name: constraintName,
171172
Table: table,
172173
OnDelete: constraint.OnDelete,
173174
Def: constraintDef,

schema/diff.go

Lines changed: 165 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,24 @@ func (t *PatchTable) alter() []string {
7676
ret = append(ret, c.alter()...)
7777
}
7878
}
79-
// TODO: others
79+
for _, idx := range t.indexes {
80+
if idx.from == nil {
81+
ret = append(ret, idx.create()...)
82+
} else if idx.to == nil {
83+
ret = append(ret, idx.drop()...)
84+
} else {
85+
ret = append(ret, idx.alter()...)
86+
}
87+
}
88+
for _, ctr := range t.constraints {
89+
if ctr.from == nil {
90+
ret = append(ret, ctr.create()...)
91+
} else if ctr.to == nil {
92+
ret = append(ret, ctr.drop()...)
93+
} else {
94+
ret = append(ret, ctr.alter()...)
95+
}
96+
}
8097
return ret
8198
}
8299

@@ -92,6 +109,7 @@ func (t *PatchTable) drop() []string {
92109
type PatchColumn struct {
93110
from, to *Column
94111
tableName string
112+
newTable bool
95113
}
96114

97115
func (c *PatchColumn) GenerateSQL() []string {
@@ -106,6 +124,9 @@ func (c *PatchColumn) GenerateSQL() []string {
106124

107125
func (c *PatchColumn) create() []string {
108126
sb := &strings.Builder{}
127+
if !c.newTable {
128+
fmt.Fprintf(sb, "ALTER TABLE %s ADD COLUMN ", c.tableName)
129+
}
109130
fmt.Fprint(sb, c.to.Name, " ", c.to.Type)
110131
if !c.to.Nullable {
111132
fmt.Fprint(sb, " NOT NULL")
@@ -179,40 +200,49 @@ func (i *PatchIndex) GenerateSQL() []string {
179200
return i.drop()
180201
}
181202

182-
func (i *PatchIndex) create() []string {
203+
func createIndexDDL(idx *Index) string {
183204
sb := &strings.Builder{}
184205
fmt.Fprint(sb, "CREATE")
185-
if i.to.IsUnique {
206+
if idx.IsUnique {
186207
fmt.Fprint(sb, " UNIQUE")
187208
}
188209
fmt.Fprint(sb, " INDEX")
189-
if i.to.Concurrently {
210+
if idx.Concurrently {
190211
fmt.Fprint(sb, " CONCURRENTLY")
191212
}
192213
fmt.Fprintf(sb, " %s ON %s",
193-
i.to.Name, *i.to.Table)
194-
if len(i.to.MethodName) > 0 {
195-
fmt.Fprint(sb, " USING ", i.to.MethodName)
214+
idx.Name, *idx.Table)
215+
if len(idx.MethodName) > 0 {
216+
fmt.Fprint(sb, " USING ", idx.MethodName)
196217
}
197218
sb.WriteByte('(')
198-
if len(i.to.ColDef) > 0 {
199-
sb.WriteString(i.to.ColDef)
219+
if len(idx.ColDef) > 0 {
220+
sb.WriteString(idx.ColDef)
200221
} else {
201-
fmt.Fprint(sb, strings.Join(i.to.Columns, ", "))
222+
fmt.Fprint(sb, strings.Join(idx.Columns, ", "))
202223
}
203224
sb.WriteByte(')')
204-
if len(i.to.With) > 0 {
205-
fmt.Fprint(sb, " WITH ", i.to.With)
225+
if len(idx.With) > 0 {
226+
fmt.Fprint(sb, " WITH ", idx.With)
206227
}
207-
if len(i.to.Tablespace) > 0 {
208-
fmt.Fprint(sb, " TABLESPACE ", i.to.Tablespace)
228+
if len(idx.Tablespace) > 0 {
229+
fmt.Fprint(sb, " TABLESPACE ", idx.Tablespace)
209230
}
210-
if len(i.to.Where) > 0 {
211-
fmt.Fprint(sb, " WHERE ", i.to.Where)
231+
if len(idx.Where) > 0 {
232+
fmt.Fprint(sb, " WHERE ", idx.Where)
212233
}
213-
return []string{sb.String()}
234+
return sb.String()
235+
}
236+
237+
func (i *PatchIndex) create() []string {
238+
return []string{createIndexDDL(i.to)}
239+
}
240+
func (i *PatchIndex) alter() []string {
241+
if strings.EqualFold(createIndexDDL(i.from), createIndexDDL(i.to)) {
242+
return nil
243+
}
244+
return append(i.drop(), i.create()...)
214245
}
215-
func (i *PatchIndex) alter() []string { return nil }
216246
func (i *PatchIndex) drop() []string {
217247
// always drop unused indexes
218248
return []string{
@@ -223,43 +253,59 @@ func (i *PatchIndex) drop() []string {
223253
type PatchConstraint struct {
224254
from, to *Constraint
225255
tableName string
256+
newTable bool
226257
}
227258

228259
func (c *PatchConstraint) GenerateSQL() []string {
229260
if c.from != nil && c.to != nil {
261+
c.from.Table = &c.tableName
262+
c.to.Table = &c.tableName
230263
return c.alter()
231264
}
232265
if c.from == nil {
266+
c.to.Table = &c.tableName
233267
return c.create()
234268
}
269+
c.from.Table = &c.tableName
235270
return c.drop()
236271
}
237272

238-
func (c *PatchConstraint) create() []string {
273+
func createConstraintDDL(ctr *Constraint, newTable bool) string {
239274
sb := &strings.Builder{}
240-
fmt.Fprint(sb, "CONSTRAINT ", c.to.Name)
241-
if len(c.to.Check) > 0 {
242-
fmt.Fprint(sb, " CHECK (", c.to.Check, ")")
275+
if !newTable {
276+
fmt.Fprintf(sb, "ALTER TABLE %s ADD ", *ctr.Table)
243277
}
244-
switch c.to.Type {
278+
fmt.Fprint(sb, "CONSTRAINT ", ctr.Name)
279+
if len(ctr.Check) > 0 {
280+
fmt.Fprint(sb, " CHECK (", ctr.Check, ")")
281+
}
282+
switch ctr.Type {
245283
case TypeFK:
246-
if c.to.ReferenceTable == nil {
247-
fmt.Fprint(sb, " FOREIGN KEY (", strings.Join(c.to.Columns, ", "), ")")
248-
fmt.Fprintf(sb, " REFERENCES %s (%s)", *c.to.ReferenceTable, strings.Join(c.to.ReferenceColumns, ", "))
249-
if len(c.to.OnDelete) > 0 {
250-
fmt.Fprint(sb, " ON DELETE ", c.to.OnDelete)
284+
if ctr.ReferenceTable == nil {
285+
fmt.Fprint(sb, " FOREIGN KEY (", strings.Join(ctr.Columns, ", "), ")")
286+
fmt.Fprintf(sb, " REFERENCES %s (%s)", *ctr.ReferenceTable, strings.Join(ctr.ReferenceColumns, ", "))
287+
if len(ctr.OnDelete) > 0 {
288+
fmt.Fprint(sb, " ON DELETE ", ctr.OnDelete)
251289
}
252290
}
253291
case TypePK:
254-
fmt.Fprint(sb, " PRIMARY KEY (", strings.Join(c.to.Columns, ", "), ")")
292+
fmt.Fprint(sb, " PRIMARY KEY (", strings.Join(ctr.Columns, ", "), ")")
255293
case TypeUQ:
256-
fmt.Fprint(sb, " UNIQUE (", strings.Join(c.to.Columns, ", "), ")")
294+
fmt.Fprint(sb, " UNIQUE (", strings.Join(ctr.Columns, ", "), ")")
257295
}
258-
return []string{sb.String()}
296+
return sb.String()
297+
}
298+
299+
func (c *PatchConstraint) create() []string {
300+
return []string{createConstraintDDL(c.to, c.newTable)}
259301
}
260302

261303
func (c *PatchConstraint) alter() []string {
262-
return nil
304+
if strings.EqualFold(createConstraintDDL(c.from, c.newTable),
305+
createConstraintDDL(c.to, c.newTable)) {
306+
return nil
307+
}
308+
return append(c.drop(), c.create()...)
263309
}
264310

265311
func (c *PatchConstraint) drop() []string {
@@ -283,26 +329,36 @@ func (r *PatchRelation) GenerateSQL() []string {
283329
return r.drop()
284330
}
285331

286-
func (r *PatchRelation) create() []string {
332+
func createRelationDDL(r *Relation) string {
287333
sb := &strings.Builder{}
288-
fmt.Fprintf(sb, "ALTER TABLE %s ADD FOREIGN KEY (", r.to.Table.Name)
289-
for i, c := range r.to.Columns {
334+
fmt.Fprintf(sb, "ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (", r.Table.Name, r.Name)
335+
for i, c := range r.Columns {
290336
if i > 0 {
291337
sb.WriteString(", ")
292338
}
293339
sb.WriteString(c.Name)
294340
}
295-
fmt.Fprintf(sb, ") REFERENCES %s (", r.to.ParentTable.Name)
296-
for i, c := range r.to.ParentColumns {
341+
fmt.Fprintf(sb, ") REFERENCES %s (", r.ParentTable.Name)
342+
for i, c := range r.ParentColumns {
297343
if i > 0 {
298344
sb.WriteString(", ")
299345
}
300346
sb.WriteString(c.Name)
301347
}
302348
sb.WriteByte(')')
303-
return []string{sb.String()}
349+
return sb.String()
350+
}
351+
352+
func (r *PatchRelation) create() []string {
353+
return []string{createRelationDDL(r.to)}
354+
}
355+
func (r *PatchRelation) alter() []string {
356+
if strings.EqualFold(createRelationDDL(r.from),
357+
createRelationDDL(r.to)) {
358+
return nil
359+
}
360+
return append(r.drop(), r.create()...)
304361
}
305-
func (r *PatchRelation) alter() []string { return nil }
306362
func (r *PatchRelation) drop() []string {
307363
// TODO:
308364
// declare r record;
@@ -389,6 +445,9 @@ func (s *PatchSchema) Build(from, to *Schema) {
389445
}
390446
}
391447
for _, idx := range t.Indexes {
448+
if idx.Table == nil {
449+
idx.Table = &t.Name
450+
}
392451
pi := &PatchIndex{
393452
from: idx,
394453
}
@@ -400,7 +459,38 @@ func (s *PatchSchema) Build(from, to *Schema) {
400459
}
401460
pt.indexes = append(pt.indexes, pi)
402461
}
462+
463+
if rt != nil {
464+
for _, idx := range rt.Indexes {
465+
if idx.Table == nil {
466+
idx.Table = &rt.Name
467+
}
468+
pi := &PatchIndex{
469+
to: idx,
470+
}
471+
ti, err := t.FindIndexByName(idx.Name)
472+
fnd := false
473+
if err == nil {
474+
pi.from = ti
475+
476+
for _, v := range pt.indexes {
477+
if v.from == pi.from &&
478+
v.to == pi.to {
479+
fnd = true
480+
break
481+
}
482+
}
483+
}
484+
if !fnd {
485+
pt.indexes = append(pt.indexes, pi)
486+
}
487+
}
488+
}
489+
403490
for _, c := range t.Constraints {
491+
if c.Table == nil {
492+
c.Table = &t.Name
493+
}
404494
pc := &PatchConstraint{
405495
tableName: t.Name,
406496
from: c,
@@ -413,6 +503,34 @@ func (s *PatchSchema) Build(from, to *Schema) {
413503
}
414504
pt.constraints = append(pt.constraints, pc)
415505
}
506+
507+
if rt != nil {
508+
for _, c := range rt.Constraints {
509+
if c.Table == nil {
510+
c.Table = &rt.Name
511+
}
512+
pc := &PatchConstraint{
513+
tableName: rt.Name,
514+
to: c,
515+
}
516+
tc, err := t.FindConstraintByName(c.Name)
517+
fnd := false
518+
if err == nil {
519+
pc.from = tc
520+
521+
for _, v := range pt.constraints {
522+
if v.from == pc.from &&
523+
v.to == pc.to {
524+
fnd = true
525+
break
526+
}
527+
}
528+
}
529+
if !fnd {
530+
pt.constraints = append(pt.constraints, pc)
531+
}
532+
}
533+
}
416534
}
417535
// create tables
418536
for _, rt := range to.Tables {
@@ -435,19 +553,27 @@ func (s *PatchSchema) Build(from, to *Schema) {
435553
pc := &PatchColumn{
436554
tableName: rt.Name,
437555
to: c,
556+
newTable: true,
438557
}
439558
pt.columns = append(pt.columns, pc)
440559
}
441560
for _, idx := range rt.Indexes {
561+
if idx.Table == nil {
562+
idx.Table = &rt.Name
563+
}
442564
pi := &PatchIndex{
443565
to: idx,
444566
}
445567
pt.indexes = append(pt.indexes, pi)
446568
}
447569
for _, c := range rt.Constraints {
570+
if c.Table == nil {
571+
c.Table = &rt.Name
572+
}
448573
pc := &PatchConstraint{
449574
tableName: rt.Name,
450575
to: c,
576+
newTable: true,
451577
}
452578
pt.constraints = append(pt.constraints, pc)
453579
}

0 commit comments

Comments
 (0)