AllenNeuralDynamics / AllenNeuralDynamics/aind-json-utils-test-repo

Add module to merge json files

Offen
#2 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Python
Sterne
0
Forks
0
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

## Summary

Create a module that merges two JSON files using a precedence-based strategy. A designated `main.json` file acts as the authoritative source — its existing values are never overwritten. A second "incoming" JSON file provides supplemental data that fills in missing keys only.

---

## Requirements

### Input
- The module accepts two JSON file paths as input.
- One file is always designated as `main.json` (the primary/authoritative source).
- The other file is the **incoming** JSON (the secondary/supplemental source).

### Merge Behavior

1. **Top-level keys that exist only in `main.json`** → preserved as-is.
2. **Top-level keys that exist only in the incoming JSON** → added to the merged result.
3. **Top-level keys that exist in both files:**
- If the value in `main.json` is **already populated** (non-null, non-empty), it takes precedence and must **not** be overwritten.
- If the value in `main.json` is `null`, `""`, `{}`, or `[]` (empty/unset), the incoming value may fill it in.
4. **Nested objects (recursive merge):**
- When both files have an object at the same key, the merge should recurse into the nested structure and apply the same precedence rules at every level.
- `main.json` values always win at any depth if they are populated.
5. **Arrays:**
- If `main.json` has a non-empty array at a given key, it is preserved entirely (no element-level merge).
- If `main.json` has an empty array and the incoming file has a non-empty one, the incoming array is used.

### Output
- The module returns (or writes) the merged JSON result.

---

## Example

**`main.json`**
```json
{
"name": "Acme Corp",
"address": {
"street": "123 Main St",
"city": "",
"state": "WA"
},
"tags": ["enterprise"],
"metadata": {
"created_by": "admin",
"notes": null
},
"contacts": []
}
```

**`incoming.json`**
```json
{
"name": "Acme Corporation",
"address": {
"street": "123 Main St",
"city": "Seattle",
"state": "WA",
"zip": "98101"
},
"tags": ["startup", "west-coast"],
"metadata": {
"created_by": "import-script",
"notes": "Imported from CRM",
"source": "crm-v2"
},
"contacts": [
{ "email": "info@example.com" }
],
"industry": "Technology"
}
```

**Expected merged result:**
```json
{
"name": "Acme Corp",
"address": {
"street": "123 Main St",
"city": "Seattle",
"state": "WA",
"zip": "98101"
},
"tags": ["enterprise"],
"metadata": {
"created_by": "admin",
"notes": "Imported from CRM",
"source": "crm-v2"
},
"contacts": [
{ "email": "info@acme.com" }
],
"industry": "Technology"
}
```

### Why each key resolved the way it did

| Key | Resolution | Reason |
|---|---|---|
| `name` | `"Acme Corp"` | Main is populated → preserved |
| `address.street` | `"123 Main St"` | Main is populated → preserved |
| `address.city` | `"Seattle"` | Main is empty string → incoming fills it |
| `address.state` | `"WA"` | Main is populated → preserved |
| `address.zip` | `"98101"` | Only in incoming → added |
| `tags` | `["enterprise"]` | Main has non-empty array → preserved |
| `metadata.created_by` | `"admin"` | Main is populated → preserved |
| `metadata.notes` | `"Imported from CRM"` | Main is null → incoming fills it |
| `metadata.source` | `"crm-v2"` | Only in incoming → added |
| `contacts` | `[{ "email": "info@example.com" }]` | Main is empty array → incoming fills it |
| `industry` | `"Technology"` | Only in incoming → added |

---

## Acceptance Criteria

- [ ] Module reads two JSON files from disk (or accepts two parsed objects).
- [ ] Merge is recursive for nested objects.
- [ ] `main.json` populated values are never overwritten at any depth.
- [ ] Empty/null values in `main.json` are filled by incoming data.
- [ ] Keys unique to either file appear in the final output.
- [ ] Non-empty arrays in `main.json` are preserved without element-level merging.
- [ ] Unit tests cover: flat merge, deep merge, empty-value replacement, array precedence, and keys unique to each file.
- [ ] Code handles edge cases: missing files, invalid JSON, deeply nested structures, and mismatched types at the same key.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.