ajv-validator / ajv

The fastest JSON schema Validator. Supports JSON Schema draft-04/06/07/2019-09/2020-12 and JSON Type Definition (RFC8927)
https://ajv.js.org
MIT License
13.71k stars 872 forks source link

Fragments maintain cache-like behaviour, which is never cleared #1293

Open NitayRabi opened 3 years ago

NitayRabi commented 3 years ago

What version of Ajv are you using? Does the issue happen if you use the latest version? 6.12.4

Ajv options object

{useDefaults: true}

Your code

test.only('Should allow removing and adding "nested" schemas', t => {

    const SOME_TYPE = 'SomeType'
    const SOME_STRING = 'some string'
    const SOME_NUMBER = 5

    const ajv = aJV({useDefaults: true})

    // Add initial schema (supports a string)
    ajv.addSchema({[SOME_TYPE]: STRING_SCHEMA}, 'data')
    const validate = ajv.getSchema(`data#/${SOME_TYPE}`)
    t.deepEqual(validate(SOME_STRING), true) // Works of course

    // Replace schema with new one (supports a number) 
    ajv.removeSchema('data')
    ajv.addSchema({[SOME_TYPE]: NUMBER_SCHEMA}, 'data')

    // Returns a cached validator due to fragments
    const validate2 = ajv.getSchema(`data#/${SOME_TYPE}`)
    t.deepEqual(validate2(SOME_NUMBER), true) // Breaks - expects a string
    t.deepEqual(validate2(SOME_STRING), false)
})

**Why does this happen ? In some cases a fragments object is populated - https://github.com/ajv-validator/ajv/blob/master/lib/ajv.js#L218

This object is not cleared when calling removeSchema (unlike _refs & _schemas) https://github.com/ajv-validator/ajv/blob/master/lib/ajv.js#L262

What results did you expect?

Are you going to resolve the issue?

epoberezkin commented 3 years ago

This is done on purpose - the fragment can be used by other schemas that are not removed... What's the use case that requires to remove the fragment?

jmbeach commented 2 years ago

Ended up here trying to figure out why removeSchema, followed by addSchema wasn't working for me. My schema object has a different "id" than the "key" I use for it. This code allows me to replace the schema:

this.ajv.removeSchema(this.ajv.getSchema(schemaName)?.schema);
this.ajv.removeSchema(schemaName);

Originally, when I just did removeSchema(schemaName), the schema was still stored under ajv.refs