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

[data / saved query] BWCA all the routes #158790

Merged
merged 21 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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 @@ -22,6 +22,8 @@ const {
getSavedQueryCount,
} = createSavedQueryService(http);

const version = '1';

const savedQueryAttributes: SavedQueryAttributes = {
title: 'foo',
description: 'bar',
Expand All @@ -45,6 +47,7 @@ describe('saved query service', () => {
expect(http.post).toBeCalled();
expect(http.post).toHaveBeenCalledWith('/api/saved_query/_create', {
body: '{"title":"foo","description":"bar","query":{"language":"kuery","query":"response:200"},"filters":[]}',
version,
});
});
});
Expand All @@ -55,6 +58,7 @@ describe('saved query service', () => {
expect(http.put).toBeCalled();
expect(http.put).toHaveBeenCalledWith('/api/saved_query/foo', {
body: '{"title":"foo","description":"bar","query":{"language":"kuery","query":"response:200"},"filters":[]}',
version,
});
});
});
Expand All @@ -67,7 +71,7 @@ describe('saved query service', () => {
});
const result = await getAllSavedQueries();
expect(http.post).toBeCalled();
expect(http.post).toHaveBeenCalledWith('/api/saved_query/_all');
expect(http.post).toHaveBeenCalledWith('/api/saved_query/_all', { version });
expect(result).toEqual([{ attributes: savedQueryAttributes }]);
});
});
Expand All @@ -82,6 +86,7 @@ describe('saved query service', () => {
expect(http.post).toBeCalled();
expect(http.post).toHaveBeenCalledWith('/api/saved_query/_find', {
body: '{"page":1,"perPage":50,"search":""}',
version,
});
expect(result).toEqual({
queries: [{ attributes: savedQueryAttributes }],
Expand All @@ -94,23 +99,23 @@ describe('saved query service', () => {
it('should get the given ID', async () => {
await getSavedQuery('my_id');
expect(http.get).toBeCalled();
expect(http.get).toHaveBeenCalledWith('/api/saved_query/my_id');
expect(http.get).toHaveBeenCalledWith('/api/saved_query/my_id', { version });
});
});

describe('deleteSavedQuery', function () {
it('should delete the given ID', async () => {
await deleteSavedQuery('my_id');
expect(http.delete).toBeCalled();
expect(http.delete).toHaveBeenCalledWith('/api/saved_query/my_id');
expect(http.delete).toHaveBeenCalledWith('/api/saved_query/my_id', { version });
});
});

describe('getSavedQueryCount', function () {
it('should get the total', async () => {
await getSavedQueryCount();
expect(http.get).toBeCalled();
expect(http.get).toHaveBeenCalledWith('/api/saved_query/_count');
expect(http.get).toHaveBeenCalledWith('/api/saved_query/_count', { version });
});
});
});
14 changes: 10 additions & 4 deletions src/plugins/data/public/query/saved_query/saved_query_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,30 @@ import { HttpStart } from '@kbn/core/public';
import { SavedQuery } from './types';
import type { SavedQueryAttributes } from '../../../common';

const version = '1';

export const createSavedQueryService = (http: HttpStart) => {
const createQuery = async (attributes: SavedQueryAttributes, { overwrite = false } = {}) => {
const savedQuery = await http.post<SavedQuery>('/api/saved_query/_create', {
body: JSON.stringify(attributes),
version,
});
return savedQuery;
};

const updateQuery = async (id: string, attributes: SavedQueryAttributes) => {
const savedQuery = await http.put<SavedQuery>(`/api/saved_query/${id}`, {
body: JSON.stringify(attributes),
version,
});
return savedQuery;
};

// we have to tell the saved objects client how many to fetch, otherwise it defaults to fetching 20 per page
const getAllSavedQueries = async (): Promise<SavedQuery[]> => {
const { savedQueries } = await http.post<{ savedQueries: SavedQuery[] }>(
'/api/saved_query/_all'
'/api/saved_query/_all',
{ version }
);
return savedQueries;
};
Expand All @@ -44,21 +49,22 @@ export const createSavedQueryService = (http: HttpStart) => {
total: number;
}>('/api/saved_query/_find', {
body: JSON.stringify({ page, perPage, search }),
version,
});

return { total, queries };
};

const getSavedQuery = (id: string): Promise<SavedQuery> => {
return http.get<SavedQuery>(`/api/saved_query/${id}`);
return http.get<SavedQuery>(`/api/saved_query/${id}`, { version });
};

const deleteSavedQuery = (id: string) => {
return http.delete<{}>(`/api/saved_query/${id}`);
return http.delete<{}>(`/api/saved_query/${id}`, { version });
};

const getSavedQueryCount = async (): Promise<number> => {
return http.get<number>('/api/saved_query/_count');
return http.get<number>('/api/saved_query/_count', { version });
};

return {
Expand Down
128 changes: 128 additions & 0 deletions src/plugins/data/server/query/route_types.ts
davismcphee marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import type { SerializableRecord } from '@kbn/utility-types';

/*
* These types are used to define the shape of the response from the saved query API
*/

// @ts-expect-error
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why this is necessary - this type is essentially copied from MatchAllFilterMeta where it works.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bizarrely, this seems to be caused by Filter being an interface instead of a type. It looks like that's why packages/kbn-es-query/src/filters/build_filters/types.ts uses a type with // eslint-disable-next-line @typescript-eslint/consistent-type-definitions instead:

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type Filter = {
$state?: {
store: FilterStateStore;
};
meta: FilterMeta;
query?: Record<string, any>;
};

I have no idea why the compiler doesn't like this though 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm mostly confused because I made sure my copied Filter is also a type and yet the compiler still complains.

interface MatchAllFilterMetaRestResponse extends FilterMetaRestResponse, SerializableRecord {
field: string;
formattedValue: string;
}

type PhrasesFilterMetaRestResponse = FilterMetaRestResponse & {
params: PhraseFilterValue[]; // The unformatted values
field?: string;
};

interface RangeFilterParamsRestResponse extends SerializableRecord {
from?: number | string;
to?: number | string;
gt?: number | string;
lt?: number | string;
gte?: number | string;
lte?: number | string;
format?: string;
}

type RangeFilterMetaRestResponse = FilterMetaRestResponse & {
params?: RangeFilterParamsRestResponse;
field?: string;
formattedValue?: string;
type: 'range';
};

type PhraseFilterValue = string | number | boolean;

interface PhraseFilterMetaParamsRestResponse extends SerializableRecord {
query: PhraseFilterValue; // The unformatted value
}

type PhraseFilterMetaRestResponse = FilterMetaRestResponse & {
params?: PhraseFilterMetaParamsRestResponse;
field?: string;
index?: string;
};

type FilterMetaParamsRestResponse =
| FilterRestResponse
| FilterRestResponse[]
| RangeFilterMetaRestResponse
| RangeFilterParamsRestResponse
| PhraseFilterMetaRestResponse
| PhraseFilterMetaParamsRestResponse
| PhrasesFilterMetaRestResponse
| MatchAllFilterMetaRestResponse
| string
| string[]
| boolean
| boolean[]
| number
| number[];

interface QueryRestResponse {
query: string | { [key: string]: any };
language: string;
}

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
type FilterMetaRestResponse = {
alias?: string | null;
disabled?: boolean;
negate?: boolean;
// controlledBy is there to identify who owns the filter
controlledBy?: string;
// allows grouping of filters
group?: string;
// index and type are optional only because when you create a new filter, there are no defaults
index?: string;
isMultiIndex?: boolean;
type?: string;
key?: string;
params?: FilterMetaParamsRestResponse;
value?: string;
};

type FilterStateStoreRestResponse = 'appState' | 'globalState';

interface FilterRestResponse {
$state?: {
store: FilterStateStoreRestResponse;
};
meta: FilterMetaRestResponse;
query?: Record<string, any>;
}
davismcphee marked this conversation as resolved.
Show resolved Hide resolved

interface RefreshIntervalRestResponse {
pause: boolean;
value: number;
}

interface TimeRangeRestResponse {
from: string;
to: string;
mode?: 'absolute' | 'relative';
}

type SavedQueryTimeFilterRestResponse = TimeRangeRestResponse & {
refreshInterval: RefreshIntervalRestResponse;
};

export interface SavedQueryRestResponse {
id: string;
attributes: {
filters: FilterRestResponse[];
title: string;
description: string;
query: QueryRestResponse;
timefilter?: SavedQueryTimeFilterRestResponse | undefined;
};
}
Loading