diff --git a/CHANGELOG.md b/CHANGELOG.md index ea4a2792..46d245f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * [UIPQB-70](https://issues.folio.org/browse/UIPQB-70) Array fields support verification. * [UIPQB-80](https://issues.folio.org/browse/UIPQB-80) Add operators for NumberType and adjust operators for IntegerType. * [UIPQB-73](https://folio-org.atlassian.net/browse/UIPQB-73) Result Viewer shows current date if date column is not present. +* [UIPQB-82](https://folio-org.atlassian.net/browse/UIPQB-82) [Query Builder] Support querying based on nested objects within arrays. ## [1.0.0](https://github.com/folio-org/ui-plugin-query-builder/tree/v1.0.0) (2023-10-12) diff --git a/src/QueryBuilder/QueryBuilder/helpers/selectOptions.js b/src/QueryBuilder/QueryBuilder/helpers/selectOptions.js index a4438284..d257ec11 100644 --- a/src/QueryBuilder/QueryBuilder/helpers/selectOptions.js +++ b/src/QueryBuilder/QueryBuilder/helpers/selectOptions.js @@ -115,8 +115,21 @@ export const getOperatorOptions = ({ export const getFieldOptions = (options) => { const ids = options?.filter(o => Boolean(o.idColumnName)).map(o => o.idColumnName) || []; - return options?.filter(o => !ids.includes(o.name)).map(o => ({ - label: o.labelAlias, + return options?.filter(o => !ids.includes(o.name)).reduce((acc, item) => { + if (item.dataType.itemDataType?.properties) { + const nestedNamedFields = item.dataType.itemDataType?.properties.map(child => ({ + ...child, + name: `${item.name}[*]->${child.name}`, + })); + + acc = [...acc, item, ...nestedNamedFields]; + } else { + acc.push(item); + } + + return acc; + }, []).map(o => ({ + label: o.labelAliasFullyQualified || o.labelAlias, value: o.name, dataType: o.dataType.dataType, source: o.source, diff --git a/src/QueryBuilder/QueryBuilder/helpers/selectOptions.test.js b/src/QueryBuilder/QueryBuilder/helpers/selectOptions.test.js index 65bee6f3..ab42ee1e 100644 --- a/src/QueryBuilder/QueryBuilder/helpers/selectOptions.test.js +++ b/src/QueryBuilder/QueryBuilder/helpers/selectOptions.test.js @@ -269,3 +269,90 @@ describe('select options', () => { }); }); }); + +describe('getFieldOptions', () => { + it('returns the expected field options', () => { + // Mock input options + const options = { + columns: [ + { + 'name': 'user_full_name', + 'dataType': { + 'dataType': 'stringType', + }, + 'labelAlias': 'User full name', + 'visibleByDefault': true, + }, + { + 'name': 'user_active', + 'dataType': { + 'dataType': 'object_type', + 'itemDataType': { 'properties': [ + { + 'name': 'user_field1', + 'dataType': { + 'dataType': 'stringType', + }, + 'labelAlias': 'User full name', + 'labelAliasFullyQualified': 'User userField1', + 'visibleByDefault': true, + }, + { + 'name': 'user_field2', + 'dataType': { + 'dataType': 'stringType', + }, + 'labelAlias': 'User full name', + 'labelAliasFullyQualified': 'User userField2', + 'visibleByDefault': true, + }, + ] }, + }, + 'labelAlias': 'User active', + 'visibleByDefault': true, + 'values': [ + { label: 'True', value: 'true' }, + { label: 'False', value: 'false' }, + ], + }, + ], + }; + + const optionsResult = getFieldOptions(options.columns); + + const expectedOutput = [ + { + 'dataType': 'stringType', + 'label': 'User full name', + 'value': 'user_full_name', + }, + { + 'dataType': 'object_type', + 'label': 'User active', + 'value': 'user_active', + 'values': [ + { + 'label': 'True', + 'value': 'true', + }, + { + 'label': 'False', + 'value': 'false', + }, + ], + }, + { + 'dataType': 'stringType', + 'label': 'User userField1', + 'value': 'user_active[*]->user_field1', + }, + { + 'dataType': 'stringType', + 'label': 'User userField2', + 'value': 'user_active[*]->user_field2', + }, + ]; + + expect(optionsResult).toEqual(expectedOutput); + }); +});