-
-
Notifications
You must be signed in to change notification settings - Fork 208
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
fix: update internal schema merging #665
Conversation
index.js
Outdated
} | ||
Object.assign(mergedSchema.properties, allOfSchema.properties) | ||
} | ||
for (let location of locations) { |
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.
Won't a simple for loop be faster than iterators?
It was the case last time I checked
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.
This kind of change doesn't create any perf difference unless it places in a very very high-loaded bottleneck (not this library). This library could be optimized by reducing the amount of time it clones the schemas.
Feel free to run benchmarks and prove me wrong.
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.
I see, no problem I'll take your word 😄
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
index.js
Outdated
} | ||
for (const subSchema of Object.values(schema)) { | ||
if ( | ||
typeof subSchema === 'object' && |
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.
Not familiar so just asking, we are sure there can't be a null value right?
typeof subSchema === 'object' && | |
subSchema != null && |
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.
It shouldn't be, but this is a good catch. Will add a check.
0d36211
to
fe65ff4
Compare
Need a proper review for this one. This is more difficult than it might seem. |
package.json
Outdated
"ajv": "^8.10.0", | ||
"ajv-formats": "^2.1.1", | ||
"fast-deep-equal": "^3.1.3", | ||
"fast-uri": "^2.1.0", | ||
"rfdc": "^1.2.0", | ||
"json-schema-ref-resolver": "^1.0.1" | ||
"json-schema-ref-resolver": "^1.0.1", | ||
"json-schema-merge-allof": "^0.8.1" |
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.
The use of https://www.npmjs.com/package/json-schema-merge-allof does not inspire me a lot of faith as it seems an unmaintained module. Is there an alternative? Can we fork or embed its code in here?
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.
Unfortunatelly this is the best solution I could find. We can write our own solution, but I don't have time for this right now. Anyway it should be better that our currect merge logic.
Waiting for https://github.com/fastify/merge-json-schemas release. |
|
||
const schema = { | ||
allOf: [ | ||
{ type: 'string' }, | ||
{ type: 'number' } | ||
] | ||
} | ||
t.throws(() => build(schema), new Error('allOf schemas have different type values')) | ||
try { | ||
build(schema) |
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.
build(schema) | |
build(schema) | |
t.fail('Should have thrown') |
|
||
const schema = { | ||
allOf: [ | ||
{ format: 'date' }, | ||
{ format: 'time' } | ||
] | ||
} | ||
t.throws(() => build(schema), new Error('allOf schemas have different format values')) | ||
try { | ||
build(schema) |
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.
build(schema) | |
build(schema) | |
t.fail('Should have thrown') |
} | ||
if ( | ||
schema.$id !== undefined && | ||
schema.$id.charAt(0) !== '#' |
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.
What if schema.$id is an empty string?
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.
It shouldn't be an empty string. If user explicitly add a schema $id field with empty string value, it's kind of his problem. Anyway, this code will prefix all nested schemas' $refs with an empty string then.
mergeAllOfSchema(context, location, schema, clone(schema)) | ||
schema = location.schema | ||
code += ` | ||
else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`) |
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.
else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`) | |
else throw new TypeError(\`The value of '${schemaRef}' does not match the schema definition.\`) |
?
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.
I didn't add this error. If you want to update the error message for this error, you can create another PR.
}) | ||
const noElseGreetingOutput = JSON.stringify({ | ||
kind: 'greeting', | ||
foo: 'FOO', | ||
bar: 42, | ||
hi: 'HI', | ||
hello: 45, | ||
a: 'A', | ||
b: 35 | ||
}) | ||
const noElseGreetingOutput = JSON.stringify({}) |
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.
Why did you change this?
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.
Because the test was wrong.
Here is a schema:
fast-json-stringify/test/if-then-else.test.js
Line 167 in 69a34a2
const noElseSchema = { |
Here is an input data:
fast-json-stringify/test/if-then-else.test.js
Line 209 in 69a34a2
const greetingInput = { |
As you can see the if
condition doesn't fullfil as greetingInput.kind
equal greeting
and not a foobar
, so it should use else
schema instead of then
. And as else
schema is missing the result is an empty object.
}) | ||
|
||
test('allOf: throw Error if nullable mismatch /1', (t) => { | ||
test('recursive nested allOfs', (t) => { |
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.
Why did you change these two allOf tests?
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.
I didn't change the test here. I removed allOf: throw Error if nullable mismatch /1
test and added a couple of new tests. I dropped the allOf: throw Error if nullable mismatch /1
because now the merging algoritm is more accurate and can resolve the situation when two schemas has different nullable
keyword values.
If one schema has nullable
= true and another one has nullable
= false the merged schema will have nullable
= false. Now fast-json-stringify
just throws an error in this case.
Tbh. This is a quite complex PR. I dont think that I could approve it with the full confidence that I understood everything. I read over it, and tbh. I did not make a deep dive. Just a raw review, if everything makes still kind of sense. Also I dont want to stall to merge this, just because I am not confident enough to approve it. For my approval I just need the confidence, that we didnt break the api contract and if we break it, it should be an informed decision.As we have a good code coverage in this project, it would enough for me, if no old tests were chaged, and if they were changed, that they dont reflect a significant behavioural change. I would like to know why some of the tests got changed/removed in the allof.test.js, as it seems the only place where the behaviour changed significantly. If those questions are answered, I am happy to approve it. |
@Uzlopak let me know if you have any further concerns, otherwise I'd like to ship this soon. |
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.
Thank you for the explaination.
LGTM
Signed-off-by: Matteo Collina <[email protected]>
This reverts commit 9dd8cb6.
This PR adds a proper schema merging for different cases:
Fix #648
Fix #642