Skip to content

Commit 66d3988

Browse files
authored
feat: support short-circuiting append operations when there are multiple appends, not just 1 item (#153)
* feat: when we derive an overlay, if the delta is just appending an array item, we do not need to delete and recreate the array * chore: simplify
1 parent 3863ba5 commit 66d3988

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

overlay/compare.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,13 @@ func walkTreesAndCollectActions(path simplePath, y1 *yaml.Node, y2 yaml.Node) ([
117117
return walkSequenceNode(path, y1, y2)
118118
}
119119

120-
if len(y2.Content) == len(y1.Content)+1 &&
120+
if len(y2.Content) > len(y1.Content) &&
121121
yamlEquals(y2.Content[:len(y1.Content)], y1.Content) {
122122
return []Action{{
123123
Target: path.ToJSONPath(),
124124
Update: yaml.Node{
125125
Kind: y1.Kind,
126-
Content: []*yaml.Node{y2.Content[len(y1.Content)]},
126+
Content: y2.Content[len(y1.Content):],
127127
},
128128
}}, nil
129129
}

overlay/compare_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/speakeasy-api/openapi/overlay/loader"
88
"github.com/stretchr/testify/assert"
99
"github.com/stretchr/testify/require"
10+
"gopkg.in/yaml.v3"
1011
)
1112

1213
func TestCompare(t *testing.T) {
@@ -38,3 +39,44 @@ func TestCompare(t *testing.T) {
3839
NodeMatchesFile(t, node, "testdata/openapi-overlayed.yaml")
3940

4041
}
42+
43+
func TestCompare_ArrayAppendMultiple(t *testing.T) {
44+
t.Parallel()
45+
46+
original := `items:
47+
- name: a
48+
- name: b
49+
`
50+
target := `items:
51+
- name: a
52+
- name: b
53+
- name: c
54+
- name: d
55+
`
56+
var origNode yaml.Node
57+
require.NoError(t, yaml.Unmarshal([]byte(original), &origNode))
58+
var targetNode yaml.Node
59+
require.NoError(t, yaml.Unmarshal([]byte(target), &targetNode))
60+
61+
o, err := overlay.Compare("test", &origNode, targetNode)
62+
require.NoError(t, err)
63+
64+
// Emits a single append update for the new tail elements
65+
require.Len(t, o.Actions, 1)
66+
assert.Equal(t, `$["items"]`, o.Actions[0].Target)
67+
assert.False(t, o.Actions[0].Remove)
68+
require.Len(t, o.Actions[0].Update.Content, 2)
69+
70+
// Round-trip: applying the overlay should produce the target
71+
err = o.ApplyTo(&origNode)
72+
require.NoError(t, err)
73+
74+
var expected yaml.Node
75+
require.NoError(t, yaml.Unmarshal([]byte(target), &expected))
76+
77+
actualYAML, err := yaml.Marshal(&origNode)
78+
require.NoError(t, err)
79+
expectedYAML, err := yaml.Marshal(&expected)
80+
require.NoError(t, err)
81+
assert.Equal(t, string(expectedYAML), string(actualYAML))
82+
}

0 commit comments

Comments
 (0)