Enable root modifications
Though I can not see why you would want to..... But there's no reason you would not be able to
This commit is contained in:
@@ -147,6 +147,52 @@ func (p *JSONProcessor) ProcessContent(content string, pattern string, luaExpr s
|
||||
|
||||
// updateJSONValue updates a value in the JSON structure based on its JSONPath
|
||||
func (p *JSONProcessor) updateJSONValue(jsonData interface{}, path string, newValue interface{}) error {
|
||||
// Special handling for root node
|
||||
if path == "$" {
|
||||
// For the root node, we'll copy the value to the jsonData reference
|
||||
// This is a special case since we can't directly replace the interface{} variable
|
||||
|
||||
// We need to handle different types of root elements
|
||||
switch rootValue := newValue.(type) {
|
||||
case map[string]interface{}:
|
||||
// For objects, we need to copy over all keys
|
||||
rootMap, ok := jsonData.(map[string]interface{})
|
||||
if !ok {
|
||||
// If the original wasn't a map, completely replace it with the new map
|
||||
// This is handled by the jsonpath.Set function
|
||||
return jsonpath.Set(jsonData, path, newValue)
|
||||
}
|
||||
|
||||
// Clear the original map
|
||||
for k := range rootMap {
|
||||
delete(rootMap, k)
|
||||
}
|
||||
|
||||
// Copy all keys from the new map
|
||||
for k, v := range rootValue {
|
||||
rootMap[k] = v
|
||||
}
|
||||
return nil
|
||||
|
||||
case []interface{}:
|
||||
// For arrays, we need to handle similarly
|
||||
rootArray, ok := jsonData.([]interface{})
|
||||
if !ok {
|
||||
// If the original wasn't an array, use jsonpath.Set
|
||||
return jsonpath.Set(jsonData, path, newValue)
|
||||
}
|
||||
|
||||
// Clear and recreate the array
|
||||
*&rootArray = rootValue
|
||||
return nil
|
||||
|
||||
default:
|
||||
// For other types, use jsonpath.Set
|
||||
return jsonpath.Set(jsonData, path, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
// For non-root paths, use the regular Set method
|
||||
err := jsonpath.Set(jsonData, path, newValue)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update JSON value at path '%s': %w", path, err)
|
||||
|
@@ -937,16 +937,16 @@ func TestJSONProcessor_RestructuringData(t *testing.T) {
|
||||
"people": {
|
||||
"developers": [
|
||||
{
|
||||
"age": 25,
|
||||
"id": 1,
|
||||
"name": "Alice",
|
||||
"age": 25
|
||||
"name": "Alice"
|
||||
}
|
||||
],
|
||||
"managers": [
|
||||
{
|
||||
"age": 30,
|
||||
"id": 2,
|
||||
"name": "Bob",
|
||||
"age": 30
|
||||
"name": "Bob"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1042,3 +1042,83 @@ func TestJSONProcessor_FilteringArrayElements(t *testing.T) {
|
||||
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
// TestJSONProcessor_RootNodeModification tests modifying the root node directly
|
||||
func TestJSONProcessor_RootNodeModification(t *testing.T) {
|
||||
content := `{
|
||||
"name": "original",
|
||||
"value": 100
|
||||
}`
|
||||
|
||||
expected := `{
|
||||
"name": "modified",
|
||||
"description": "This is a completely modified root",
|
||||
"values": [1, 2, 3]
|
||||
}`
|
||||
|
||||
p := &JSONProcessor{}
|
||||
result, modCount, matchCount, err := p.ProcessContent(content, "$", `
|
||||
-- Completely replace the root node
|
||||
v = {
|
||||
name = "modified",
|
||||
description = "This is a completely modified root",
|
||||
values = {1, 2, 3}
|
||||
}
|
||||
`)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error processing content: %v", err)
|
||||
}
|
||||
|
||||
if matchCount != 1 {
|
||||
t.Errorf("Expected 1 match, got %d", matchCount)
|
||||
}
|
||||
|
||||
if modCount != 1 {
|
||||
t.Errorf("Expected 1 modification, got %d", modCount)
|
||||
}
|
||||
|
||||
// Normalize whitespace for comparison
|
||||
normalizedResult := normalizeWhitespace(result)
|
||||
normalizedExpected := normalizeWhitespace(expected)
|
||||
|
||||
if normalizedResult != normalizedExpected {
|
||||
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
// TestJSONProcessor_RootNodeModificationToPrimitive tests modifying the root node to a primitive value
|
||||
func TestJSONProcessor_RootNodeModificationToPrimitive(t *testing.T) {
|
||||
content := `{
|
||||
"name": "original",
|
||||
"value": 100
|
||||
}`
|
||||
|
||||
expected := `42`
|
||||
|
||||
p := &JSONProcessor{}
|
||||
result, modCount, matchCount, err := p.ProcessContent(content, "$", `
|
||||
-- Replace the root node with a primitive value
|
||||
v = 42
|
||||
`)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error processing content: %v", err)
|
||||
}
|
||||
|
||||
if matchCount != 1 {
|
||||
t.Errorf("Expected 1 match, got %d", matchCount)
|
||||
}
|
||||
|
||||
if modCount != 1 {
|
||||
t.Errorf("Expected 1 modification, got %d", modCount)
|
||||
}
|
||||
|
||||
// Normalize whitespace for comparison
|
||||
normalizedResult := normalizeWhitespace(result)
|
||||
normalizedExpected := normalizeWhitespace(expected)
|
||||
|
||||
if normalizedResult != normalizedExpected {
|
||||
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||
}
|
||||
}
|
||||
|
@@ -138,10 +138,6 @@ func Set(data interface{}, path string, value interface{}) error {
|
||||
return fmt.Errorf("failed to parse JSONPath %q: %w", path, err)
|
||||
}
|
||||
|
||||
if len(steps) <= 1 {
|
||||
return fmt.Errorf("cannot set root node; the provided path %q is invalid", path)
|
||||
}
|
||||
|
||||
success := false
|
||||
err = setWithPath(data, steps, &success, value, "$", ModifyFirstMode)
|
||||
if err != nil {
|
||||
@@ -157,10 +153,6 @@ func SetAll(data interface{}, path string, value interface{}) error {
|
||||
return fmt.Errorf("failed to parse JSONPath %q: %w", path, err)
|
||||
}
|
||||
|
||||
// if len(steps) <= 1 {
|
||||
// return fmt.Errorf("cannot set root node; the provided path %q is invalid", path)
|
||||
// }
|
||||
|
||||
success := false
|
||||
err = setWithPath(data, steps, &success, value, "$", ModifyAllMode)
|
||||
if err != nil {
|
||||
@@ -178,17 +170,20 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
|
||||
// Skip root step
|
||||
actualSteps := steps
|
||||
if len(steps) > 0 && steps[0].Type == RootStep {
|
||||
// if len(steps) == 1 {
|
||||
// return fmt.Errorf("cannot set root node; the provided path %q is invalid", currentPath)
|
||||
// }
|
||||
actualSteps = steps[1:]
|
||||
}
|
||||
|
||||
// Process the first step
|
||||
// if len(actualSteps) == 0 {
|
||||
// return fmt.Errorf("cannot set root node; no steps provided for path %q", currentPath)
|
||||
// }
|
||||
// If we have no steps left, we're setting the root value
|
||||
if len(actualSteps) == 0 {
|
||||
// For the root node, we need to handle it differently depending on what's passed in
|
||||
// since we can't directly replace the interface{} variable
|
||||
|
||||
// We'll signal success and let the JSONProcessor handle updating the root
|
||||
*success = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process the first step
|
||||
step := actualSteps[0]
|
||||
remainingSteps := actualSteps[1:]
|
||||
isLastStep := len(remainingSteps) == 0
|
||||
|
Reference in New Issue
Block a user