From f7d14cb944e9f95d0a7b7f63794933689c103389 Mon Sep 17 00:00:00 2001 From: Steve Reis <stevereis93@gmail.com> Date: Wed, 8 Jun 2022 14:14:18 +0000 Subject: [PATCH] feat(GrahpQL): Filter and formula fields available --- .../engine/connectors/exareme/converters.ts | 19 +++++++++++++++++++ .../connectors/exareme/main.connector.ts | 14 ++++++++++++++ api/src/engine/engine.interfaces.ts | 18 ++++++++++++++++++ api/src/engine/engine.resolver.ts | 18 ++++++++++++++++++ .../models/filter/filter-configuration.ts | 11 +++++++++++ .../models/formula/formula-operation.model.ts | 12 ++++++++++++ api/src/schema.gql | 15 +++++++++++++++ .../users/interceptors/users.interceptor.ts | 3 +++ api/src/users/users.service.ts | 2 +- 9 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 api/src/engine/models/filter/filter-configuration.ts create mode 100644 api/src/engine/models/formula/formula-operation.model.ts diff --git a/api/src/engine/connectors/exareme/converters.ts b/api/src/engine/connectors/exareme/converters.ts index a1c28d5..b252820 100644 --- a/api/src/engine/connectors/exareme/converters.ts +++ b/api/src/engine/connectors/exareme/converters.ts @@ -221,6 +221,25 @@ export const dataToExperiment = ( .flat() : []; + const allVariables = exp.filterVariables || []; + + // add filter variables + const extractVariablesFromFilter = (filter: any): any => + filter.rules.forEach((r: any) => { + if (r.rules) { + extractVariablesFromFilter(r); + } + if (r.id) { + allVariables.push(r.id); + } + }); + + if (exp && exp.filter) { + extractVariablesFromFilter(JSON.parse(exp.filter)); + } + + exp.filterVariables = Array.from(new Set(allVariables)); + return exp; } catch (e) { return { diff --git a/api/src/engine/connectors/exareme/main.connector.ts b/api/src/engine/connectors/exareme/main.connector.ts index e0bde63..ea93932 100644 --- a/api/src/engine/connectors/exareme/main.connector.ts +++ b/api/src/engine/connectors/exareme/main.connector.ts @@ -23,6 +23,7 @@ import { PartialExperiment, } from 'src/engine/models/experiment/experiment.model'; import { ListExperiments } from 'src/engine/models/experiment/list-experiments.model'; +import { FormulaOperation } from 'src/engine/models/formula/formula-operation.model'; import { Group } from 'src/engine/models/group.model'; import { Variable } from 'src/engine/models/variable.model'; import { ExperimentCreateInput } from 'src/experiments/models/input/experiment-create.input'; @@ -52,6 +53,19 @@ export default class ExaremeService implements IEngineService { private readonly httpService: HttpService, ) {} + async getFormulaConfiguration(): Promise<FormulaOperation[]> { + return [ + { + variableType: 'real', + operationTypes: ['log', 'exp', 'center', 'standardize'], + }, + { + variableType: 'nominal', + operationTypes: ['dummy', 'poly', 'contrast', 'additive'], + }, + ]; + } + getConfiguration(): IConfiguration { return { contactLink: 'https://ebrains.eu/support/', diff --git a/api/src/engine/engine.interfaces.ts b/api/src/engine/engine.interfaces.ts index 08fb861..f1cf66f 100644 --- a/api/src/engine/engine.interfaces.ts +++ b/api/src/engine/engine.interfaces.ts @@ -13,6 +13,8 @@ import { ExperimentCreateInput } from '../experiments/models/input/experiment-cr import { ExperimentEditInput } from '../experiments/models/input/experiment-edit.input'; import { ListExperiments } from './models/experiment/list-experiments.model'; import { ResultUnion } from './models/result/common/result-union.model'; +import { FormulaOperation } from './models/formula/formula-operation.model'; +import { FilterConfiguration } from './models/filter/filter-configuration'; export interface IEngineOptions { type: string; @@ -122,6 +124,22 @@ export interface IEngineService { data?: UpdateUserInput, ): Promise<User | undefined>; + /** + * This is a method that is used to get the list of formula operations + * that are available in the engine. + * @param req - Request - Optional request object from the HTTP request + * @returns - Formula configuration + */ + getFormulaConfiguration?(req?: Request): Promise<FormulaOperation[]>; + + /** + * This is a method that is used to get the filter configuration + * that is available in the engine. + * @param req - Request - Optional request object from the HTTP request + * @returns Filter configuration + */ + getFilterConfiguration?(req?: Request): Promise<FilterConfiguration[]>; + /** * Perform a logout on the current logged in user * @param req - Request - this is the request object from the HTTP request. diff --git a/api/src/engine/engine.resolver.ts b/api/src/engine/engine.resolver.ts index 78b2abd..9a20cc5 100644 --- a/api/src/engine/engine.resolver.ts +++ b/api/src/engine/engine.resolver.ts @@ -19,6 +19,8 @@ import { ErrorsInterceptor } from './interceptors/errors.interceptor'; import { Configuration } from './models/configuration.model'; import { Domain } from './models/domain.model'; import { Algorithm } from './models/experiment/algorithm.model'; +import { FilterConfiguration } from './models/filter/filter-configuration'; +import { FormulaOperation } from './models/formula/formula-operation.model'; @UseInterceptors(ErrorsInterceptor) @UseGuards(GlobalAuthGuard) @@ -73,4 +75,20 @@ export class EngineResolver { async algorithms(@GQLRequest() req: Request) { return this.engineService.getAlgorithms(req); } + + @Query(() => [FormulaOperation]) + async formula() { + if (this.engineService.getFormulaConfiguration) + return this.engineService.getFormulaConfiguration(); + + return []; + } + + @Query(() => FilterConfiguration) + async filter() { + if (this.engineService.getFilterConfiguration) + return this.engineService.getFilterConfiguration(); + + return []; + } } diff --git a/api/src/engine/models/filter/filter-configuration.ts b/api/src/engine/models/filter/filter-configuration.ts new file mode 100644 index 0000000..4360570 --- /dev/null +++ b/api/src/engine/models/filter/filter-configuration.ts @@ -0,0 +1,11 @@ +import { Field, ObjectType } from '@nestjs/graphql'; + +@ObjectType() +export class FilterConfiguration { + @Field(() => [String], { + description: 'List of types that can considered as number', + defaultValue: ['real', 'integer'], + nullable: true, + }) + numberTypes?: string[]; +} diff --git a/api/src/engine/models/formula/formula-operation.model.ts b/api/src/engine/models/formula/formula-operation.model.ts new file mode 100644 index 0000000..8207751 --- /dev/null +++ b/api/src/engine/models/formula/formula-operation.model.ts @@ -0,0 +1,12 @@ +import { Field, ObjectType } from '@nestjs/graphql'; + +@ObjectType() +export class FormulaOperation { + @Field({ description: 'Type name of the variable' }) + variableType: string; + + @Field(() => [String], { + description: 'List of operation available for this type', + }) + operationTypes: string[]; +} diff --git a/api/src/schema.gql b/api/src/schema.gql index bacb2ed..4311e4d 100644 --- a/api/src/schema.gql +++ b/api/src/schema.gql @@ -158,6 +158,19 @@ type Algorithm { description: String } +type FilterConfiguration { + """List of types that can considered as number""" + numberTypes: [String!] +} + +type FormulaOperation { + """Type name of the variable""" + variableType: String! + + """List of operation available for this type""" + operationTypes: [String!]! +} + type GroupResult { name: String! description: String @@ -358,6 +371,8 @@ type Query { configuration: Configuration! domains(ids: [String!] = []): [Domain!]! algorithms: [Algorithm!]! + formula: [FormulaOperation!]! + filter: FilterConfiguration! user: User! experimentList(page: Float = 0, name: String = ""): ListExperiments! experiment(id: String!): Experiment! diff --git a/api/src/users/interceptors/users.interceptor.ts b/api/src/users/interceptors/users.interceptor.ts index e41804c..d0fd278 100644 --- a/api/src/users/interceptors/users.interceptor.ts +++ b/api/src/users/interceptors/users.interceptor.ts @@ -20,6 +20,9 @@ export class UsersInterceptor implements NestInterceptor { const ctx = GqlExecutionContext.create(context); const req = ctx.getContext().req ?? ctx.switchToHttp().getRequest(); + if (req.userExtended) return next.handle(); // user already extended + req.userExtended = true; + const user: User = req.user; if (user && user.id) { await this.usersService.extendedUser(user); diff --git a/api/src/users/users.service.ts b/api/src/users/users.service.ts index bcf4317..3138f9a 100644 --- a/api/src/users/users.service.ts +++ b/api/src/users/users.service.ts @@ -60,7 +60,7 @@ export class UsersService { } catch (err) { if (err instanceof NotFoundException) this.logger.debug( - `Extension of ${user.id} aborted, no user found in database`, + `Extension of ${user.id} not needed, user not found in database`, ); } } -- GitLab