Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/Add support for runtime_mappings [Issue: #152] #196

Merged
merged 4 commits into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{
"eslint.enable": true,
"eslint.autoFixOnSave": true,
"files.eol": "\n",
"vsicons.presets.angular": false,
"editor.detectIndentation": true,
"[json]": {
"editor.tabSize": 2
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"author": "Suhas Karanth <sudo.suhas@gmail.com>",
"contributors": [
"austin ce <austin.cawley@gmail.com>",
"Julien Maitrehenry <julien.maitrehenry@me.com>",
"ochan12 <mateochando@gmail.com>",
"kennylindahl <haxxblaster@gmail.com>",
"foxstarius <aj.franzon@gmail.com>",
Expand Down
2 changes: 2 additions & 0 deletions src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ exports.SearchTemplate = require('./search-template');
exports.consts = require('./consts');

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

exports.RuntimeField = require('./runtime-field');
82 changes: 82 additions & 0 deletions src/core/request-body-search.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
InnerHits = require('./inner-hits');

const { checkType, setDefault, recursiveToJSON } = require('./util');
const RuntimeField = require('./runtime-field');

/**
* Helper function to call `recursiveToJSON` on elements of array and assign to object.
Expand Down Expand Up @@ -406,6 +407,87 @@
return this;
}

/**
* Computes a document property dynamically based on the supplied `runtimeField`.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-search-request.html)
*
* Added in Elasticsearch v7.11.0
* [Release note](https://www.elastic.co/guide/en/elasticsearch/reference/7.11/release-notes-7.11.0.html)
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeMapping(
* 'sessionId-name',
* esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['name'].value)`
* )
* )
*
* @example
* // runtime fields can also be used in query aggregation
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeMapping(
* 'sessionId-eventName',
* esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['eventName'].value)`,
* )
* )
* .agg(esb.cardinalityAggregation('uniqueCount', `sessionId-eventName`)),;
*
* @param {string} runtimeFieldName Name for the computed runtime mapping field.
* @param {RuntimeField} runtimeField Instance of RuntimeField
*
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*
*/
runtimeMapping(runtimeFieldName, runtimeField) {
checkType(runtimeField, RuntimeField);

setDefault(this._body, 'runtime_mappings', {});
this._body.runtime_mappings[runtimeFieldName] = runtimeField;
return this;
}

/**
* Computes one or more document properties dynamically based on supplied `RuntimeField`s.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-search-request.html)
*
* Added in Elasticsearch v7.11.0
* [Release note](https://www.elastic.co/guide/en/elasticsearch/reference/7.11/release-notes-7.11.0.html)
*
* @example
* const fieldA = esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['name'].value)`
* );
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeMappings({
* 'sessionId-name': fieldA,
* })
*
* @param {Object} runtimeMappings Object with `runtimeFieldName` as key and instance of `RuntimeField` as the value.
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
runtimeMappings(runtimeMappings) {
checkType(runtimeMappings, Object);

Object.keys(runtimeMappings).forEach(runtimeFieldName =>
this.runtimeMapping(
runtimeFieldName,
runtimeMappings[runtimeFieldName]
)
);

return this;
}

/**
* Computes a document property dynamically based on the supplied `Script`.
*
Expand Down Expand Up @@ -612,7 +694,7 @@
return this;
}

// TODO: Scroll related changes

Check warning on line 697 in src/core/request-body-search.js

View workflow job for this annotation

GitHub Actions / check (10.x)

Unexpected 'todo' comment

Check warning on line 697 in src/core/request-body-search.js

View workflow job for this annotation

GitHub Actions / check (12.x)

Unexpected 'todo' comment

Check warning on line 697 in src/core/request-body-search.js

View workflow job for this annotation

GitHub Actions / check (14.x)

Unexpected 'todo' comment
// Maybe only slice needs to be supported.

/**
Expand Down
91 changes: 91 additions & 0 deletions src/core/runtime-field.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict';

const isNil = require('lodash.isnil');
const validType = [
'boolean',
'composite',
'date',
'double',
'geo_point',
'ip',
'keyword',
'long',
'lookup'
];

/**
* Class supporting the Elasticsearch runtime field.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime.html)
*
* Added in Elasticsearch v7.11.0
* [Release note](https://www.elastic.co/guide/en/elasticsearch/reference/7.11/release-notes-7.11.0.html)
*
* @param {string=} type One of `boolean`, `composite`, `date`, `double`, `geo_point`, `ip`, `keyword`, `long`, `lookup`.
* @param {string=} script Source of the script.
*
* @example
* const field = esb.runtimeField('keyword', `emit(doc['sessionId'].value + '::' + doc['name'].value)`);
*/
class RuntimeField {
// eslint-disable-next-line require-jsdoc
constructor(type, script) {
this._body = {};
this._isTypeSet = false;
this._isScriptSet = false;

if (!isNil(type)) {
this.type(type);
}

if (!isNil(script)) {
this.script(script);
}
}

/**
* Sets the source of the script.
* @param {string} script
* @returns {void}
*/
script(script) {
this._body.script = {
source: script
};
this._isScriptSet = true;
}

/**
* Sets the type of the runtime field.
* @param {string} type One of `boolean`, `composite`, `date`, `double`, `geo_point`, `ip`, `keyword`, `long`, `lookup`.
* @returns {void}
*/
type(type) {
const typeLower = type.toLowerCase();
if (!validType.includes(typeLower)) {
throw new Error(`\`type\` must be one of ${validType.join(', ')}`);
}
this._body.type = typeLower;
this._isTypeSet = true;
}

/**
* Override default `toJSON` to return DSL representation for the `script`.
*
* @override
* @returns {Object} returns an Object which maps to the elasticsearch query DSL
*/
toJSON() {
if (!this._isTypeSet) {
throw new Error('`type` should be set');
}

if (!this._isScriptSet) {
throw new Error('`script` should be set');
}

return this._body;
}
}

module.exports = RuntimeField;
124 changes: 124 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,73 @@ declare namespace esb {
*/
storedFields(fields: object | string): this;



/**
* Computes a document property dynamically based on the supplied `runtimeField`.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-search-request.html)
*
* Added in Elasticsearch v7.11.0
* [Release note](https://www.elastic.co/guide/en/elasticsearch/reference/7.11/release-notes-7.11.0.html)
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeMapping(
* 'sessionId-name',
* esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['name'].value)`
* )
* )
*
* @example
* // runtime fields can also be used in query aggregation
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeMapping(
* 'sessionId-eventName',
* esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['eventName'].value)`,
* )
* )
* .agg(esb.cardinalityAggregation('uniqueCount', `sessionId-eventName`)),;
*
* @param {string} runtimeFieldName Name for the computed runtime mapping field.
* @param {RuntimeField} runtimeField Instance of RuntimeField
*
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*
*/
runtimeMapping(runtimeFieldName: string, runtimeField: RuntimeField): this;


/**
* Computes one or more document properties dynamically based on supplied `RuntimeField`s.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-search-request.html)
*
* Added in Elasticsearch v7.11.0
* [Release note](https://www.elastic.co/guide/en/elasticsearch/reference/7.11/release-notes-7.11.0.html)
*
* @example
* const fieldA = esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['name'].value)`
* );
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeMappings({
* 'sessionId-name': fieldA,
* })
*
* @param {Object} runtimeMappings Object with `runtimeFieldName` as key and instance of `RuntimeField` as the value.
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
runtimeMappings(runtimeMappings: object): this;

/**
* Computes a document property dynamically based on the supplied `Script`.
*
Expand Down Expand Up @@ -8761,6 +8828,63 @@ declare namespace esb {
*/
export function highlight(fields?: string | string[]): Highlight;

/**
* Class supporting the Elasticsearch runtime field.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime.html)
*
* Added in Elasticsearch v7.11.0
* [Release note](https://www.elastic.co/guide/en/elasticsearch/reference/7.11/release-notes-7.11.0.html)
*
* @param {string=} type One of `boolean`, `composite`, `date`, `double`, `geo_point`, `ip`, `keyword`, `long`, `lookup`.
* @param {string=} script Source of the script.
*
* @example
* const field = esb.runtimeField('keyword', `emit(doc['sessionId'].value + '::' + doc['name'].value)`);
*/
export class RuntimeField {
constructor(type?: string, script?: string);

/**
* Sets the type of the runtime field.
*
* @param {string} type One of `boolean`, `composite`, `date`, `double`, `geo_point`, `ip`, `keyword`, `long`, `lookup`.
* @returns {void}
*/
type(type: 'boolean' | 'composite' | 'date' | 'double' | 'geo_point' | 'ip' | 'keyword' | 'long' | 'lookup');

/**
* Sets the source of the script.
*
* @param {string} script
* @returns {void}
*/
script(script: string);

/**
* Override default `toJSON` to return DSL representation for the `script`.
*
* @override
*/
toJSON(): object;
}

/**
* Class supporting the Elasticsearch runtime field.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime.html)
*
* Added in Elasticsearch v7.11.0
* [Release note](https://www.elastic.co/guide/en/elasticsearch/reference/7.11/release-notes-7.11.0.html)
*
* @param {string=} type One of `boolean`, `composite`, `date`, `double`, `geo_point`, `ip`, `keyword`, `long`, `lookup`.
* @param {string=} script Source of the script.
*
* @example
* const field = esb.runtimeField('keyword', `emit(doc['sessionId'].value + '::' + doc['name'].value)`);
*/
export function runtimeField(type?: 'boolean' | 'composite' | 'date' | 'double' | 'geo_point' | 'ip' | 'keyword' | 'long' | 'lookup', script?: string): RuntimeField;

/**
* Class supporting the Elasticsearch scripting API.
*
Expand Down
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,
RuntimeField,
SearchTemplate,
Query,
util: { constructorWrapper }
Expand Down Expand Up @@ -640,6 +641,9 @@ exports.innerHits = constructorWrapper(InnerHits);
exports.SearchTemplate = SearchTemplate;
exports.searchTemplate = constructorWrapper(SearchTemplate);

exports.RuntimeField = RuntimeField;
exports.runtimeField = constructorWrapper(RuntimeField);

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