feat(diff): prune-guard Updates()/Prunes() + фиксация семантики dedup
This commit is contained in:
@@ -37,6 +37,44 @@ func (c Changeset) Actionable() []RecordDiff {
|
||||
return out
|
||||
}
|
||||
|
||||
// Updates returns managed (non-ReadOnly) diffs that add or bring a record in
|
||||
// line with the template (Kind == Add or Kind == Update). It never contains
|
||||
// Delete diffs, so it is safe for callers to apply automatically without
|
||||
// risking data loss from an incomplete or empty template.
|
||||
func (c Changeset) Updates() []RecordDiff {
|
||||
var out []RecordDiff
|
||||
for _, d := range c.Diffs {
|
||||
if d.ReadOnly {
|
||||
continue
|
||||
}
|
||||
if d.Kind == Add || d.Kind == Update {
|
||||
out = append(out, d)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Prunes returns managed (non-ReadOnly) diffs where a record exists in the
|
||||
// zone but is absent from the template (Kind == Delete). These are
|
||||
// potentially destructive: an incomplete or empty template would surface
|
||||
// every managed zone record here. Callers should require explicit
|
||||
// confirmation before applying Prunes(), unlike Updates().
|
||||
//
|
||||
// Updates() and Prunes() partition Actionable(): every diff in Actionable()
|
||||
// appears in exactly one of the two.
|
||||
func (c Changeset) Prunes() []RecordDiff {
|
||||
var out []RecordDiff
|
||||
for _, d := range c.Diffs {
|
||||
if d.ReadOnly {
|
||||
continue
|
||||
}
|
||||
if d.Kind == Delete {
|
||||
out = append(out, d)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Diff compares a template against the actual zone records.
|
||||
// Records present in the zone but absent from the template yield Delete.
|
||||
func Diff(template, actual []model.Record) Changeset {
|
||||
@@ -70,6 +108,14 @@ func Diff(template, actual []model.Record) Changeset {
|
||||
return Changeset{Diffs: diffs}
|
||||
}
|
||||
|
||||
// index builds a lookup of records by Key(). If two records in recs share
|
||||
// the same Key() (e.g. a provider returning a duplicate RRset entry), this
|
||||
// is a deliberate, documented choice, not an oversight: the LAST record with
|
||||
// that Key() wins, since later map assignments overwrite earlier ones for
|
||||
// the same key during the loop below. Diff() only ever sees the winning
|
||||
// (last) record for a duplicated key; earlier duplicates are silently
|
||||
// collapsed. See TestIndexDedupLastWriteWins in diff_test.go, which pins
|
||||
// this behavior down.
|
||||
func index(recs []model.Record) map[string]model.Record {
|
||||
m := make(map[string]model.Record, len(recs))
|
||||
for _, r := range recs {
|
||||
|
||||
Reference in New Issue
Block a user