2020-04-01 06:13:27 +03:00
|
|
|
import { ThunkDispatch } from 'redux-thunk';
|
|
|
|
import { AnyAction } from 'redux';
|
2021-04-06 19:28:15 +03:00
|
|
|
import { isEqual } from 'lodash';
|
2020-04-01 06:13:27 +03:00
|
|
|
import { State } from '../types/redux';
|
|
|
|
import { currentBackend } from '../backend';
|
|
|
|
import { getIntegrationProvider } from '../integrations';
|
|
|
|
import { selectIntegration } from '../reducers';
|
|
|
|
import { EntryValue } from '../valueObjects/Entry';
|
2016-12-07 15:44:07 -02:00
|
|
|
|
|
|
|
/*
|
2019-09-24 22:16:09 +02:00
|
|
|
* Constant Declarations
|
2016-12-07 15:44:07 -02:00
|
|
|
*/
|
|
|
|
export const SEARCH_ENTRIES_REQUEST = 'SEARCH_ENTRIES_REQUEST';
|
|
|
|
export const SEARCH_ENTRIES_SUCCESS = 'SEARCH_ENTRIES_SUCCESS';
|
|
|
|
export const SEARCH_ENTRIES_FAILURE = 'SEARCH_ENTRIES_FAILURE';
|
|
|
|
|
2021-04-06 19:28:15 +03:00
|
|
|
export const QUERY_REQUEST = 'QUERY_REQUEST';
|
|
|
|
export const QUERY_SUCCESS = 'QUERY_SUCCESS';
|
|
|
|
export const QUERY_FAILURE = 'QUERY_FAILURE';
|
2016-12-07 15:44:07 -02:00
|
|
|
|
|
|
|
export const SEARCH_CLEAR = 'SEARCH_CLEAR';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Simple Action Creators (Internal)
|
|
|
|
* We still need to export them for tests
|
|
|
|
*/
|
2020-05-18 09:52:06 +02:00
|
|
|
export function searchingEntries(searchTerm: string, searchCollections: string[], page: number) {
|
2016-12-07 15:44:07 -02:00
|
|
|
return {
|
|
|
|
type: SEARCH_ENTRIES_REQUEST,
|
2020-05-18 09:52:06 +02:00
|
|
|
payload: { searchTerm, searchCollections, page },
|
2021-04-06 19:28:15 +03:00
|
|
|
} as const;
|
2016-12-07 15:44:07 -02:00
|
|
|
}
|
|
|
|
|
2021-04-06 19:28:15 +03:00
|
|
|
export function searchSuccess(entries: EntryValue[], page: number) {
|
2016-12-07 15:44:07 -02:00
|
|
|
return {
|
|
|
|
type: SEARCH_ENTRIES_SUCCESS,
|
|
|
|
payload: {
|
|
|
|
entries,
|
|
|
|
page,
|
|
|
|
},
|
2021-04-06 19:28:15 +03:00
|
|
|
} as const;
|
2016-12-07 15:44:07 -02:00
|
|
|
}
|
|
|
|
|
2021-04-06 19:28:15 +03:00
|
|
|
export function searchFailure(error: Error) {
|
2016-12-07 15:44:07 -02:00
|
|
|
return {
|
|
|
|
type: SEARCH_ENTRIES_FAILURE,
|
2021-04-06 19:28:15 +03:00
|
|
|
payload: { error },
|
|
|
|
} as const;
|
2016-12-07 15:44:07 -02:00
|
|
|
}
|
|
|
|
|
2021-04-06 19:28:15 +03:00
|
|
|
export function querying(searchTerm: string) {
|
2016-12-07 15:44:07 -02:00
|
|
|
return {
|
|
|
|
type: QUERY_REQUEST,
|
|
|
|
payload: {
|
|
|
|
searchTerm,
|
|
|
|
},
|
2021-04-06 19:28:15 +03:00
|
|
|
} as const;
|
2016-12-07 15:44:07 -02:00
|
|
|
}
|
|
|
|
|
2020-07-06 14:05:01 +03:00
|
|
|
type SearchResponse = {
|
2020-04-01 06:13:27 +03:00
|
|
|
entries: EntryValue[];
|
|
|
|
pagination: number;
|
|
|
|
};
|
|
|
|
|
2020-07-06 14:05:01 +03:00
|
|
|
type QueryResponse = {
|
|
|
|
hits: EntryValue[];
|
|
|
|
query: string;
|
|
|
|
};
|
|
|
|
|
2021-04-06 19:28:15 +03:00
|
|
|
export function querySuccess(namespace: string, hits: EntryValue[]) {
|
2016-12-07 15:44:07 -02:00
|
|
|
return {
|
|
|
|
type: QUERY_SUCCESS,
|
|
|
|
payload: {
|
2016-12-29 17:18:24 -02:00
|
|
|
namespace,
|
2021-04-06 19:28:15 +03:00
|
|
|
hits,
|
2016-12-07 15:44:07 -02:00
|
|
|
},
|
2021-04-06 19:28:15 +03:00
|
|
|
} as const;
|
2016-12-07 15:44:07 -02:00
|
|
|
}
|
|
|
|
|
2021-04-06 19:28:15 +03:00
|
|
|
export function queryFailure(error: Error) {
|
2016-12-07 15:44:07 -02:00
|
|
|
return {
|
2020-02-13 10:48:02 +01:00
|
|
|
type: QUERY_FAILURE,
|
2021-04-06 19:28:15 +03:00
|
|
|
payload: { error },
|
|
|
|
} as const;
|
2016-12-07 15:44:07 -02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Exported simple Action Creators
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function clearSearch() {
|
2021-04-06 19:28:15 +03:00
|
|
|
return { type: SEARCH_CLEAR } as const;
|
2016-12-07 15:44:07 -02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Exported Thunk Action Creators
|
|
|
|
*/
|
|
|
|
|
|
|
|
// SearchEntries will search for complete entries in all collections.
|
2021-04-06 19:28:15 +03:00
|
|
|
export function searchEntries(searchTerm: string, searchCollections: string[], page = 0) {
|
|
|
|
return async (dispatch: ThunkDispatch<State, undefined, AnyAction>, getState: () => State) => {
|
2016-12-07 15:44:07 -02:00
|
|
|
const state = getState();
|
2020-04-01 06:13:27 +03:00
|
|
|
const { search } = state;
|
2018-06-11 19:03:43 -07:00
|
|
|
const backend = currentBackend(state.config);
|
2020-05-18 09:52:06 +02:00
|
|
|
const allCollections = searchCollections || state.collections.keySeq().toArray();
|
2018-08-07 14:46:54 -06:00
|
|
|
const collections = allCollections.filter(collection =>
|
2021-04-06 19:28:15 +03:00
|
|
|
selectIntegration(state, collection, 'search'),
|
2018-08-07 14:46:54 -06:00
|
|
|
);
|
2021-04-06 19:28:15 +03:00
|
|
|
const integration = selectIntegration(state, collections[0], 'search');
|
2020-04-01 06:13:27 +03:00
|
|
|
|
|
|
|
// avoid duplicate searches
|
|
|
|
if (
|
2021-04-06 19:28:15 +03:00
|
|
|
search.isFetching &&
|
|
|
|
search.term === searchTerm &&
|
|
|
|
isEqual(allCollections, search.collections) &&
|
2020-04-01 06:13:27 +03:00
|
|
|
// if an integration doesn't exist, 'page' is not used
|
2021-04-06 19:28:15 +03:00
|
|
|
(search.page === page || !integration)
|
2020-04-01 06:13:27 +03:00
|
|
|
) {
|
|
|
|
return;
|
|
|
|
}
|
2021-04-06 19:28:15 +03:00
|
|
|
|
|
|
|
dispatch(searchingEntries(searchTerm, allCollections, page));
|
2018-06-11 19:03:43 -07:00
|
|
|
|
|
|
|
const searchPromise = integration
|
2018-08-07 14:46:54 -06:00
|
|
|
? getIntegrationProvider(state.integrations, backend.getToken, integration).search(
|
|
|
|
collections,
|
|
|
|
searchTerm,
|
|
|
|
page,
|
|
|
|
)
|
2020-05-18 09:52:06 +02:00
|
|
|
: backend.search(
|
|
|
|
state.collections
|
|
|
|
.filter((_, key: string) => allCollections.indexOf(key) !== -1)
|
|
|
|
.valueSeq()
|
|
|
|
.toArray(),
|
|
|
|
searchTerm,
|
|
|
|
);
|
2018-06-11 19:03:43 -07:00
|
|
|
|
2021-04-06 19:28:15 +03:00
|
|
|
try {
|
|
|
|
const response: SearchResponse = await searchPromise;
|
|
|
|
return dispatch(searchSuccess(response.entries, response.pagination));
|
|
|
|
} catch (error) {
|
|
|
|
return dispatch(searchFailure(error));
|
|
|
|
}
|
2016-12-07 15:44:07 -02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instead of searching for complete entries, query will search for specific fields
|
|
|
|
// in specific collections and return raw data (no entries).
|
2020-04-01 06:13:27 +03:00
|
|
|
export function query(
|
|
|
|
namespace: string,
|
|
|
|
collectionName: string,
|
|
|
|
searchFields: string[],
|
|
|
|
searchTerm: string,
|
2020-07-06 14:05:01 +03:00
|
|
|
file?: string,
|
|
|
|
limit?: number,
|
2020-04-01 06:13:27 +03:00
|
|
|
) {
|
2020-07-06 14:05:01 +03:00
|
|
|
return async (dispatch: ThunkDispatch<State, {}, AnyAction>, getState: () => State) => {
|
2021-04-06 19:28:15 +03:00
|
|
|
dispatch(querying(searchTerm));
|
2018-06-11 19:03:43 -07:00
|
|
|
|
2016-12-07 15:44:07 -02:00
|
|
|
const state = getState();
|
2018-06-11 19:03:43 -07:00
|
|
|
const backend = currentBackend(state.config);
|
|
|
|
const integration = selectIntegration(state, collectionName, 'search');
|
2018-08-07 14:46:54 -06:00
|
|
|
const collection = state.collections.find(
|
|
|
|
collection => collection.get('name') === collectionName,
|
|
|
|
);
|
2018-06-11 19:03:43 -07:00
|
|
|
|
|
|
|
const queryPromise = integration
|
2018-08-07 14:46:54 -06:00
|
|
|
? getIntegrationProvider(state.integrations, backend.getToken, integration).searchBy(
|
|
|
|
searchFields.map(f => `data.${f}`),
|
|
|
|
collectionName,
|
|
|
|
searchTerm,
|
|
|
|
)
|
2020-07-06 14:05:01 +03:00
|
|
|
: backend.query(collection, searchFields, searchTerm, file, limit);
|
2018-06-11 19:03:43 -07:00
|
|
|
|
2020-07-06 14:05:01 +03:00
|
|
|
try {
|
|
|
|
const response: QueryResponse = await queryPromise;
|
2021-04-06 19:28:15 +03:00
|
|
|
return dispatch(querySuccess(namespace, response.hits));
|
2020-07-06 14:05:01 +03:00
|
|
|
} catch (error) {
|
2021-04-06 19:28:15 +03:00
|
|
|
return dispatch(queryFailure(error));
|
2020-07-06 14:05:01 +03:00
|
|
|
}
|
2016-12-07 15:44:07 -02:00
|
|
|
};
|
|
|
|
}
|
2021-04-06 19:28:15 +03:00
|
|
|
|
|
|
|
export type SearchAction = ReturnType<
|
|
|
|
| typeof searchingEntries
|
|
|
|
| typeof searchSuccess
|
|
|
|
| typeof searchFailure
|
|
|
|
| typeof querying
|
|
|
|
| typeof querySuccess
|
|
|
|
| typeof queryFailure
|
|
|
|
| typeof clearSearch
|
|
|
|
>;
|