-
-
Notifications
You must be signed in to change notification settings - Fork 210
fix: ref with same id in properties #464
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
@climba03003 I think it's better to do it in the fast-json-stringify-compiler. We do the same thing in the ajv-compiler. |
But the problem still exist in here if you use it directly. |
I would say that it shouldn't work. fastify.getSchema creates the wrong schema, so I think I may sense to fix it in the Fastify (fast-json-stringify-compiler). |
You can see my test, it is nothing related to |
I mean, it's not a problem of fjs that we pass target schema duplicate in the external schemas. If we continue this logic inside fjs and make schema $id not strict, we will have to also check for duplicates inside external schemas and we don't need that. |
The bug actually cause by Line 896 in 12fa1e9
And later on in Lines 951 to 971 in 12fa1e9
Which is definitely something wrong within Edit: I am wrong #462 suffer from it as well. |
The reason why this test fails is that I forgot to clone external schemas, but not the duplicate schema. I added external schema cloning and your test to the #462. Thanks for finding it. This happens because fjs modifies external schemas. If you want to fix this bug as a separate PR, you need to clone external schemas. You don't need to delete any duplications. |
It does not work without the https://github.com/fastify/fast-json-stringify/runs/6925112158?check_suite_focus=true |
945f72a
to
ec61ef5
Compare
Oh, I got it. Yeah, this is one of the reasons why I decided to use ajv. In #462, we pass json pointer to the original schema instead of coping oneOf/anyOf schema. I would say that this is a slightly different problem than fastify/fast-json-stringify-compiler#14. Your solution fixes two things oneOf/anyOf case and top-level schema duplicate case. IMHO top-level schema duplicate case should be fixed in the fast-json-stringify-compiler. If we merge #462 oneOf/anyOf will be fixed. Does it work for you? If you want I can explain in more detail. |
Yes, #462 works. So, this separate PR is needed for |
Why do you think #462 is a breaking change? |
Even if the test-case in here and fastify are all passed.
From this line, it means we support some weird / wrong |
There is said that Fastify supports the json schema draft 7 standard. I suppose if something is not working it's a bug. Each fix changes something in behavior. |
Your solution fixes it only partially. Only top level $ids. test('ref with same id in properties', (t) => {
t.plan(2)
const externalSchema = {
ObjectId: {
$id: 'ObjectId',
type: 'string',
definitions: {
p: { $id: 'p' }
}
},
File: {
$id: 'File',
type: 'object',
properties: {
_id: { $ref: 'ObjectId' },
name: { type: 'string' },
owner: { $ref: 'ObjectId' }
}
}
}
t.test('anyOf', (t) => {
t.plan(1)
const schema = {
$id: 'Article',
type: 'object',
properties: {
_id: { $ref: 'ObjectId' },
image: {
anyOf: [
{ $ref: 'File' },
{ type: 'null' }
]
}
}
}
const stringify = build(schema, { schema: externalSchema })
const output = stringify({ _id: 'foo', image: { _id: 'bar', name: 'hello', owner: 'baz' } })
t.equal(output, '{"_id":"foo","image":{"_id":"bar","name":"hello","owner":"baz"}}')
})
t.test('oneOf', (t) => {
t.plan(1)
const schema = {
$id: 'Article',
type: 'object',
properties: {
_id: { $ref: 'ObjectId' },
image: {
oneOf: [
{ $ref: 'File' },
{ type: 'null' }
]
}
}
}
const stringify = build(schema, { schema: externalSchema })
const output = stringify({ _id: 'foo', image: { _id: 'bar', name: 'hello', owner: 'baz' } })
t.equal(output, '{"_id":"foo","image":{"_id":"bar","name":"hello","owner":"baz"}}')
})
}) |
I am not the one releasing this module and it can be land as patch or minor decided by who releasing it. But, if it's turns out breaking too many people. I think it might revert again. I do see landing 462 benefit a lot.
It will be complicated in fixing nested thing. I think I will stay in this step. |
And it should remove the duplicate schema only if schemas are equal. Otherwise, it should throw an error. |
This solution do not mutate the original schema that added to So, when ever we delete the |
This shouldn't compile correctly. test('ref with same id in properties', (t) => {
t.plan(2)
const externalSchema = {
ObjectId: {
$id: 'ObjectId',
type: 'string',
},
File: {
$id: 'File',
type: 'object',
properties: {
_id: { $ref: 'ObjectId' },
name: { type: 'string' },
owner: { $ref: 'ObjectId' }
}
}
}
t.test('anyOf', (t) => {
t.plan(1)
const schema = {
$id: 'Article',
type: 'object',
properties: {
_id: { $ref: 'ObjectId' },
image: {
anyOf: [
{ $ref: 'File' },
{
$id: 'File',
type: 'number',
},
{ type: 'null' },
]
}
}
}
const stringify = build(schema, { schema: externalSchema })
const output = stringify({ _id: 'foo', image: { _id: 'bar', name: 'hello', owner: 'baz' } })
t.equal(output, '{"_id":"foo","image":{"_id":"bar","name":"hello","owner":"baz"}}')
})
t.test('oneOf', (t) => {
t.plan(1)
const schema = {
$id: 'Article',
type: 'object',
properties: {
_id: { $ref: 'ObjectId' },
image: {
oneOf: [
{ $ref: 'File' },
{ type: 'null' }
]
}
}
}
const stringify = build(schema, { schema: externalSchema })
const output = stringify({ _id: 'foo', image: { _id: 'bar', name: 'hello', owner: 'baz' } })
t.equal(output, '{"_id":"foo","image":{"_id":"bar","name":"hello","owner":"baz"}}')
})
}) |
Although it is the wrong behavior. But, it is possible currently. const stringify = FJS(
{
$id: "https://example.com/schemas/base",
type: "object",
properties: {
p1: { $id: "p1", type: "string" },
p2: { $ref: "p1" },
},
},
{
schema: {
p1: {
$id: "p1",
type: "number",
},
},
}
);
console.log(stringify({ p1: "", p2: "" })); |
No, it's not. Why did you change the test? The key point is oneOf/anyOf/if-then - cases when we use ajv test('anyOf', (t) => {
t.plan(1)
const externalSchema = {
ObjectId: {
$id: 'ObjectId',
type: 'string',
}
}
const schema = {
type: 'object',
properties: {
image: {
anyOf: [
{ $ref: 'ObjectId' },
{
$id: 'ObjectId',
type: 'number',
}
]
}
}
}
build(schema, { schema: externalSchema })
t.pass()
}) |
ec61ef5
to
5cf259f
Compare
This fix should handle both case now. |
Closing in favor of #462. |
I don't think it is a good fix, but it just works.
Fixes fastify/fastify#4028
This PR is a fix before #462 lands. Since #462 changed a lot in the internal ref resolve and may introduce breaking change.
I see the needs of a temporary fix.
@ivan-tymoshenko do you have better idea on this?
Checklist
npm run test
andnpm run benchmark
and the Code of conduct