UNPKG

@gooddata/gooddata-js

Version:
169 lines (144 loc) 5.29 kB
// (C) 2007-2020 GoodData Corporation import { VisualizationObject, IVisualizationWidget } from "@gooddata/typings"; import isEmpty from "lodash/isEmpty"; import omit from "lodash/omit"; import isArray from "lodash/isArray"; import isObject from "lodash/isObject"; import isString from "lodash/isString"; import stringify from "json-stable-stringify"; import { v4 as uuid } from "uuid"; import { IProperties } from "./interfaces"; import { isUri } from "./DataLayer/helpers/uri"; /* * Helpers */ const getReferenceValue = (id: string, references: VisualizationObject.IReferenceItems) => references[id]; const getReferenceId = (value: string, references: VisualizationObject.IReferenceItems) => Object.keys(references).find(id => references[id] === value); type IdGenerator = () => string; const defaultIdGenerator: IdGenerator = () => uuid().replace(/-/g, ""); type StringTransformation = (value: string) => string; /** * Recursively traverses the object and tries to apply a conversion to every string value */ const traverse = (obj: any, convert: StringTransformation): any => { if (isArray(obj)) { return obj.map(a => traverse(a, convert)); } else if (isObject(obj)) { const object = obj as Record<string, any>; return Object.keys(object).reduce((result: any, key: string) => { result[key] = traverse(object[key], convert); return result; }, {} as any); } else if (isString(obj)) { return convert(obj); } else { return obj; } }; interface IConversionResult { convertedProperties: IProperties; convertedReferences: VisualizationObject.IReferenceItems; } type ConversionFunction = ( originalProperties: IProperties, originalReferences: VisualizationObject.IReferenceItems, idGenerator: IdGenerator, ) => IConversionResult; export type IObjectWithProperties = VisualizationObject.IVisualizationObject | IVisualizationWidget; export type ReferenceConverter = ( mdObject: IObjectWithProperties, idGenerator?: IdGenerator, ) => IObjectWithProperties; const createConverter = (conversionFunction: ConversionFunction): ReferenceConverter => < T extends IObjectWithProperties >( mdObject: T, idGenerator: IdGenerator = defaultIdGenerator, ): T => { const { content } = mdObject; if (!content) { return mdObject; } const { properties } = content; if (!properties) { return mdObject; } // prepare result objects const originalProperties: IProperties = JSON.parse(properties); const originalReferences = content.references || {}; const { convertedProperties, convertedReferences } = conversionFunction( originalProperties, originalReferences, idGenerator, ); // set the new properties and references const referencesProp = isEmpty(convertedReferences) ? undefined : { references: convertedReferences }; const result: T = { ...mdObject, content: { ...omit(mdObject.content, "references"), properties: stringify(convertedProperties), ...referencesProp, }, }; return result; }; /* * Conversion from References to URIs */ const convertReferenceToUri = ( references: VisualizationObject.IReferenceItems, ): StringTransformation => value => getReferenceValue(value, references) || value; /** * Converts reference based values to actual URIs * * @param mdObject The object to convert properties of * @param [idGenerator=uuid] Function that returns unique ids */ export const convertReferencesToUris = createConverter((originalProperties, originalReferences) => { const convertedProperties = traverse(originalProperties, convertReferenceToUri(originalReferences)); return { convertedProperties, convertedReferences: originalReferences, }; }); /* * Conversion from URIs to References */ const createUriToReferenceConverter = ( originalReferences: VisualizationObject.IReferenceItems, idGenerator: IdGenerator, ) => { const convertedReferences: VisualizationObject.IReferenceItems = {}; return { convertedReferences, conversion: (value: string) => { if (!isUri(value)) { return value; } const id = getReferenceId(value, originalReferences) || // try to reuse original references getReferenceId(value, convertedReferences) || // or use already converted new references idGenerator(); // or get a completely new id convertedReferences[id] = value; return id; }, }; }; /** * Converts URIs to reference based values * * @param mdObject The object to convert properties of * @param [idGenerator=uuid] Function that returns unique ids */ export const convertUrisToReferences = createConverter( (originalProperties, originalReferences, idGenerator) => { const converter = createUriToReferenceConverter(originalReferences, idGenerator); const convertedProperties = traverse(originalProperties, converter.conversion); return { convertedProperties, convertedReferences: converter.convertedReferences, }; }, );