Skip to content

Commit

Permalink
Merge pull request #5 from lemonde/joins
Browse files Browse the repository at this point in the history
Index joins
  • Loading branch information
gregberge committed Apr 8, 2014
2 parents f544482 + 048355e commit c282504
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 10 deletions.
47 changes: 45 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ function outputFormatter(document) {

Type: `Object`

Filters formatter that are used in `index.search`.
Filters formatter that can be used in `index.search`.

```js
new Index({
Expand All @@ -167,6 +167,29 @@ function formatIdFilter(value, context) {
}
```

#### joins

Type: `Object`

Joins that can be used in `index.search`.

```js
new Index({
joins: {
myJoin: {
index: customIndex,
queryTemplate: 'customQueryTemplate',
localField: 'local_id',
foreignField: 'id',
type: 'INNER',
returnFields: false,
returnScores: false,
eturnFacets: false
}
}
});
```

### index.create(documents, [options], callback)

Insert a new document in the index.
Expand All @@ -192,7 +215,7 @@ index.create([
], { lang: 'FRENCH' }, function (err) { ... });
```

## index.destroy(values, [options], callback)
### index.destroy(values, [options], callback)

Destroy a documents in the index.

Expand Down Expand Up @@ -259,6 +282,26 @@ index.search('my query', {
}, function (err, res) { ... });
```

#### joins

Type: `Object`

Joins applied to the query. Joins used the joins defined in the constructor.

```js
index.search('my query', {
joins: {
myJoin: {
query: 'join query',
template: 'myTemplate',
filters: {
myJoinFilter: 'test'
}
}
}
})
```

#### OSS search options

All [search options known by OSS](https://github.com/jaeksoft/opensearchserver/wiki/Search-field) can be used in the search function.
Expand Down
51 changes: 51 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function Index(options) {
this.formatters = options.formatters || {};
this.templates = options.templates || {};
this.filters = options.filters || {};
this.joins = options.joins || {};
this.lang = options.lang || 'ENGLISH';

// Accept single indexer.
Expand Down Expand Up @@ -200,6 +201,56 @@ Index.prototype.search = function search(query, options, callback) {
return filters;
}, []);

// Map joins.
options.joins = _.map(options.joins, function (join, name) {

// Get join index options.
var indexJoin = index.joins[name];

// If join is not found on the index, return null.
if (! indexJoin) return null;

// Default template and filters.
join = _.defaults(join, {
template: 'default',
filters: {}
});

// Get template.
var template = indexJoin.index.templates[join.template];

// If template is not found, return null.
if (! template) return null;

// Build query.
var query = _.map(template.searchFields, function (field) {
return field.field + ':(' + join.query + ')^' + field.boost;
})
.join(' OR ');


// Build filters and append them to query.
query = _.map(join.filters, function (value, key) {
return indexJoin.index.filters[key](value);
})
.filter(function (filter) {
return filter.type === 'QueryFilter';
})
.map(function (filter) {
return filter.negative ? '-(' + filter.query + ')' : '(' + filter.query + ')';
})
.concat(['(' + query + ')'])
.join(' AND ');

return _.defaults({
queryString: query,
indexName: indexJoin.index.name
}, _.omit(indexJoin, 'index'));
})
.filter(function (join) {
return join;
});

// Remove unknown keys.
options = _.omit(options, 'template', 'filterOptions');

Expand Down
132 changes: 124 additions & 8 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ describe('Index', function () {
expect(searcher.search).to.be.calledWith('my_index', {
lang: 'ENGLISH',
query: 'my query',
filters: []
filters: [],
joins: []
});
done();
});
Expand All @@ -253,7 +254,8 @@ describe('Index', function () {
lang: 'ENGLISH',
query: 'my query',
foo: 'bar',
filters: []
filters: [],
joins: []
});
done();
});
Expand All @@ -270,7 +272,8 @@ describe('Index', function () {
query: 'my query',
foo: 'bar',
x: 'y',
filters: []
filters: [],
joins: []
});
done();
});
Expand All @@ -286,7 +289,8 @@ describe('Index', function () {
lang: 'ENGLISH',
query: 'my query',
z: 'x',
filters: []
filters: [],
joins: []
});
done();
});
Expand Down Expand Up @@ -326,7 +330,8 @@ describe('Index', function () {
expect(searcher.search).to.be.calledWith('my_index', {
lang: 'ENGLISH',
query: 'my query',
filters: []
filters: [],
joins: []
});
done();
});
Expand Down Expand Up @@ -355,7 +360,8 @@ describe('Index', function () {
negative: false,
query: 'id:x'
}
]
],
joins: []
});
done();
});
Expand Down Expand Up @@ -396,7 +402,8 @@ describe('Index', function () {
negative: false,
query: 'id2:x'
}
]
],
joins: []
});
done();
});
Expand All @@ -415,7 +422,8 @@ describe('Index', function () {
expect(searcher.search).to.be.calledWith('my_index', {
lang: 'ENGLISH',
query: 'my query',
filters: []
filters: [],
joins: []
});
done();
});
Expand Down Expand Up @@ -444,10 +452,118 @@ describe('Index', function () {
negative: false,
query: 'id:bar'
}
],
joins: []
});
done();
});
});

it('should handle joins', function (done) {
index.filters = {
id: function (value) {
return {
type: 'QueryFilter',
negative: false,
query: 'id:' + value
};
}
};

index.joins = {
articles: {
index: new Index({
name: 'articles',
templates: {
searchText: {
returnedFields: [
'id'
],
searchFields: [
{
field: 'title',
mode: 'TERM_AND_PHRASE',
boost: 2
},
{
field: 'text',
mode: 'TERM_AND_PHRASE',
boost: 1
}
]
}
},
searcher: searcher,
filters: {
sectionId: function (value) {
return {
type: 'QueryFilter',
negative: false,
query: 'section_id:' + value
};
},
roleId: function (value) {
return {
type: 'QueryFilter',
negative: true,
query: 'role_id:' + value
};
}
}
}),
queryTemplate: 'generic',
localField: 'article_id',
foreignField: 'id',
type: 'INNER',
returnFields: false,
returnScores: false,
returnFacets: false
}
};


index.search('my query', {
filters: { id: 210384 },
joins: {
articles: {
query: 'join query',
template: 'searchText',
filters: {
sectionId: 213,
roleId: 230
}
}
}
}, function (err, res) {
if (err) return done(err);
expect(res.documents).to.eql([]);
expect(searcher.search).to.be.calledWith('my_index', {
lang: 'ENGLISH',
query: 'my query',
filters: [
{
type: 'QueryFilter',
negative: false,
query: 'id:210384'
}
],
joins: [
{
foreignField: 'id',
indexName: 'articles',
localField: 'article_id',
queryString: '(section_id:213) AND -(role_id:230) AND (title:(join query)^2 OR text:(join query)^1)',
queryTemplate: 'generic',
returnFacets: false,
returnFields: false,
returnScores: false,
type: 'INNER'
}
]
});
done();
});

});
});
});

0 comments on commit c282504

Please sign in to comment.