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

[Discover] Migrate remaining context files from js to ts #99019

Merged
merged 7 commits into from
May 6, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,71 +9,77 @@
import sinon from 'sinon';
import moment from 'moment';

import { IndexPatternsContract } from '../../../../../../data/public';
import { EsHitRecordList } from './context';

type SortHit = {
[key in string]: number; // timeField name
} & {
sort: [number, number];
};

export function createIndexPatternsStub() {
return {
return ({
get: sinon.spy((indexPatternId) =>
Promise.resolve({
id: indexPatternId,
isTimeNanosBased: () => false,
popularizeField: () => {},
})
),
};
} as unknown) as IndexPatternsContract;
}

/**
* A stubbed search source with a `fetch` method that returns all of `_stubHits`.
*/
export function createSearchSourceStub(hits, timeField) {
const searchSourceStub = {
export function createSearchSourceStub(hits: EsHitRecordList, timeField?: string) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const searchSourceStub: any = {
_stubHits: hits,
_stubTimeField: timeField,
_createStubHit: (timestamp, tiebreaker = 0) => ({
_createStubHit: (timestamp: number, tiebreaker = 0) => ({
[searchSourceStub._stubTimeField]: timestamp,
sort: [timestamp, tiebreaker],
}),
setParent: sinon.spy(() => searchSourceStub),
setField: sinon.spy(() => searchSourceStub),
removeField: sinon.spy(() => searchSourceStub),
getField: sinon.spy((key) => {
const previousSetCall = searchSourceStub.setField.withArgs(key).lastCall;
return previousSetCall ? previousSetCall.args[1] : null;
}),
fetch: sinon.spy(() =>
Promise.resolve({
hits: {
hits: searchSourceStub._stubHits,
total: searchSourceStub._stubHits.length,
},
})
),
};

searchSourceStub.setParent = sinon.spy(() => searchSourceStub);
searchSourceStub.setField = sinon.spy(() => searchSourceStub);
searchSourceStub.removeField = sinon.spy(() => searchSourceStub);

searchSourceStub.getField = sinon.spy((key) => {
const previousSetCall = searchSourceStub.setField.withArgs(key).lastCall;
return previousSetCall ? previousSetCall.args[1] : null;
});

searchSourceStub.fetch = sinon.spy(() =>
Promise.resolve({
hits: {
hits: searchSourceStub._stubHits,
total: searchSourceStub._stubHits.length,
},
})
);

return searchSourceStub;
}

/**
* A stubbed search source with a `fetch` method that returns a filtered set of `_stubHits`.
*/
export function createContextSearchSourceStub(hits, timeField = '@timestamp') {
const searchSourceStub = createSearchSourceStub(hits, timeField);
export function createContextSearchSourceStub(timeFieldName: string) {
const searchSourceStub = createSearchSourceStub([], timeFieldName);

searchSourceStub.fetch = sinon.spy(() => {
const timeField = searchSourceStub._stubTimeField;
const timeField: keyof SortHit = searchSourceStub._stubTimeField;
const lastQuery = searchSourceStub.setField.withArgs('query').lastCall.args[1];
const timeRange = lastQuery.query.bool.must.constant_score.filter.range[timeField];
const lastSort = searchSourceStub.setField.withArgs('sort').lastCall.args[1];
const sortDirection = lastSort[0][timeField].order;
const sortFunction =
sortDirection === 'asc'
? (first, second) => first[timeField] - second[timeField]
: (first, second) => second[timeField] - first[timeField];
? (first: SortHit, second: SortHit) => first[timeField] - second[timeField]
: (first: SortHit, second: SortHit) => second[timeField] - first[timeField];
const filteredHits = searchSourceStub._stubHits
.filter(
(hit) =>
(hit: SortHit) =>
moment(hit[timeField]).isSameOrAfter(timeRange.gte) &&
moment(hit[timeField]).isSameOrBefore(timeRange.lte)
)
Expand All @@ -87,5 +93,5 @@ export function createContextSearchSourceStub(hits, timeField = '@timestamp') {
});
});

return searchSourceStub;
return searchSourceStub as sinon.SinonStub;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,40 @@
* Side Public License, v 1.
*/

import { EsQuerySortValue, SortDirection } from '../../../../../../data/public';
import { createIndexPatternsStub, createSearchSourceStub } from './_stubs';

import { fetchAnchorProvider } from './anchor';
import { AnchorHitRecord, fetchAnchorProvider } from './anchor';

describe('context app', function () {
describe('function fetchAnchor', function () {
let fetchAnchor;
let searchSourceStub;
let fetchAnchor: (
indexPatternId: string,
anchorId: string,
sort: EsQuerySortValue[]
) => Promise<AnchorHitRecord>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let searchSourceStub: any;

describe('function fetchAnchor', function () {
beforeEach(() => {
searchSourceStub = createSearchSourceStub([{ _id: 'hit1' }]);
searchSourceStub = createSearchSourceStub([
{ _id: 'hit1', fields: [], sort: [], _source: {} },
]);
fetchAnchor = fetchAnchorProvider(createIndexPatternsStub(), searchSourceStub);
});

it('should use the `fetch` method of the SearchSource', function () {
return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(() => {
expect(searchSourceStub.fetch.calledOnce).toBe(true);
});
});

it('should configure the SearchSource to not inherit from the implicit root', function () {
return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(() => {
const setParentSpy = searchSourceStub.setParent;
expect(setParentSpy.calledOnce).toBe(true);
Expand All @@ -42,8 +49,8 @@ describe('context app', function () {

it('should set the SearchSource index pattern', function () {
return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(() => {
const setFieldSpy = searchSourceStub.setField;
expect(setFieldSpy.firstCall.args[1].id).toEqual('INDEX_PATTERN_ID');
Expand All @@ -52,8 +59,8 @@ describe('context app', function () {

it('should set the SearchSource version flag to true', function () {
return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(() => {
const setVersionSpy = searchSourceStub.setField.withArgs('version');
expect(setVersionSpy.calledOnce).toBe(true);
Expand All @@ -63,8 +70,8 @@ describe('context app', function () {

it('should set the SearchSource size to 1', function () {
return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(() => {
const setSizeSpy = searchSourceStub.setField.withArgs('size');
expect(setSizeSpy.calledOnce).toBe(true);
Expand All @@ -74,8 +81,8 @@ describe('context app', function () {

it('should set the SearchSource query to an ids query', function () {
return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(() => {
const setQuerySpy = searchSourceStub.setField.withArgs('query');
expect(setQuerySpy.calledOnce).toBe(true);
Expand All @@ -96,24 +103,27 @@ describe('context app', function () {

it('should set the SearchSource sort order', function () {
return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(() => {
const setSortSpy = searchSourceStub.setField.withArgs('sort');
expect(setSortSpy.calledOnce).toBe(true);
expect(setSortSpy.firstCall.args[1]).toEqual([{ '@timestamp': 'desc' }, { _doc: 'desc' }]);
expect(setSortSpy.firstCall.args[1]).toEqual([
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]);
});
});

it('should reject with an error when no hits were found', function () {
searchSourceStub._stubHits = [];

return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(
() => {
expect().fail('expected the promise to be rejected');
fail('expected the promise to be rejected');
},
(error) => {
expect(error).toBeInstanceOf(Error);
Expand All @@ -125,8 +135,8 @@ describe('context app', function () {
searchSourceStub._stubHits = [{ property1: 'value1' }, { property2: 'value2' }];

return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then((anchorDocument) => {
expect(anchorDocument).toHaveProperty('property1', 'value1');
expect(anchorDocument).toHaveProperty('$$_isAnchor', true);
Expand All @@ -135,20 +145,19 @@ describe('context app', function () {
});

describe('useNewFields API', () => {
let fetchAnchor;
let searchSourceStub;

beforeEach(() => {
searchSourceStub = createSearchSourceStub([{ _id: 'hit1' }]);
searchSourceStub = createSearchSourceStub([
{ _id: 'hit1', fields: [], sort: [], _source: {} },
]);
fetchAnchor = fetchAnchorProvider(createIndexPatternsStub(), searchSourceStub, true);
});

it('should request fields if useNewFieldsApi set', function () {
searchSourceStub._stubHits = [{ property1: 'value1' }, { property2: 'value2' }];

return fetchAnchor('INDEX_PATTERN_ID', 'id', [
{ '@timestamp': 'desc' },
{ _doc: 'desc' },
{ '@timestamp': SortDirection.desc },
{ _doc: SortDirection.desc },
]).then(() => {
const setFieldsSpy = searchSourceStub.setField.withArgs('fields');
const removeFieldsSpy = searchSourceStub.removeField.withArgs('fieldsFromSource');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,31 @@
* Side Public License, v 1.
*/

import _ from 'lodash';
import { get } from 'lodash';
import { i18n } from '@kbn/i18n';

export function fetchAnchorProvider(indexPatterns, searchSource, useNewFieldsApi = false) {
return async function fetchAnchor(indexPatternId, anchorId, sort) {
import {
ISearchSource,
IndexPatternsContract,
EsQuerySortValue,
} from '../../../../../../data/public';
import { EsHitRecord } from './context';

export interface AnchorHitRecord extends EsHitRecord {
// eslint-disable-next-line @typescript-eslint/naming-convention
$$_isAnchor: boolean;
}

export function fetchAnchorProvider(
indexPatterns: IndexPatternsContract,
searchSource: ISearchSource,
useNewFieldsApi: boolean = false
) {
return async function fetchAnchor(
indexPatternId: string,
anchorId: string,
sort: EsQuerySortValue[]
): Promise<AnchorHitRecord> {
const indexPattern = await indexPatterns.get(indexPatternId);
searchSource
.setParent(undefined)
Expand All @@ -36,7 +56,7 @@ export function fetchAnchorProvider(indexPatterns, searchSource, useNewFieldsApi
}
const response = await searchSource.fetch();

if (_.get(response, ['hits', 'total'], 0) < 1) {
if (get(response, ['hits', 'total'], 0) < 1) {
throw new Error(
i18n.translate('discover.context.failedToLoadAnchorDocumentErrorDescription', {
defaultMessage: 'Failed to load anchor document.',
Expand All @@ -45,8 +65,9 @@ export function fetchAnchorProvider(indexPatterns, searchSource, useNewFieldsApi
}

return {
..._.get(response, ['hits', 'hits', 0]),
...get(response, ['hits', 'hits', 0]),
// eslint-disable-next-line @typescript-eslint/naming-convention
$$_isAnchor: true,
};
} as AnchorHitRecord;
};
}
Loading