mirror of
https://github.com/datahub-project/datahub.git
synced 2025-07-16 05:34:54 +00:00
235 lines
7.1 KiB
TypeScript
235 lines
7.1 KiB
TypeScript
import { warn } from '@ember/debug';
|
|
import { ApiStatus } from 'wherehows-web/utils/api';
|
|
import { getJSON, putJSON } from 'wherehows-web/utils/api/fetcher';
|
|
import { datasetUrlById, datasetUrlByUrn } from 'wherehows-web/utils/api/datasets/shared';
|
|
import {
|
|
IDatasetProperties,
|
|
IDatasetPropertiesGetResponse,
|
|
IDatasetPinotPropertiesGetResponse,
|
|
IDatasetPinotProperties
|
|
} from 'wherehows-web/typings/api/datasets/properties';
|
|
|
|
/**
|
|
* Describes the interface for an element in the list generated by the buildPropertiesList function
|
|
* @interface IPropertyItem
|
|
*/
|
|
interface IPropertyItem {
|
|
isSelectController: boolean;
|
|
key: keyof IDatasetProperties;
|
|
value: string | Element;
|
|
}
|
|
|
|
/**
|
|
* Constructs the dataset properties endpoint url based on the id
|
|
* @param {number} id dataset id
|
|
*/
|
|
const datasetPropertiesUrlById = (id: number) => `${datasetUrlById(id)}/properties`;
|
|
|
|
const datasetDeprecationUrlById = (id: number) => `${datasetUrlById(id)}/deprecate`;
|
|
|
|
/**
|
|
* Returns the url for a dataset deprecation endpoint by urn
|
|
* @param {string} urn
|
|
* @return {string}
|
|
*/
|
|
const datasetDeprecationUrlByUrn = (urn: string) => `${datasetUrlByUrn(urn)}/deprecate`;
|
|
|
|
/**
|
|
* Reads the response from the dataset properties endpoint and returns properties if found
|
|
* @param {number} id the dataset id to get properties for
|
|
* @returns {IDatasetPropertiesGetResponse | IDatasetPinotPropertiesGetResponse}
|
|
*/
|
|
const readDatasetProperties = async <T extends IDatasetPropertiesGetResponse | IDatasetPinotPropertiesGetResponse>(
|
|
id: number
|
|
): Promise<IDatasetProperties> => {
|
|
const { status, properties, message } = await getJSON<T>({ url: datasetPropertiesUrlById(id) });
|
|
|
|
if (status === ApiStatus.OK && properties) {
|
|
return properties;
|
|
}
|
|
|
|
// treat the error status with a record not found msg as empty set
|
|
if (status === ApiStatus.ERROR && message === 'record not found') {
|
|
return {};
|
|
}
|
|
|
|
throw new Error('Exception occurred reading the dataset properties');
|
|
};
|
|
|
|
/**
|
|
* Formats the property value as a date string
|
|
* @param {keyof IDatasetProperties} property
|
|
* @param {*} value
|
|
* @returns {*}
|
|
*/
|
|
const formatPropertyDateValue = (property: keyof IDatasetProperties, value: any): any => {
|
|
const isoStringDateProperties = ['modification_time', 'begin_date', 'lumos_process_time', 'end_date', 'oracle_time'];
|
|
|
|
if (isoStringDateProperties.includes(property)) {
|
|
if (+value < 0) {
|
|
return value;
|
|
}
|
|
|
|
try {
|
|
return new Date(value).toISOString();
|
|
} catch (e) {
|
|
warn(`Property ${property} has an unexpected value ${value}`);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
if (property === 'dumpdate') {
|
|
return [['-', 0, 4], ['-', 4, 6], [' ', 6, 8], [':', 8, 10], [':', 10, 12], ['', 12, 14]].reduce(
|
|
(dateString, props: [string, number, number]): string => {
|
|
const [postfix, start, end] = props;
|
|
return value ? dateString + ('' + value).substring(start, end) + postfix : dateString;
|
|
},
|
|
''
|
|
);
|
|
}
|
|
|
|
return value;
|
|
};
|
|
|
|
/**
|
|
* Builds a list of IPropertyItem values
|
|
* @param {IDatasetProperties} properties
|
|
* @returns {Array<IPropertyItem>}
|
|
* @link IPropertyItem
|
|
*/
|
|
const buildPropertiesList = (properties: IDatasetProperties): Array<IPropertyItem> => {
|
|
return Object.keys(properties).reduce((propertiesList, property: keyof IDatasetProperties) => {
|
|
if (['elements', 'view_depends_on'].includes(property)) {
|
|
return propertiesList;
|
|
}
|
|
|
|
const typeofPropertyIsNotObject = typeof properties[property] !== 'object';
|
|
const connectionURL = properties['connectionURL'];
|
|
let value: string | Element;
|
|
let listItem: IPropertyItem = {
|
|
isSelectController: ['view_expanded_text', 'viewSqlText'].includes(property),
|
|
key: property,
|
|
value: window.JsonHuman.format(properties[property])
|
|
};
|
|
|
|
if (typeofPropertyIsNotObject) {
|
|
if (connectionURL) {
|
|
const list = connectionURL.split(',') || [];
|
|
value = list.length ? window.JsonHuman.format(list) : connectionURL;
|
|
} else {
|
|
const tempValue = formatPropertyDateValue(property, properties[property]);
|
|
value = !tempValue && tempValue !== 0 ? 'NULL' : tempValue;
|
|
}
|
|
|
|
listItem = { ...listItem, value };
|
|
}
|
|
|
|
return [...propertiesList, listItem];
|
|
}, []);
|
|
};
|
|
|
|
/**
|
|
* Reads the dataset properties returned by the properties endpoint and builds a list of IPropertyItem values
|
|
* @param {number} id
|
|
* @returns {Promise<Array<IPropertyItem>>}
|
|
*/
|
|
const readNonPinotProperties = async (id: number): Promise<Array<IPropertyItem>> => {
|
|
try {
|
|
return buildPropertiesList(<IDatasetProperties>await readDatasetProperties(id));
|
|
} catch (e) {
|
|
warn('Exception occurred building the properties list for non pinot properties');
|
|
throw e;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Describes the inteface of object returned from the api request to get pinot properties
|
|
* @interface IDatasetSamplesAndColumns
|
|
*/
|
|
interface IDatasetSamplesAndColumns {
|
|
hasSamples: boolean;
|
|
samples: Array<string>;
|
|
columns: Array<string>;
|
|
}
|
|
/**
|
|
* Extracts samples and columns for a dataset that is sourced from pinot
|
|
* @param {IDatasetPinotProperties} [properties=<IDatasetPinotProperties>{}]
|
|
* @returns
|
|
*/
|
|
const getDatasetSamplesAndColumns = (
|
|
properties: IDatasetPinotProperties = <IDatasetPinotProperties>{}
|
|
): IDatasetSamplesAndColumns | void => {
|
|
const { elements = [{ columnNames: [], results: [] }] } = properties;
|
|
const [{ columnNames = [], results }] = elements;
|
|
if (columnNames.length) {
|
|
return {
|
|
hasSamples: true, // TODO: remove the, can be derived from samples.length
|
|
samples: results,
|
|
columns: columnNames
|
|
};
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Reads a subset: samples and columns from a datasets properties that are derived from pinot
|
|
* @param {number} id the id of the pinot dataset
|
|
* @returns
|
|
*/
|
|
const readPinotProperties = async (id: number) => {
|
|
try {
|
|
return getDatasetSamplesAndColumns(<IDatasetPinotProperties>await readDatasetProperties(id));
|
|
} catch (e) {
|
|
warn('Exception occurred building the samples and columns for pinot properties');
|
|
throw e;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Updates the properties on the dataset for deprecation
|
|
* @param {number} id the id of the dataset
|
|
* @param {boolean} deprecated flag indicating deprecation
|
|
* @param {string} [deprecationNote=''] optional note accompanying deprecation change
|
|
*/
|
|
const updateDatasetDeprecation = async (id: number, deprecated: boolean, deprecationNote: string = '') => {
|
|
const { status, msg } = await putJSON<{ status: ApiStatus; msg: string }>({
|
|
url: datasetDeprecationUrlById(id),
|
|
data: {
|
|
deprecated,
|
|
deprecationNote
|
|
}
|
|
});
|
|
|
|
if (status !== ApiStatus.OK) {
|
|
throw new Error(msg);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Persists the changes to a datasets deprecation properties by urn
|
|
* @param {string} urn
|
|
* @param {boolean} deprecated
|
|
* @param {string} deprecationNote
|
|
* @return {Promise<void>}
|
|
*/
|
|
const updateDatasetDeprecationByUrn = (
|
|
urn: string,
|
|
deprecated: boolean,
|
|
deprecationNote: string = ''
|
|
): Promise<void> => {
|
|
return putJSON<void>({
|
|
url: datasetDeprecationUrlByUrn(urn),
|
|
data: {
|
|
deprecated,
|
|
deprecationNote
|
|
}
|
|
});
|
|
};
|
|
|
|
export {
|
|
readDatasetProperties,
|
|
readNonPinotProperties,
|
|
readPinotProperties,
|
|
updateDatasetDeprecation,
|
|
updateDatasetDeprecationByUrn
|
|
};
|