Skip to content

Commit 09cb805

Browse files
committed
This has already been fixed but now ordering is also irrelevent.
1 parent 5e9483b commit 09cb805

2 files changed

Lines changed: 513 additions & 0 deletions

File tree

what-changed/model/schema.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,11 @@ func extractSchemaChanges(
21932193
return
21942194
}
21952195

2196+
if isOrderInsensitiveSchemaCompositionLabel(label) {
2197+
extractOrderInsensitiveSchemaChanges(lSchema, rSchema, label, sc, changes)
2198+
return
2199+
}
2200+
21962201
x := "%x"
21972202
// create hash key maps to check equality
21982203
lKeys := make([]string, 0, len(lSchema))
@@ -2274,6 +2279,139 @@ func extractSchemaChanges(
22742279
}
22752280
}
22762281

2282+
type schemaCompositionEntry struct {
2283+
identity string
2284+
proxy *base.SchemaProxy
2285+
}
2286+
2287+
func isOrderInsensitiveSchemaCompositionLabel(label string) bool {
2288+
switch label {
2289+
case v3.AllOfLabel, v3.AnyOfLabel, v3.OneOfLabel:
2290+
return true
2291+
default:
2292+
return false
2293+
}
2294+
}
2295+
2296+
func schemaCompositionEntryIdentity(proxy *base.SchemaProxy) string {
2297+
if proxy == nil {
2298+
return "nil"
2299+
}
2300+
if proxy.IsReference() {
2301+
return "ref:" + proxy.GetReference()
2302+
}
2303+
return fmt.Sprintf("hash:%x", proxy.Hash())
2304+
}
2305+
2306+
func buildSchemaCompositionEntries(schema []low.ValueReference[*base.SchemaProxy]) []schemaCompositionEntry {
2307+
entries := make([]schemaCompositionEntry, 0, len(schema))
2308+
for i := range schema {
2309+
proxy := schema[i].Value
2310+
entries = append(entries, schemaCompositionEntry{
2311+
identity: schemaCompositionEntryIdentity(proxy),
2312+
proxy: proxy,
2313+
})
2314+
}
2315+
return entries
2316+
}
2317+
2318+
func matchSchemaCompositionIdentityCounts(
2319+
leftEntries, rightEntries []schemaCompositionEntry,
2320+
) map[string]int {
2321+
rightCounts := make(map[string]int)
2322+
matchedCounts := make(map[string]int)
2323+
2324+
for i := range rightEntries {
2325+
rightCounts[rightEntries[i].identity]++
2326+
}
2327+
for i := range leftEntries {
2328+
identity := leftEntries[i].identity
2329+
if matchedCounts[identity] < rightCounts[identity] {
2330+
matchedCounts[identity]++
2331+
}
2332+
}
2333+
return matchedCounts
2334+
}
2335+
2336+
func filterUnmatchedSchemaCompositionEntries(
2337+
entries []schemaCompositionEntry,
2338+
matchedCounts map[string]int,
2339+
) []schemaCompositionEntry {
2340+
usedCounts := make(map[string]int)
2341+
unmatched := make([]schemaCompositionEntry, 0, len(entries))
2342+
2343+
for i := range entries {
2344+
identity := entries[i].identity
2345+
if usedCounts[identity] < matchedCounts[identity] {
2346+
usedCounts[identity]++
2347+
continue
2348+
}
2349+
unmatched = append(unmatched, entries[i])
2350+
}
2351+
return unmatched
2352+
}
2353+
2354+
func schemaCompositionChangeBreaking(label string, changeType int) bool {
2355+
switch label {
2356+
case v3.AllOfLabel:
2357+
if changeType == ObjectAdded {
2358+
return BreakingAdded(CompSchema, PropAllOf)
2359+
}
2360+
return BreakingRemoved(CompSchema, PropAllOf)
2361+
case v3.AnyOfLabel:
2362+
if changeType == ObjectAdded {
2363+
return BreakingAdded(CompSchema, PropAnyOf)
2364+
}
2365+
return BreakingRemoved(CompSchema, PropAnyOf)
2366+
case v3.OneOfLabel:
2367+
if changeType == ObjectAdded {
2368+
return BreakingAdded(CompSchema, PropOneOf)
2369+
}
2370+
return BreakingRemoved(CompSchema, PropOneOf)
2371+
case v3.PrefixItemsLabel:
2372+
if changeType == ObjectAdded {
2373+
return BreakingAdded(CompSchema, PropPrefixItems)
2374+
}
2375+
return BreakingRemoved(CompSchema, PropPrefixItems)
2376+
default:
2377+
return changeType != ObjectAdded
2378+
}
2379+
}
2380+
2381+
func extractOrderInsensitiveSchemaChanges(
2382+
lSchema []low.ValueReference[*base.SchemaProxy],
2383+
rSchema []low.ValueReference[*base.SchemaProxy],
2384+
label string,
2385+
sc *[]*SchemaChanges,
2386+
changes *[]*Change,
2387+
) {
2388+
leftEntries := buildSchemaCompositionEntries(lSchema)
2389+
rightEntries := buildSchemaCompositionEntries(rSchema)
2390+
matchedCounts := matchSchemaCompositionIdentityCounts(leftEntries, rightEntries)
2391+
2392+
leftUnmatched := filterUnmatchedSchemaCompositionEntries(leftEntries, matchedCounts)
2393+
rightUnmatched := filterUnmatchedSchemaCompositionEntries(rightEntries, matchedCounts)
2394+
2395+
pairs := min(len(leftUnmatched), len(rightUnmatched))
2396+
for i := 0; i < pairs; i++ {
2397+
*sc = append(*sc, CompareSchemas(leftUnmatched[i].proxy, rightUnmatched[i].proxy))
2398+
}
2399+
2400+
for i := pairs; i < len(leftUnmatched); i++ {
2401+
CreateChange(changes, ObjectRemoved, label,
2402+
leftUnmatched[i].proxy.GetValueNode(), nil,
2403+
schemaCompositionChangeBreaking(label, ObjectRemoved),
2404+
leftUnmatched[i].proxy, nil)
2405+
}
2406+
2407+
for i := pairs; i < len(rightUnmatched); i++ {
2408+
CreateChange(changes, ObjectAdded, label,
2409+
nil, rightUnmatched[i].proxy.GetValueNode(),
2410+
schemaCompositionChangeBreaking(label, ObjectAdded),
2411+
nil, rightUnmatched[i].proxy)
2412+
}
2413+
}
2414+
22772415
// checkDependentRequiredChanges compares two DependentRequired maps and returns any changes found
22782416
func checkDependentRequiredChanges(
22792417
left, right *orderedmap.Map[low.KeyReference[string], low.ValueReference[[]string]],

0 commit comments

Comments
 (0)