Skip to content

Commit

Permalink
global: update query state from response
Browse files Browse the repository at this point in the history
  • Loading branch information
zzacharo committed Oct 15, 2020
1 parent 2b774db commit 2e46338
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 56 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"expect": "^26.5.3",
"json": "^10.0.0",
"lodash": "^4.17.20",
"node-sass": "^4.12.0",
"node-sass": "^4.14.0",
"qs": "^6.8.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
Expand Down
34 changes: 17 additions & 17 deletions src/lib/api/UrlHandlerApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import _isNaN from 'lodash/isNaN';
import _isNil from 'lodash/isNil';
import _cloneDeep from 'lodash/cloneDeep';

const pushHistory = query => {
const pushHistory = (query) => {
if (window.history.pushState) {
window.history.pushState({ path: query }, '', query);
}
};

const replaceHistory = query => {
const replaceHistory = (query) => {
if (window.history.replaceState) {
window.history.replaceState({ path: query }, '', query);
}
Expand All @@ -32,7 +32,7 @@ class UrlParser {
this.parse = this.parse.bind(this);
}

_sanitizeParamValue = value => {
_sanitizeParamValue = (value) => {
let parsedValue = parseInt(value);
if (_isNaN(parsedValue)) {
try {
Expand All @@ -58,7 +58,7 @@ class UrlParser {
parse(queryString = '') {
const parsedParams = Qs.parse(queryString, { ignoreQueryPrefix: true });
const params = {};
Object.entries(parsedParams).forEach(entry => {
Object.entries(parsedParams).forEach((entry) => {
const key = entry[0];
const value = entry[1];
params[key] = this._sanitizeParamValue(value);
Expand Down Expand Up @@ -115,7 +115,7 @@ export class UrlHandlerApi {

// build the serializer from URL params to Query state by flipping the urlParamsMapping
this.fromUrlParamsMapping = {};
Object.keys(this.urlParamsMapping).forEach(stateKey => {
Object.keys(this.urlParamsMapping).forEach((stateKey) => {
this.fromUrlParamsMapping[this.urlParamsMapping[stateKey]] = stateKey;
});

Expand All @@ -128,7 +128,7 @@ export class UrlHandlerApi {
* Map filters from list to string that is human readable
* [ 'type', 'photo', [ 'subtype', 'png' ]] => type:photo+subtype:png
*/
_filterListToString = filter => {
_filterListToString = (filter) => {
const childFilter =
filter.length === 3
? this.urlFilterSeparator.concat(this._filterListToString(filter[2]))
Expand All @@ -139,27 +139,27 @@ export class UrlHandlerApi {
/**
* Map each query state field to an URL param
*/
_mapQueryStateToUrlParams = queryState => {
_mapQueryStateToUrlParams = (queryState) => {
const params = {};
Object.keys(queryState)
.filter(stateKey => stateKey in this.urlParamsMapping)
.filter(stateKey => {
.filter((stateKey) => stateKey in this.urlParamsMapping)
.filter((stateKey) => {
// filter out negative or null values
if (
(stateKey === 'page' || stateKey === 'size') &&
queryState[stateKey] <= 0
) {
return false;
}
if (stateKey === 'hiddenParams'){
if (stateKey === 'hiddenParams') {
return false;
}
return queryState[stateKey] !== null;
})
.forEach(stateKey => {
.forEach((stateKey) => {
const paramKey = this.urlParamsMapping[stateKey];
if (stateKey === 'filters') {
params[paramKey] = queryState[stateKey].map(filter =>
params[paramKey] = queryState[stateKey].map((filter) =>
this._filterListToString(filter)
);
} else {
Expand All @@ -179,7 +179,7 @@ export class UrlHandlerApi {
* Map filters from string to list
* type:photo+subtype:png => [ 'type', 'photo', [ 'subtype', 'png' ]]
*/
_filterStringToList = filterStr => {
_filterStringToList = (filterStr) => {
const childSepPos = filterStr.indexOf(this.urlFilterSeparator);
const hasChild = childSepPos > -1;

Expand All @@ -203,9 +203,9 @@ export class UrlHandlerApi {
/**
* Map each URL param to a query state field
*/
_mapUrlParamsToQueryState = urlParamsObj => {
_mapUrlParamsToQueryState = (urlParamsObj) => {
const result = {};
Object.keys(urlParamsObj).forEach(paramKey => {
Object.keys(urlParamsObj).forEach((paramKey) => {
if (this.urlParamValidator.isValid(paramKey, urlParamsObj[paramKey])) {
const queryStateKey = this.fromUrlParamsMapping[paramKey];
result[queryStateKey] = urlParamsObj[paramKey];
Expand All @@ -215,7 +215,7 @@ export class UrlHandlerApi {
// if only 1 filter, create an array with one element
urlParamsObj[paramKey] = [urlParamsObj[paramKey]];
}
result[queryStateKey] = urlParamsObj[paramKey].map(filter =>
result[queryStateKey] = urlParamsObj[paramKey].map((filter) =>
this._filterStringToList(filter)
);
}
Expand All @@ -226,7 +226,7 @@ export class UrlHandlerApi {

_mergeParamsIntoState = (urlStateObj, queryState) => {
const _queryState = _cloneDeep(queryState);
Object.keys(urlStateObj).forEach(stateKey => {
Object.keys(urlStateObj).forEach((stateKey) => {
if (stateKey in _queryState) {
_queryState[stateKey] = urlStateObj[stateKey];
}
Expand Down
8 changes: 5 additions & 3 deletions src/lib/api/contrib/elasticsearch/ESResponseSerializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ export class ESResponseSerializer {
* @param {object} payload the backend response payload
*/
serialize(payload) {
const { aggregations, hits, ...extras } = payload;
return {
aggregations: payload.aggregations || {},
hits: payload.hits.hits.map(hit => hit._source),
total: payload.hits.total.value,
aggregations: aggregations || {},
hits: hits.hits.map((hit) => hit._source),
total: hits.total.value,
extras: extras,
};
}
}
8 changes: 5 additions & 3 deletions src/lib/api/contrib/invenio/InvenioResponseSerializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ export class InvenioResponseSerializer {
* @param {object} payload the backend response payload
*/
serialize(payload) {
const { aggregations, hits, ...extras } = payload;
return {
aggregations: payload.aggregations || {},
hits: payload.hits.hits,
total: payload.hits.total,
aggregations: aggregations || {},
hits: hits.hits,
total: hits.total,
extras: extras,
};
}
}
2 changes: 2 additions & 0 deletions src/lib/components/ReactSearchKit/ReactSearchKit.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class ReactSearchKit extends Component {
? props.urlHandlerApi.customHandler ||
new UrlHandlerApi(props.urlHandlerApi.overrideConfig)
: null,
updateQueryStateFromResponse: props.updateQueryStateFromResponse,
searchOnInit: props.searchOnInit,
initialQueryState: props.initialQueryState,
};
Expand Down Expand Up @@ -97,6 +98,7 @@ ReactSearchKit.defaultProps = {
eventListenerEnabled: false,
overridableId: '',
initialQueryState: {},
updateQueryStateFromResponse: false,
};

export default Overridable.component('ReactSearchKit', ReactSearchKit);
82 changes: 56 additions & 26 deletions src/lib/state/actions/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,31 @@ import {
RESULTS_UPDATE_LAYOUT,
} from '../types';

export const setInitialState = initialState => {
return dispatch => {
export const setInitialState = (initialState) => {
return (dispatch) => {
dispatch({
type: SET_QUERY_COMPONENT_INITIAL_STATE,
payload: initialState,
});
};
};

export const onAppInitialized = searchOnInit => {
return dispatch => {
export const onAppInitialized = (searchOnInit) => {
return (dispatch, getState, config) => {
if (searchOnInit) {
dispatch(executeQuery({ shouldUpdateUrlQueryString: false }));
dispatch(
executeQuery({
shouldUpdateUrlQueryString: false,
shouldUpdateStateFromResponse:
config.updateQueryStateFromResponse || false,
})
);
}
};
};

export const updateQueryString = queryString => {
return dispatch => {
export const updateQueryString = (queryString) => {
return (dispatch) => {
dispatch({
type: SET_QUERY_STRING,
payload: queryString,
Expand All @@ -55,7 +61,7 @@ export const updateQueryString = queryString => {
};

export const updateQuerySorting = (sortByValue, sortOrderValue) => {
return dispatch => {
return (dispatch) => {
dispatch({
type: SET_QUERY_SORTING,
payload: { sortBy: sortByValue, sortOrder: sortOrderValue },
Expand All @@ -64,8 +70,8 @@ export const updateQuerySorting = (sortByValue, sortOrderValue) => {
};
};

export const updateQuerySortBy = sortByValue => {
return dispatch => {
export const updateQuerySortBy = (sortByValue) => {
return (dispatch) => {
dispatch({
type: SET_QUERY_SORT_BY,
payload: sortByValue,
Expand All @@ -74,29 +80,29 @@ export const updateQuerySortBy = sortByValue => {
};
};

export const updateQuerySortOrder = sortOrderValue => {
return dispatch => {
export const updateQuerySortOrder = (sortOrderValue) => {
return (dispatch) => {
dispatch({ type: SET_QUERY_SORT_ORDER, payload: sortOrderValue });
dispatch(executeQuery());
};
};

export const updateQueryPaginationPage = page => {
return dispatch => {
export const updateQueryPaginationPage = (page) => {
return (dispatch) => {
dispatch({ type: SET_QUERY_PAGINATION_PAGE, payload: page });
dispatch(executeQuery());
};
};

export const updateQueryPaginationSize = size => {
return dispatch => {
export const updateQueryPaginationSize = (size) => {
return (dispatch) => {
dispatch({ type: SET_QUERY_PAGINATION_SIZE, payload: size });
dispatch(executeQuery());
};
};

export const updateQueryFilters = filters => {
return dispatch => {
export const updateQueryFilters = (filters) => {
return (dispatch) => {
dispatch({
type: SET_QUERY_FILTERS,
payload: filters,
Expand All @@ -105,7 +111,7 @@ export const updateQueryFilters = filters => {
};
};

export const updateResultsLayout = layout => {
export const updateResultsLayout = (layout) => {
return async (dispatch, getState, config) => {
const urlHandlerApi = config.urlHandlerApi;
if (urlHandlerApi) {
Expand All @@ -125,20 +131,39 @@ export const updateResultsLayout = layout => {
};

export const resetQuery = () => {
return dispatch => {
return (dispatch) => {
dispatch({
type: RESET_QUERY,
});
dispatch(executeQuery());
};
};

export const updateQueryStateFromResponse = (responseState) => {
return (dispatch, getState, config) => {
let queryState = _cloneDeep(getState().query);
const urlHandlerApi = config.urlHandlerApi;
queryState = {
...queryState,
...responseState,
};
dispatch({
type: SET_QUERY_STATE,
payload: queryState,
});
if (urlHandlerApi) {
urlHandlerApi.replace(queryState);
}
};
};

export const executeQuery = ({
shouldUpdateUrlQueryString = true,
shouldReplaceUrlQueryString = false,
shouldUpdateStateFromResponse = false,
} = {}) => {
return async (dispatch, getState, config) => {
const queryState = _cloneDeep(getState().query);
let queryState = _cloneDeep(getState().query);
const searchApi = config.searchApi;
const urlHandlerApi = config.urlHandlerApi;

Expand All @@ -153,12 +178,17 @@ export const executeQuery = ({
dispatch({ type: RESULTS_LOADING });
try {
const response = await searchApi.search(queryState);
if (shouldUpdateStateFromResponse) {
dispatch(updateQueryStateFromResponse(response.extras));
}

dispatch({
type: RESULTS_FETCH_SUCCESS,
payload: {
aggregations: response.aggregations,
hits: response.hits,
total: response.total,
extras: response.extras,
},
});
} catch (reason) {
Expand All @@ -168,8 +198,8 @@ export const executeQuery = ({
};
};

export const updateSuggestions = suggestionString => {
return dispatch => {
export const updateSuggestions = (suggestionString) => {
return (dispatch) => {
dispatch({
type: SET_SUGGESTION_STRING,
payload: suggestionString,
Expand Down Expand Up @@ -198,7 +228,7 @@ export const executeSuggestionQuery = () => {
};

export const clearSuggestions = () => {
return dispatch => {
return (dispatch) => {
dispatch({
type: CLEAR_QUERY_SUGGESTIONS,
payload: {
Expand All @@ -208,8 +238,8 @@ export const clearSuggestions = () => {
};
};

export const updateQueryState = queryState => {
return dispatch => {
export const updateQueryState = (queryState) => {
return (dispatch) => {
dispatch({
type: SET_QUERY_STATE,
payload: queryState,
Expand Down
1 change: 1 addition & 0 deletions src/lib/state/reducers/results.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default (state = {}, action) => {
aggregations: action.payload.aggregations,
hits: action.payload.hits,
total: action.payload.total,
extras: action.payload.extras,
},
error: {},
};
Expand Down
Loading

0 comments on commit 2e46338

Please sign in to comment.