avian2 / jsonmerge

Merge a series of JSON documents.
MIT License
214 stars 25 forks source link

How do I use `"mergeStrategy": "append"` by default? #28

Closed ahuff44 closed 7 years ago

ahuff44 commented 7 years ago

I want the following assertion to pass:

schema = ???
base = None
base = jsonmerge.merge(base, {"a": ["1"], "b": 3}, schema)
base = jsonmerge.merge(base, {"a": ["2"], "b": 4}, schema)

assert base == {"a": ["1", "2"], b: 4}

I know that this is possible with

schema = {
  'properties': {
    'a': {'mergeStrategy': 'append'},
    'b': {'mergeStrategy': 'overwrite'}
  }
}

but in my case, I trying to write a general system where the array key isn't necessarily a top-level key named "a"; I want to merge any and all arrays using "append" instead of "overwrite".

Is this possible somehow? Ideally I would be able to set schema like so: (this obviously does not currently work)

schema = {
  "mergeStrategy": {
    "typeMatch": {
      "object": "objectMerge",
      "array": "append",
      "default": "overwrite"
    }
  }
} 

It seems like the best route would be to create a custom merge strategy, but I'm hoping there's an easier solution that I've overlooked

avian2 commented 7 years ago

Theoretically, what you want could be done with a schema like this:

schema = {
    "oneOf": [
        {
            "type": "array",
            "mergeStrategy": "append"
        },
        {
            "type": "object",
            "additionalProperties": {
                "$ref": "#"
            }
        },
        {
            "type": "string"
        },
        {
            "type": "number"
        },
    ]
}

This seems to work correctly for validation with current jsonschema (even though self-referential schemas are technically undefined behavior). Unfortunately, oneOfkeyword is not currently supported at all in jsonmerge, so this does not work for merging right now.

I'll look into implementing a basic support for oneOf that will work with the schema above. It should be relatively straightforward compared to anyOf and allOf.

For a quick-and-dirty fix, modify the WalkInstance.default_strategy method. I don't think you can achieve what you want with a custom merge strategy.

avian2 commented 7 years ago

The oneOf recipe mentioned above should now work with jsonmerge from the master branch.