-
-
Notifications
You must be signed in to change notification settings - Fork 210
fix: ignore defined type if anyOf and oneOf are defined #611
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
We should catch a case when there is a Example1: {
type: 'object',
oneOf: [
{ type: 'string' },
{ type: 'object' }
]
} Example2: {
required: ['foo', 'bar'],
oneOf: [
{ type: 'string' },
{ type: 'object' }
]
} Ideally, we should catch this case with a isShemaValid, although it's hard to catch it there. |
isnt ajv already validating it? |
It shows a warning. IMHO, it should throw an error. Anyway, we should have tests for cases |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To fix this issue, you should merge (look how we merge allOf subschemas) each oneOf/anyOf option with a parent schema. Otherwise, you will fix one problem but create another.
Complex test:
test('should merge oneOf schema with parent schema', (t) => {
t.plan(1)
const schema = {
properties: {
bat: { type: 'string' }
},
oneOf: [
{
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' }
}
},
{
type: 'object',
properties: {
foo: { type: 'string' },
baz: { type: 'string' }
}
}
],
required: ['foo']
}
const stringify = build(schema)
t.equal(stringify({ bat: 'bat', foo: 'foo' }), '{"bat":"bat","foo":"foo"}')
t.throws(() => stringify({ bat: 'bar' })) // foo is required
})
A simple test to show the breaking change:
test('breaking change', (t) => {
t.plan(1)
const schema = {
properties: {
foo: { type: 'string' }
},
oneOf: [{ type: 'object' }]
}
const stringify = build(schema)
t.equal(stringify({ foo: 'foo' }), '{"foo":"foo"}')
})
If you have some time to deal with it, you can think about merging nested test('should merge nested oneOf schemas with parent schema', (t) => {
t.plan(1)
const schema = {
type: 'object',
oneOf: [
{
oneOf: [
{ required: ['test1'] },
{ required: ['test2'] }
]
}
],
required: ['test0']
}
const stringify = build(schema)
t.throws(() => stringify({ test1: 'data' })) // test0 is missing
t.throws(() => stringify({ test0: 'data' })) // test1 is missing
}) |
That is basically a total rewrite of anyOf and oneOf logic. |
That is why this issue has been waiting for someone so long) |
I would start by creating a separate module with the |
I was under the shower and had the same thought while washing my hair. We basically should have some schema helper which creates disjunct, union and intersections of two or more schemas. So if we have an allOf, it should merge the schemas together. But in case of oneOf we have to check if actually only one schema is matching, so we basically have to call every validation function per schema and check if we have exactly one matching schema and call its corresponding serializer fn. In case of anyOf, we have to first create a matrix of merged schemas and then have to check which schemas are matching and then call based on the determined matching schemas the correct merged schema from the matrix E.g. we have three schemas. We need 7 variations. We can store them in an array use the bitwise positions for the lookup. So
and in the for loop we validate them like let serializerArrayPos = 0 |
|
Not the solution we need. |
Closes #290
Checklist
npm run test
andnpm run benchmark
and the Code of conduct