diff --git a/src/charts/grid.tsx b/src/charts/grid.tsx index 2c115fd..8af7f97 100644 --- a/src/charts/grid.tsx +++ b/src/charts/grid.tsx @@ -18,7 +18,12 @@ const switchMode = (currentMode: string) => { type OnChangeProps = (input: number | string) => void; -type FilterIndexSignature = "integer" | "number" | "string"; +// Only some field types are filterable +// Iterate over a union type +// https://stackoverflow.com/a/59420158/5129731 +// Members come from values of Field.type +const filterableFields= ['integer' , 'number' , 'string'] as const; +type FilterIndexSignature = typeof filterableFields[number]; interface NumberFilterProps { onChange: OnChangeProps; @@ -147,6 +152,18 @@ interface Props { theme?: string; } +const filterableFieldSet = new Set(filterableFields); +function isFilterableFieldType (fieldType: any): fieldType is FilterIndexSignature { + return filterableFieldSet.has(fieldType); +} + +// Non-primitive field types cannot be outputted directly as React children +// Members come from possible values of Field.type +const shouldStringifyFieldSet = new Set([ + 'boolean', + 'object' +]) + class DataResourceTransformGrid extends React.PureComponent { static defaultProps = { metadata: {}, @@ -173,21 +190,13 @@ class DataResourceTransformGrid extends React.PureComponent { const { primaryKey = [] } = schema; const tableColumns = schema.fields.map((field: Dx.Field) => { - if ( - field.type === "string" || - field.type === "number" || - field.type === "integer" - ) { + if (isFilterableFieldType(field.type)) { return { Header: field.name, accessor: field.name, fixed: primaryKey.indexOf(field.name) !== -1 && "left", filterMethod: (filter: Dx.JSONObject, row: Dx.JSONObject) => { - if ( - field.type === "string" || - field.type === "number" || - field.type === "integer" - ) { + if (isFilterableFieldType(field.type)) { return filterMethod[field.type](filters[field.name])(filter, row); } }, @@ -197,17 +206,19 @@ class DataResourceTransformGrid extends React.PureComponent { field.name, (newFilter: { [key: string]: Function }) => { this.setState({ filters: { ...filters, ...newFilter } }); - } - ) + }, + ), }; } else { return { Header: field.name, id: field.name, accessor: (rowValue: { [key: string]: any }) => { - return field.type === "boolean" ? rowValue[field.name].toString() : rowValue[field.name] + return shouldStringifyFieldSet.has(field.type) + ? JSON.stringify(rowValue[field.name]) + : rowValue[field.name]; }, - fixed: primaryKey.indexOf(field.name) !== -1 && "left" + fixed: primaryKey.indexOf(field.name) !== -1 && "left", }; } }); diff --git a/src/utilities/types.ts b/src/utilities/types.ts index eb379f6..7445d62 100644 --- a/src/utilities/types.ts +++ b/src/utilities/types.ts @@ -78,7 +78,9 @@ export interface Schema { export const defaultPrimaryKey = "dx-default-pk"; export interface Field { name: string; - type: string; + // Types are based on the json-schema standard, with some variations + // https://specs.frictionlessdata.io/table-schema/#types-and-formats + type: 'string' | 'integer' | 'number' | 'boolean' | 'datetime' | 'object' | string; // Other types are permitted, but not explicitly handled }