ajv
ajv copied to clipboard
option compile from addKeyword doesn't change on a remove and then add again
Here my issue (if it's one):
I setup a keyword with addKeyword and the compile option. I have some external variables used inside. At the first iteration everything is ok, but at the second one we see the variables doesn't change. Is it a normal behavior or an issue ?
What version of Ajv are you using?
version 8.12.0
Your code
const AjvModule = require('ajv/dist/2020');
const express = require('express');
const ajv = new AjvModule();
const schemaName = 'schemaTest';
const keyword = "variableKeywork";
ajv.addSchema({
"description": "test",
"type": "object",
"properties": {
"item1": {
"type": "string"
},
"item2": {
"type": "integer"
}
},
"variableKeywork": true
}, schemaName);
const app = express();
const desc = {
item1: "test",
item2: 1
}
app.get(`/test`, (req, res) => {
desc.item1 = req.query.param;
const time = new Date();
console.log(`Date outside addKeyword: ${time}`);
console.log(`sentTo2 outside addKeyword : ${req.query.sentTo2}`);
console.log(`keyword present : ${JSON.stringify(ajv.getKeyword(keyword))}`);
ajv.addKeyword({
keyword: keyword,
modifying: true,
compile: (value) => function validate(data, root) {
console.log(`Date inside addKeyword: ${time}`);
console.log(`sentTo2 inside addKeyword : ${req.query.sentTo2}`);
if (Boolean(req.query.sentTo2)) {
root.rootData.item2 = req.query.param;
}
console.log(JSON.stringify(root.rootData))
return true
}
});
console.log(`keyword present : ${JSON.stringify(ajv.getKeyword(keyword))}`);
const isDataValid = ajv.validate(schemaName, desc);
ajv.removeKeyword(keyword);
console.log(`keyword present : ${JSON.stringify(ajv.getKeyword(keyword))}`);
res.json(isDataValid);
});
app.listen(8080, function () {
console.log("serveur started");
});
// try with http://localhost:8080/test?param=1&sentTo2=true
// and then http://localhost:8080/test?param=1&sentTo2=false
Output obtained
serveur started
Date outside addKeyword: Mon Apr 08 2024 17:24:53 GMT+0200 (Central European Summer Time)
sentTo2 outside addKeyword : true
keyword present : false
keyword present : {"keyword":"variableKeywork","modifying":true,"type":[],"schemaType":[]}
Date inside addKeyword: Mon Apr 08 2024 17:24:53 GMT+0200 (Central European Summer Time)
sentTo2 inside addKeyword : true
{"item1":"1","item2":"1"}
keyword present : false
Date outside addKeyword: Mon Apr 08 2024 17:25:18 GMT+0200 (Central European Summer Time)
sentTo2 outside addKeyword : false
keyword present : false
keyword present : {"keyword":"variableKeywork","modifying":true,"type":[],"schemaType":[]}
Date inside addKeyword: Mon Apr 08 2024 17:24:53 GMT+0200 (Central European Summer Time)
sentTo2 inside addKeyword : true
{"item1":"1","item2":"1"}
keyword present : false
What results did you expect?
the ajv.removeKeyword really remove the keyword and allow us the define it again.
Are you going to resolve the issue?
Can you please produce a minimal example using this runkit template? It should be possible to reproduce the issue without express.
Hello, I have updated the example with a runkit template : runkit example
I have looked into this and I have been able to replicate with an even simpler example. https://runkit.com/jasoniangreen/addkeyword-bug-2411
I got to the bottom of the issue @rgpro007. Here you can see my minimal example that reproduces the issue and then fixes it. The reason you are hitting this issue is that for performance reasons, AJV caches a lot of things. In this case you have a cached schema which has already been compiled. When you try to compile the same schema again, it skips certain steps to save time.
The simple solution is to use ajv.removeSchema (see line 21) before you try and compile it again. Alternatively you could clone the schema {...schema} which would also work because the cache uses a WeakMap which recognises the schema by reference.
After reviewing the docs I am confident this is how it is intended to be and the docs are clear enough on how you should only compile schemas once. So I will close this one and leave you with two links:
- https://ajv.js.org/guide/managing-schemas.html#cache-key-schema-vs-key-vs-id
- https://ajv.js.org/guide/managing-schemas.html#caching-schemas-in-your-code
Thank for you help. I will modify my code.