-
Notifications
You must be signed in to change notification settings - Fork 885
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
[MDS] Support Vega Visualizations #5975
Merged
bandinib-amzn
merged 11 commits into
opensearch-project:main
from
huyaboo:vega-mds-support
Mar 8, 2024
Merged
Changes from 9 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
efe5116
Add MDS support for Vega
huyaboo eb9c9ef
Refactor field to data_source_id
huyaboo ddba426
Add to CHANGELOG.md
huyaboo 76aa282
Added test cases and renamed field to use data_source_name
huyaboo 5658eb5
Add prefix datasource name test case and add example in default hjson
huyaboo 3c4a03b
Merge branch 'main' into vega-mds-support
huyaboo ef3fd46
Move CHANGELOG to appropriate section
huyaboo be65384
Increased test coverage of search() method
huyaboo a5aa803
Merge branch 'main' into vega-mds-support
huyaboo fb8fe84
Merge branch 'main' into vega-mds-support
huyaboo f9747f3
Merge branch 'main' into vega-mds-support
huyaboo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
159 changes: 159 additions & 0 deletions
159
src/plugins/vis_type_vega/public/data_model/search_api.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { SavedObjectsClientContract, SavedObjectsFindOptions } from 'opensearch-dashboards/public'; | ||
import { SearchAPI, SearchAPIDependencies } from './search_api'; | ||
import { ISearchStart } from 'src/plugins/data/public'; | ||
import { IUiSettingsClient } from 'opensearch-dashboards/public'; | ||
|
||
jest.mock('rxjs', () => ({ | ||
combineLatest: jest.fn().mockImplementation((obj) => obj), | ||
})); | ||
|
||
jest.mock('../../../data/public', () => ({ | ||
getSearchParamsFromRequest: jest.fn().mockImplementation((obj, _) => obj), | ||
})); | ||
|
||
interface MockSearch { | ||
params?: Record<string, unknown>; | ||
dataSourceId?: string; | ||
pipe: () => {}; | ||
} | ||
|
||
describe('SearchAPI.search', () => { | ||
// This will only test that searchApiParams were correctly set. As such, every other function can be mocked | ||
const getSearchAPI = (dataSourceEnabled: boolean) => { | ||
const savedObjectsClient = {} as SavedObjectsClientContract; | ||
|
||
const searchStartMock = {} as ISearchStart; | ||
searchStartMock.search = jest.fn().mockImplementation((obj, _) => { | ||
const mockedSearchResults = {} as MockSearch; | ||
mockedSearchResults.params = obj; | ||
mockedSearchResults.pipe = jest.fn().mockReturnValue(mockedSearchResults.params); | ||
return mockedSearchResults; | ||
}); | ||
|
||
const uiSettings = {} as IUiSettingsClient; | ||
uiSettings.get = jest.fn().mockReturnValue(0); | ||
uiSettings.get.bind = jest.fn().mockReturnValue(0); | ||
|
||
const dependencies = { | ||
savedObjectsClient, | ||
dataSourceEnabled, | ||
search: searchStartMock, | ||
uiSettings, | ||
} as SearchAPIDependencies; | ||
const searchAPI = new SearchAPI(dependencies); | ||
searchAPI.findDataSourceIdbyName = jest.fn().mockImplementation((name) => { | ||
if (!dataSourceEnabled) { | ||
throw new Error(); | ||
} | ||
if (name === 'exampleName') { | ||
return Promise.resolve('some-id'); | ||
} | ||
}); | ||
|
||
return searchAPI; | ||
}; | ||
|
||
test('If MDS is disabled and there is no datasource, return params without datasource id', async () => { | ||
const searchAPI = getSearchAPI(false); | ||
const requests = [{ name: 'example-id' }]; | ||
const fetchParams = ((await searchAPI.search(requests)) as unknown) as MockSearch[]; | ||
expect(fetchParams[0].params).toBe(requests[0]); | ||
expect(fetchParams[0].hasOwnProperty('dataSourceId')).toBe(false); | ||
}); | ||
|
||
test('If MDS is disabled and there is a datasource, it should throw an errorr', () => { | ||
const searchAPI = getSearchAPI(false); | ||
const requests = [{ name: 'example-id', data_source_name: 'non-existent-datasource' }]; | ||
expect(searchAPI.search(requests)).rejects.toThrowError(); | ||
}); | ||
|
||
test('If MDS is enabled and there is no datasource, return params without datasource id', async () => { | ||
const searchAPI = getSearchAPI(true); | ||
const requests = [{ name: 'example-id' }]; | ||
const fetchParams = ((await searchAPI.search(requests)) as unknown) as MockSearch[]; | ||
expect(fetchParams[0].params).toBe(requests[0]); | ||
expect(fetchParams[0].hasOwnProperty('dataSourceId')).toBe(false); | ||
}); | ||
|
||
test('If MDS is enabled and there is a datasource, return params with datasource id', async () => { | ||
const searchAPI = getSearchAPI(true); | ||
const requests = [{ name: 'example-id', data_source_name: 'exampleName' }]; | ||
const fetchParams = ((await searchAPI.search(requests)) as unknown) as MockSearch[]; | ||
expect(fetchParams[0].hasOwnProperty('params')).toBe(true); | ||
expect(fetchParams[0].dataSourceId).toBe('some-id'); | ||
}); | ||
}); | ||
|
||
describe('SearchAPI.findDataSourceIdbyName', () => { | ||
const savedObjectsClient = {} as SavedObjectsClientContract; | ||
savedObjectsClient.find = jest.fn().mockImplementation((query: SavedObjectsFindOptions) => { | ||
if (query.search === `"uniqueDataSource"`) { | ||
return Promise.resolve({ | ||
total: 1, | ||
savedObjects: [{ id: 'some-datasource-id', attributes: { title: 'uniqueDataSource' } }], | ||
}); | ||
} else if (query.search === `"duplicateDataSource"`) { | ||
return Promise.resolve({ | ||
total: 2, | ||
savedObjects: [ | ||
{ id: 'some-datasource-id', attributes: { title: 'duplicateDataSource' } }, | ||
{ id: 'some-other-datasource-id', attributes: { title: 'duplicateDataSource' } }, | ||
], | ||
}); | ||
} else if (query.search === `"DataSource"`) { | ||
return Promise.resolve({ | ||
total: 2, | ||
savedObjects: [ | ||
{ id: 'some-datasource-id', attributes: { title: 'DataSource' } }, | ||
{ id: 'some-other-datasource-id', attributes: { title: 'DataSource Copy' } }, | ||
], | ||
}); | ||
} else { | ||
return Promise.resolve({ | ||
total: 0, | ||
savedObjects: [], | ||
}); | ||
} | ||
}); | ||
|
||
const getSearchAPI = (dataSourceEnabled: boolean) => { | ||
const dependencies = { savedObjectsClient, dataSourceEnabled } as SearchAPIDependencies; | ||
return new SearchAPI(dependencies); | ||
}; | ||
|
||
test('If dataSource is disabled, throw error', () => { | ||
const searchAPI = getSearchAPI(false); | ||
expect(searchAPI.findDataSourceIdbyName('nonexistentDataSource')).rejects.toThrowError( | ||
'data_source_name cannot be used because data_source.enabled is false' | ||
); | ||
}); | ||
|
||
test('If dataSource is enabled but no matching dataSourceName, then throw error', () => { | ||
const searchAPI = getSearchAPI(true); | ||
expect(searchAPI.findDataSourceIdbyName('nonexistentDataSource')).rejects.toThrowError( | ||
'Expected exactly 1 result for data_source_name "nonexistentDataSource" but got 0 results' | ||
); | ||
}); | ||
|
||
test('If dataSource is enabled but multiple dataSourceNames, then throw error', () => { | ||
const searchAPI = getSearchAPI(true); | ||
expect(searchAPI.findDataSourceIdbyName('duplicateDataSource')).rejects.toThrowError( | ||
'Expected exactly 1 result for data_source_name "duplicateDataSource" but got 2 results' | ||
); | ||
}); | ||
|
||
test('If dataSource is enabled but only one dataSourceName, then return id', async () => { | ||
const searchAPI = getSearchAPI(true); | ||
expect(await searchAPI.findDataSourceIdbyName('uniqueDataSource')).toBe('some-datasource-id'); | ||
}); | ||
|
||
test('If dataSource is enabled and the dataSourceName is a prefix of another, ensure the prefix is only returned', async () => { | ||
const searchAPI = getSearchAPI(true); | ||
expect(await searchAPI.findDataSourceIdbyName('DataSource')).toBe('some-datasource-id'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic is to check no duplicate datasource names between all datasources.
But we set the paging size 10 here: https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5975/files#diff-f1c265abe9e3b3c11a64d4110cf3e6a010dfe369cf6eed9a20ea532763489fbdR125
In that case, will the duplication check only applies to first 10 datasources?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So there are two cases where
possibleDataSourceIds
before filtering is > 1:data_source_name
is a duplicate of another (which means querying cannot be done)data_source_name
s. For example, if the name wereVega Data Source
and the other wereVega Data Source Copy
, then thefind
query forVega Data Source
will return both these data source names. The filtering is done to ensure thatVega Data Source
is chosen and notVega Data Source Copy
.The paging limit of 10 helps keep the number of possible datasources low since this is client-side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible for the initial paging to be free of duplicates, but duplication happens when applied across all data sources?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is not a blocker of this PR.
I don't think we are able to create datasource with duplication name, so this logic should be fine.