Skip to content

Commit f5f4da8

Browse files
committed
feat: CQDG-680 add FERLOAD_URL
1 parent c7edfc4 commit f5f4da8

File tree

13 files changed

+121
-35
lines changed

13 files changed

+121
-35
lines changed

Diff for: .env.example

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ KEYCLOAK_URL=
1010
KEYCLOAK_REALM=
1111
KEYCLOAK_CLIENT=
1212

13+
# Ferload
14+
FERLOAD_URL=
15+
1316
# Suggestion configuration
1417
MAX_NUMBER_OF_GF_SUGGESTIONS=
1518
GENES_SUGGESTIONS_INDEX_NAME=
@@ -36,6 +39,4 @@ FILE_ID_KEY=
3639
STUDY_ID_KEY=
3740
PARTICIPANT_ID_KEY=
3841
BIOSPECIMEN_ID_KEY=
39-
FAMILY_ID_KEY=
40-
41-
ADD_CAG_COUNT=
42+
FAMILY_ID_KEY=

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cqdg-wrapper-next",
3-
"version": "2.0.10",
3+
"version": "2.0.11",
44
"description": ":factory: a data-model aware GraphQL API that sits above an Elasticsearch cluster",
55
"main": "src/index.js",
66
"type": "module",

Diff for: src/config/env.ts

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export const keycloakURL = process.env.KEYCLOAK_URL || 'https://auth.qa.juno.cqd
1111
export const keycloakRealm = process.env.KEYCLOAK_REALM || 'CQDG';
1212
export const keycloakClient = process.env.KEYCLOAK_CLIENT || 'cqdg-client';
1313

14+
export const ferloadURL = process.env.FERLOAD_URL || 'https://ferload.qa.juno.cqdg.ferlab.bio';
15+
1416
export const esHost = process.env.ES_HOST || 'http://localhost:9200';
1517
export const esUser = process.env.ES_USER;
1618
export const esPass = process.env.ES_PASS;

Diff for: src/graphql/biospecimen/model.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getBody } from '#src/services/elasticsearch/utils';
44
import { BiospecimenType } from './types/biospecimen';
55

66
const get = async (file_id, context) => {
7-
const { body } = await context.es.get({ index: esBiospecimenIndex, file_id });
7+
const { body } = await context.esClient.get({ index: esBiospecimenIndex, file_id });
88
return body._source;
99
};
1010

