Skip to content

Commit

Permalink
Merge pull request #42 from mcollina/fix-depth-without-basic-keys
Browse files Browse the repository at this point in the history
Fixed an edge case where deep patterns without a key are not checked.
  • Loading branch information
mcollina authored Sep 22, 2016
2 parents f5310a3 + 28ccfa3 commit cc93485
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 51 deletions.
66 changes: 18 additions & 48 deletions bloomrun.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
var Bucket = require('./lib/bucket')
var Iterator = require('./lib/iterator')
var PatternSet = require('./lib/patternSet')
var genKeys = require('./lib/genKeys')
var matchingBuckets = require('./lib/matchingBuckets')
var deepMatch = require('./lib/deepMatch')
var deepSort = require('./lib/deepSort')
var onlyRegex = require('./lib/onlyRegex')

function BloomRun (opts) {
Expand All @@ -16,50 +13,17 @@ function BloomRun (opts) {

this._isDeep = opts && opts.indexing === 'depth'
this._buckets = []
this._regexBucket = {data: []}
this._regexBucket = new Bucket(this._isDeep)
this._defaultResult = null
}

function addPatterns (toAdd) {
this.filter.add(toAdd)
}

function addPatternSet (patternSet) {
this.add(patternSet.pattern, patternSet.payload)
}

function removePattern (bucket, pattern, payload) {
var foundPattern = false

for (var i = 0; i < bucket.data.length; i++) {
if (deepMatch(pattern, bucket.data[i].pattern)) {
if (payload === null || payload === bucket.data[i].payload) {
bucket.data.splice(i, 1)
foundPattern = true

removePattern(bucket, pattern, payload)
}
}
}

return foundPattern
}

function removeBucket (buckets, bucket) {
for (var i = 0; i < buckets.length; i++) {
if (bucket === buckets[i]) {
buckets.splice(i, 1)
}
}
}

BloomRun.prototype.default = function (payload) {
this._defaultResult = payload
}

BloomRun.prototype.add = function (pattern, payload) {
if (onlyRegex(pattern)) {
this._regexBucket.data.push(new PatternSet(pattern, payload, this._isDeep))
this._regexBucket.add(new PatternSet(pattern, payload, this._isDeep))
return this
}

Expand All @@ -69,22 +33,28 @@ BloomRun.prototype.add = function (pattern, payload) {
if (buckets.length > 0) {
bucket = buckets[0]
} else {
bucket = new Bucket()
bucket = new Bucket(this._isDeep)
this._buckets.push(bucket)
}

genKeys(pattern).forEach(addPatterns, bucket)

var patternSet = new PatternSet(pattern, payload, this._isDeep)
bucket.data.push(patternSet)

if (this._isDeep) {
bucket.data.sort(deepSort)
}
bucket.add(patternSet)

return this
}

function addPatternSet (patternSet) {
this.add(patternSet.pattern, patternSet.payload)
}

function removeBucket (buckets, bucket) {
for (var i = 0; i < buckets.length; i++) {
if (bucket === buckets[i]) {
buckets.splice(i, 1)
}
}
}

BloomRun.prototype.remove = function (pattern, payload) {
var matches = matchingBuckets(this._buckets, pattern)
payload = payload || null
Expand All @@ -93,9 +63,9 @@ BloomRun.prototype.remove = function (pattern, payload) {
for (var i = 0; i < matches.length; i++) {
var bucket = matches[i]

if (removePattern(bucket, pattern, payload)) {
if (bucket.remove(pattern, payload)) {
removeBucket(this._buckets, bucket)
bucket.data.forEach(addPatternSet, this)
bucket.forEach(addPatternSet, this)
}
}
}
Expand Down
44 changes: 43 additions & 1 deletion lib/bucket.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,55 @@
'use strict'

var BloomFilter = require('bloomfilter').BloomFilter
var deepSort = require('./deepSort')
var genKeys = require('./genKeys')
var deepMatch = require('./deepMatch')

function Bucket () {
function Bucket (isDeep) {
this.filter = new BloomFilter(
32 * 256, // number of bits to allocate.
16 // number of hash functions.
)
this.data = []
this.isDeep = isDeep
}

Bucket.prototype.add = function (set) {
genKeys(set.pattern).forEach(addPatterns, this)
this.data.push(set)
if (this.isDeep) {
this.data.sort(deepSort)
}
return this
}

function addPatterns (toAdd) {
this.filter.add(toAdd)
}

Bucket.prototype.remove = function (pattern, payload) {
var foundPattern = false
var data = this.data

for (var i = 0; i < data.length; i++) {
if (deepMatch(pattern, data[i].pattern)) {
if (payload === null || payload === data[i].payload) {
data.splice(i, 1)
foundPattern = true

// to remove all occurences
this.remove(pattern, payload)
break
}
}
}

return foundPattern
}

Bucket.prototype.forEach = function (func, that) {
this.data.forEach(func, that)
return this
}

module.exports = Bucket
4 changes: 2 additions & 2 deletions lib/onlyRegex.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use strict'

function onlyRegex (pattern) {
var match = false
var match = true

for (var key in pattern) {
if (pattern[key] instanceof RegExp) {
match = true
} else if (match) {
} else if (typeof pattern[key] !== 'object') {
match = false
break
}
Expand Down
18 changes: 18 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -533,3 +533,21 @@ test('List matches partially, in key order (2)', function (t) {
3
])
})

test('recursive depth support, no other keys', function (t) {
t.plan(1)

var instance = bloomrun({ indexing: 'depth' })
var pattern1 = { some: { key: 'value' } }
var pattern2 = { some: { key: 'value', a: 'b' } }

function payloadOne () { }
function payloadTwo () { }

instance.add(pattern1, payloadOne)
instance.add(pattern2, payloadTwo)

t.equal(instance.lookup({
some: { key: 'value', a: 'b', c: 'd' }
}), payloadTwo)
})

0 comments on commit cc93485

Please sign in to comment.