/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { hashArray, uuid, type Hashable, type PlainObject, } from '@finos/legend-shared'; import { PackageableElement, type PackageableElementVisitor, } from '../packageableElements/PackageableElement.js'; import type { RawLambda } from '../rawValueSpecification/RawLambda.js'; import { CORE_HASH_STRUCTURE, hashObjectWithoutSourceInformation, } from '../../../Core_HashUtils.js'; import { AnnotatedElement } from '../packageableElements/domain/AnnotatedElement.js'; import type { Mapping } from '../packageableElements/mapping/Mapping.js'; import type { PackageableRuntime } from '../packageableElements/runtime/PackageableRuntime.js'; import type { PackageableElementReference } from '../packageableElements/PackageableElementReference.js'; import type { Package } from '../packageableElements/domain/Package.js'; import type { Class } from '../packageableElements/domain/Class.js'; import type { Enumeration } from '../packageableElements/domain/Enumeration.js'; import type { Association } from '../packageableElements/domain/Association.js'; import type { EmbeddedData } from '../data/EmbeddedData.js'; import { ConcreteFunctionDefinition } from '../packageableElements/function/ConcreteFunctionDefinition.js'; import { generateFunctionPrettyName } from '../../../helpers/PureLanguageHelper.js'; import type { StereotypeReference } from '../packageableElements/domain/StereotypeReference.js'; import type { AppDirNode } from '../packageableElements/ingest/IngestDefinition.js'; export abstract class AccessPoint implements Hashable { id: string; title: string | undefined; description: string | undefined; stereotypes: StereotypeReference[] = []; __owner: AccessPointGroup; constructor(id: string, owner: AccessPointGroup) { this.id = id; this.__owner = owner; } get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_ACCESS_POINT, this.id, this.title ?? '', this.description ?? '', hashArray(this.stereotypes.map((val) => val.pointerHashCode)), ]); } } export class FunctionAccessPoint extends AccessPoint { query: RawLambda; constructor(id: string, query: RawLambda, owner: AccessPointGroup) { super(id, owner); this.query = query; } override get hashCode(): string { return hashArray([ super.hashCode, CORE_HASH_STRUCTURE.FUNCTION_ACCESS_POINT, this.query, ]); } } export enum LakehouseTargetEnv { Snowflake = 'Snowflake', Databricks = 'Databricks', BigQuery = 'BigQuery', DuckDb = 'DuckDb', } export enum DataProductAccessType { MODEL = 'model', NATIVE = 'native', LAKEHOUSE = 'lakehouse', } export class LakehouseAccessPoint extends AccessPoint { targetEnvironment: string; classification: string | undefined; func: RawLambda; reproducible: boolean | undefined; constructor( id: string, targetEnv: string, func: RawLambda, owner: AccessPointGroup, ) { super(id, owner); this.targetEnvironment = targetEnv; this.func = func; } override get hashCode(): string { return hashArray([ super.hashCode, CORE_HASH_STRUCTURE.LAKEHOUSE_ACCESS_POINT, this.targetEnvironment, this.classification ?? '', this.func, this.reproducible ?? '', ]); } } export class UnknownAccessPoint extends AccessPoint { content!: PlainObject; override get hashCode(): string { return hashArray([ super.hashCode, CORE_HASH_STRUCTURE.UNKNOWN_ACCESS_POINT, hashObjectWithoutSourceInformation(this.content), ]); } } export class DataProductRuntimeInfo { id!: string; description: string | undefined; runtime!: PackageableElementReference; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_RUNTIME_INFO, this.id, this.description ?? '', this.runtime.valueForSerialization ?? '', ]); } } export type DataProductElement = Package | Class | Enumeration | Association; export interface ElementScope { element: PackageableElementReference; exclude?: boolean | undefined; } export class DataProductElementScope implements Hashable { exclude: boolean | undefined; element!: PackageableElementReference; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_ELEMENT_SCOPE, this.exclude ?? '', this.element.valueForSerialization ?? '', ]); } } export class DataProductDiagram implements Hashable { title!: string; description: string | undefined; diagram!: PackageableElement; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_DIAGRAM, this.title, this.description ?? '', this.diagram.path, ]); } } export class AccessPointGroup extends AnnotatedElement implements Hashable { id!: string; title: string | undefined; description: string | undefined; accessPoints: AccessPoint[] = []; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_ACCESS_POINT_GROUP, this.id, this.title ?? '', this.description ?? '', hashArray(this.accessPoints), hashArray(this.stereotypes.map((val) => val.pointerHashCode)), ]); } } export class ModelAccessPointGroup extends AccessPointGroup implements Hashable { mapping!: PackageableElementReference; featuredElements: DataProductElementScope[] = []; diagrams: DataProductDiagram[] = []; override get hashCode(): string { return hashArray([ super.hashCode, CORE_HASH_STRUCTURE.DATA_PRODUCT_MODEL_ACCESS_POINT_GROUP, this.mapping.valueForSerialization ?? '', hashArray(this.featuredElements), hashArray(this.diagrams), ]); } } export class NativeModelExecutionContext implements Hashable { key!: string; mapping!: PackageableElementReference; runtime: PackageableElementReference | undefined; __owner!: NativeModelAccess; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_NATIVE_MODEL_EXECUTION_CONTEXT, this.key, this.mapping.valueForSerialization ?? '', this.runtime?.valueForSerialization ?? '', ]); } } export class NativeModelAccess implements Hashable { featuredElements: DataProductElementScope[] = []; nativeModelExecutionContexts: NativeModelExecutionContext[] = []; defaultExecutionContext!: NativeModelExecutionContext; diagrams: DataProductDiagram[] = []; sampleQueries: SampleQuery[] = []; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_NATIVE_MODEL_ACCESS, hashArray(this.nativeModelExecutionContexts), hashArray(this.featuredElements), hashArray(this.diagrams), hashArray(this.sampleQueries), this.defaultExecutionContext.key, ]); } } export abstract class SampleQuery implements Hashable { id!: string; title!: string; description: string | undefined; executionContextKey!: string; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_SAMPLE_QUERY, this.id, this.title, this.description ?? '', this.executionContextKey, ]); } } export class InLineSampleQuery extends SampleQuery implements Hashable { query!: RawLambda; override get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_INLINE_SAMPLE_QUERY, super.hashCode, this.query, ]); } } export class PackageableElementSampleQuery extends SampleQuery implements Hashable { query!: PackageableElementReference; override get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_PACKAGEABLE_ELEMENT_SAMPLE_QUERY, super.hashCode, this.query.value instanceof ConcreteFunctionDefinition ? generateFunctionPrettyName(this.query.value, { fullPath: true, spacing: false, notIncludeParamName: true, }) : (this.query.valueForSerialization ?? ''), ]); } } export class Email implements Hashable { title!: string; address!: string; constructor(address: string, title: string) { this.address = address; this.title = title; } get hashCode(): string { return hashArray([CORE_HASH_STRUCTURE.EMAIL, this.title, this.address]); } } export class DataProductLink { label: string | undefined; url: string; constructor(url: string, label?: string) { this.url = url; this.label = label; } get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_LINK, this.label ?? '', this.url, ]); } } export class SupportInfo implements Hashable { documentation: DataProductLink | undefined; website: DataProductLink | undefined; faqUrl: DataProductLink | undefined; supportUrl: DataProductLink | undefined; emails: Email[] = []; expertise: Expertise[] | undefined; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.SUPPORT_INFO, this.documentation ?? '', this.website ?? '', this.faqUrl ?? '', this.supportUrl ?? '', hashArray(this.emails), hashArray(this.expertise ?? []), ]); } } export enum DataProduct_DeliveryFrequency { DAILY = 'DAILY', WEEKLY = 'WEEKLY', MONTHLY = 'MONTHLY', QUARTERLY = 'QUARTERLY', YEARLY = 'YEARLY', ON_DEMAND = 'ON_DEMAND', INTRA_DAY = 'INTRADAY', } export enum DataProduct_Region { APAC = 'APAC', EMEA = 'EMEA', LAMR = 'LAMR', NAMR = 'NAMR', } export abstract class DataProductIcon implements Hashable { abstract get hashCode(): string; } export class DataProductLibraryIcon extends DataProductIcon implements Hashable { libraryId!: string; iconId!: string; constructor(libraryId: string, iconId: string) { super(); this.libraryId = libraryId; this.iconId = iconId; } get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_ICON_LIBRARY, this.libraryId, this.iconId, ]); } } export class DataProductEmbeddedImageIcon extends DataProductIcon implements Hashable { imageUrl!: string; constructor(imageUrl: string) { super(); this.imageUrl = imageUrl; } get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_ICON_EMBEDDED_IMAGE, this.imageUrl, ]); } } // handle incoming icons not yet modeled export class UnknownDataProductIcon extends DataProductIcon implements Hashable { content!: PlainObject; constructor(content: PlainObject) { super(); this.content = content; } override get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.INTERNAL__UNKNOWN_DATA_PRODUCT_ICON, hashObjectWithoutSourceInformation(this.content), ]); } } export abstract class DataProductType implements Hashable { get hashCode(): string { return hashArray([CORE_HASH_STRUCTURE.DATA_PRODUCT_TYPE]); } } export class InternalDataProductType extends DataProductType {} export class ExternalDataProductType extends DataProductType { link!: DataProductLink; override get hashCode(): string { return hashArray([CORE_HASH_STRUCTURE.DATA_PRODUCT_TYPE, this.link]); } } export class Expertise implements Hashable { readonly uuid = uuid(); description: string | undefined; expertIds: string[] | undefined; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_EXPERTISE, this.description ?? '', hashArray(this.expertIds ?? []), ]); } } export class DataProductOperationalMetadata implements Hashable { coverageRegions: DataProduct_Region[] | undefined; updateFrequency: DataProduct_DeliveryFrequency | undefined; get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_OPERATIONAL_METADATA, hashArray(this.coverageRegions ?? []), this.updateFrequency ?? '', ]); } } // ---------------------------------------- Owner ----------------------------------------- export abstract class DataProductOwner implements Hashable { abstract get hashCode(): string; } export class AppDirOwner extends DataProductOwner implements Hashable { production: AppDirNode | undefined; prodParallel: AppDirNode | undefined; override get hashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT_OWNER, this.production?.hashCode ?? '', this.prodParallel?.hashCode ?? '', ]); } } export class DataProduct extends PackageableElement { title: string | undefined; description: string | undefined; icon: DataProductIcon | undefined; accessPointGroups: AccessPointGroup[] = []; nativeModelAccess: NativeModelAccess | undefined; supportInfo: SupportInfo | undefined; type: DataProductType | undefined; sampleValues: EmbeddedData[] | undefined; operationalMetadata: DataProductOperationalMetadata | undefined; owner: DataProductOwner | undefined; override accept_PackageableElementVisitor( visitor: PackageableElementVisitor, ): T { return visitor.visit_DataProduct(this); } protected override get _elementHashCode(): string { return hashArray([ CORE_HASH_STRUCTURE.DATA_PRODUCT, this.title ?? '', this.description ?? '', this.icon ?? '', hashArray(this.accessPointGroups), this.nativeModelAccess ?? '', this.supportInfo ?? '', this.type ?? '', hashArray(this.stereotypes.map((val) => val.pointerHashCode)), hashArray(this.taggedValues), hashArray(this.sampleValues ?? []), this.operationalMetadata ?? '', this.owner ?? '', ]); } }