Skip to content
Snippets Groups Projects
Commit fca79819 authored by Steve Reis's avatar Steve Reis
Browse files

Merge branch 'develop' into 'main'

Merge Request for the MIP 6.5 release

See merge request sibmip/gateway!24
parents b54b8207 995ab67e
No related branches found
No related tags found
No related merge requests found
Showing
with 983 additions and 15 deletions
image: docker:20
services:
- docker:20-dind
stages:
- build
- release
- deploy
variables:
CONTAINER_BASE_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
build:
stage: build
script:
- docker build -t $CONTAINER_BASE_IMAGE ./api
- docker push $CONTAINER_BASE_IMAGE
only:
- main
- develop
- /^release-.*$/
ENGINE_TYPE=exareme
ENGINE_BASE_URL=http://127.0.0.1:8080/services/
GATEWAY_PORT=8081
...@@ -20,5 +20,6 @@ module.exports = { ...@@ -20,5 +20,6 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
'prettier/prettier': ['error', { "endOfLine": "auto"}, { usePrettierrc: true }],
}, },
}; };
...@@ -32,4 +32,7 @@ lerna-debug.log* ...@@ -32,4 +32,7 @@ lerna-debug.log*
!.vscode/settings.json !.vscode/settings.json
!.vscode/tasks.json !.vscode/tasks.json
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
\ No newline at end of file
# env
.env
\ No newline at end of file
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
cd api
npm run lint
FROM node:12.13-alpine As development
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --development
COPY . .
RUN npm run build
RUN npm run test
FROM node:12.13-alpine as production
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
RUN apk update && apk add bash
RUN apk add --no-cache bash
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --production
COPY . .
COPY --from=development /usr/src/app/dist ./dist
CMD ["node", "dist/main"]
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@nestjs/axios": "^0.0.1", "@nestjs/axios": "^0.0.1",
"@nestjs/common": "^8.0.0", "@nestjs/common": "^8.0.0",
"@nestjs/config": "^1.0.1",
"@nestjs/core": "^8.0.0", "@nestjs/core": "^8.0.0",
"@nestjs/graphql": "^9.0.4", "@nestjs/graphql": "^9.0.4",
"@nestjs/platform-express": "^8.0.0", "@nestjs/platform-express": "^8.0.0",
...@@ -18,6 +19,8 @@ ...@@ -18,6 +19,8 @@
"apollo-server-express": "^3.3.0", "apollo-server-express": "^3.3.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"graphql": "^15.5.3", "graphql": "^15.5.3",
"graphql-type-json": "^0.3.2",
"jsonata": "^1.8.5",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.2.0" "rxjs": "^7.2.0"
...@@ -35,6 +38,7 @@ ...@@ -35,6 +38,7 @@
"eslint": "^7.30.0", "eslint": "^7.30.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0", "eslint-plugin-prettier": "^3.4.0",
"husky": "^7.0.2",
"jest": "^27.0.6", "jest": "^27.0.6",
"prettier": "^2.3.2", "prettier": "^2.3.2",
"supertest": "^6.1.3", "supertest": "^6.1.3",
...@@ -1765,6 +1769,32 @@ ...@@ -1765,6 +1769,32 @@
} }
} }
}, },
"node_modules/@nestjs/config": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@nestjs/config/-/config-1.0.1.tgz",
"integrity": "sha512-azMl4uYlFIhYsywFxPJT81RxF3Pnn0TZW3EEmr0Wa0Wex8R2xpvBNrCcrOgW3TB1xGMP7eqBrlfsVh5ZP82szg==",
"dependencies": {
"dotenv": "10.0.0",
"dotenv-expand": "5.1.0",
"lodash.get": "4.4.2",
"lodash.has": "4.5.2",
"lodash.set": "4.3.2",
"uuid": "8.3.2"
},
"peerDependencies": {
"@nestjs/common": "^7.0.0 || ^8.0.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^6.0.0 || ^7.2.0"
}
},
"node_modules/@nestjs/config/node_modules/dotenv": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
"engines": {
"node": ">=10"
}
},
"node_modules/@nestjs/core": { "node_modules/@nestjs/core": {
"version": "8.0.6", "version": "8.0.6",
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.0.6.tgz", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.0.6.tgz",
...@@ -4392,6 +4422,11 @@ ...@@ -4392,6 +4422,11 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/dotenv-expand": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
...@@ -5548,6 +5583,14 @@ ...@@ -5548,6 +5583,14 @@
"graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0" "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
} }
}, },
"node_modules/graphql-type-json": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz",
"integrity": "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==",
"peerDependencies": {
"graphql": ">=0.8.0"
}
},
"node_modules/graphql-ws": { "node_modules/graphql-ws": {
"version": "5.4.0", "version": "5.4.0",
"resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.4.0.tgz", "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.4.0.tgz",
...@@ -5695,6 +5738,21 @@ ...@@ -5695,6 +5738,21 @@
"node": ">=10.17.0" "node": ">=10.17.0"
} }
}, },
"node_modules/husky": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.2.tgz",
"integrity": "sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg==",
"dev": true,
"bin": {
"husky": "lib/bin.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
}
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
...@@ -7124,6 +7182,14 @@ ...@@ -7124,6 +7182,14 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/jsonata": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/jsonata/-/jsonata-1.8.5.tgz",
"integrity": "sha512-ilDyTBkg6qhNoNVr8PUPzz5GYvRK+REKOM5MdOGzH2y6V4yvPRMegSvbZLpbTtI0QAgz09QM7drDhSHUlwp9pA==",
"engines": {
"node": ">= 8"
}
},
"node_modules/jsonc-parser": { "node_modules/jsonc-parser": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
...@@ -7217,12 +7283,27 @@ ...@@ -7217,12 +7283,27 @@
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
"dev": true "dev": true
}, },
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"node_modules/lodash.has": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz",
"integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI="
},
"node_modules/lodash.merge": { "node_modules/lodash.merge": {
"version": "4.6.2", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true "dev": true
}, },
"node_modules/lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
},
"node_modules/lodash.sortby": { "node_modules/lodash.sortby": {
"version": "4.7.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
...@@ -11891,6 +11972,26 @@ ...@@ -11891,6 +11972,26 @@
"uuid": "8.3.2" "uuid": "8.3.2"
} }
}, },
"@nestjs/config": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@nestjs/config/-/config-1.0.1.tgz",
"integrity": "sha512-azMl4uYlFIhYsywFxPJT81RxF3Pnn0TZW3EEmr0Wa0Wex8R2xpvBNrCcrOgW3TB1xGMP7eqBrlfsVh5ZP82szg==",
"requires": {
"dotenv": "10.0.0",
"dotenv-expand": "5.1.0",
"lodash.get": "4.4.2",
"lodash.has": "4.5.2",
"lodash.set": "4.3.2",
"uuid": "8.3.2"
},
"dependencies": {
"dotenv": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
}
}
},
"@nestjs/core": { "@nestjs/core": {
"version": "8.0.6", "version": "8.0.6",
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.0.6.tgz", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.0.6.tgz",
...@@ -13914,6 +14015,11 @@ ...@@ -13914,6 +14015,11 @@
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
"peer": true "peer": true
}, },
"dotenv-expand": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
},
"ee-first": { "ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
...@@ -14791,6 +14897,12 @@ ...@@ -14791,6 +14897,12 @@
"tslib": "^2.1.0" "tslib": "^2.1.0"
} }
}, },
"graphql-type-json": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz",
"integrity": "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==",
"requires": {}
},
"graphql-ws": { "graphql-ws": {
"version": "5.4.0", "version": "5.4.0",
"resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.4.0.tgz", "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.4.0.tgz",
...@@ -14901,6 +15013,12 @@ ...@@ -14901,6 +15013,12 @@
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
"dev": true "dev": true
}, },
"husky": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.2.tgz",
"integrity": "sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg==",
"dev": true
},
"iconv-lite": { "iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
...@@ -15985,6 +16103,11 @@ ...@@ -15985,6 +16103,11 @@
"minimist": "^1.2.5" "minimist": "^1.2.5"
} }
}, },
"jsonata": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/jsonata/-/jsonata-1.8.5.tgz",
"integrity": "sha512-ilDyTBkg6qhNoNVr8PUPzz5GYvRK+REKOM5MdOGzH2y6V4yvPRMegSvbZLpbTtI0QAgz09QM7drDhSHUlwp9pA=="
},
"jsonc-parser": { "jsonc-parser": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
...@@ -16061,12 +16184,27 @@ ...@@ -16061,12 +16184,27 @@
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
"dev": true "dev": true
}, },
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.has": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz",
"integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI="
},
"lodash.merge": { "lodash.merge": {
"version": "4.6.2", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true "dev": true
}, },
"lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
},
"lodash.sortby": { "lodash.sortby": {
"version": "4.7.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
......
...@@ -18,11 +18,13 @@ ...@@ -18,11 +18,13 @@
"test:watch": "jest --watch", "test:watch": "jest --watch",
"test:cov": "jest --coverage", "test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json" "test:e2e": "jest --config ./test/jest-e2e.json",
"prepare": "cd .. && husky install api/.husky"
}, },
"dependencies": { "dependencies": {
"@nestjs/axios": "^0.0.1", "@nestjs/axios": "^0.0.1",
"@nestjs/common": "^8.0.0", "@nestjs/common": "^8.0.0",
"@nestjs/config": "^1.0.1",
"@nestjs/core": "^8.0.0", "@nestjs/core": "^8.0.0",
"@nestjs/graphql": "^9.0.4", "@nestjs/graphql": "^9.0.4",
"@nestjs/platform-express": "^8.0.0", "@nestjs/platform-express": "^8.0.0",
...@@ -30,6 +32,8 @@ ...@@ -30,6 +32,8 @@
"apollo-server-express": "^3.3.0", "apollo-server-express": "^3.3.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"graphql": "^15.5.3", "graphql": "^15.5.3",
"graphql-type-json": "^0.3.2",
"jsonata": "^1.8.5",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.2.0" "rxjs": "^7.2.0"
...@@ -47,6 +51,7 @@ ...@@ -47,6 +51,7 @@
"eslint": "^7.30.0", "eslint": "^7.30.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0", "eslint-plugin-prettier": "^3.4.0",
"husky": "^7.0.2",
"jest": "^27.0.6", "jest": "^27.0.6",
"prettier": "^2.3.2", "prettier": "^2.3.2",
"supertest": "^6.1.3", "supertest": "^6.1.3",
......
export type Dictionary<T> = { [key: string]: T };
import { firstValueFrom, Observable } from 'rxjs';
import { IEngineOptions, IEngineService } from 'src/engine/engine.interfaces';
import { Domain } from 'src/engine/models/domain.model';
import { ExperimentCreateInput } from 'src/engine/models/experiment/input/experiment-create.input';
import {
Experiment,
PartialExperiment,
} from 'src/engine/models/experiment/experiment.model';
import { ListExperiments } from 'src/engine/models/experiment/list-experiments.model';
import { ExperimentEditInput } from 'src/engine/models/experiment/input/experiment-edit.input';
import { Algorithm } from 'src/engine/models/experiment/algorithm.model';
import { HttpService } from '@nestjs/axios';
import { Group } from 'src/engine/models/group.model';
import { Dictionary } from 'src/common/interfaces/utilities.interface';
export default class CSVService implements IEngineService {
constructor(
private readonly options: IEngineOptions,
private readonly httpService: HttpService,
) {}
logout() {
throw new Error('Method not implemented.');
}
getAlgorithms(): Algorithm[] | Promise<Algorithm[]> {
throw new Error('Method not implemented.');
}
createExperiment(
data: ExperimentCreateInput,
isTransient: boolean,
): Experiment | Promise<Experiment> {
throw new Error('Method not implemented.');
}
listExperiments(
page: number,
name: string,
): ListExperiments | Promise<ListExperiments> {
throw new Error('Method not implemented.');
}
getExperiment(uuid: string): Experiment | Promise<Experiment> {
throw new Error('Method not implemented.');
}
removeExperiment(
uuid: string,
): PartialExperiment | Promise<PartialExperiment> {
throw new Error('Method not implemented.');
}
editExperient(
uuid: string,
expriment: ExperimentEditInput,
): Experiment | Promise<Experiment> {
throw new Error('Method not implemented.');
}
async getDomains(): Promise<Domain[]> {
const path = this.options.baseurl;
const { data } = await firstValueFrom(this.httpService.get<string>(path));
const rows = data
.split('\r\n')
.map((row) => row.split('\t').filter((i) => i))
.filter((row) => row.length >= 2);
rows.shift(); // remove headers
const vars = [];
const groups: Dictionary<Group> = {};
const rootGroup: Group = {
id: 'Global group',
groups: [],
};
rows.forEach((row) => {
const variable = {
id: row[0].toLowerCase(),
label: row[0],
};
row.shift(); // get ride of the variable name, keep only groups
vars.push(variable);
row
.filter((group) => !groups[group.toLowerCase()])
.forEach((group, i) => {
const groupId = group.toLowerCase();
if (i === 0) rootGroup.groups.push(groupId);
groups[groupId] = {
id: groupId,
label: group,
variables: [],
groups: [],
};
});
const groupId = row[row.length - 1].toLowerCase(); // group's variable container
groups[groupId].variables.push(variable.id); // add variable
row
.reverse()
.map((group) => group.toLowerCase())
.forEach((group, i) => {
const groupId = group.toLowerCase();
if (i !== row.length - 1) {
const parentId = row[i + 1].toLowerCase();
if (groups[parentId].groups.indexOf(groupId) === -1)
groups[parentId].groups.push(groupId);
}
});
});
rootGroup.groups = [...new Set(rootGroup.groups)]; // get distinct values
return [
{
id: 'Dummy',
label: 'Dummy',
datasets: [{ id: 'DummyDataset', label: 'Dummy Dataset' }],
groups: Object.values(groups),
rootGroup: rootGroup,
variables: vars,
},
];
}
getActiveUser(): string {
const dummyUser = {
username: 'anonymous',
subjectId: 'anonymousId',
fullname: 'anonymous',
email: 'anonymous@anonymous.com',
agreeNDA: true,
};
return JSON.stringify(dummyUser);
}
editActiveUser(): Observable<string> {
throw new Error('Method not implemented.');
}
getExperimentREST(): Observable<string> {
throw new Error('Method not implemented.');
}
deleteExperiment(): Observable<string> {
throw new Error('Method not implemented.');
}
editExperimentREST(): Observable<string> {
throw new Error('Method not implemented.');
}
startExperimentTransient(): Observable<string> {
throw new Error('Method not implemented.');
}
startExperiment(): Observable<string> {
throw new Error('Method not implemented.');
}
getExperiments(): string {
return '[]';
}
getAlgorithmsREST(): string {
return '[]';
}
}
import { HttpService } from "@nestjs/axios"; import { Observable } from 'rxjs';
import { IEngineOptions, IEngineService } from "src/engine/engine.interface"; import { IEngineService } from 'src/engine/engine.interfaces';
import { Domain } from 'src/engine/models/domain.model';
import { ExperimentCreateInput } from 'src/engine/models/experiment/input/experiment-create.input';
import {
Experiment,
PartialExperiment,
} from 'src/engine/models/experiment/experiment.model';
import { ListExperiments } from 'src/engine/models/experiment/list-experiments.model';
import { ExperimentEditInput } from 'src/engine/models/experiment/input/experiment-edit.input';
import { Algorithm } from 'src/engine/models/experiment/algorithm.model';
export default class DataShieldService implements IEngineService { export default class DataShieldService implements IEngineService {
constructor(private readonly options: IEngineOptions, private readonly httpService: HttpService) { } logout(): void {
throw new Error('Method not implemented.');
}
demo(): string { getAlgorithms(): Algorithm[] | Promise<Algorithm[]> {
return "datashield"; throw new Error('Method not implemented.');
} }
}
\ No newline at end of file createExperiment(
data: ExperimentCreateInput,
isTransient: boolean,
): Experiment | Promise<Experiment> {
throw new Error('Method not implemented.');
}
listExperiments(
page: number,
name: string,
): ListExperiments | Promise<ListExperiments> {
throw new Error('Method not implemented.');
}
getExperiment(uuid: string): Experiment | Promise<Experiment> {
throw new Error('Method not implemented.');
}
removeExperiment(
uuid: string,
): PartialExperiment | Promise<PartialExperiment> {
throw new Error('Method not implemented.');
}
editExperient(
uuid: string,
expriment: ExperimentEditInput,
): Experiment | Promise<Experiment> {
throw new Error('Method not implemented.');
}
getDomains(): Domain[] {
throw new Error('Method not implemented.');
}
getActiveUser(): string {
throw new Error('Method not implemented.');
}
editActiveUser(): Observable<string> {
throw new Error('Method not implemented.');
}
getExperimentREST(): Observable<string> {
throw new Error('Method not implemented.');
}
deleteExperiment(): Observable<string> {
throw new Error('Method not implemented.');
}
editExperimentREST(): Observable<string> {
throw new Error('Method not implemented.');
}
startExperimentTransient(): Observable<string> {
throw new Error('Method not implemented.');
}
startExperiment(): Observable<string> {
throw new Error('Method not implemented.');
}
getExperiments(): string {
throw new Error('Method not implemented.');
}
getAlgorithmsREST(): string {
throw new Error('Method not implemented.');
}
}
import { Category } from 'src/engine/models/category.model';
import { AlgorithmParameter } from 'src/engine/models/experiment/algorithm-parameter.model';
import { Algorithm } from 'src/engine/models/experiment/algorithm.model';
import { Experiment } from 'src/engine/models/experiment/experiment.model';
import { ExperimentCreateInput } from 'src/engine/models/experiment/input/experiment-create.input';
import { Group } from 'src/engine/models/group.model';
import { ResultUnion } from 'src/engine/models/result/common/result-union.model';
import {
GroupResult,
GroupsResult,
} from 'src/engine/models/result/groups-result.model';
import { RawResult } from 'src/engine/models/result/raw-result.model';
import { Variable } from 'src/engine/models/variable.model';
import { Entity } from './interfaces/entity.interface';
import { ExperimentData } from './interfaces/experiment/experiment.interface';
import { ResultExperiment } from './interfaces/experiment/result-experiment.interface';
import { Hierarchy } from './interfaces/hierarchy.interface';
import { VariableEntity } from './interfaces/variable-entity.interface';
import {
descriptiveModelToTables,
descriptiveSingleToTables,
transformToAlgorithms,
transformToExperiment,
} from './transformations';
export const dataToGroup = (data: Hierarchy): Group => {
return {
id: data.code,
label: data.label,
groups: data.groups
? data.groups.map(dataToGroup).map((group) => group.id)
: [],
variables: data.variables
? data.variables.map((data: VariableEntity) => data.code)
: [],
};
};
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: [],
};
};
const algoParamInputToData = (param: AlgorithmParameter) => {
return {
name: param.name,
label: param.name,
value: param.value.join(','),
};
};
export const experimentInputToData = (data: ExperimentCreateInput) => {
const formula =
((data.transformations?.length > 0 || data.interactions?.length > 0) && {
single:
data.transformations?.map((t) => ({
var_name: t.name,
unary_operation: t.operation,
})) || [],
interactions:
data.interactions?.map((v) =>
v.reduce((a, e, i) => ({ ...a, [`var${i + 1}`]: e }), {}),
) || [],
}) ||
null;
return {
algorithm: {
parameters: [
{
name: 'dataset',
label: 'dataset',
value: data.datasets.join(','),
},
{
name: 'filter',
label: 'filter',
value: data.filter,
},
{
name: 'pathology',
label: 'pathology',
value: data.domain,
},
{
name: 'y',
label: 'y',
value: data.variables.join(','),
},
...(formula
? [
{
name: 'formula',
value: JSON.stringify(formula),
},
]
: []),
].concat(data.algorithm.parameters.map(algoParamInputToData)),
type: data.algorithm.type ?? 'string',
name: data.algorithm.name,
},
name: data.name,
};
};
export const descriptiveDataToTableResult = (
data: ResultExperiment,
): GroupsResult[] => {
const result = new GroupsResult();
result.groups = [
new GroupResult({
name: 'Variables',
description: 'Descriptive statistics for the variables of interest.',
results: descriptiveSingleToTables.evaluate(data),
}),
];
result.groups.push(
new GroupResult({
name: 'Model',
description:
'Intersection table for the variables of interest as it appears in the experiment.',
results: descriptiveModelToTables.evaluate(data),
}),
);
return [result];
};
export const dataToExperiment = (data: ExperimentData): Experiment => {
const expTransform = transformToExperiment.evaluate(data);
const exp: Experiment = {
...expTransform,
results: [],
};
exp.results = data.result
? data.result
.map((result) => dataToResult(result, exp.algorithm.name))
.flat()
: [];
return exp;
};
export const dataToAlgorithms = (data: string): Algorithm[] => {
return transformToAlgorithms.evaluate(data);
};
export const dataToRaw = (result: ResultExperiment): RawResult[] => {
return [
{
rawdata: result.data,
},
];
};
export const dataToResult = (
result: ResultExperiment,
algo: string,
): Array<typeof ResultUnion> => {
switch (result.type.toLowerCase()) {
case 'application/json':
return dataJSONtoResult(result, algo);
default:
return dataToRaw(result);
}
};
export const dataJSONtoResult = (
result: ResultExperiment,
algo: string,
): Array<typeof ResultUnion> => {
switch (algo.toLowerCase()) {
case 'descriptive_stats':
return descriptiveDataToTableResult(result);
default:
return [];
}
};
export interface Entity {
code: string;
label?: string;
}
import { ResultExperiment } from './result-experiment.interface';
export interface ExperimentData {
name: string;
uuid?: string;
status?: string;
createdBy?: string;
shared?: boolean;
viewed?: boolean;
result?: ResultExperiment[];
}
import { ExperimentData } from './experiment.interface';
export interface ExperimentsData {
experiments: ExperimentData[];
currentpage?: number;
totalExperiments?: number;
totalPages?: number;
}
export interface ResultExperiment {
data: unknown;
type: string;
}
import { VariableEntity } from './variable-entity.interface';
export interface Hierarchy {
code: string;
label: string;
groups: Hierarchy[];
variables: VariableEntity[];
}
import { Hierarchy } from './hierarchy.interface';
import { VariableEntity } from './variable-entity.interface';
export interface Pathology {
code: string;
label: string;
datasets: VariableEntity[];
metadataHierarchy: Hierarchy;
}
import { Entity } from './entity.interface';
export interface VariableEntity extends Entity {
type?: 'nominal' | 'ordinal' | 'real' | 'integer' | 'text' | 'date';
description?: string;
enumerations?: Entity[];
group?: Entity[];
info?: string;
}
import { HttpService } from "@nestjs/axios"; import { HttpService } from '@nestjs/axios';
import { IEngineOptions, IEngineService } from "src/engine/engine.interface"; import {
BadRequestException,
HttpException,
HttpStatus,
Inject,
Injectable,
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import { firstValueFrom, map, Observable } from 'rxjs';
import { ENGINE_MODULE_OPTIONS } from 'src/engine/engine.constants';
import { IEngineOptions, IEngineService } from 'src/engine/engine.interfaces';
import { Domain } from 'src/engine/models/domain.model';
import { Algorithm } from 'src/engine/models/experiment/algorithm.model';
import {
Experiment,
PartialExperiment,
} from 'src/engine/models/experiment/experiment.model';
import { ExperimentCreateInput } from 'src/engine/models/experiment/input/experiment-create.input';
import { ExperimentEditInput } from 'src/engine/models/experiment/input/experiment-edit.input';
import { ListExperiments } from 'src/engine/models/experiment/list-experiments.model';
import { Group } from 'src/engine/models/group.model';
import { Variable } from 'src/engine/models/variable.model';
import {
dataToAlgorithms,
dataToCategory,
dataToExperiment,
dataToGroup,
dataToVariable,
experimentInputToData,
} from './converters';
import { ExperimentData } from './interfaces/experiment/experiment.interface';
import { ExperimentsData } from './interfaces/experiment/experiments.interface';
import { Hierarchy } from './interfaces/hierarchy.interface';
import { Pathology } from './interfaces/pathology.interface';
@Injectable()
export default class ExaremeService implements IEngineService { export default class ExaremeService implements IEngineService {
constructor(private readonly options: IEngineOptions, private readonly httpService: HttpService) { } constructor(
@Inject(ENGINE_MODULE_OPTIONS) private readonly options: IEngineOptions,
private readonly httpService: HttpService,
@Inject(REQUEST) private readonly req: Request,
) {}
demo(): string { async logout() {
return "exareme" const path = `${this.options.baseurl}logout`;
await firstValueFrom(this.httpService.get(path));
}
async createExperiment(
data: ExperimentCreateInput,
isTransient = false,
): Promise<Experiment> {
const form = experimentInputToData(data);
const path =
this.options.baseurl + `experiments${isTransient ? '/transient' : ''}`;
const resultAPI = await firstValueFrom(
this.httpService.post<ExperimentData>(path, form),
);
return dataToExperiment(resultAPI.data);
}
async listExperiments(page: number, name: string): Promise<ListExperiments> {
const path = this.options.baseurl + 'experiments';
const resultAPI = await firstValueFrom(
this.httpService.get<ExperimentsData>(path, { params: { page, name } }),
);
return {
...resultAPI.data,
experiments: resultAPI.data.experiments.map(dataToExperiment),
};
}
async getAlgorithms(): Promise<Algorithm[]> {
const path = this.options.baseurl + 'algorithms';
const resultAPI = await firstValueFrom(this.httpService.get<string>(path));
return dataToAlgorithms(resultAPI.data);
}
async getExperiment(uuid: string): Promise<Experiment> {
const path = this.options.baseurl + `experiments/${uuid}`;
const resultAPI = await firstValueFrom(
this.httpService.get<ExperimentData>(path),
);
return dataToExperiment(resultAPI.data);
}
async editExperient(
uuid: string,
expriment: ExperimentEditInput,
): Promise<Experiment> {
const path = this.options.baseurl + `experiments/${uuid}`;
const resultAPI = await firstValueFrom(
this.httpService.patch<ExperimentData>(path, expriment),
);
return dataToExperiment(resultAPI.data);
}
async removeExperiment(uuid: string): Promise<PartialExperiment> {
const path = this.options.baseurl + `experiments/${uuid}`;
try {
await firstValueFrom(this.httpService.delete(path));
return {
uuid: uuid,
};
} catch (error) {
throw new BadRequestException(`${uuid} does not exists`);
} }
} }
\ No newline at end of file
async getDomains(ids: string[]): Promise<Domain[]> {
const path = this.options.baseurl + 'pathologies';
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,
rootGroup: dataToGroup(data.metadataHierarchy),
datasets: data.datasets ? data.datasets.map(dataToCategory) : [],
variables: data.metadataHierarchy
? this.flattenVariables(data.metadataHierarchy, groups)
: [],
};
}) ?? []
);
} catch (error) {
throw new HttpException(
`Error in exareme engine : '${error.response.data['message']}'`,
error.response.data['statusCode'] ?? HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
getActiveUser(): Observable<string> {
const path = this.options.baseurl + 'activeUser';
return this.httpService
.get<string>(path)
.pipe(map((response) => response.data));
}
editActiveUser(): Observable<string> {
const path = this.options.baseurl + 'activeUser/agreeNDA';
return this.httpService
.post<string>(path, this.req.body)
.pipe(map((response) => response.data));
}
getExperimentREST(uuid: string): Observable<string> {
const path = this.options.baseurl + `experiments/${uuid}`;
return this.httpService
.get<string>(path)
.pipe(map((response) => response.data));
}
deleteExperiment(uuid: string): Observable<string> {
const path = this.options.baseurl + `experiments/${uuid}`;
return this.httpService.delete(path).pipe(map((response) => response.data));
}
editExperimentREST(uuid: string): Observable<string> {
const path = this.options.baseurl + `experiments/${uuid}`;
return this.httpService
.patch(path, this.req.body)
.pipe(map((response) => response.data));
}
startExperimentTransient(): Observable<string> {
const path = this.options.baseurl + 'experiments/transient';
return this.httpService
.post(path, this.req.body)
.pipe(map((response) => response.data));
}
startExperiment(): Observable<string> {
const path = this.options.baseurl + 'experiments';
return this.httpService
.post(path, this.req.body)
.pipe(map((response) => response.data));
}
getExperiments(): Observable<string> {
const path = this.options.baseurl + 'experiments';
return this.httpService
.get<string>(path, { params: this.req.query })
.pipe(map((response) => response.data));
}
getAlgorithmsREST(): Observable<string> {
const path = this.options.baseurl + 'algorithms';
return this.httpService
.get<string>(path, { params: this.req.query })
.pipe(map((response) => response.data));
}
// UTILITIES
private flattenGroups = (data: Hierarchy): Group[] => {
let groups: Group[] = [dataToGroup(data)];
if (data.groups) {
groups = groups.concat(data.groups.flatMap(this.flattenGroups));
}
return groups;
};
private flattenVariables = (data: Hierarchy, groups: Group[]): Variable[] => {
const group = groups.find((group) => group.id == data.code);
let variables = data.variables ? data.variables.map(dataToVariable) : [];
variables.forEach((variable) => (variable.groups = group ? [group] : []));
if (data.groups) {
variables = variables.concat(
data.groups.flatMap((hierarchy) =>
this.flattenVariables(hierarchy, groups),
),
);
}
return variables;
};
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment