use asynchronous search matching

This commit is contained in:
Andris Reinman 2017-03-10 16:59:04 +02:00
parent 9314708e1f
commit cae2ad9e95
5 changed files with 2427 additions and 227 deletions

View file

@ -6,36 +6,32 @@ let indexer = new Indexer();
module.exports.matchSearchQuery = matchSearchQuery;
let queryHandlers = {
// atom beautify uses invalid indentation that messes up shorthand methods
/*eslint-disable object-shorthand */
// always matches
all: function () {
return true;
all(message, query, callback) {
return callback(null, true);
},
// matches if the message object includes (exists:true) or does not include (exists:false) specifiec flag
flag: function (message, query) {
flag(message, query, callback) {
let pos = [].concat(message.flags || []).indexOf(query.value);
return query.exists ? pos >= 0 : pos < 0;
return callback(null, query.exists ? pos >= 0 : pos < 0);
},
// matches message receive date
internaldate: function (message, query) {
internaldate(message, query, callback) {
switch (query.operator) {
case '<':
return getShortDate(message.internaldate) < getShortDate(query.value);
return callback(null, getShortDate(message.internaldate) < getShortDate(query.value));
case '=':
return getShortDate(message.internaldate) === getShortDate(query.value);
return callback(null, getShortDate(message.internaldate) === getShortDate(query.value));
case '>=':
return getShortDate(message.internaldate) >= getShortDate(query.value);
return callback(null, getShortDate(message.internaldate) >= getShortDate(query.value));
}
return false;
return callback(null, false);
},
// matches message header date
date: function (message, query) {
date(message, query, callback) {
let date;
if (message.headerdate) {
date = message.headerdate;
@ -49,39 +45,97 @@ let queryHandlers = {
switch (query.operator) {
case '<':
return getShortDate(date) < getShortDate(query.value);
return callback(null, getShortDate(date) < getShortDate(query.value));
case '=':
return getShortDate(date) === getShortDate(query.value);
return callback(null, getShortDate(date) === getShortDate(query.value));
case '>=':
return getShortDate(date) >= getShortDate(query.value);
return callback(null, getShortDate(date) >= getShortDate(query.value));
}
return false;
return callback(null, false);
},
// matches message body
body: function (message, query) {
let body = indexer.getContents(message.mimeTree).toString();
let bodyStart = body.match(/\r?\r?\n/);
if (!bodyStart) {
return false;
}
return body.substr(bodyStart.index + bodyStart[0].length).toLowerCase().indexOf((query.value || '').toString().toLowerCase()) >= 0;
body(message, query, callback) {
let data = indexer.getContents(message.mimeTree, {
type: 'text'
});
let resolveData = next => {
if (data.type !== 'stream') {
return next(null, data.value);
}
let chunks = [];
let chunklen = 0;
data.value.once('error', err => next(err));
data.value.on('readable', () => {
let chunk;
while ((chunk = data.value.read()) !== null) {
chunks.push(chunk);
chunklen += chunk.length;
}
});
data.value.on('end', () => {
next(null, Buffer.concat(chunks, chunklen));
});
};
resolveData((err, body) => {
if (err) {
return callback(err);
}
callback(null, body.toString().toLowerCase().indexOf((query.value || '').toString().toLowerCase()) >= 0);
});
},
// matches message source
text: function (message, query) {
let body = indexer.getContents(message.mimeTree).toString();
return body.toLowerCase().indexOf((query.value || '').toString().toLowerCase()) >= 0;
text(message, query, callback) {
let data = indexer.getContents(message.mimeTree, {
type: 'content'
});
let resolveData = next => {
if (data.type !== 'stream') {
return next(null, data.value);
}
let chunks = [];
let chunklen = 0;
data.value.once('error', err => next(err));
data.value.on('readable', () => {
let chunk;
while ((chunk = data.value.read()) !== null) {
chunks.push(chunk);
chunklen += chunk.length;
}
});
data.value.on('end', () => {
next(null, Buffer.concat(chunks, chunklen));
});
};
resolveData((err, text) => {
if (err) {
return callback(err);
}
callback(null, text.toString().toLowerCase().indexOf((query.value || '').toString().toLowerCase()) >= 0);
});
},
// matches message UID number. Sequence queries are also converted to UID queries
uid: function (message, query) {
return query.value.indexOf(message.uid) >= 0;
uid(message, query, callback) {
return callback(null, query.value.indexOf(message.uid) >= 0);
},
// matches message source size
size: function (message, query) {
size(message, query, callback) {
let size = message.size;
if (!size) {
size = (message.raw || '').length;
@ -89,18 +143,18 @@ let queryHandlers = {
switch (query.operator) {
case '<':
return size < query.value;
return callback(null, size < query.value);
case '=':
return size === query.value;
return callback(null, size === query.value);
case '>':
return size > query.value;
return callback(null, size > query.value);
}
return false;
return callback(null, false);
},
// matches message headers
header: function (message, query) {
header(message, query, callback) {
let mimeTree = message.mimeTree;
if (!mimeTree) {
mimeTree = indexer.parseMimeTree(message.raw || '');
@ -123,24 +177,22 @@ let queryHandlers = {
value = (parts.join(':') || '');
if (key === header && (!term || value.toLowerCase().indexOf(term) >= 0)) {
return true;
return callback(null, true);
}
}
return false;
return callback(null, false);
},
// matches messages with modifyIndex exual or greater than criteria
modseq: function (message, query) {
return message.modseq >= query.value;
modseq(message, query, callback) {
return callback(null, message.modseq >= query.value);
},
// charset argument is ignored
charset: function () {
return true;
charset(message, query, callback) {
return callback(null, true);
}
/*eslint-enable object-shorthand */
};
/**
@ -164,20 +216,41 @@ function getShortDate(date) {
* @param {Object} query Query term object
* @returns {Boolean} Term matched (true) or not (false)
*/
function matchSearchTerm(message, query) {
function matchSearchTerm(message, query, callback) {
if (Array.isArray(query)) {
// AND, all terms need to match
return matchSearchQuery(message, query);
return matchSearchQuery(message, query, callback);
}
if (!query || typeof query !== 'object') {
// unknown query term
return false;
return setImmediate(() => callback(null, false));
}
switch (query.key) {
case 'or':
{
// OR, only single match needed
let checked = 0;
let checkNext = () => {
if (checked >= query.value.length) {
return callback(null, false);
}
let term = query.value[checked++];
matchSearchTerm(message, term, (err, match) => {
if (err) {
return callback(err);
}
if (match) {
return callback(null, true);
}
setImmediate(checkNext);
});
};
return setImmediate(checkNext);
}
/*
// OR, only single match needed
for (let i = query.value.length - 1; i >= 0; i--) {
if (matchSearchTerm(message, query.value[i])) {
@ -185,15 +258,21 @@ function matchSearchTerm(message, query) {
}
}
return false;
*/
case 'not':
// return reverse match
return !matchSearchTerm(message, query.value);
return matchSearchTerm(message, query.value, (err, match) => {
if (err) {
return callback(err);
}
callback(null, !match);
});
default:
// check if there is a handler for the term and use it
if (queryHandlers.hasOwnProperty(query.key)) {
return queryHandlers[query.key](message, query);
return setImmediate(() => queryHandlers[query.key](message, query, callback));
}
return false;
return setImmediate(() => callback(null, false));
}
}
@ -204,16 +283,35 @@ function matchSearchTerm(message, query) {
* @param {Object} query Query term object
* @returns {Boolean} Term matched (true) or not (false)
*/
function matchSearchQuery(message, query) {
function matchSearchQuery(message, query, callback) {
if (!Array.isArray(query)) {
query = [].concat(query || []);
}
for (let i = 0, len = query.length; i < len; i++) {
if (!matchSearchTerm(message, query[i])) {
return false;
let checked = 0;
let checkNext = () => {
if (checked >= query.length) {
return callback(null, true);
}
let term = query[checked++];
matchSearchTerm(message, term, (err, match) => {
if (err) {
return callback(err);
}
if (!match) {
return callback(null, false);
}
setImmediate(checkNext);
});
};
return setImmediate(checkNext);
/*
for (let i = 0, len = query.length; i < len; i++) {
if (!matchSearchTerm(message, query[i])) {
return false;
}
}
}
return true;
return true;
*/
}

View file

@ -4,6 +4,9 @@
let parseQueryTerms = require('../lib/commands/search').parseQueryTerms;
let matchSearchQuery = require('../lib/search').matchSearchQuery;
let Indexer = require('../lib/indexer/indexer');
let indexer = new Indexer();
let chai = require('chai');
let expect = chai.expect;
chai.config.includeStack = true;
@ -400,8 +403,8 @@ describe('#parseQueryTerms', function () {
describe('Search term match tests', function () {
describe('AND', function () {
it('should find all matches', function () {
expect(matchSearchQuery({}, [{
it('should find all matches', function (done) {
matchSearchQuery({}, [{
key: 'all',
value: true
}, {
@ -413,11 +416,15 @@ describe('Search term match tests', function () {
}, {
key: 'all',
value: true
}])).to.be.true;
}], (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should fail on single error', function () {
expect(matchSearchQuery({}, [{
it('should fail on single error', function (done) {
matchSearchQuery({}, [{
key: 'all',
value: true
}, {
@ -430,13 +437,17 @@ describe('Search term match tests', function () {
key: 'flag',
value: 'zzzzzzz',
exists: true
}])).to.be.false;
}], (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('OR', function () {
it('should succeed with at least one match', function () {
expect(matchSearchQuery({}, {
it('should succeed with at least one match', function (done) {
matchSearchQuery({}, {
key: 'or',
value: [{
key: 'flag',
@ -450,11 +461,15 @@ describe('Search term match tests', function () {
value: 'zzzzzzz',
exists: true
}]
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should fail with no matches', function () {
expect(matchSearchQuery({}, {
it('should fail with no matches', function (done) {
matchSearchQuery({}, {
key: 'or',
value: [{
key: 'flag',
@ -465,419 +480,581 @@ describe('Search term match tests', function () {
value: 'zzzzzzz',
exists: true
}]
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('NOT', function () {
it('should succeed with false value', function () {
expect(matchSearchQuery({}, {
it('should succeed with false value', function (done) {
matchSearchQuery({}, {
key: 'not',
value: {
key: 'flag',
value: 'zzzzzzz',
exists: true
}
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should fail with thruthy value', function () {
expect(matchSearchQuery({}, {
it('should fail with thruthy value', function (done) {
matchSearchQuery({}, {
key: 'not',
value: {
key: 'all',
value: true
}
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('ALL', function () {
it('should match ALL', function () {
expect(matchSearchQuery({}, {
it('should match ALL', function (done) {
matchSearchQuery({}, {
key: 'all',
value: true
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
});
describe('FLAG', function () {
it('should match existing flag', function () {
expect(matchSearchQuery({
it('should match existing flag', function (done) {
matchSearchQuery({
flags: ['abc', 'def', 'ghi']
}, {
key: 'flag',
value: 'def',
exists: true
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should match non-existing flag', function () {
expect(matchSearchQuery({
it('should match non-existing flag', function (done) {
matchSearchQuery({
flags: ['abc', 'def', 'ghi']
}, {
key: 'flag',
value: 'zzzzz',
exists: false
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should fail non-existing flag', function () {
expect(matchSearchQuery({
it('should fail non-existing flag', function (done) {
matchSearchQuery({
flags: ['abc', 'def', 'ghi']
}, {
key: 'flag',
value: 'zzzzz',
exists: true
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
it('should fail existing flag', function () {
expect(matchSearchQuery({
it('should fail existing flag', function (done) {
matchSearchQuery({
flags: ['abc', 'def', 'ghi']
}, {
key: 'flag',
value: 'abc',
exists: false
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('INTERNALDATE', function () {
it('should match <', function () {
expect(matchSearchQuery({
it('should match <', function (done) {
matchSearchQuery({
internaldate: new Date('1999-01-01')
}, {
key: 'internaldate',
value: '2001-01-01',
operator: '<'
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match <', function () {
expect(matchSearchQuery({
it('should not match <', function (done) {
matchSearchQuery({
internaldate: new Date('1999-01-01')
}, {
key: 'internaldate',
value: '1998-01-01',
operator: '<'
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
it('should match =', function () {
expect(matchSearchQuery({
it('should match =', function (done) {
matchSearchQuery({
internaldate: new Date('1999-01-01')
}, {
key: 'internaldate',
value: '1999-01-01',
operator: '='
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match <', function () {
expect(matchSearchQuery({
it('should not match <', function (done) {
matchSearchQuery({
internaldate: new Date('1999-01-01')
}, {
key: 'internaldate',
value: '1999-01-02',
operator: '='
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
it('should match >=', function () {
expect(matchSearchQuery({
it('should match >=', function (done) {
matchSearchQuery({
internaldate: new Date('1999-01-01')
}, {
key: 'internaldate',
value: '1999-01-01',
operator: '>='
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
expect(matchSearchQuery({
internaldate: new Date('1999-01-02')
}, {
key: 'internaldate',
value: '1999-01-01',
operator: '>='
})).to.be.true;
matchSearchQuery({
internaldate: new Date('1999-01-02')
}, {
key: 'internaldate',
value: '1999-01-01',
operator: '>='
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
});
it('should not match >=', function () {
expect(matchSearchQuery({
it('should not match >=', function (done) {
matchSearchQuery({
internaldate: new Date('1999-01-01')
}, {
key: 'internaldate',
value: '1999-01-02',
operator: '>='
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('DATE', function () {
let raw = 'Subject: test\r\nDate: 1999-01-01\r\n\r\nHello world!';
it('should match <', function () {
expect(matchSearchQuery({
raw
it('should match <', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'date',
value: '2001-01-01',
operator: '<'
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match <', function () {
expect(matchSearchQuery({
raw
it('should not match <', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'date',
value: '1998-01-01',
operator: '<'
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
it('should match =', function () {
expect(matchSearchQuery({
raw
it('should match =', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'date',
value: '1999-01-01',
operator: '='
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match <', function () {
expect(matchSearchQuery({
raw
it('should not match <', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'date',
value: '1999-01-02',
operator: '='
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
it('should match >=', function () {
expect(matchSearchQuery({
raw
it('should match >=', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'date',
value: '1999-01-01',
operator: '>='
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
expect(matchSearchQuery({
raw
}, {
key: 'date',
value: '1998-01-01',
operator: '>='
})).to.be.true;
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'date',
value: '1998-01-01',
operator: '>='
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
});
it('should not match >=', function () {
expect(matchSearchQuery({
raw
it('should not match >=', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'date',
value: '1999-01-02',
operator: '>='
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('BODY', function () {
let raw = 'Subject: test\r\n\r\nHello world!';
it('should match a string', function () {
expect(matchSearchQuery({
raw
it('should match a string', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'body',
value: 'hello'
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match a string', function () {
expect(matchSearchQuery({
raw
it('should not match a string', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'body',
value: 'test'
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('TEXT', function () {
let raw = 'Subject: test\r\n\r\nHello world!';
it('should match a string', function () {
expect(matchSearchQuery({
raw
it('should match a string', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'text',
value: 'hello'
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
expect(matchSearchQuery({
raw
}, {
key: 'text',
value: 'test'
})).to.be.true;
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'text',
value: 'test'
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
});
it('should not match a string', function () {
expect(matchSearchQuery({
raw
it('should not match a string', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'text',
value: 'zzzzz'
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('UID', function () {
it('should match message uid', function () {
expect(matchSearchQuery({
it('should match message uid', function (done) {
matchSearchQuery({
uid: 123
}, {
key: 'uid',
value: [11, 123, 134]
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match message uid', function () {
expect(matchSearchQuery({
it('should not match message uid', function (done) {
matchSearchQuery({
uid: 124
}, {
key: 'uid',
value: [11, 123, 134]
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('SIZE', function () {
it('should match <', function () {
expect(matchSearchQuery({
raw: new Buffer(10)
it('should match <', function (done) {
matchSearchQuery({
size: 10
}, {
key: 'size',
value: 11,
operator: '<'
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match <', function () {
expect(matchSearchQuery({
raw: new Buffer(10)
it('should not match <', function (done) {
matchSearchQuery({
size: 10
}, {
key: 'size',
value: 9,
operator: '<'
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
it('should match =', function () {
expect(matchSearchQuery({
raw: new Buffer(10)
it('should match =', function (done) {
matchSearchQuery({
size: 10
}, {
key: 'size',
value: 10,
operator: '='
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match =', function () {
expect(matchSearchQuery({
raw: new Buffer(10)
it('should not match =', function (done) {
matchSearchQuery({
size: 10
}, {
key: 'size',
value: 11,
operator: '='
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
it('should match >', function () {
expect(matchSearchQuery({
raw: new Buffer(10)
it('should match >', function (done) {
matchSearchQuery({
size: 10
}, {
key: 'size',
value: 9,
operator: '>'
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match <', function () {
expect(matchSearchQuery({
raw: new Buffer(10)
it('should not match <', function (done) {
matchSearchQuery({
size: 10
}, {
key: 'size',
value: 11,
operator: '>'
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('header', function () {
let raw = 'Subject: test\r\n\r\nHello world!';
it('should match header value', function () {
expect(matchSearchQuery({
raw
it('should match header value', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'header',
value: 'test',
header: 'subject'
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should match empty header value', function () {
expect(matchSearchQuery({
raw
it('should match empty header value', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'header',
value: '',
header: 'subject'
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match header value', function () {
expect(matchSearchQuery({
raw
it('should not match header value', function (done) {
matchSearchQuery({
mimeTree: indexer.parseMimeTree(raw)
}, {
key: 'header',
value: 'tests',
header: 'subject'
})).to.be.false;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.false;
done();
});
});
});
describe('MODSEQ', function () {
it('should match equal modseq', function () {
expect(matchSearchQuery({
it('should match equal modseq', function (done) {
matchSearchQuery({
modseq: 500
}, {
key: 'modseq',
value: [500]
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should match greater modseq', function () {
expect(matchSearchQuery({
it('should match greater modseq', function (done) {
matchSearchQuery({
modseq: 1000
}, {
key: 'modseq',
value: [500]
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
it('should not match lesser modseq', function () {
expect(matchSearchQuery({
it('should not match lesser modseq', function (done) {
matchSearchQuery({
modseq: 500
}, {
key: 'modseq',
value: [100]
})).to.be.true;
}, (err, match) => {
expect(err).to.not.exist;
expect(match).to.be.true;
done();
});
});
});
});

22
imap.js
View file

@ -1029,15 +1029,21 @@ server.onSearch = function (path, options, session, callback) {
message.raw = message.raw.toString();
}
let match = session.matchSearchQuery(message, options.query);
if (match && highestModseq < message.modseq) {
highestModseq = message.modseq;
}
if (match) {
uidList.push(message.uid);
}
session.matchSearchQuery(message, options.query, (err, match) => {
if (err) {
return cursor.close(() => callback(err));
}
processNext();
if (match && highestModseq < message.modseq) {
highestModseq = message.modseq;
}
if (match) {
uidList.push(message.uid);
}
processNext();
});
});
};

View file

@ -22,7 +22,7 @@
"dependencies": {
"addressparser": "^1.0.1",
"bcryptjs": "^2.4.3",
"clone": "^2.1.0",
"clone": "^2.1.1",
"config": "^1.25.1",
"joi": "^10.2.2",
"libbase64": "^0.1.0",

1919
yarn.lock Normal file

File diff suppressed because it is too large Load diff