Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

default not working in anyOf and oneOf but allOf #127

Closed
mrx8 opened this issue Feb 19, 2016 · 3 comments
Closed

default not working in anyOf and oneOf but allOf #127

mrx8 opened this issue Feb 19, 2016 · 3 comments

Comments

@mrx8
Copy link

mrx8 commented Feb 19, 2016

Schema:

{
  "anyOf": [{
    "type" : "object",
    "properties": {
      "key1": {"type": "string", "default": "A"}
    },
    "required": ["key1"]
  }]
}

input-data:

{}

should result in:

{
  "key1": "A"
}

But it produces errors if default is used. This happens in case of "anyOf" and "oneOf". "allOf" works.
Tested with ajv version 3.4.0 on Node.js v4.2.6 on 64bit Linux.
Option useDefault: true is used

@epoberezkin
Copy link
Member

That is how it is implemented: see docs Assigning defaults, the end of the section.

The reason for ignoring defaults in compound keywords is that the possible algorithm to decide which branch to take the default from is

  1. quite arbitrary - it has nothing to do with the standard
  2. complex - it requires keeping track of applied defaults and rolling back in case anyOf branch validation failed
  3. confusing / non-deterministic - it's impossible to know in advance whether the default will be applied or not, and that was the main reason for me to decide not to implement it.

Obviously in the case like in your example the default could have been applied, but you don't really need anyOf with a single branch. If anyOf/oneOf has multiple branches it becomes very messy.

There is some discussion on the subject in #42.

@epoberezkin
Copy link
Member

The solution I can suggest is to define a custom keyword say applyDefault that would apply the default if the option useDefaults is true in cases when it would be ignored otherwise, after successful validation.

Given that from version 3.7.0 you have access to the parent data object and the property in this object that points to the current data you can easily check if the current data is defined and if it is not assign the default value.

You'll just have to modify the schema to make the property not-required (it is kind of redundant in cases you have default) - this applyDefault will be executed after branch validation if it was successful, not before.

var schema = {
  "anyOf": [{
    "type" : "object",
    "properties": {
      "key1": {"type": "string", "applyDefault": "A"}
    }
  }]
};

ajv.addKeyword('applyDefault', { compile: function(schema) {
  if (!this._opts.useDefaults) return function() { return true; }
  var default = schema.applyDefault;
  return function(data, dataPath, parentData, parentDataProperty) {
    if (data === undefined) parentData[parentDataProperty] = default;
    return true;
  };
}})

@epoberezkin
Copy link
Member

above won't work :) but something along these lines will :)

e.g. this:

{
  "anyOf": [{
    "type" : "object",
    "properties": {
      "key1": {"type": "string"}
    },
    "defaultProperties": {
      "key1": "A"
    }
  }]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants
@epoberezkin @mrx8 and others