feat(pgsql): diff against the live database by default for direct output
Direct pgsql output (job output.conn_env, merge --output-conn) now reads the live schema and executes only the differences. full_ddl: true (job option) or --full-ddl (merge) restores the full idempotent DDL; file output is unchanged. - compare PKs by columns, skip constraint-backed indexes, normalize index method, FK actions, serial/numeric types, default literals/casts and truncated names - diff table and column comments instead of re-emitting them - remove leftover ZZDUMP debug code
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package pgsql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -1044,9 +1046,57 @@ func normalizeDefaultLiteral(s string) string {
|
||||
if end := strings.LastIndex(s, "'"); end > 0 {
|
||||
rest := strings.TrimSpace(s[end+1:])
|
||||
if rest == "" || strings.HasPrefix(rest, "::") {
|
||||
return strings.ReplaceAll(s[1:end], "''", "'")
|
||||
return normalizeJSONLiteral(strings.ReplaceAll(s[1:end], "''", "'"))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
if strings.HasPrefix(s, "(") && strings.Contains(s, ")::") {
|
||||
return normalizeCastExpression(s)
|
||||
}
|
||||
return normalizeJSONLiteral(s)
|
||||
}
|
||||
|
||||
// normalizeJSONLiteral compacts JSON text, since jsonb reports defaults re-spaced
|
||||
// ('["a", "b"]') while the model usually holds them minified.
|
||||
func normalizeJSONLiteral(s string) string {
|
||||
if !strings.HasPrefix(s, "[") && !strings.HasPrefix(s, "{") {
|
||||
return s
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := json.Compact(&buf, []byte(s)); err != nil {
|
||||
return s
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// normalizeCastExpression strips whitespace and the redundant parentheses PostgreSQL adds
|
||||
// around an expression it casts: (gen_random_uuid())::text -> gen_random_uuid()::text.
|
||||
func normalizeCastExpression(s string) string {
|
||||
s = strings.Join(strings.Fields(s), "")
|
||||
for strings.HasPrefix(s, "(") {
|
||||
end := strings.LastIndex(s, ")::")
|
||||
if end < 0 {
|
||||
break
|
||||
}
|
||||
inner := s[1:end]
|
||||
depth := 0
|
||||
balanced := true
|
||||
for _, r := range inner {
|
||||
if r == '(' {
|
||||
depth++
|
||||
} else if r == ')' {
|
||||
depth--
|
||||
if depth < 0 {
|
||||
balanced = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !balanced || depth != 0 {
|
||||
break
|
||||
}
|
||||
s = inner + s[end+1:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user