Skip to content

Commit

Permalink
Merge pull request #9 from sudo-suhas/feat-search-templ
Browse files Browse the repository at this point in the history
Add support for Search Template
  • Loading branch information
sudo-suhas authored Jun 26, 2017
2 parents 5240e8f + a741996 commit bf4e7ba
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ or [`bodybuilder`](https://github.com/danpaz/bodybuilder)
Although there were [breaking changes](https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking_60_search_changes.html),
all deprecated queries, features in 5.0 were avoided or not implemented.

What's Included:
* [Request body search](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html)
* [Queries](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html)
* [Aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html)
* [Search Template](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html)

## Install
```
npm install elastic-builder --save
Expand Down
2 changes: 2 additions & 0 deletions docs/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ toc:
- ValueCountAggregation
- name: Bucket Aggregations
- BucketAggregationBase
- AdjacencyMatrixAggregation
- ChildrenAggregation
- HistogramAggregationBase
- DateHistogramAggregation
Expand Down Expand Up @@ -146,3 +147,4 @@ toc:
- Sort
- Rescore
- InnerHits
- SearchTemplate
81 changes: 81 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7034,6 +7034,87 @@ export class InnerHits {
*/
export function innerHits(name?: string): InnerHits;

/**
* Class supporting the Elasticsearch search template API.
*
* The `/_search/template` endpoint allows to use the mustache language to
* pre render search requests, before they are executed and fill existing
* templates with template parameters.
*
* @param {string=} type One of `inline`, `id`, `file`. `id` is also
* aliased as `indexed`
* @param {string|Object=} source Source of the search template.
* This needs to be specified if optional argument `type` is passed.
*/
export class SearchTemplate {
constructor(type?: string, source?: string | object);

/**
* Sets the type of search template to be `inline` and specifies the query.
*
* @param {string|Query} query Either a `Query` object or a string.
*/
inline(query: string | object): this;

/**
* Specify the indexed search template by `templateName` which will be
* retrieved from cluster state.
*
* @param {string} templId The unique identifier for the indexed template
*/
id(templId: string): this;

/**
* Specify the indexed search template by `templateName` which will be
* retrieved from cluster state.
*
* Alias for `SearchTemplate.id`
*
* @param {string} templId The unique identifier for the indexed template
*/
indexed(templId: string): this;

/**
* Specify the search template by filename stored in the scripts folder,
* with `mustache` extension.
*
* @param {string} fileName The name of the search template stored as a file
* in the scripts folder.
* For file `config/scripts/storedTemplate.mustache`,
* `fileName` should be `storedTemplate`
*/
file(fileName: string): this;

/**
* Specifies any named parameters that are used to render the search template.
*
* @param {Object} params Named parameters to be used for rendering.
*/
params(params: object): this;

/**
* Override default `toJSON` to return DSL representation for the Search Template.
*
* @override
* @returns {Object} returns an Object which maps to the elasticsearch query DSL
*/
toJSON(): object;
}

/**
* Class supporting the Elasticsearch search template API.
*
* The `/_search/template` endpoint allows to use the mustache language to
* pre render search requests, before they are executed and fill existing
* templates with template parameters.
*
* @param {string=} type One of `inline`, `id`, `file`. `id` is also
* aliased as `indexed`
* @param {string|Object=} source Source of the search template.
* This needs to be specified if optional argument `type` is passed.
*/
export function searchTemplate(type?: string, source?: string | object): SearchTemplate;

export namespace recipes {
/**
* Recipe for the now removed `missing` query.
Expand Down
2 changes: 2 additions & 0 deletions src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ exports.Rescore = require('./rescore');

exports.InnerHits = require('./inner-hits');

exports.SearchTemplate = require('./search-template');

exports.consts = require('./consts');

exports.util = require('./util');
195 changes: 195 additions & 0 deletions src/core/search-template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
'use strict';

const isNil = require('lodash.isnil');

const { recursiveToJSON } = require('./util');

/**
* Class supporting the Elasticsearch search template API.
*
* The `/_search/template` endpoint allows to use the mustache language to
* pre render search requests, before they are executed and fill existing
* templates with template parameters.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html)
*
* @param {string=} type One of `inline`, `id`, `file`. `id` is also
* aliased as `indexed`
* @param {string|Object=} source Source of the search template.
* This needs to be specified if optional argument `type` is passed.
*
* @example
* const templ = bob.searchTemplate('inline', {
* query: bob.matchQuery('{{my_field}}', '{{my_value}}'),
* size: '{{my_size}}'
* }).params({
* my_field: 'message',
* my_value: 'some message',
* my_size: 5
* });
*
* @example
* const templ = new bob.SearchTemplate(
* 'inline',
* '{ "query": { "terms": {{#toJson}}statuses{{/toJson}} }}'
* ).params({
* statuses: {
* status: ['pending', 'published']
* }
* });
*
* @example
* const templ = new bob.SearchTemplate(
* 'inline',
* '{ "query": { "bool": { "must": {{#toJson}}clauses{{/toJson}} } } }'
* ).params({
* clauses: [
* bob.termQuery('user', 'boo'),
* bob.termQuery('user', 'bar'),
* bob.termQuery('user', 'baz')
* ]
* });
*/
class SearchTemplate {
// eslint-disable-next-line require-jsdoc
constructor(type, source) {
this._isTypeSet = false;
this._body = {};

if (!isNil(type) && !isNil(source)) {
const typeLower = type.toLowerCase();

if (
typeLower !== 'inline' &&
typeLower !== 'id' &&
typeLower !== 'indexed' && // alias for id
typeLower !== 'file'
) {
throw new Error('`type` must be one of `inline`, `id`, `indexed`, `file`');
}

this[typeLower](source);
}
}

/**
* Print warning message to console namespaced by class name.
*
* @param {string} msg
* @private
*/
_warn(msg) {
console.warn(`[SearchTemplate] ${msg}`);
}

/**
* Print warning messages to not mix `SearchTemplate` source
*
* @private
*/
_checkMixedRepr() {
if (this._isTypeSet) {
this._warn('Search template source(`inline`/`id`/`file`) was already specified!');
this._warn('Overwriting.');

delete this._body.file;
delete this._body.id;
delete this._body.file;
}
}

/**
* Helper method to set the type and source
*
* @param {string} type
* @param {*} source
* @returns {SearchTemplate} returns `this` so that calls can be chained.
* @private
*/
_setSource(type, source) {
this._checkMixedRepr();

this._body[type] = source;
this._isTypeSet = true;
return this;
}

/**
* Sets the type of search template to be `inline` and specifies the
* template with `query` and other optional fields such as `size`.
*
* @param {string|Object} templ Either an object or a string.
* @returns {SearchTemplate} returns `this` so that calls can be chained.
*/
inline(templ) {
return this._setSource('inline', templ);
}

/**
* Specify the indexed search template by `templateName` which will be
* retrieved from cluster state.
*
* @param {string} templId The unique identifier for the indexed template.
* @returns {SearchTemplate} returns `this` so that calls can be chained.
*/
id(templId) {
return this._setSource('id', templId);
}

/**
* Specify the indexed search template by `templateName` which will be
* retrieved from cluster state.
*
* Alias for `SearchTemplate.id`
*
* @param {string} templId The unique identifier for the indexed template.
* @returns {SearchTemplate} returns `this` so that calls can be chained.
*/
indexed(templId) {
return this.id(templId);
}

/**
* Specify the search template by filename stored in the scripts folder,
* with `mustache` extension.
*
* @example
* // `templId` - Name of the query template in config/scripts/, i.e.,
* // storedTemplate.mustache.
* const templ = new bob.SearchTemplate('file', 'storedTemplate').params({
* query_string: 'search for these words'
* });
*
* @param {string} fileName The name of the search template stored as a file
* in the scripts folder.
* For file `config/scripts/storedTemplate.mustache`,
* `fileName` should be `storedTemplate`
* @returns {SearchTemplate} returns `this` so that calls can be chained.
*/
file(fileName) {
return this._setSource('file', fileName);
}

/**
* Specifies any named parameters that are used to render the search template.
*
* @param {Object} params Named parameters to be used for rendering.
* @returns {SearchTemplate} returns `this` so that calls can be chained.
*/
params(params) {
this._body.params = params;
return this;
}

/**
* Override default `toJSON` to return DSL representation for the Search Template.
*
* @override
* @returns {Object} returns an Object which maps to the elasticsearch query DSL
*/
toJSON() {
return recursiveToJSON(this._body);
}
}

module.exports = SearchTemplate;
4 changes: 4 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
Sort,
Rescore,
InnerHits,
SearchTemplate,
util: { constructorWrapper }
} = require('./core');

Expand Down Expand Up @@ -513,6 +514,9 @@ exports.rescore = constructorWrapper(Rescore);
exports.InnerHits = InnerHits;
exports.innerHits = constructorWrapper(InnerHits);

exports.SearchTemplate = SearchTemplate;
exports.searchTemplate = constructorWrapper(SearchTemplate);

exports.prettyPrint = function prettyPrint(obj) {
console.log(JSON.stringify(obj, null, 2));
};
Loading

0 comments on commit bf4e7ba

Please sign in to comment.