Skip to content

Commit 3b653a1

Browse files
committed
kvao: implement key filter
1 parent 01ce7df commit 3b653a1

File tree

6 files changed

+67
-6
lines changed

6 files changed

+67
-6
lines changed

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ benchmark.js
99
analyse.r
1010
docs/html
1111
npm-debug.log
12+
.travis.yml

lib/connectors/kv-memory.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var assert = require('assert');
44
var Connector = require('loopback-connector').Connector;
55
var debug = require('debug')('loopback:connector:kv-memory');
6+
var minimatch = require('minimatch');
67
var util = require('util');
78

89
exports.initialize = function initializeDataSource(dataSource, cb) {
@@ -160,8 +161,10 @@ KeyValueMemoryConnector.prototype.iterateKeys =
160161
function(modelName, filter, options, callback) {
161162
var store = this._getStoreForModel(modelName);
162163
var self = this;
164+
var checkFilter = createMatcher(filter.match);
165+
163166
var keys = Object.keys(store).filter(function(key) {
164-
return !self._removeIfExpired(modelName, key);
167+
return !self._removeIfExpired(modelName, key) && checkFilter(key);
165168
});
166169

167170
debug('ITERATE KEYS %j -> %s keys', modelName, keys.length);
@@ -175,6 +178,18 @@ function(modelName, filter, options, callback) {
175178
};
176179
};
177180

181+
function createMatcher(pattern) {
182+
if (!pattern) return function matchAll() { return true; };
183+
184+
return minimatch.filter(pattern, {
185+
nobrace: true,
186+
noglobstar: true,
187+
dot: true,
188+
noext: true,
189+
nocomment: true,
190+
});
191+
}
192+
178193
KeyValueMemoryConnector.prototype.disconnect = function(callback) {
179194
if (this._cleanupTimer)
180195
clearInterval(this._cleanupTimer);

lib/kvao/iterate-keys.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ var utils = require('../utils');
99
* @param {Object} filter An optional filter object with the following
1010
* properties:
1111
* - `match` - glob string to use to filter returned keys, e.g. 'userid.*'
12+
* All connectors are required to support `*` and `?`.
13+
* They may also support additional special characters that are specific
14+
* to the backing store.
15+
*
1216
* @param {Object} options
1317
*
1418
* @returns {AsyncIterator} An object implementing "next(cb) -> Promise"

lib/kvao/keys.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ var utils = require('../utils');
1313
* @param {Object} filter An optional filter object with the following
1414
* properties:
1515
* - `match` - glob string to use to filter returned keys, e.g. 'userid.*'
16+
* All connectors are required to support `*` and `?`.
17+
* They may also support additional special characters that are specific
18+
* to the backing store.
1619
* @param {Object} options
1720
* @callback callback
1821
* @param {Error=} err

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"depd": "^1.0.0",
4646
"inflection": "^1.6.0",
4747
"loopback-connector": "^2.1.0",
48+
"minimatch": "^3.0.3",
4849
"node-uuid": "^1.4.2",
4950
"qs": "^3.1.0",
5051
"strong-globalize": "^2.6.2",

test/kvao/keys.suite.js

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
99
var CacheItem;
1010
beforeEach(function unpackContext() {
1111
CacheItem = helpers.givenCacheItem(dataSourceFactory);
12+
CacheItem.sortedKeys = function(filter, options) {
13+
return this.keys(filter, options).then(function(keys) {
14+
keys.sort();
15+
return keys;
16+
});
17+
};
1218
});
1319

1420
it('returns all keys - Callback API', function(done) {
@@ -41,10 +47,9 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
4147
return helpers.givenKeys(AnotherModel, ['otherKey1', 'otherKey2']);
4248
})
4349
.then(function() {
44-
return CacheItem.keys();
50+
return CacheItem.sortedKeys();
4551
})
4652
.then(function(keys) {
47-
keys.sort();
4853
should(keys).eql(['key1', 'key2']);
4954
});
5055
});
@@ -53,16 +58,48 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
5358
var expectedKeys = [];
5459
for (var ix = 0; ix < 1000; ix++)
5560
expectedKeys.push('key-' + ix);
61+
expectedKeys.sort();
5662

5763
return helpers.givenKeys(CacheItem, expectedKeys)
5864
.then(function() {
59-
return CacheItem.keys();
65+
return CacheItem.sortedKeys();
6066
})
6167
.then(function(keys) {
62-
keys.sort();
63-
expectedKeys.sort();
6468
should(keys).eql(expectedKeys);
6569
});
6670
});
71+
72+
context('with "filter.match"', function() {
73+
beforeEach(function createTestData() {
74+
return helpers.givenKeys(CacheItem, [
75+
'hallo',
76+
'hello',
77+
'hxllo',
78+
'hllo',
79+
'heeello',
80+
'foo',
81+
'bar',
82+
]);
83+
});
84+
85+
it('supports "?" operator', function() {
86+
return CacheItem.sortedKeys({ match: 'h?llo' }).then(function(keys) {
87+
should(keys).eql(['hallo', 'hello', 'hxllo']);
88+
});
89+
});
90+
91+
it('supports "*" operator', function() {
92+
return CacheItem.sortedKeys({ match: 'h*llo' }).then(function(keys) {
93+
should(keys).eql(['hallo', 'heeello', 'hello', 'hllo', 'hxllo']);
94+
});
95+
});
96+
97+
it('handles no matches found', function() {
98+
return CacheItem.sortedKeys({ match: 'not-found' })
99+
.then(function(keys) {
100+
should(keys).eql([]);
101+
});
102+
});
103+
});
67104
});
68105
};

0 commit comments

Comments
 (0)