refactor: move shouldMergeObjects from rawpaths to heuristics

This commit is contained in:
AJ ONeal 2026-06-11 19:12:17 -06:00
parent fbd00ae4d2
commit febea43708
No known key found for this signature in database
2 changed files with 34 additions and 32 deletions

View File

@ -382,6 +382,40 @@ func capitalize(s string) string {
} }
// singularize does a naive singularization for common English plurals. // singularize does a naive singularization for common English plurals.
// shouldMergeObjects decides whether a pool of objects should be treated as
// one struct type with optional fields, rather than multiple distinct types.
//
// Heuristic: if ≥ 2 keys appear in more than half the objects, the objects
// likely share a common shape with optional fields. This catches the common
// case of API responses where every record has the same core fields but some
// records have extra ones (e.g. pagination results).
func shouldMergeObjects(objects []map[string]any) bool {
n := len(objects)
if n < 2 {
return false
}
// Count how many objects contain each key.
keyCount := make(map[string]int)
for _, obj := range objects {
for k := range obj {
keyCount[k]++
}
}
// Count keys that appear in a majority of objects.
threshold := n / 2
highFreq := 0
for _, count := range keyCount {
if count > threshold {
highFreq++
}
}
// Two or more high-frequency keys means the objects share a common core.
return highFreq >= 2
}
func singularize(s string) string { func singularize(s string) string {
// Uncountable / already-singular words ending in -s. // Uncountable / already-singular words ending in -s.
switch strings.ToLower(s) { switch strings.ToLower(s) {

View File

@ -370,36 +370,4 @@ func joinPath(prefix, field string) string {
return prefix + "." + field return prefix + "." + field
} }
// shouldMergeObjects decides whether a pool of objects should be treated as
// one struct type with optional fields, rather than multiple distinct types.
//
// Heuristic: if ≥ 2 keys appear in more than half the objects, the objects
// likely share a common shape with optional fields. This catches the common
// case of API responses where every record has the same core fields but some
// records have extra ones (e.g. pagination results).
func shouldMergeObjects(objects []map[string]any) bool {
n := len(objects)
if n < 2 {
return false
}
// Count how many objects contain each key.
keyCount := make(map[string]int)
for _, obj := range objects {
for k := range obj {
keyCount[k]++
}
}
// Count keys that appear in a majority of objects.
threshold := n / 2
highFreq := 0
for _, count := range keyCount {
if count > threshold {
highFreq++
}
}
// Two or more high-frequency keys means the objects share a common core.
return highFreq >= 2
}