# JSON Multi Merge

A high-performance JSON merging library powered by Rust, featuring advanced merge rules and key
modifiers.

## Features

- **Recursive Object Merging**: Deep merge nested JSON objects
- **Array Replacement**: Second object's arrays take precedence
- **Key Modifiers**:
  - `key!` - Replace value instead of merging
  - `key--` - Remove this key from the result
- **Type Conflict Resolution**: Last object's type wins
- **Null Handling**: Treat null as a regular value
- **High Performance**: Rust backend for efficient deep merges

## Installation

```bash
pip install json-multi-merge
```

## Usage

## Input Requirements

The `merge` function accepts a list of Python dictionaries:

```python
# Valid usage
merge([{"a": 1}, {"b": 2}])

# Invalid usage (will raise TypeError)
merge([{"a": 1}, [1, 2, 3]])  # Second item is not a dict
merge("not a list")            # Not a list at all

### Basic Merge
```python
from json_multi_merge import merge

a = {"name": "Alice", "age": 30}
b = {"age": 31, "city": "Paris"}
result = merge(a, b)
# {'name': 'Alice', 'age': 31, 'city': 'Paris'}
```

### Nested Object Merging
```python
base = {
    "user": {
        "name": "Alice",
        "contact": {"email": "alice@example.com"}
    }
}
update = {
    "user": {
        "contact": {"phone": "555-1234"},
        "preferences": {"theme": "dark"}
    }
}
result = merge(base, update)
# {
#   "user": {
#     "name": "Alice",
#     "contact": {"email": "alice@example.com", "phone": "555-1234"},
#     "preferences": {"theme": "dark"}
#   }
# }
```

## Merging Multiple Objects

Merge any number of JSON objects sequentially:

```python
result = merge(
    {"base": 1},
    {"base": 2, "new!": "value"},
    {"base--": None, "final": True}
)
# Result: {'new': 'value', 'final': True}
```

### Batch Processing Example
```python
configs = [
    {"defaults": {"timeout": 30}},
    {"defaults": {"retries": 3}},
    {"defaults!": {"cache": "enabled"}},
    {"defaults--": {}, "environment": "prod"}
]

final_config = merge(*configs)
# Result: {'environment': 'prod'}
```

### Array Replacement
```python
base = {"tags": ["old"], "items": [1, 2]}
update = {"tags": ["new"], "items!": [3, 4]}
result = merge(base, update)
# {"tags": ["new"], "items": [3, 4]}
```

### Key Modifiers
**Replace (!) and Omit (--)**
```python
config = {
    "debug": True,
    "plugins": ["basic"],
    "temp_data": {"key": "value"}
}
update = {
    "debug!": False,
    "plugins--": None,
    "temp_data--": {"key": "value"}
}
result = merge(config, update)
# {"debug": False}
```

### Deeply Nested Modifiers
```python
base = {
    "system": {
        "settings": {
            "logging": {"level": "info"},
            "backups": {"enabled": False}
        }
    }
}
update = {
    "system!": {
        "settings--": {"logging": {"level": "info"}},
        "new_settings": {"cache_size": "256MB"}
    }
}
result = merge(base, update)
# {
#   "system": {
#     "new_settings": {"cache_size": "256MB"}
#   }
# }
```

### Type Conflicts
```python
base = {"data": {"values": [1, 2, 3]}}
update = {"data": "invalid"}
result = merge(base, update)
# {"data": "invalid"}
```

### Null Handling
```python
base = {"user": None}
update = {"user!": {"name": "Bob"}}
result = merge(base, update)
# {"user": {"name": "Bob"}}
```

## API Reference

### `merge(base: dict, update: dict) -> dict`
Merges two JSON objects according to the rules:
1. Objects are merged recursively
2. Arrays are replaced
3. Key modifiers change merge behavior:
   - `key!`: Replace value completely
   - `key--`: Remove key from result
4. Last object's value type wins in conflicts

## Performance

The Rust implementation provides significant performance benefits for:
- Large JSON documents (10k+ elements)
- Deeply nested structures (10+ levels)
- Batch processing operations

```python
# Benchmark example (1k nested objects)
import timeit
setup = '''
import json_multi_merge
base = {"data": {"nested": {"value": 1}}}
update = {"data": {"nested": {"value!": 2}}}
'''
print(timeit.timeit('json_multi_merge.merge(base, update)', setup, number=10000))
# Typical result: ~0.8 seconds (vs ~4.2 seconds for pure Python equivalent)
```

## License

MIT License - See [LICENSE](LICENSE) for details.
