| 15 | } |
| 16 | |
| 17 | func generateMigration(diff *schema.MetadataDiff) (string, error) { |
| 18 | var buf strings.Builder |
| 19 | |
| 20 | // Safe order for migrations: |
| 21 | // 1. Drop dependent objects first (in reverse dependency order) |
| 22 | // - Use topological sort to drop in safe order |
| 23 | // 2. Create/Alter objects (in dependency order) |
| 24 | // - Use topological sort to create in safe order |
| 25 | |
| 26 | // Phase 1: Drop dependent objects using topological sort |
| 27 | dropObjectsInOrder(diff, &buf) |
| 28 | |
| 29 | // Only add blank line if we have drops AND we're about to create something |
| 30 | dropPhaseHasContent := buf.Len() > 0 |
| 31 | createPhaseWillHaveContent := hasCreateOrAlterObjects(diff) |
| 32 | |
| 33 | if dropPhaseHasContent && createPhaseWillHaveContent { |
| 34 | _, _ = buf.WriteString("\n") |
| 35 | } |
| 36 | |
| 37 | // Phase 2: Create/Alter objects using topological sort |
| 38 | createObjectsInOrder(diff, &buf) |
| 39 | |
| 40 | return buf.String(), nil |
| 41 | } |
| 42 | |
| 43 | // dropObjectsInOrder drops all objects in reverse topological order (most dependent first) |
| 44 | func dropObjectsInOrder(diff *schema.MetadataDiff, buf *strings.Builder) { |