// Package migrations contains the reviewed SQL bundled with the application. // SQL execution and database lifecycle remain in internal/data. package migrations import ( _ "embed" "fmt" "regexp" "strings" ) //go:embed legacy-framework.sql var frameworkSQL string //go:embed cleanup-legacy.sql var cleanupSQL string func FrameworkSQL() string { return frameworkSQL } func CleanupSQL() string { return cleanupSQL } // Statements understands the DELIMITER directives in the bundled, trusted // scripts. It does not split stored-procedure bodies on their semicolons. func Statements(source string) ([]string, error) { delimiter := ";" var buffer strings.Builder var statements []string for _, line := range strings.Split(source, "\n") { trimmed := strings.TrimSpace(line) if strings.HasPrefix(trimmed, "DELIMITER ") { delimiter = strings.TrimSpace(strings.TrimPrefix(trimmed, "DELIMITER ")) if delimiter == "" { return nil, fmt.Errorf("empty SQL delimiter") } continue } if buffer.Len() == 0 && (trimmed == "" || strings.HasPrefix(trimmed, "--")) { continue } buffer.WriteString(line) buffer.WriteByte('\n') if strings.HasSuffix(trimmed, delimiter) { statement := strings.TrimSuffix(strings.TrimSpace(buffer.String()), delimiter) statements = append(statements, statement) buffer.Reset() } } if strings.TrimSpace(buffer.String()) != "" { return nil, fmt.Errorf("unterminated SQL script") } return statements, nil } func CleanupTables() []string { block := regexp.MustCompile(`(?s)INSERT INTO _sw_cleanup_targets_20261106\([^\n]+\) VALUES\s*(.*?);`).FindStringSubmatch(cleanupSQL) if len(block) != 2 { panic("cleanup table manifest is missing") } var names []string for _, match := range regexp.MustCompile(`\('([a-z0-9_]+)'`).FindAllStringSubmatch(block[1], -1) { names = append(names, match[1]) } return names } func LegacyArchives() map[string]string { archives := map[string]string{} for _, match := range regexp.MustCompile("`([a-z0-9_]+)` TO `(legacy_sw_20261103_[a-z0-9_]+)`").FindAllStringSubmatch(frameworkSQL, -1) { archives[match[1]] = match[2] } return archives } func FrameworkCreatedTables() []string { var names []string for _, match := range regexp.MustCompile("(?m)^CREATE TABLE `?([a-z0-9_]+)`? ").FindAllStringSubmatch(frameworkSQL, -1) { names = append(names, match[1]) } return names }