mirror of
https://github.com/datahub-project/datahub.git
synced 2026-01-05 06:16:37 +00:00
280 lines
10 KiB
TypeScript
280 lines
10 KiB
TypeScript
import { BaseEntity, IBaseEntityStatics, statics } from '@datahub/data-models/entity/base-entity';
|
|
import { IDatasetApiView } from '@datahub/metadata-types/types/entity/dataset/dataset-entity';
|
|
import { readDataset } from '@datahub/data-models/api/dataset/dataset';
|
|
import { readDatasetSchema } from '@datahub/data-models/api/dataset/schema';
|
|
import DatasetSchema from '@datahub/data-models/entity/dataset/modules/schema';
|
|
import { set } from '@ember/object';
|
|
import { isNotFoundApiError } from '@datahub/utils/api/shared';
|
|
import { IEntityRenderProps } from '@datahub/data-models/types/entity/rendering/entity-render-props';
|
|
import { oneWay } from '@ember/object/computed';
|
|
import { DatasetPlatform } from '@datahub/metadata-types/constants/entity/dataset/platform';
|
|
import { decodeUrn } from '@datahub/utils/validators/urn';
|
|
import { readCategories } from '@datahub/data-models/entity/dataset/read-categories';
|
|
import { getPrefix } from '@datahub/data-models/entity/dataset/utils/segments';
|
|
import { readDatasetsCount } from '@datahub/data-models/api/dataset/count';
|
|
import { setProperties } from '@ember/object';
|
|
import { DatasetLineage } from '@datahub/data-models/entity/dataset/modules/lineage';
|
|
import { readUpstreamDatasets } from '@datahub/data-models/api/dataset/lineage';
|
|
import { DatasetLineageList } from '@datahub/metadata-types/types/entity/dataset/lineage';
|
|
import { getRenderProps } from '@datahub/data-models/entity/dataset/render-props';
|
|
import { NotImplementedError } from '@datahub/data-models/constants/entity/shared';
|
|
import { IDatasetSnapshot } from '@datahub/metadata-types/types/metadata/dataset-snapshot';
|
|
import { IBrowsePath, IEntityLinkAttrsWithCount, IEntityLinkAttrs } from '@datahub/data-models/types/entity/shared';
|
|
import { IInstitutionalMemory } from '@datahub/data-models/types/entity/common/wiki/institutional-memory';
|
|
import { readDatasetInstitutionalMemory, writeDatasetInstitutionalMemory } from '@datahub/data-models/api/dataset/wiki';
|
|
import { InstitutionalMemory } from '@datahub/data-models/models/aspects/institutional-memory';
|
|
import { returnDefaultIfNotFound } from '@datahub/utils/api/fetcher';
|
|
|
|
/**
|
|
* Common function used here for the read operation for datasets. If an item is not found we often have to
|
|
* default to a UI provided factory value, which can be inserted here to be run as part of the catch
|
|
* function in a promise situation
|
|
* @type {<T>(value: T): (e: Error) => T}
|
|
*/
|
|
const returnValueIfNotFound = <T>(value: T): ((e: Error) => T) => (e: Error): T => {
|
|
if (isNotFoundApiError(e)) {
|
|
return value;
|
|
}
|
|
throw e;
|
|
};
|
|
|
|
/**
|
|
* Defines the data model for the Dataset entity.
|
|
*/
|
|
@statics<IBaseEntityStatics<IDatasetApiView>>()
|
|
export class DatasetEntity extends BaseEntity<IDatasetApiView> {
|
|
/**
|
|
* The human friendly alias for Dataset entities
|
|
*/
|
|
static displayName: 'datasets' = 'datasets';
|
|
|
|
get displayName(): 'datasets' {
|
|
return DatasetEntity.displayName;
|
|
}
|
|
|
|
/**
|
|
* Discriminant when included in a tagged Entity union
|
|
*/
|
|
static kind = 'DatasetEntity';
|
|
|
|
get kind(): string {
|
|
return DatasetEntity.kind;
|
|
}
|
|
|
|
/**
|
|
* Shows the urn as an unencoded value
|
|
*/
|
|
get rawUrn(): string {
|
|
return decodeUrn(this.urn);
|
|
}
|
|
|
|
/**
|
|
* Creates a link for this specific entity instance, useful for generating a dynamic link from a
|
|
* single particular dataset entity
|
|
*/
|
|
get linkForEntity(): IEntityLinkAttrs {
|
|
return DatasetEntity.getLinkForEntity({
|
|
entityUrn: this.urn,
|
|
displayName: this.name
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Reads the snapshots for a list of Dataset urns
|
|
* @static
|
|
*/
|
|
static readSnapshots(_urns: Array<string>): Promise<Array<IDatasetSnapshot>> {
|
|
throw new Error(NotImplementedError);
|
|
}
|
|
|
|
/**
|
|
* Holds the classified data retrieved from the API layer for the schema information as a DatasetSchema
|
|
* class
|
|
* @type {DatasetSchema}
|
|
*/
|
|
schema?: DatasetSchema;
|
|
|
|
/**
|
|
* Holds the classified data retrieved from the API layer for the upstream datasets list as an array of
|
|
* DatasetLineage classes
|
|
* @type {Array<DatasetLineage>}
|
|
*/
|
|
upstreams?: Array<DatasetLineage>;
|
|
|
|
/**
|
|
* Holds the raw data from the API layer for the institutional memory wiki links related to this dataset
|
|
* entity by urn
|
|
*/
|
|
institutionalMemories?: Array<InstitutionalMemory>;
|
|
|
|
/**
|
|
* Reference to the data entity, is the data platform to which the dataset belongs
|
|
* @type {DatasetPlatform}
|
|
*/
|
|
@oneWay('entity.platform')
|
|
platform?: DatasetPlatform;
|
|
|
|
/**
|
|
* Reference to the data entity's native name, should not be something that is editable but gives us a
|
|
* more human readable form for the dataset vs the urn
|
|
*/
|
|
get name(): string {
|
|
return this.entity ? this.entity.nativeName : '';
|
|
}
|
|
|
|
/**
|
|
* Retrieves the value of the Dataset entity identified by this.urn
|
|
*/
|
|
get readEntity(): Promise<IDatasetApiView> {
|
|
return readDataset(this.urn);
|
|
}
|
|
|
|
/**
|
|
* Class properties common across instances
|
|
* Dictates how visual ui components should be rendered
|
|
* Implemented as a getter to ensure that reads are idempotent
|
|
* @readonly
|
|
* @static
|
|
* @type {IEntityRenderProps}
|
|
*/
|
|
static get renderProps(): IEntityRenderProps {
|
|
return getRenderProps();
|
|
}
|
|
|
|
/**
|
|
* Builds a search query keyword from a list of segments for the a DatasetEntity instance
|
|
*/
|
|
static getQueryForHierarchySegments(_segments: Array<string>): never {
|
|
throw new Error(NotImplementedError);
|
|
}
|
|
|
|
/**
|
|
* Is a promise that retrieves the schema information and returns and sets the schema information in a
|
|
* thennable format
|
|
*/
|
|
async readSchema(): Promise<DatasetSchema> {
|
|
const schema = await readDatasetSchema(this.urn);
|
|
const datasetSchema = new DatasetSchema(schema);
|
|
set(this, 'schema', datasetSchema);
|
|
return datasetSchema;
|
|
}
|
|
|
|
/**
|
|
* Asynchronously retrieves the upstream datasets for this dataset and assigns to the upstreams property
|
|
*/
|
|
async readUpstreams(): Promise<Array<DatasetLineage>> {
|
|
const lineageList = await readUpstreamDatasets(this.urn).catch(
|
|
// Handling for an expected possibility of receiving a 404 error for this upstream dataset response, which
|
|
// would require us to replace error with just an empty list
|
|
returnValueIfNotFound([] as DatasetLineageList)
|
|
);
|
|
|
|
const upstreams = lineageList.map((lineage): DatasetLineage => new DatasetLineage(lineage));
|
|
set(this, 'upstreams', upstreams);
|
|
return upstreams;
|
|
}
|
|
|
|
/**
|
|
* Reads the institutional memory wiki links related to this dataset and stores it on the entity as well as returning
|
|
* it as a value from this function
|
|
*/
|
|
async readInstitutionalMemory(): Promise<Array<InstitutionalMemory>> {
|
|
// Handling for expected possibility of receiving a 404 for institutional memory for this dataset, which would
|
|
// likely mean nothing has been added yet and we should allow the user to be the first to add something
|
|
const { elements: institutionalMemories } = await returnDefaultIfNotFound(
|
|
readDatasetInstitutionalMemory(this.urn),
|
|
{
|
|
elements: [] as Array<IInstitutionalMemory>
|
|
}
|
|
);
|
|
|
|
const institutionalMemoriesMap = institutionalMemories.map(
|
|
(link): InstitutionalMemory => new InstitutionalMemory(link)
|
|
);
|
|
set(this, 'institutionalMemories', institutionalMemoriesMap);
|
|
return institutionalMemoriesMap;
|
|
}
|
|
|
|
/**
|
|
* Writes the institutional memory wiki links back to the backend to save any user changes (add/delete)
|
|
*/
|
|
async writeInstitutionalMemory(): Promise<void> {
|
|
const { institutionalMemories } = this;
|
|
institutionalMemories &&
|
|
(await writeDatasetInstitutionalMemory(
|
|
this.urn,
|
|
institutionalMemories.map((link): IInstitutionalMemory => link.readWorkingCopy())
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Interim implementation to read categories for datasets
|
|
* TODO META-8863
|
|
*/
|
|
static async readCategories(...args: Array<string>): Promise<IBrowsePath> {
|
|
const [category, ...rest] = args;
|
|
const prefix = await getPrefix(category || '', rest || []);
|
|
const entitiesOrCategories = await readCategories(category || '', prefix);
|
|
const groups = entitiesOrCategories
|
|
.filter(({ entityUrn }): boolean => !entityUrn)
|
|
.map(
|
|
({ segments = [], displayName }): IEntityLinkAttrsWithCount<unknown> =>
|
|
this.getLinkForCategory({
|
|
segments,
|
|
displayName,
|
|
count: 0
|
|
})
|
|
);
|
|
const entities = entitiesOrCategories
|
|
.filter(({ entityUrn }): boolean => Boolean(entityUrn))
|
|
.map(
|
|
({ entityUrn = '', displayName }): IEntityLinkAttrs<unknown> =>
|
|
this.getLinkForEntity({
|
|
entityUrn,
|
|
displayName
|
|
})
|
|
);
|
|
|
|
return {
|
|
segments: args,
|
|
title: rest[rest.length - 1] || category || this.displayName,
|
|
count: 0,
|
|
entities,
|
|
groups
|
|
};
|
|
}
|
|
|
|
// TODO META-8863 remove once dataset is migrated
|
|
static async readCategoriesCount(...args: Array<string>): Promise<number> {
|
|
const [category, ...rest] = args;
|
|
const prefix = await getPrefix(category || '', rest || []);
|
|
return await readDatasetsCount({ platform: category || '', prefix });
|
|
}
|
|
|
|
constructor(readonly urn: string, entityData?: IDatasetApiView) {
|
|
super(urn);
|
|
// Sometimes we do not need readEntity to get this information as it was already provided by another entity
|
|
// and we can just instantiate the class with it
|
|
if (entityData) {
|
|
set(this, 'entity', entityData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Custom factory for the dataset entity. We don't use the base entity factory as the dataset behavior currently
|
|
* does not match the expectations of the base entity. Moving forward, when the backend response matches with the
|
|
* expected dataset behavior, we may find a use case to rely on that function rather than use of this custom one
|
|
* @param {string} urn - provides the context for what dataset entity to create by its urn identifier
|
|
*/
|
|
export const createDatasetEntity = async (urn: string, fetchedEntity?: IDatasetApiView): Promise<DatasetEntity> => {
|
|
const dataset = new DatasetEntity(urn);
|
|
const entity = fetchedEntity || (await dataset.readEntity);
|
|
|
|
setProperties(dataset, {
|
|
entity
|
|
});
|
|
|
|
return dataset;
|
|
};
|