Skip to content

Commit

Permalink
UIIN-2445: Escape quotes to search for Subjects and Contributor. (#2172)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmytro-Melnyshyn authored Jun 7, 2023
1 parent 6144be7 commit fa846ed
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* Prevent double-escaping of query when Browsing. Fixes UIIN-2435.
* When adding items, cursor is in the barcode field as default. Refs UIIN-2205.
* Quick export from instance detail view. Refs UIIN-2430.
* Escape quotes to search for Subjects and Contributor. Refs UIIN-2445.

## [9.4.5](https://github.com/folio-org/ui-inventory/tree/v9.4.5) (2023-04-03)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v9.4.4...v9.4.5)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('InstanceMovementDetails', () => {
});
it('render Action Menu', () => {
renderInstanceMovementDetails();
const actionMenu = screen.getByText(/Action Menu/i)
const actionMenu = screen.getByText(/Action Menu/i);
expect(actionMenu).toBeInTheDocument();
});
it('render HoldingsListContainer', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/BrowseResultsList/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const getSearchParams = (row, qindex) => {
[browseModeOptions.SUBJECTS]: {
qindex: queryIndexes.SUBJECT,
query: row.value,
authorityId: row.authorityId,
...(row.authorityId && { filters: `${FACETS.AUTHORITY_ID}.${row.authorityId}` }),
},
};

Expand Down
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ export const FACETS = {
NAME_TYPE: 'nameType',
SEARCH_CONTRIBUTORS: 'searchContributors',
HOLDINGS_TYPE: 'holdingsType',
AUTHORITY_ID: 'authorityId',
};

export const FACETS_CQL = {
Expand Down Expand Up @@ -284,6 +285,7 @@ export const FACETS_CQL = {
NAME_TYPE: 'contributorNameTypeId',
SEARCH_CONTRIBUTORS: 'contributors.contributorNameTypeId',
HOLDINGS_TYPE: 'holdings.holdingsTypeId',
AUTHORITY_ID: 'authorityId',
};

export const FACETS_TO_REQUEST = {
Expand Down
7 changes: 6 additions & 1 deletion src/filterConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ export const instanceFilterConfig = [
cql: FACETS_CQL.SEARCH_CONTRIBUTORS,
values: [],
},
{
name: FACETS.AUTHORITY_ID,
cql: FACETS_CQL.AUTHORITY_ID,
values: [],
},
];

export const instanceIndexes = [
Expand All @@ -122,7 +127,7 @@ export const instanceIndexes = [
{ label: 'ui-inventory.search.oclc', value: 'oclc', queryTemplate: 'oclc="%{query.query}"' },
{ label: 'ui-inventory.search.instanceNotes', value: 'instanceNotes', queryTemplate: 'notes.note all "%{query.query}" or administrativeNotes all "%{query.query}"' },
{ label: 'ui-inventory.search.instanceAdministrativeNotes', value: 'instanceAdministrativeNotes', queryTemplate: 'administrativeNotes all "%{query.query}"' },
{ label: 'ui-inventory.subject', value: 'subject', queryTemplate: ({ query, authorityId }) => `subjects.value==/string "${query}"${authorityId ? ` and authorityId=="${authorityId}"` : ''}` },
{ label: 'ui-inventory.subject', value: 'subject', queryTemplate: 'subjects.value==/string "%{query.query}"' },
{ label: 'ui-inventory.effectiveCallNumberShelving', value: 'callNumber', queryTemplate: 'itemEffectiveShelvingOrder==/string "%{query.query}"' },
{ label: 'ui-inventory.instanceHrid', value: 'hrid', queryTemplate: 'hrid=="%{query.query}"' },
{ label: 'ui-inventory.instanceId', value: 'id', queryTemplate: 'id="%{query.query}"' },
Expand Down
14 changes: 3 additions & 11 deletions src/routes/buildManifestObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,24 @@ const INITIAL_RESULT_COUNT = 100;
const DEFAULT_SORT = 'title';

const getQueryTemplateContributor = (queryValue) => `contributors.name==/string "${queryValue}"`;
const getQueryTemplateSubjects = (queryValue, andAuthorityId) => `subjects.value==/string "${queryValue}"${andAuthorityId}`;
const getQueryTemplateCallNumber = (queryValue) => `itemEffectiveShelvingOrder==/string "${queryValue}"`;

export function buildQuery(queryParams, pathComponents, resourceData, logger, props) {
const { indexes, sortMap, filters } = getFilterConfig(queryParams.segment);
const query = { ...resourceData.query };
const queryIndex = queryParams?.qindex ?? 'all';
const queryValue = get(queryParams, 'query', '');
const authorityId = queryParams?.authorityId;
let queryTemplate = getQueryTemplate(queryIndex, indexes);

if (queryParams?.selectedBrowseResult) {
if (queryIndex === queryIndexes.SUBJECT) {
const queryVal = queryValue.replace(/"/g, '\\"');
const andAuthorityId = authorityId ? ` and authorityId==${authorityId}` : '';

queryTemplate = getQueryTemplateSubjects(queryVal, andAuthorityId);
}

if (queryIndex === queryIndexes.CALL_NUMBER) {
queryTemplate = getQueryTemplateCallNumber(queryValue);
}

if (queryIndex === queryIndexes.CONTRIBUTOR) {
queryTemplate = getQueryTemplateContributor(queryValue);
const escapedQueryValue = queryValue.replaceAll('"', '\\"');

queryTemplate = getQueryTemplateContributor(escapedQueryValue);
}

query.selectedBrowseResult = null; // reset this parameter so the next search uses `=` instead of `==/string`
Expand Down Expand Up @@ -174,7 +167,6 @@ export function buildManifestObject() {
filters: '',
sort: '',
selectedBrowseResult: false,
authorityId: '',
},
},
resultCount: { initialValue: INITIAL_RESULT_COUNT },
Expand Down
30 changes: 16 additions & 14 deletions src/routes/buildManifestObject.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const getBuildQueryArgs = ({

const defaultQueryParamsMap = {
[queryIndexes.CALL_NUMBER]: { qindex: queryIndexes.CALL_NUMBER, query: 'Some call number query' },
[queryIndexes.CONTRIBUTOR]: { qindex: queryIndexes.CONTRIBUTOR, query: 'Some contributor query' },
[queryIndexes.SUBJECT]: { qindex: queryIndexes.SUBJECT, query: 'Some subject query' },
[queryIndexes.CONTRIBUTOR]: { qindex: queryIndexes.CONTRIBUTOR, query: 'Some "contributor" query' },
[queryIndexes.SUBJECT]: { qindex: queryIndexes.SUBJECT, query: 'Some "subject" query' },
};

describe('buildQuery', () => {
Expand All @@ -39,30 +39,32 @@ describe('buildQuery', () => {
const queryParams = { ...defaultQueryParamsMap[qindex] };
const cql = buildQuery(...getBuildQueryArgs({ queryParams }));

const queryTemplate = getQueryTemplate(qindex);
expect(cql).toEqual(expect.stringContaining(`${queryTemplate.replace('%{query.query}', defaultQueryParamsMap[qindex].query)}`));
expect(cql).toContain('(contributors.name="Some \\"contributor\\" query")');
});

describe('\'Subject\' search option', () => {
describe('when there in no an authorityId in query params', () => {
it('should build query', () => {
describe('when a record is not linked with an authority record', () => {
it('should build query without the authorityId', () => {
const qindex = queryIndexes.SUBJECT;
const queryParams = { ...defaultQueryParamsMap[qindex] };
const cql = buildQuery(...getBuildQueryArgs({ queryParams }));

const queryTemplate = getQueryTemplate(qindex);
expect(cql).toEqual(expect.stringContaining(queryTemplate(queryParams)));
expect(cql).toEqual('(subjects.value==/string "Some \\"subject\\" query") sortby title');
});
});

describe('when there in an authorityId in query params', () => {
describe('when a record is linked with an authority record', () => {
it('should build query with the authorityId', () => {
const qindex = queryIndexes.SUBJECT;
const queryParams = { ...defaultQueryParamsMap[qindex], authorityId: 'UUID' };
const queryParams = {
...defaultQueryParamsMap[qindex],
filters: 'authorityId.37c01934-37c3-4874-a992-3912fcf526db',
};
const cql = buildQuery(...getBuildQueryArgs({ queryParams }));

const queryTemplate = getQueryTemplate(qindex);
expect(cql).toEqual(expect.stringContaining(queryTemplate(queryParams)));
expect(cql).toContain(
'(subjects.value==/string "Some \\"subject\\" query") and authorityId=="37c01934-37c3-4874-a992-3912fcf526db")'
);
});
});
});
Expand All @@ -88,7 +90,7 @@ describe('buildQuery', () => {
};
const cql = buildQuery(...getBuildQueryArgs({ queryParams }));

expect(cql).toEqual(expect.stringContaining(`contributors.name==/string "${defaultQueryParamsMap[qindex].query}"`));
expect(cql).toContain('(contributors.name==/string "Some \\"contributor\\" query")');
});

it('should build query for \'Subjects\' browse option', () => {
Expand All @@ -99,7 +101,7 @@ describe('buildQuery', () => {
};
const cql = buildQuery(...getBuildQueryArgs({ queryParams }));

expect(cql).toEqual(expect.stringContaining(`subjects.value==/string "${defaultQueryParamsMap[qindex].query}"`));
expect(cql).toContain('(subjects.value==/string "Some \\"subject\\" query")');
});
});
});
9 changes: 0 additions & 9 deletions test/jest/helpers/Harness.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,6 @@ Harness.propTypes = {
translations: PropTypes.object,
})
),
shouldMockOffsetSize: PropTypes.bool,
width: PropTypes.number,
height: PropTypes.number,
};

Harness.defaultProps = {
width: 500,
height: 500,
shouldMockOffsetSize: true,
};

export default Harness;

0 comments on commit fa846ed

Please sign in to comment.