Skip to content

Commit

Permalink
fix(apiQueries,reduxHelpers): issues/380 query schema (#381)
Browse files Browse the repository at this point in the history
* apiQueries, reduxHelpers, parse queries for specific API endpoints
* openshiftView, rhelView, apply parseRhsmQuery
  • Loading branch information
cdcabrera committed Aug 20, 2020
1 parent c3a214e commit 6b05ebf
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 33 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@
"!src/index.js",
"!src/setupTests.js",
"!src/components/app.js",
"!src/helpers/index.js",
"!src/common/index.js",
"!src/redux/index.js",
"!src/redux/store.js",
"!src/redux/middleware/**",
"!src/redux/actions/index.js",
"!src/redux/common/index.js",
"!src/redux/reducers/index.js",
"!src/redux/selectors/index.js"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ exports[`OpenshiftView Component should display an alternate graph on query-stri
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
}
viewId="OpenShift"
Expand Down Expand Up @@ -110,7 +108,6 @@ exports[`OpenshiftView Component should display an alternate graph on query-stri
productId="lorem ipsum"
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
Expand Down Expand Up @@ -172,8 +169,6 @@ exports[`OpenshiftView Component should have a fallback title: title 1`] = `
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
}
viewId="OpenShift"
Expand Down Expand Up @@ -231,7 +226,6 @@ exports[`OpenshiftView Component should have a fallback title: title 1`] = `
productId="lorem ipsum"
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
Expand Down Expand Up @@ -413,8 +407,6 @@ exports[`OpenshiftView Component should render a non-connected component: non-co
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
}
viewId="OpenShift"
Expand Down Expand Up @@ -472,7 +464,6 @@ exports[`OpenshiftView Component should render a non-connected component: non-co
productId="lorem ipsum"
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
Expand Down
11 changes: 6 additions & 5 deletions src/components/openshiftView/openshiftView.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import { Badge, Button } from '@patternfly/react-core';
import { PageLayout, PageHeader, PageSection, PageToolbar } from '../pageLayout/pageLayout';
import { RHSM_API_QUERY_GRANULARITY_TYPES as GRANULARITY_TYPES, RHSM_API_QUERY_TYPES } from '../../types/rhsmApiTypes';
import { connect, reduxSelectors } from '../../redux';
import { apiQueries, connect, reduxSelectors } from '../../redux';
import GraphCard from '../graphCard/graphCard';
import C3GraphCard from '../c3GraphCard/c3GraphCard';
import { Select } from '../form/select';
Expand Down Expand Up @@ -89,21 +89,22 @@ class OpenshiftView extends React.Component {
const { graphFilters, inventoryFilters } = this.state;
const { query, initialToolbarFilters, location, routeDetail, t, viewId } = this.props;
const isC3 = location?.parsedSearch?.c3 === '';
const { graphQuery, inventoryQuery, toolbarQuery } = apiQueries.parseRhsmQuery(query);

return (
<PageLayout>
<PageHeader viewId={viewId}>
{t(`curiosity-view.title`, { appName: helpers.UI_DISPLAY_NAME, context: viewId })}
</PageHeader>
<PageToolbar>
<Toolbar filterOptions={initialToolbarFilters} query={query} viewId={viewId} />
<Toolbar filterOptions={initialToolbarFilters} query={toolbarQuery} viewId={viewId} />
</PageToolbar>
<PageSection>
{(isC3 && (
<C3GraphCard
key={routeDetail.pathParameter}
filterGraphData={graphFilters}
query={query}
query={graphQuery}
productId={routeDetail.pathParameter}
viewId={viewId}
cardTitle={t('curiosity-graph.cardHeading')}
Expand All @@ -115,7 +116,7 @@ class OpenshiftView extends React.Component {
<GraphCard
key={routeDetail.pathParameter}
filterGraphData={graphFilters}
query={query}
query={graphQuery}
productId={routeDetail.pathParameter}
viewId={viewId}
cardTitle={t('curiosity-graph.cardHeading')}
Expand All @@ -129,7 +130,7 @@ class OpenshiftView extends React.Component {
<InventoryList
key={routeDetail.pathParameter}
filterInventoryData={inventoryFilters}
query={query}
query={inventoryQuery}
productId={routeDetail.pathParameter}
viewId={viewId}
cardTitle={t('curiosity-inventory.cardHeading')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ exports[`RhelView Component should display an alternate graph on query-string up
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
}
viewId="RHEL"
Expand Down Expand Up @@ -97,7 +95,6 @@ exports[`RhelView Component should display an alternate graph on query-string up
productId="lorem ipsum"
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
Expand Down Expand Up @@ -173,8 +170,6 @@ exports[`RhelView Component should have a fallback title: title 1`] = `
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
}
viewId="RHEL"
Expand Down Expand Up @@ -205,7 +200,6 @@ exports[`RhelView Component should have a fallback title: title 1`] = `
productId="lorem ipsum"
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
Expand Down Expand Up @@ -393,8 +387,6 @@ exports[`RhelView Component should render a non-connected component: non-connect
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
}
viewId="RHEL"
Expand Down Expand Up @@ -425,7 +417,6 @@ exports[`RhelView Component should render a non-connected component: non-connect
productId="lorem ipsum"
query={
Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
}
Expand Down
11 changes: 6 additions & 5 deletions src/components/rhelView/rhelView.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { Badge, Button } from '@patternfly/react-core';
import { PageLayout, PageHeader, PageSection, PageToolbar } from '../pageLayout/pageLayout';
import { RHSM_API_QUERY_GRANULARITY_TYPES as GRANULARITY_TYPES, RHSM_API_QUERY_TYPES } from '../../types/rhsmApiTypes';
import { connect, reduxSelectors } from '../../redux';
import { apiQueries, connect, reduxSelectors } from '../../redux';
import GraphCard from '../graphCard/graphCard';
import C3GraphCard from '../c3GraphCard/c3GraphCard';
import Toolbar from '../toolbar/toolbar';
Expand Down Expand Up @@ -44,21 +44,22 @@ class RhelView extends React.Component {
viewId
} = this.props;
const isC3 = location?.parsedSearch?.c3 === '';
const { graphQuery, toolbarQuery, inventoryQuery } = apiQueries.parseRhsmQuery(query);

return (
<PageLayout>
<PageHeader viewId={viewId}>
{t(`curiosity-view.title`, { appName: helpers.UI_DISPLAY_NAME, context: viewId })}
</PageHeader>
<PageToolbar>
<Toolbar filterOptions={initialToolbarFilters} query={query} viewId={viewId} />
<Toolbar filterOptions={initialToolbarFilters} query={toolbarQuery} viewId={viewId} />
</PageToolbar>
<PageSection>
{(isC3 && (
<C3GraphCard
key={routeDetail.pathParameter}
filterGraphData={initialGraphFilters}
query={query}
query={graphQuery}
productId={routeDetail.pathParameter}
viewId={viewId}
cardTitle={t('curiosity-graph.socketsHeading')}
Expand All @@ -68,7 +69,7 @@ class RhelView extends React.Component {
<GraphCard
key={routeDetail.pathParameter}
filterGraphData={initialGraphFilters}
query={query}
query={graphQuery}
productId={routeDetail.pathParameter}
viewId={viewId}
cardTitle={t('curiosity-graph.socketsHeading')}
Expand All @@ -80,7 +81,7 @@ class RhelView extends React.Component {
<InventoryList
key={routeDetail.pathParameter}
filterInventoryData={initialInventoryFilters}
query={query}
query={inventoryQuery}
productId={routeDetail.pathParameter}
viewId={viewId}
cardTitle={t('curiosity-inventory.cardHeading')}
Expand Down
29 changes: 29 additions & 0 deletions src/redux/common/__tests__/__snapshots__/apiQueries.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ApiQueries should have specific functions: apiQueries 1`] = `
Object {
"parseRhsmQuery": [Function],
}
`;

exports[`ApiQueries should parse a query object into specific api facets: rhsm 1`] = `
Object {
"graphQuery": Object {
"granularity": "daily",
},
"inventoryQuery": Object {
"limit": 10,
"offset": 0,
},
"query": Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
},
"toolbarQuery": Object {
"granularity": "daily",
"limit": 10,
"offset": 0,
},
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ Array [
]
`;

exports[`ReduxHelpers should generate an expected API query with an existing schema: rhsm query 1`] = `
Object {
"granularity": "daily",
}
`;

exports[`ReduxHelpers should generate an expected API response with an existing schema: array 1`] = `
Array [
Object {
Expand Down Expand Up @@ -261,6 +267,7 @@ Object {
"getMessageFromResults": [Function],
"getSingleResponseFromResultArray": [Function],
"getStatusFromResults": [Function],
"setApiQuery": [Function],
"setNormalizedResponse": [Function],
"setResponseSchemas": [Function],
"setStateProp": [Function],
Expand Down
20 changes: 20 additions & 0 deletions src/redux/common/__tests__/apiQueries.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { apiQueries } from '../apiQueries';
import {
RHSM_API_QUERY_GRANULARITY_TYPES as GRANULARITY_TYPES,
RHSM_API_QUERY_TYPES
} from '../../../types/rhsmApiTypes';

describe('ApiQueries', () => {
it('should have specific functions', () => {
expect(apiQueries).toMatchSnapshot('apiQueries');
});

it('should parse a query object into specific api facets', () => {
const rhsmApiQuery = {
[RHSM_API_QUERY_TYPES.GRANULARITY]: GRANULARITY_TYPES.DAILY,
[RHSM_API_QUERY_TYPES.LIMIT]: 10,
[RHSM_API_QUERY_TYPES.OFFSET]: 0
};
expect(apiQueries.parseRhsmQuery(rhsmApiQuery)).toMatchSnapshot('rhsm');
});
});
14 changes: 14 additions & 0 deletions src/redux/common/__tests__/reduxHelpers.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { reduxHelpers } from '../reduxHelpers';
import {
RHSM_API_QUERY_GRANULARITY_TYPES as GRANULARITY_TYPES,
RHSM_API_QUERY_TYPES,
RHSM_API_QUERY_SET_REPORT_CAPACITY_TYPES
} from '../../../types/rhsmApiTypes';

describe('ReduxHelpers', () => {
it('should have specific functions', () => {
Expand All @@ -12,6 +17,15 @@ describe('ReduxHelpers', () => {
expect(reduxHelpers.HTTP_STATUS_RANGE('lorem')).toBe('lorem_STATUS_RANGE');
});

it('should generate an expected API query with an existing schema', () => {
const rhsmQuery = {
[RHSM_API_QUERY_TYPES.GRANULARITY]: GRANULARITY_TYPES.DAILY,
[RHSM_API_QUERY_TYPES.LIMIT]: 10,
[RHSM_API_QUERY_TYPES.OFFSET]: 0
};
expect(reduxHelpers.setApiQuery(rhsmQuery, RHSM_API_QUERY_SET_REPORT_CAPACITY_TYPES)).toMatchSnapshot('rhsm query');
});

it('should generate an expected API response with an existing schema', () => {
expect(reduxHelpers.setResponseSchemas([{ LOREM: 'ipsum' }, { HELLO: 'world' }])).toMatchSnapshot('object');
expect(
Expand Down
26 changes: 26 additions & 0 deletions src/redux/common/apiQueries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { rhsmApiTypes } from '../../types/rhsmApiTypes';
import { reduxHelpers } from './reduxHelpers';

/**
* Parse a query object against a schema for specific RHSM endpoints.
*
* @param {object} query
* @returns {{query: {}, graphQuery: {}, inventoryQuery: {}, toolbarQuery: {}}}
*/
const parseRhsmQuery = (query = {}) => {
const graphQuery = reduxHelpers.setApiQuery(query, rhsmApiTypes.RHSM_API_QUERY_SET_REPORT_CAPACITY_TYPES);
const inventoryQuery = reduxHelpers.setApiQuery(query, rhsmApiTypes.RHSM_API_QUERY_SET_INVENTORY_TYPES);

return {
query,
graphQuery,
inventoryQuery,
toolbarQuery: query
};
};

const apiQueries = {
parseRhsmQuery
};

export { apiQueries as default, apiQueries };
4 changes: 4 additions & 0 deletions src/redux/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { apiQueries } from './apiQueries';
import { reduxHelpers } from './reduxHelpers';

export { reduxHelpers as default, reduxHelpers, apiQueries };
28 changes: 27 additions & 1 deletion src/redux/common/reduxHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,39 @@ const REJECTED_ACTION = (base = '') => `${base}_REJECTED`;
*/
const HTTP_STATUS_RANGE = status => `${status}_STATUS_RANGE`;

/**
* Set an API query based on specific API "acceptable values" schema.
*
* @param {object} values
* @param {object} schema
* @param {*} [initialValue]
* @returns {object}
*/
const setApiQuery = (values, schema, initialValue) => {
const generated = {};
const schemaArr = (schema && Object.values(schema)) || [];

schemaArr.forEach(value => {
if (initialValue === undefined) {
if (value in values) {
generated[value] = values?.[value];
}
} else {
generated[value] = values?.[value] || initialValue;
}
});

return generated;
};

// ToDo: research applying a maintained schema map/normalizer such as, normalizr
/**
* Apply a set of schemas using either an array of objects in the
* form of [{ madeUpKey: 'some_api_key' }], or an array of arrays
* in the form of [['some_api_key','another_api_key']]
*
* @param {Array} schemas
* @param {*} initialValue
* @param {*} [initialValue]
* @returns {Array}
*/
const setResponseSchemas = (schemas = [], initialValue) =>
Expand Down Expand Up @@ -392,6 +417,7 @@ const reduxHelpers = {
PENDING_ACTION,
REJECTED_ACTION,
HTTP_STATUS_RANGE,
setApiQuery,
setResponseSchemas,
setNormalizedResponse,
generatedPromiseActionReducer,
Expand Down
Loading

0 comments on commit 6b05ebf

Please sign in to comment.