@@ -14,7 +14,7 @@ const getBy = async ({ field, value, path, args, context }) => {
1414
: false;
1515
const body = getBody({ field, value, path, nested: isNested });
1616

17-
const res = await context.es.search({
17+
const res = await context.esClient.search({
1818
index: esBiospecimenIndex,
1919
size: args.first,
2020
sort: args.sort,

Diff for: src/graphql/file/model.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getBody } from '#src/services/elasticsearch/utils';
44
import { FileType } from './types/file';
55

66
const get = async (file_id, context) => {
7-
const { body } = await context.es.get({ index: esFileIndex, file_id });
7+
const { body } = await context.esClient.get({ index: esFileIndex, file_id });
88
return body._source;
99
};
1010

@@ -14,7 +14,7 @@ const getBy = async ({ field, value, path, args, context }) => {
1414
: false;
1515
const body = getBody({ field, value, path, nested: isNested });
1616

17-
const res = await context.es.search({
17+
const res = await context.esClient.search({
1818
index: esFileIndex,
1919
size: args.first,
2020
sort: args.sort,

Diff for: src/graphql/file/resolver.ts

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { hitsResolver } from '@ferlab/next/lib/common/resolvers';
2+
import fetch from 'node-fetch';
3+
4+
import { ferloadURL } from '#src/config/env';
5+
6+
import ParticipantModel from '../participant/model';
7+
8+
export const hitsResolverNested = async (parent, args, type, esClient) => {
9+
try {
10+
const participant_ids = parent.participants.map((participant) => participant.participant_id);
11+
12+
const results = await ParticipantModel.getBy({
13+
field: 'participant_id',
14+
value: participant_ids,
15+
path: '',
16+
args,
17+
esClient,
18+
});
19+
20+
return results;
21+
} catch (error) {
22+
console.error('hitsResolverNested error', error);
23+
return null;
24+
}
25+
};
26+
27+
const filesResolver = async (parent, args, type, context) => {
28+
try {
29+
const { esClient, auth } = context;
30+
const filesHits = await hitsResolver(parent, args, type, esClient);
31+
const file_ids: string[] = filesHits?.edges.map((file) => file.file_id);
32+
33+
const res = await fetch(`${ferloadURL}/permissions/by-list`, {
34+
method: 'POST',
35+
headers: {
36+
'Content-Type': 'application/json',
37+
Authorization: `Bearer ${auth?.token}`,
38+
},
39+
body: JSON.stringify({ file_ids }),
40+
});
41+
42+
if (res.status !== 200) {
43+
return filesHits;
44+
}
45+
46+
const filesAuthorized: string[] = res?.json && (await res.json());
47+
48+
const filesWithUserAccess = filesHits?.edges.map((file) => {
49+
let user_authorized = false;
50+
if (filesAuthorized.includes(file.file_id)) {
51+
user_authorized = true;
52+
}
53+
return { ...file, user_authorized };
54+
});
55+
56+
return { ...filesHits, edges: filesWithUserAccess };
57+
} catch (error) {
58+
console.error('filesResolver error', error);
59+
return null;
60+
}
61+
};
62+
63+
export default filesResolver;

Diff for: src/graphql/file/types/file.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import {
77
MatchBoxStateType,
88
} from '@ferlab/next/lib/common/types';
99
import GraphQLJSON from '@ferlab/next/lib/common/types/jsonType';
10-
import { GraphQLFloat, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLString } from 'graphql';
10+
import { GraphQLBoolean, GraphQLFloat, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLString } from 'graphql';
1111

1212
import { esFileIndex } from '#src/config/env';
1313

1414
import { BiospecimensType } from '../../biospecimen/types/biospecimen';
15-
import { ParticipantsType } from '../../participant/types/participant';
15+
import { ParticipantsType, ParticipantType } from '../../participant/types/participant';
1616
import { StudyType } from '../../study/types/study';
1717
import extendedMapping from '../extendedMapping';
18+
import filesResolver, { hitsResolverNested } from '../resolver';
1819
import FileAgg from './fileAgg';
1920
import SequencingExperimentType from './sequencingExperiment';
2021

@@ -38,7 +39,12 @@ export const FileType = new GraphQLObjectType({
3839
study_code: { type: GraphQLString },
3940
study_id: { type: GraphQLString },
4041
study: { type: StudyType },
41-
//todo: create resolve: get participants and samples from participant_index
42+
data_access: { type: GraphQLString },
43+
user_authorized: { type: GraphQLBoolean },
44+
participants_by_index: {
45+
type: ParticipantsType,
46+
resolve: (parent, args, context) => hitsResolverNested(parent, args, ParticipantType, context.esClient),
47+
},
4248
participants: { type: ParticipantsType },
4349
biospecimens: { type: BiospecimensType },
4450
sequencing_experiment: { type: SequencingExperimentType },
@@ -74,7 +80,7 @@ export const FilesType = new GraphQLObjectType({
7480
hits: {
7581
type: FileHitsType,
7682
args: hitsArgsType,
77-
resolve: (parent, args, context) => hitsResolver(parent, args, FileType, context.esClient),
83+
resolve: (parent, args, context) => filesResolver(parent, args, FileType, context),
7884
},
7985
mapping: { type: GraphQLJSON },
8086
extended: {

Diff for: src/graphql/gene/model.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getBody } from '../../services/elasticsearch/utils';
33
import { GeneType } from './types/gene';
44

55
const get = async (file_id, context) => {
6-
const { body } = await context.es.get({ index: esGeneIndex, file_id });
6+
const { body } = await context.esClient.get({ index: esGeneIndex, file_id });
77
return body._source;
88
};
99

@@ -13,7 +13,7 @@ const getBy = async ({ field, value, path, args, context }) => {
1313
: false;
1414
const body = getBody({ field, value, path, nested: isNested });
1515

16-
const res = await context.es.search({
16+
const res = await context.esClient.search({
1717
index: esGeneIndex,
1818
size: args.first,
1919
sort: args.sort,

Diff for: src/graphql/participant/model.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
1+
import { Client } from '@opensearch-project/opensearch';
2+
13
import { esParticipantIndex } from '#src/config/env';
24
import { getBody } from '#src/services/elasticsearch/utils';
35

46
import { ParticipantType } from './types/participant';
57

6-
const get = async (file_id, context) => {
7-
const { body } = await context.es.get({ index: esParticipantIndex, file_id });
8+
const get = async (participant_id, esClient) => {
9+
const { body } = await esClient.get({ index: esParticipantIndex, participant_id });
810
return body._source;
911
};
1012

11-
const getBy = async ({ field, value, path, args, context }) => {
12-
const body = getBody({ field, value, path, nested: ParticipantType?.extensions?.nestedFields?.includes(path) });
13+
interface IgetBy {
14+
field: string;
15+
value: string | string[];
16+
path?: string;
17+
args: any;
18+
esClient: Client;
19+
}
1320

14-
const res = await context.es.search({
21+
const getBy = async ({ field, value, path, args, esClient }: IgetBy) => {
22+
const nested = ParticipantType?.extensions?.nestedFields?.includes(path);
23+
const body = getBody({ field, value, path, nested });
24+
const res = await esClient.search({
1525
index: esParticipantIndex,
1626
size: args.first,
1727
sort: args.sort,
1828
body,
1929
});
20-
2130
const hits = res?.body?.hits?.hits || [];
2231
return hits.map((hit) => hit._source) || [];
2332
};

Diff for: src/graphql/study/model.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getBody } from '../../services/elasticsearch/utils';
33
import { StudyType } from './types/study';
44

55
const get = async (file_id, context) => {
6-
const { body } = await context.es.get({ index: esStudyIndex, file_id });
6+
const { body } = await context.esClient.get({ index: esStudyIndex, file_id });
77
return body._source;
88
};
99

@@ -13,7 +13,7 @@ const getBy = async ({ field, value, path, args, context }) => {
1313
: false;
1414
const body = getBody({ field, value, path, nested: isNested });
1515

16-
const res = await context.es.search({
16+
const res = await context.esClient.search({
1717
index: esStudyIndex,
1818
size: args.first,
1919
sort: args.sort,

Diff for: src/graphql/variant/model.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getBody } from '../../services/elasticsearch/utils';
33
import { VariantType } from './types/variant';
44

55
const get = async (file_id, context) => {
6-
const { body } = await context.es.get({ index: esVariantIndex, file_id });
6+
const { body } = await context.esClient.get({ index: esVariantIndex, file_id });
77
return body._source;
88
};
99

@@ -13,7 +13,7 @@ const getBy = async ({ field, value, path, args, context }) => {
1313
: false;
1414
const body = getBody({ field, value, path, nested: isNested });
1515

16-
const res = await context.es.search({
16+
const res = await context.esClient.search({
1717
index: esVariantIndex,
1818
size: args.first,
1919
sort: args.sort,

Diff for: src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const startApp = async () => {
4646
'/graphql',
4747
cors(),
4848
express.json({ limit: '50mb' }),
49-
expressMiddleware(server, { context: resolveContext })
49+
expressMiddleware(server, { context: ({ req }) => resolveContext(req) })
5050
);
5151
app.use('/download', downloadRouter(resolveContext));
5252
httpServer.listen({ port });

Diff for: src/services/elasticsearch/utils.ts

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
export const getBody = ({ field, value, path, nested = false }) => {
2+
let must: any = [{ match: { [field]: value } }];
3+
4+
if (Array.isArray(value)) {
5+
must = [
6+
{
7+
terms: {
8+
[field]: value,
9+
},
10+
},
11+
];
12+
}
13+
214
if (nested) {
315
return {
416
query: {
@@ -7,23 +19,16 @@ export const getBody = ({ field, value, path, nested = false }) => {
719
{
820
nested: {
921
path,
10-
query: { bool: { must: [{ match: { [field]: value } }] } },
22+
query: { bool: { must } },
1123
},
1224
},
1325
],
1426
},
1527
},
1628
};
1729
}
30+
1831
return {
19-
query: {
20-
bool: {
21-
must: [
22-
{
23-
match: { [field]: value },
24-
},
25-
],
26-
},
27-
},
32+
query: { bool: { must } },
2833
};
2934
};

0 commit comments

Comments
 (0)