|
1 | 1 | package plugins |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "encoding/json" |
4 | 5 | "fmt" |
5 | 6 | "strings" |
6 | 7 |
|
@@ -126,53 +127,62 @@ func setTargetField(res *resource.Resource, value any, mapping FieldMapping) err |
126 | 127 | } |
127 | 128 |
|
128 | 129 | func setWithPathCreation(data any, ptr jsonpointer.Pointer, value any) (any, error) { |
129 | | - // try setting value if the path already exists |
130 | | - if updatedData, err := ptr.Set(data, value); err == nil { |
131 | | - return updatedData, nil |
| 130 | + // Try direct set first - most common case |
| 131 | + if result, err := ptr.Set(data, value); err == nil { |
| 132 | + return result, nil |
132 | 133 | } |
133 | 134 |
|
134 | | - // otherwise, we need to create the path first |
| 135 | + // Create missing path structure |
135 | 136 | tokens := ptr.DecodedTokens() |
136 | 137 | if len(tokens) == 0 { |
137 | 138 | return value, nil |
138 | 139 | } |
139 | | - result := data |
140 | 140 |
|
141 | | - // JSON Pointer Set() fails if intermediate paths don't exist, so we must |
142 | | - // build the path incrementally from root to target, creating missing containers |
143 | | - for i := 1; i <= len(tokens)-1; i++ { |
144 | | - partialPath := "/" + strings.Join(tokens[:i], "/") |
145 | | - partialPtr, err := jsonpointer.New(partialPath) |
146 | | - if err != nil { |
147 | | - return nil, fmt.Errorf("failed to create partial pointer: %w", err) |
| 141 | + result := deepCopyData(data) |
| 142 | + |
| 143 | + // Create each missing parent container |
| 144 | + for i := 0; i < len(tokens)-1; i++ { |
| 145 | + parentPath := "/" + strings.Join(tokens[:i+1], "/") |
| 146 | + parentPtr, _ := jsonpointer.New(parentPath) |
| 147 | + |
| 148 | + // Skip if parent already exists and is not nil |
| 149 | + if parent, _, err := parentPtr.Get(result); err == nil && parent != nil { |
| 150 | + continue |
148 | 151 | } |
149 | | - // Get() is used as existence test - error means path doesn't exist and needs creation |
150 | | - _, _, err = partialPtr.Get(result) |
151 | | - if err != nil { |
152 | | - nextToken := tokens[i] |
153 | | - var newContainer any |
154 | | - // create array if next token is numeric (e.g., "/ports/0") |
155 | | - if isNumericString(nextToken) { |
156 | | - newContainer = make([]any, 0) |
157 | | - } else { |
158 | | - // create map otherwise (e.g., "/spec/strategy") |
159 | | - newContainer = make(map[string]any) |
160 | | - } |
161 | 152 |
|
162 | | - // create the missing path segment |
163 | | - result, err = partialPtr.Set(result, newContainer) |
164 | | - if err != nil { |
165 | | - return nil, fmt.Errorf("failed to create intermediate path %q: %w", partialPath, err) |
166 | | - } |
| 153 | + // Create container based on next token type |
| 154 | + var container any |
| 155 | + if isNumericString(tokens[i+1]) { |
| 156 | + container = make([]any, 0) |
| 157 | + } else { |
| 158 | + container = make(map[string]any) |
| 159 | + } |
| 160 | + |
| 161 | + // Set the container (jsonpointer handles the rest) |
| 162 | + var err error |
| 163 | + if result, err = parentPtr.Set(result, container); err != nil { |
| 164 | + return nil, fmt.Errorf("failed to create path at %q: %w", parentPath, err) |
167 | 165 | } |
168 | 166 | } |
169 | 167 |
|
170 | | - result, err := ptr.Set(result, value) |
| 168 | + // Final set should now succeed |
| 169 | + return ptr.Set(result, value) |
| 170 | +} |
| 171 | + |
| 172 | +// deepCopyData creates a deep copy of the data structure using JSON marshal/unmarshal. |
| 173 | +func deepCopyData(data any) any { |
| 174 | + // Use JSON marshal/unmarshal for deep copy - simple and reliable |
| 175 | + jsonBytes, err := json.Marshal(data) |
171 | 176 | if err != nil { |
172 | | - return nil, fmt.Errorf("failed to set final value: %w", err) |
| 177 | + return data // fallback to original if copy fails |
| 178 | + } |
| 179 | + |
| 180 | + var result any |
| 181 | + if err := json.Unmarshal(jsonBytes, &result); err != nil { |
| 182 | + return data // fallback to original if copy fails |
173 | 183 | } |
174 | 184 |
|
175 | | - return result, nil |
| 185 | + return result |
176 | 186 | } |
177 | 187 |
|
178 | 188 | func updateResource(res *resource.Resource, updatedData any) error { |
|
0 commit comments