// (C) 2019-2021 GoodData Corporation import { Application, Request, Response } from "express"; import { flatMap } from "lodash"; import { IMockProject } from "../../model/MockProject"; import { IMockResponseConfig, mock, getMatchingResponse } from "../helpers/mockRequest"; import * as HttpStatusCodes from "http-status-codes"; import { getGroups } from "../helpers/groups"; import { IMetadataObject } from "../../model/MetadataObject"; import { isAttribute } from "../../model/Attribute"; import { isMetric } from "../../model/Metric"; import { CatalogType } from "./catalog"; interface ICatalogItemsRequest { readonly offset: number; readonly limit: number; readonly types?: CatalogType; readonly production: number; } export interface ICatalogItem { readonly title: string; readonly identifier: string; readonly type: CatalogType; readonly summary?: string; readonly csvDataSet?: string; readonly expression?: string; readonly format?: string; readonly groups?: ReadonlyArray; readonly links: { readonly self: string; readonly defaultDisplayForm?: string; }; } export const organizedCatalog = { register(app: Application, project: IMockProject) { mockCatalogGroups(app, project); mockCatalogQuery(app, project); mockCatalogItems(app, project); return app; }, }; const mockCatalogGroups = (app: Application, project: IMockProject) => { const organizedCatalog = project.organizedCatalog ? project.organizedCatalog : {}; const groups = organizedCatalog.groups ? organizedCatalog.groups : []; const projectId = project.project.meta.identifier; const defaultGroups: IMockResponseConfig = { response: { catalogGroups: [], }, }; mock(app, "get", `/gdc/internal/projects/${projectId}/catalog/groups`, groups, defaultGroups); }; const mockCatalogQuery = (app: Application, project: IMockProject) => { const projectId = project.project.meta.identifier; const organizedCatalog = project.organizedCatalog ? project.organizedCatalog : {}; const queryResponse = organizedCatalog.queryResponse ? organizedCatalog.queryResponse : []; app.post(`/gdc/internal/projects/${projectId}/catalog/query`, (req: Request, res: Response) => { const mockedResponse = getMatchingResponse(req, queryResponse); if (mockedResponse) { res.status(HttpStatusCodes.OK).json(mockedResponse.response); return; } const requestedTypes: CatalogType[] = req.body.catalogQueryRequest.types; const generatedResponse = generateCatalogQueryResponse(requestedTypes, project); res.status(HttpStatusCodes.OK).json(generatedResponse); }); }; const generateCatalogQueryResponse = (requestedTypes: CatalogType[], project: IMockProject) => { const filteredGroupItems = filterGroupItems(requestedTypes, project); return { catalogAvailableItems: { items: filteredGroupItems.map(groupItem => groupItem.meta.uri), }, }; }; const mockCatalogItems = (app: Application, project: IMockProject) => { const projectId = project.project.meta.identifier; const organizedCatalog = project.organizedCatalog ? project.organizedCatalog : {}; const items = organizedCatalog.items ? organizedCatalog.items : []; app.get(`/gdc/internal/projects/${projectId}/catalog/items`, (req: Request, res: Response) => { const mockedResponse = getMatchingResponse(req, items); if (mockedResponse) { res.status(HttpStatusCodes.OK).json(mockedResponse.response); return; } const requestPayload = getCatalogItemsRequest(req); const generatedResponse = generateCatalogItemsResponse(requestPayload, project); res.status(HttpStatusCodes.OK).json(generatedResponse); }); }; const getCatalogItemsRequest = (req: Request): ICatalogItemsRequest => { const { offset = "0", limit = "500", types, production } = req.query; return { offset: Number(offset), limit: Number(limit), types: types as CatalogType, production: Number(production), }; }; const generateCatalogItemsResponse = (requestPayload: ICatalogItemsRequest, project: IMockProject) => { const catalogItems = generateCatalogItems(requestPayload, project); return { catalogItems: { items: catalogItems, paging: { count: catalogItems.length, offset: requestPayload.offset }, }, }; }; const generateCatalogItems = ( requestPayload: ICatalogItemsRequest, project: IMockProject, ): ReadonlyArray => { const requestedTypes: CatalogType[] = requestPayload.types ? [requestPayload.types] : undefined; const filteredCatalogItems = filterGroupItems(requestedTypes, project); return filteredCatalogItems.map(generateCatalogItem); }; const generateCatalogItem = (groupItem: IMetadataObject): ICatalogItem => { if (isAttribute(groupItem)) { return { type: "attribute", identifier: groupItem.meta.identifier, title: groupItem.meta.title, summary: groupItem.meta.summary, links: { self: groupItem.meta.uri, defaultDisplayForm: groupItem.content.displayForms.length > 0 ? groupItem.content.displayForms[0].meta.uri : undefined, }, }; } else if (isMetric(groupItem)) { return { type: "metric", identifier: groupItem.meta.identifier, title: groupItem.meta.title, expression: groupItem.content.expression, summary: groupItem.meta.summary, links: { self: groupItem.meta.uri, }, }; } else { return { type: "fact", identifier: groupItem.meta.identifier, title: groupItem.meta.title, summary: groupItem.meta.summary, links: { self: groupItem.meta.uri, }, }; } }; const filterGroupItems = ( requestedTypes: CatalogType[] = ["attribute", "fact", "metric"], project: IMockProject, ): IMetadataObject[] => { const groups = getGroups({ type: "PRODUCTION" }, project); const groupItems: IMetadataObject[] = flatMap(groups, group => [ ...group.metrics, ...group.facts, ...group.attributes, ]); return groupItems.filter(item => requestedTypes.some(type => item.meta.category === type)); };