From 3aaeaf6ec05da90e9dd263049fb3214a0d63e04a Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Sun, 28 Feb 2016 01:16:48 +0000 Subject: [PATCH] removeSchema with RegExp to remove multiple schemas or without argument to remove all schemas, closes #103 --- KEYWORDS.md | 4 ++-- README.md | 12 +++++++++--- lib/ajv.js | 33 +++++++++++++++++++++++++++++---- lib/cache.js | 5 +++++ spec/ajv.spec.js | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 9 deletions(-) diff --git a/KEYWORDS.md b/KEYWORDS.md index e3e4c48..85d9cc8 100644 --- a/KEYWORDS.md +++ b/KEYWORDS.md @@ -599,13 +599,13 @@ __Examples__ 1. _schema_: `{ "patternRequired": [ "f.*o" ] }` - _valid_: `{ "foo": 1 }`, `{ "-fo-": 1 }`, { "foo": 1, "bar": 2 }`, any non-object + _valid_: `{ "foo": 1 }`, `{ "-fo-": 1 }`, `{ "foo": 1, "bar": 2 }`, any non-object _invalid_: `{}`, `{ "bar": 2 }`, `{ "Foo": 1 }`, 2. _schema_: `{ "patternRequired": [ "f.*o", "b.*r" ] }` - _valid_: { "foo": 1, "bar": 2 }`, `{ "foobar": 3 }`, any non-object + _valid_: `{ "foo": 1, "bar": 2 }`, `{ "foobar": 3 }`, any non-object _invalid_: `{}`, `{ "foo": 1 }`, `{ "bar": 2 }` diff --git a/README.md b/README.md index 4ad0af6..b1f095f 100644 --- a/README.md +++ b/README.md @@ -669,11 +669,17 @@ Errors will be available at `ajv.errors`. Retrieve compiled schema previously added with `addSchema` by the key passed to `addSchema` or by its full reference (id). Returned validating function has `schema` property with the reference to the original schema. -##### .removeSchema(Object schema|String key|String ref) +##### .removeSchema([Object schema|String key|String ref|RegExp pattern]) Remove added/cached schema. Even if schema is referenced by other schemas it can be safely removed as dependent schemas have local references. -Schema can be removed using key passed to `addSchema`, it's full reference (id) or using actual schema object that will be stable-stringified to remove schema from cache. +Schema can be removed using: +- key passed to `addSchema` +- it's full reference (id) +- RegExp that should match schema id or key (meta-schemas won't be removed) +- actual schema object that will be stable-stringified to remove schema from cache + +If no parameter is passed all schemas but meta-schemas will be removed and the cache will be cleared. ##### .addFormat(String name, String|RegExp|Function|Object format) @@ -829,7 +835,7 @@ Defaults: - _errorDataPath_: set `dataPath` to point to 'object' (default) or to 'property' (default behavior in versions before 2.0) when validating keywords `required`, `additionalProperties` and `dependencies`. - _messages_: Include human-readable messages in errors. `true` by default. `false` can be passed when custom messages are used (e.g. with [ajv-i18n](https://github.com/epoberezkin/ajv-i18n)). - _beautify_: format the generated function with [js-beautify](https://github.com/beautify-web/js-beautify) (the validating function is generated without line-breaks). `npm install js-beautify` to use this option. `true` or js-beautify options can be passed. -- _cache_: an optional instance of cache to store compiled schemas using stable-stringified schema as a key. For example, set-associative cache [sacjs](https://github.com/epoberezkin/sacjs) can be used. If not passed then a simple hash is used which is good enough for the common use case (a limited number of statically defined schemas). Cache should have methods `put(key, value)`, `get(key)` and `del(key)`. +- _cache_: an optional instance of cache to store compiled schemas using stable-stringified schema as a key. For example, set-associative cache [sacjs](https://github.com/epoberezkin/sacjs) can be used. If not passed then a simple hash is used which is good enough for the common use case (a limited number of statically defined schemas). Cache should have methods `put(key, value)`, `get(key)`, `del(key)` and `clear()`. ## Validation errors diff --git a/lib/ajv.js b/lib/ajv.js index a78466c..4d6c387 100644 --- a/lib/ajv.js +++ b/lib/ajv.js @@ -179,27 +179,52 @@ function Ajv(opts) { /** - * Remove cached schema - * Even if schema is referenced by other schemas it still can be removed as other schemas have local references - * @param {String|Object} schemaKeyRef key, ref or schema object + * Remove cached schema(s). + * If no parameter is passed all schemas but meta-schemas are removed. + * If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed. + * Even if schema is referenced by other schemas it still can be removed as other schemas have local references. + * @param {String|Object|RegExp} schemaKeyRef key, ref, pattern to match key/ref or schema object */ function removeSchema(schemaKeyRef) { switch (typeof schemaKeyRef) { + case 'undefined': + _removeAllSchemas(self._schemas); + _removeAllSchemas(self._refs); + self._cache.clear(); + return; case 'string': var schemaObj = _getSchemaObj(schemaKeyRef); if (schemaObj) self._cache.del(schemaObj.jsonStr); delete self._schemas[schemaKeyRef]; delete self._refs[schemaKeyRef]; - break; + return; case 'object': + if (schemaKeyRef instanceof RegExp) { + _removeAllSchemas(self._schemas, schemaKeyRef); + _removeAllSchemas(self._refs, schemaKeyRef); + return; + } var jsonStr = stableStringify(schemaKeyRef); self._cache.del(jsonStr); var id = schemaKeyRef.id; if (id) { id = resolve.normalizeId(id); + delete self._schemas[id]; delete self._refs[id]; } } + + } + + + function _removeAllSchemas(schemas, regex) { + for (var keyRef in schemas) { + var schemaObj = schemas[keyRef]; + if (!schemaObj.meta && (!regex || regex.test(keyRef))) { + self._cache.del(schemaObj.jsonStr); + delete schemas[keyRef]; + } + } } diff --git a/lib/cache.js b/lib/cache.js index fc34e44..7558874 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -19,3 +19,8 @@ Cache.prototype.get = function Cache_get(key) { Cache.prototype.del = function Cache_del(key) { delete this._cache[key]; }; + + +Cache.prototype.clear = function Cache_clear() { + this._cache = {}; +}; diff --git a/spec/ajv.spec.js b/spec/ajv.spec.js index 7abb952..3028331 100644 --- a/spec/ajv.spec.js +++ b/spec/ajv.spec.js @@ -268,6 +268,44 @@ describe('Ajv', function () { ajv.removeSchema('//e.com/int.json'); }); }); + + it('should remove all schemas but meta-schemas if called without an arguments', function() { + var schema1 = { id: '//e.com/int.json', type: 'integer' } + , str1 = stableStringify(schema1); + ajv.addSchema(schema1); + ajv._cache.get(str1) .should.be.an('object'); + + var schema2 = { type: 'integer' } + , str2 = stableStringify(schema2); + ajv.addSchema(schema2); + ajv._cache.get(str2) .should.be.an('object'); + + ajv.removeSchema(); + should.not.exist(ajv._cache.get(str1)); + should.not.exist(ajv._cache.get(str2)); + }); + + it('should remove all schemas but meta-schemas with key/id matching pattern', function() { + var schema1 = { id: '//e.com/int.json', type: 'integer' } + , str1 = stableStringify(schema1); + ajv.addSchema(schema1); + ajv._cache.get(str1) .should.be.an('object'); + + var schema2 = { id: 'str.json', type: 'string' } + , str2 = stableStringify(schema2); + ajv.addSchema(schema2, '//e.com/str.json'); + ajv._cache.get(str2) .should.be.an('object'); + + var schema3 = { type: 'integer' } + , str3 = stableStringify(schema3); + ajv.addSchema(schema3); + ajv._cache.get(str3) .should.be.an('object'); + + ajv.removeSchema(/e\.com/); + should.not.exist(ajv._cache.get(str1)); + should.not.exist(ajv._cache.get(str2)); + ajv._cache.get(str3) .should.be.an('object'); + }); });