diff --git a/api/src/common/interfaces/utilities.interface.ts b/api/src/common/interfaces/utilities.interface.ts index f226c240a132a6508bab4981c213a784f27b751a..ddf5dedfa9585bdffa46ef5a90ca643d49eacf7a 100644 --- a/api/src/common/interfaces/utilities.interface.ts +++ b/api/src/common/interfaces/utilities.interface.ts @@ -1 +1 @@ -export type Dictionary<T> = { [key: string]: T }; \ No newline at end of file +export type Dictionary<T> = { [key: string]: T }; diff --git a/api/src/engine/connectors/datashield/main.connector.ts b/api/src/engine/connectors/datashield/main.connector.ts index 104a4fe0db6e76f2feda3e54310cae9846d6bc00..c81cc65fbef911bcb160acc7bdb516ec3aa80e1d 100644 --- a/api/src/engine/connectors/datashield/main.connector.ts +++ b/api/src/engine/connectors/datashield/main.connector.ts @@ -3,7 +3,7 @@ import { IEngineService } from 'src/engine/engine.interfaces'; import { Domain } from 'src/engine/models/domain.model'; export default class DataShieldService implements IEngineService { - getDomain(): Domain[] { + getDomains(): Domain[] { throw new Error('Method not implemented.'); } diff --git a/api/src/engine/connectors/exareme/converters.ts b/api/src/engine/connectors/exareme/converters.ts new file mode 100644 index 0000000000000000000000000000000000000000..721c1bb5e091a7bba0c5eb8582c901ab4784c16f --- /dev/null +++ b/api/src/engine/connectors/exareme/converters.ts @@ -0,0 +1,35 @@ +import { Category } from 'src/engine/models/category.model'; +import { Group } from 'src/engine/models/group.model'; +import { Variable } from 'src/engine/models/variable.model'; +import { Hierarchy } from './interfaces/hierarchy.interface'; +import { VariableEntity } from './interfaces/variable-entity.interface'; +import { Entity } from './interfaces/entity.interface'; + +export const dataToGroup = (data: Hierarchy): Group => { + return { + id: data.code, + label: data.label, + groups: data.groups ? data.groups.map(dataToGroup) : [], + variables: [], + }; +}; + +export const dataToCategory = (data: Entity): Category => { + return { + id: data.code, + label: data.label, + }; +}; + +export const dataToVariable = (data: VariableEntity): Variable => { + return { + id: data.code, + label: data.label, + type: data.type, + description: data.description, + enumerations: data.enumerations + ? data.enumerations.map(dataToCategory) + : [], + groups: [], + }; +}; diff --git a/api/src/engine/connectors/exareme/interfaces/entity.interface.ts b/api/src/engine/connectors/exareme/interfaces/entity.interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..38e3ab4125544a5b3eedf6f824533042f3c9d7d3 --- /dev/null +++ b/api/src/engine/connectors/exareme/interfaces/entity.interface.ts @@ -0,0 +1,4 @@ +export interface Entity { + code: string; + label?: string; +} diff --git a/api/src/engine/connectors/exareme/interfaces/hierarchy.interface.ts b/api/src/engine/connectors/exareme/interfaces/hierarchy.interface.ts index 6d0f02bd3b8dd5ec1cf6da521e93a412204fa51a..d5017f13c8d24134de164eb2a4da9064c69c4fe0 100644 --- a/api/src/engine/connectors/exareme/interfaces/hierarchy.interface.ts +++ b/api/src/engine/connectors/exareme/interfaces/hierarchy.interface.ts @@ -1,8 +1,8 @@ -import { VariableEntity } from "./variable-entity.interface"; +import { VariableEntity } from './variable-entity.interface'; export interface Hierarchy { - code: string; - label: string; - groups: Hierarchy[]; - variables: VariableEntity[]; -} \ No newline at end of file + code: string; + label: string; + groups: Hierarchy[]; + variables: VariableEntity[]; +} diff --git a/api/src/engine/connectors/exareme/interfaces/pathology.interface.ts b/api/src/engine/connectors/exareme/interfaces/pathology.interface.ts index d9dbea5ff6d3ed6f8fbd18c108e8d982d0a40695..e71e3a0251af2e03aa7e7995e6129609a9140cd0 100644 --- a/api/src/engine/connectors/exareme/interfaces/pathology.interface.ts +++ b/api/src/engine/connectors/exareme/interfaces/pathology.interface.ts @@ -1,9 +1,9 @@ -import { Hierarchy } from "./Hierarchy.interface"; -import { VariableEntity } from "./variable-entity.interface"; +import { Hierarchy } from './hierarchy.interface'; +import { VariableEntity } from './variable-entity.interface'; export interface Pathology { - code: string; - label: string; - datasets: VariableEntity[]; - metadataHierarchy: Hierarchy; -} \ No newline at end of file + code: string; + label: string; + datasets: VariableEntity[]; + metadataHierarchy: Hierarchy; +} diff --git a/api/src/engine/connectors/exareme/interfaces/variable-entity.interface.ts b/api/src/engine/connectors/exareme/interfaces/variable-entity.interface.ts index ce1ce25b461f5dd9e495cf27f6791f114cd5ade4..06c880dcb97fb9e203a51067fe265c75492fef58 100644 --- a/api/src/engine/connectors/exareme/interfaces/variable-entity.interface.ts +++ b/api/src/engine/connectors/exareme/interfaces/variable-entity.interface.ts @@ -1,9 +1,9 @@ -import { Variable } from "./variable.interface"; +import { Entity } from './entity.interface'; -export interface VariableEntity extends Variable { - type?: 'nominal' | 'ordinal' | 'real' | 'integer' | 'text' | 'date'; - description?: string; - enumerations?: Variable[]; - group?: Variable[]; - info?: string; -} \ No newline at end of file +export interface VariableEntity extends Entity { + type?: 'nominal' | 'ordinal' | 'real' | 'integer' | 'text' | 'date'; + description?: string; + enumerations?: Entity[]; + group?: Entity[]; + info?: string; +} diff --git a/api/src/engine/connectors/exareme/interfaces/variable.interface.ts b/api/src/engine/connectors/exareme/interfaces/variable.interface.ts deleted file mode 100644 index 85174c8d88ca7ddf2e8fc320a7eb812fd3fe9d1d..0000000000000000000000000000000000000000 --- a/api/src/engine/connectors/exareme/interfaces/variable.interface.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Variable { - code: string; - label?: string; -} \ No newline at end of file diff --git a/api/src/engine/connectors/exareme/main.connector.ts b/api/src/engine/connectors/exareme/main.connector.ts index ae590365d74c0bdd3b875ae1d991f859f43fae9d..0b854ccb42ca246638a59f7607adb7f41216bd02 100644 --- a/api/src/engine/connectors/exareme/main.connector.ts +++ b/api/src/engine/connectors/exareme/main.connector.ts @@ -1,13 +1,14 @@ import { HttpService } from '@nestjs/axios'; +import { HttpException, HttpStatus } from '@nestjs/common'; import { Request } from 'express'; import { firstValueFrom, map, Observable } from 'rxjs'; -import { Dictionary } from 'src/common/interfaces/utilities.interface'; import { IEngineOptions, IEngineService } from 'src/engine/engine.interfaces'; import { Domain } from 'src/engine/models/domain.model'; import { Group } from 'src/engine/models/group.model'; -import { Hierarchy } from './interfaces/Hierarchy.interface'; +import { Variable } from 'src/engine/models/variable.model'; +import { dataToCategory, dataToGroup, dataToVariable } from './converters'; +import { Hierarchy } from './interfaces/hierarchy.interface'; import { Pathology } from './interfaces/pathology.interface'; -import { VariableEntity } from './interfaces/variable-entity.interface'; export default class ExaremeService implements IEngineService { constructor( @@ -15,42 +16,35 @@ export default class ExaremeService implements IEngineService { private readonly httpService: HttpService, ) { } - private hierarchyToGroup = (data: Hierarchy): Group => { - return { - id: data.code, - label: data.label, - groups: data.groups ? data.groups.map((child: Hierarchy) => this.hierarchyToGroup(child)) : [], - variables: [] - } - } - - private flattenGroups = (data: Hierarchy): Group[] => { - let groups: Group[] = [this.hierarchyToGroup(data)]; - - if (data.groups) { - groups = groups.concat(data.groups.flatMap(this.flattenGroups)); - } - - return groups; - } - - - async getDomain(): Promise<Domain[]> { + async getDomains(ids: string[]): Promise<Domain[]> { const path = this.options.baseurl + 'pathologies'; - const data = await firstValueFrom(this.httpService.get(path)); - - const domains = data.data.map((data: Pathology): Domain => { - return { - id: data.code, - label: data.label, - groups: data.metadataHierarchy.groups.flatMap(this.flattenGroups), - datasets: [], - variables: [], - } - }) - - return domains; + try { + const data = await firstValueFrom( + this.httpService.get<Pathology[]>(path), + ); + + return data.data + .filter((data) => !ids || ids.length == 0 || ids.includes(data.code)) + .map((data): Domain => { + const groups = this.flattenGroups(data.metadataHierarchy); + + return { + id: data.code, + label: data.label, + groups: groups, + datasets: data.datasets ? data.datasets.map(dataToCategory) : [], + variables: data.metadataHierarchy + ? this.flattenVariables(data.metadataHierarchy, groups) + : [], + }; + }); + } catch { + throw new HttpException( + `Connexion to the connector ${this.options.type} failed`, + HttpStatus.NOT_FOUND, + ); + } } demo(): string { @@ -127,48 +121,30 @@ export default class ExaremeService implements IEngineService { .pipe(map((response) => response.data)); } - private pathologiesHierarchies = ( - json: Pathology[] - ): Dictionary<Hierarchy> => { - const pathologiesDatasets: Dictionary<Hierarchy> = {}; - json.forEach(pathology => { - pathologiesDatasets[pathology.code] = pathology.metadataHierarchy; - }); - - return pathologiesDatasets; - }; - - private pathologiesVariables = (json: Pathology[]): Dictionary<VariableEntity[]> => { - const pathologiesVariables: Dictionary<VariableEntity[]> = {}; - json.forEach(pathology => { - let variables: VariableEntity[] = []; - - const dummyAccumulator = (node: any): void => { - if (node.variables) { - variables = [...variables, ...node.variables]; - } + private flattenGroups = (data: Hierarchy): Group[] => { + let groups: Group[] = [dataToGroup(data)]; - if (node.groups) { - return node.groups.map(dummyAccumulator); - } - }; + if (data.groups) { + groups = groups.concat(data.groups.flatMap(this.flattenGroups)); + } - if (pathology) { - dummyAccumulator(pathology.metadataHierarchy); - } + return groups; + }; - pathologiesVariables[pathology.code] = variables; - }); + private flattenVariables = (data: Hierarchy, groups: Group[]): Variable[] => { + const group = groups.find((group) => group.id == data.code); + let variables = data.variables ? data.variables.map(dataToVariable) : []; - return pathologiesVariables; - }; + variables.forEach((variable) => (variable.groups = group ? [group] : [])); - private pathologiesDatasets = (json: Pathology[]): Dictionary<VariableEntity[]> => { - const pathologiesDatasets: Dictionary<VariableEntity[]> = {}; - json.forEach(pathology => { - pathologiesDatasets[pathology.code] = pathology.datasets; - }); + if (data.groups) { + variables = variables.concat( + data.groups.flatMap((hierarchy) => + this.flattenVariables(hierarchy, groups), + ), + ); + } - return pathologiesDatasets; + return variables; }; } diff --git a/api/src/engine/engine.interfaces.ts b/api/src/engine/engine.interfaces.ts index 17db7ff043697a125051bdfa5791357687d3a406..09b86b731d670a83b598936d834b8993f4a8b27f 100644 --- a/api/src/engine/engine.interfaces.ts +++ b/api/src/engine/engine.interfaces.ts @@ -10,7 +10,7 @@ export interface IEngineOptions { export interface IEngineService { demo(): string; - getDomain(): Domain[] | Promise<Domain[]>; + getDomains(ids: string[]): Domain[] | Promise<Domain[]>; getAlgorithms(request: Request): Observable<string>; diff --git a/api/src/engine/engine.resolver.ts b/api/src/engine/engine.resolver.ts index 6adcf0d143a37d0960ea6dbe8d71338f32bff874..beeb589fc6de4f3294efffea16e4b55c1ac96f61 100644 --- a/api/src/engine/engine.resolver.ts +++ b/api/src/engine/engine.resolver.ts @@ -1,5 +1,5 @@ import { Inject } from '@nestjs/common'; -import { Query, Resolver } from '@nestjs/graphql'; +import { Args, Query, Resolver } from '@nestjs/graphql'; import { ENGINE_SERVICE } from './engine.constants'; import { IEngineService } from './engine.interfaces'; import { Domain } from './models/domain.model'; @@ -8,10 +8,13 @@ import { Domain } from './models/domain.model'; export class EngineResolver { constructor( @Inject(ENGINE_SERVICE) private readonly engineService: IEngineService, - ) { } + ) {} @Query(() => [Domain]) - async domain() { - return this.engineService.getDomain(); + async domains( + @Args('ids', { nullable: true, type: () => [String], defaultValue: [] }) + ids: string[], + ) { + return this.engineService.getDomains(ids); } } diff --git a/api/src/schema.gql b/api/src/schema.gql index 703c5eb6f1d38c98a2ebde2646150d24067e1848..130ebbf01bd3f0a75ab2f2d2a2e4cd6952394183 100644 --- a/api/src/schema.gql +++ b/api/src/schema.gql @@ -34,5 +34,5 @@ type Domain { } type Query { - hello: Domain! + domains(ids: [String!] = []): [Domain!]! }