From ae2fcfc513d9263bf6904db85087ca5b822ff4f4 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:21:59 -0400 Subject: [PATCH 1/3] chore: move biolink methods to utils --- src/biolink.ts | 74 ---------------------- src/graph/knowledge_graph.ts | 3 +- src/index.ts | 36 +++++++---- src/inferred_mode/inferred_mode.ts | 15 ++--- src/inferred_mode/pathfinder.ts | 9 ++- src/inferred_mode/pf_template_generator.ts | 8 +-- src/query_edge.ts | 15 ++--- src/query_graph.ts | 5 +- src/query_node.ts | 9 ++- src/results_assembly/pfocr.ts | 3 +- src/utils.ts | 52 --------------- 11 files changed, 54 insertions(+), 175 deletions(-) delete mode 100644 src/biolink.ts delete mode 100644 src/utils.ts diff --git a/src/biolink.ts b/src/biolink.ts deleted file mode 100644 index e5bb659d..00000000 --- a/src/biolink.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { BioLink } from 'biolink-model'; -import Debug from 'debug'; -const debug = Debug('bte:biothings-explorer-trapi:EdgeReverse'); - -class BioLinkModel { - biolink: BioLink; - constructor() { - this.biolink = new BioLink(); - this.biolink.loadSync(); - } - - reverse(predicate: string) { - if (typeof predicate === 'string') { - if (predicate in this.biolink.slotTree.objects) { - if (this.biolink.slotTree.objects[predicate].symmetric === true) { - return predicate; - } - return this.biolink.slotTree.objects[predicate].inverse; - } - } - - return undefined; - } - - getAncestorClasses(className: string): string | string[] { - if (className in this.biolink.classTree.objects) { - const ancestors = this.biolink.classTree.getAncestors(className).map((entity) => entity.name); - return [...ancestors, ...[className]]; - } - return className; - } - - getAncestorPredicates(predicate: string): string | string[] { - if (predicate in this.biolink.slotTree.objects) { - const ancestors = this.biolink.slotTree.getAncestors(predicate).map((entity) => entity.name); - return [...ancestors, ...[predicate]]; - } - return predicate; - } - - getDescendantClasses(className: string): string | string[] { - if (className in this.biolink.classTree.objects) { - const descendants = this.biolink.classTree.getDescendants(className).map((entity) => entity.name); - return [...descendants, ...[className]]; - } - return className; - } - - getDescendantPredicates(predicate: string): string[] { - if (predicate in this.biolink.slotTree.objects) { - const descendants = this.biolink.slotTree.getDescendants(predicate).map((entity) => entity.name); - return [...descendants, ...[predicate]]; - } - return [predicate]; - } - - getDescendantQualifiers(qualifier: string): string[] { - try { - const descendants = this.biolink.enumTree.getDescendants(qualifier).map((entity) => entity.name); - return [...descendants, qualifier]; - } catch (e) { - console.log('qual error', e); - return [qualifier]; - } - } -} - -// Freeze an instance to avoid multiple reloads -const biolink = new BioLinkModel(); -Object.freeze(biolink); - -global.BIOLINK_VERSION = biolink.biolink.biolinkJSON.version; - -export default biolink; diff --git a/src/graph/knowledge_graph.ts b/src/graph/knowledge_graph.ts index 1a28e9ca..9aa4b2da 100644 --- a/src/graph/knowledge_graph.ts +++ b/src/graph/knowledge_graph.ts @@ -1,4 +1,3 @@ -import { toArray } from '../utils'; import Debug from 'debug'; import { TrapiAttribute, @@ -14,7 +13,7 @@ import KGNode from './kg_node'; import KGEdge from './kg_edge'; import { BTEGraphUpdate } from './graph'; import { APIDefinition } from '@biothings-explorer/types'; -import { Telemetry } from '@biothings-explorer/utils'; +import { toArray, Telemetry } from '@biothings-explorer/utils'; const debug = Debug('bte:biothings-explorer-trapi:KnowledgeGraph'); diff --git a/src/index.ts b/src/index.ts index 8221e1d0..162029d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -192,7 +192,8 @@ export default class TRAPIQueryHandler { subject, object, }); - const source = ontologyKnowledgeSourceMapping[this.subclassEdges[expanded][original].source] ?? 'error-not-provided'; + const source = + ontologyKnowledgeSourceMapping[this.subclassEdges[expanded][original].source] ?? 'error-not-provided'; subclassEdge.addAdditionalAttributes('biolink:knowledge_level', 'knowledge_assertion'); subclassEdge.addAdditionalAttributes('biolink:agent_type', 'manual_agent'); subclassEdge.addSource([ @@ -430,7 +431,9 @@ export default class TRAPIQueryHandler { const descendantsByCurie: { [curie: string]: { [descendants: string]: string } } = getDescendants( queryGraph.nodes[nodeId].ids, ); - let expanded = Object.values(descendantsByCurie).map(descendants => Object.keys(descendants)).flat() + let expanded = Object.values(descendantsByCurie) + .map((descendants) => Object.keys(descendants)) + .flat(); expanded = _.uniq([...queryGraph.nodes[nodeId].ids, ...expanded]); @@ -442,10 +445,11 @@ export default class TRAPIQueryHandler { if (foundExpandedIds) { Object.entries(descendantsByCurie).forEach(([curie, descendants]) => { - Object.entries(descendants).forEach(([ descendant, source ]) => { + Object.entries(descendants).forEach(([descendant, source]) => { if (queryGraph.nodes[nodeId].ids.includes(descendant)) return; if (!this.subclassEdges[descendant]) this.subclassEdges[descendant] = {}; - if (!this.subclassEdges[descendant][curie]) this.subclassEdges[descendant][curie] = { source, qNodes: [] }; + if (!this.subclassEdges[descendant][curie]) + this.subclassEdges[descendant][curie] = { source, qNodes: [] }; this.subclassEdges[descendant][curie].qNodes.push(nodeId); }); }); @@ -474,10 +478,10 @@ export default class TRAPIQueryHandler { } async _processQueryGraph(queryGraph: TrapiQueryGraph): Promise { -const queryGraphHandler = new QueryGraph(queryGraph, this.options.schema, this._queryIsPathfinder()); -const queryEdges = await queryGraphHandler.calculateEdges(); -this.logs = [...this.logs, ...queryGraphHandler.logs]; -return queryEdges; + const queryGraphHandler = new QueryGraph(queryGraph, this.options.schema, this._queryIsPathfinder()); + const queryEdges = await queryGraphHandler.calculateEdges(); + this.logs = [...this.logs, ...queryGraphHandler.logs]; + return queryEdges; } async _edgesSupported(qEdges: QEdge[], metaKG: MetaKG): Promise { @@ -563,9 +567,17 @@ return queryEdges; } _queryIsPathfinder(): boolean { - const inferredEdgeCount = Object.values(this.queryGraph.edges).reduce((i, edge) => i + (edge.knowledge_type === 'inferred' ? 1 : 0), 0); + const inferredEdgeCount = Object.values(this.queryGraph.edges).reduce( + (i, edge) => i + (edge.knowledge_type === 'inferred' ? 1 : 0), + 0, + ); const pinnedNodes = Object.values(this.queryGraph.nodes).reduce((i, node) => i + (node.ids?.length > 0 ? 1 : 0), 0); - return inferredEdgeCount === 3 && pinnedNodes == 2 && Object.keys(this.queryGraph.edges).length === 3 && Object.keys(this.queryGraph.nodes).length === 3; + return ( + inferredEdgeCount === 3 && + pinnedNodes == 2 && + Object.keys(this.queryGraph.edges).length === 3 && + Object.keys(this.queryGraph.nodes).length === 3 + ); } _queryUsesInferredMode(): boolean { @@ -585,7 +597,7 @@ return queryEdges; const pathfinderResponse = await pathfinderHandler.query(); if (pathfinderResponse) { - this.getResponse = () => pathfinderResponse; + this.getResponse = () => pathfinderResponse; } } @@ -603,7 +615,7 @@ return queryEdges; this.options, this.path, this.predicatePath, - this.includeReasoner + this.includeReasoner, ); const inferredQueryResponse = await inferredQueryHandler.query(); if (inferredQueryResponse) { diff --git a/src/inferred_mode/inferred_mode.ts b/src/inferred_mode/inferred_mode.ts index edf9bc79..f8922983 100644 --- a/src/inferred_mode/inferred_mode.ts +++ b/src/inferred_mode/inferred_mode.ts @@ -1,8 +1,7 @@ import Debug from 'debug'; +import * as utils from '@biothings-explorer/utils'; import { LogEntry, StampedLog, Telemetry } from '@biothings-explorer/utils'; -import * as utils from '../utils'; import async from 'async'; -import biolink from '../biolink'; import { getTemplates, MatchedTemplate, TemplateLookup } from './template_lookup'; import { scaled_sigmoid, inverse_scaled_sigmoid } from '../results_assembly/score'; import TRAPIQueryHandler from '../index'; @@ -164,13 +163,13 @@ export default class InferredQueryHandler { async findTemplates(qEdge: TrapiQEdge, qSubject: TrapiQNode, qObject: TrapiQNode): Promise { debug('Looking up query Templates'); const expandedSubject = qSubject.categories.reduce((arr: string[], subjectCategory: string) => { - return utils.getUnique([...arr, ...biolink.getDescendantClasses(utils.removeBioLinkPrefix(subjectCategory))]); + return utils.getUnique([...arr, ...utils.biolink.getDescendantClasses(utils.removeBioLinkPrefix(subjectCategory))]); }, [] as string[]); const expandedPredicates = qEdge.predicates.reduce((arr: string[], predicate: string) => { - return utils.getUnique([...arr, ...biolink.getDescendantPredicates(utils.removeBioLinkPrefix(predicate))]); + return utils.getUnique([...arr, ...utils.biolink.getDescendantPredicates(utils.removeBioLinkPrefix(predicate))]); }, [] as string[]); const expandedObject = qObject.categories.reduce((arr: string[], objectCategory: string) => { - return utils.getUnique([...arr, ...biolink.getDescendantClasses(utils.removeBioLinkPrefix(objectCategory))]); + return utils.getUnique([...arr, ...utils.biolink.getDescendantClasses(utils.removeBioLinkPrefix(objectCategory))]); }, [] as string[]); const qualifierConstraints = (qEdge.qualifier_constraints || []).map((qualifierSetObj) => { return Object.fromEntries( @@ -355,7 +354,7 @@ export default class InferredQueryHandler { // Predicate matches or is descendant const predicateMatch = qEdge.predicates?.some((predicate) => { - const descendantMatch = biolink + const descendantMatch = utils.biolink .getDescendantPredicates(utils.removeBioLinkPrefix(predicate)) .includes(utils.removeBioLinkPrefix(boundEdge.predicate)); return predicate === boundEdge.predicate || descendantMatch; @@ -372,10 +371,10 @@ export default class InferredQueryHandler { let valueMatch: boolean; try { const descendants = queryQualifier.qualifier_value.includes('biolink:') - ? biolink.getDescendantPredicates( + ? utils.biolink.getDescendantPredicates( utils.removeBioLinkPrefix(queryQualifier.qualifier_value as string), ) - : biolink.getDescendantQualifiers( + : utils.biolink.getDescendantQualifiers( utils.removeBioLinkPrefix(queryQualifier.qualifier_value as string), ); valueMatch = diff --git a/src/inferred_mode/pathfinder.ts b/src/inferred_mode/pathfinder.ts index f366d256..98de9c55 100644 --- a/src/inferred_mode/pathfinder.ts +++ b/src/inferred_mode/pathfinder.ts @@ -11,11 +11,10 @@ import { } from '@biothings-explorer/types'; import InferredQueryHandler from './inferred_mode'; import { scaled_sigmoid, inverse_scaled_sigmoid } from '../results_assembly/score'; -import { LogEntry, StampedLog, Telemetry } from '@biothings-explorer/utils'; +import * as utils from '@biothings-explorer/utils'; +import { LogEntry, StampedLog, Telemetry, removeBioLinkPrefix } from '@biothings-explorer/utils'; import Debug from 'debug'; import generateTemplates from './pf_template_generator'; -import biolink from '../biolink'; -import { removeBioLinkPrefix } from '../utils'; const debug = Debug('bte:biothings-explorer-trapi:pathfinder'); interface ResultAuxObject { @@ -163,7 +162,7 @@ export default class PathfinderQueryHandler { const label = [this.mainEdge.subject, this.unpinnedNodeId, this.mainEdge.object]; const ancestorsToInject = new Set(); node.categories.forEach((category) => { - const ancestors = biolink.getAncestorClasses(removeBioLinkPrefix(category)); + const ancestors = utils.biolink.getAncestorClasses(removeBioLinkPrefix(category)); if (!Array.isArray(ancestors)) return; ancestors.forEach((ancestor) => { if (FALLBACK_ANCESTORS.includes(ancestor)) { @@ -242,7 +241,7 @@ export default class PathfinderQueryHandler { if (this.unpinnedNode.categories && !this.unpinnedNode.categories.includes('biolink:NamedThing')) { acceptableTypes = new Set(); for (const category of this.unpinnedNode.categories) { - for (const desc of biolink.getDescendantClasses(removeBioLinkPrefix(category))) { + for (const desc of utils.biolink.getDescendantClasses(removeBioLinkPrefix(category))) { acceptableTypes.add('biolink:' + desc); } } diff --git a/src/inferred_mode/pf_template_generator.ts b/src/inferred_mode/pf_template_generator.ts index dfbb5f6f..f79a2efb 100644 --- a/src/inferred_mode/pf_template_generator.ts +++ b/src/inferred_mode/pf_template_generator.ts @@ -1,7 +1,7 @@ import path from "path"; import fs from "fs/promises"; import yaml2json from "js-yaml"; -import biolink from "../biolink"; +import * as utils from "@biothings-explorer/utils"; import { TrapiQNode, TrapiQueryGraph } from "@biothings-explorer/types"; interface CategoryTable { @@ -27,8 +27,8 @@ async function loadTables() { for (const table of [categoryTable, predicateTable]) { for (const category1 in table) { for (const category2 in table[category1]) { - for (const descendant1 of biolink.getDescendantClasses(category1)) { - for (const descendant2 of biolink.getDescendantClasses(category2)) { + for (const descendant1 of utils.biolink.getDescendantClasses(category1)) { + for (const descendant2 of utils.biolink.getDescendantClasses(category2)) { if (table?.['biolink:'+descendant1]?.['biolink:'+descendant2] !== undefined) continue; if (!('biolink:'+descendant1 in table)) { @@ -175,4 +175,4 @@ export default async function generateTemplates(sub: TrapiQNode, un: TrapiQNode, queryGraphs.push(queryGraph); } return queryGraphs; -} \ No newline at end of file +} diff --git a/src/query_edge.ts b/src/query_edge.ts index a9513741..29055119 100644 --- a/src/query_edge.ts +++ b/src/query_edge.ts @@ -1,10 +1,9 @@ import helper from './helper'; import Debug from 'debug'; -import * as utils from './utils'; -import biolink from './biolink'; import { Record, RecordNode, FrozenRecord } from '@biothings-explorer/api-response-transform'; import QNode from './query_node'; import { QNodeInfo } from './query_node'; +import * as utils from '@biothings-explorer/utils'; import { LogEntry, StampedLog } from '@biothings-explorer/utils'; import { TrapiAttributeConstraint, TrapiQualifierConstraint } from '@biothings-explorer/types'; @@ -129,7 +128,7 @@ export default class QEdge { } expandPredicates(predicates: string[]): string[] { - return Array.from(new Set(predicates.reduce((acc, cur) => [...acc, ...biolink.getDescendantPredicates(cur)], []))); + return Array.from(new Set(predicates.reduce((acc, cur) => [...acc, ...utils.biolink.getDescendantPredicates(cur)], []))); } getPredicate(): string[] { @@ -141,7 +140,7 @@ export default class QEdge { debug(`Expanded edges: ${expandedPredicates}`); return expandedPredicates .map((predicate) => { - return this.isReversed() === true ? biolink.reverse(predicate) : predicate; + return this.isReversed() === true ? utils.biolink.reverse(predicate) : predicate; }) .filter((item) => !(typeof item === 'undefined')); } @@ -154,7 +153,7 @@ export default class QEdge { ? Array.isArray(qualifier_value) ? Array.from( qualifier_value.reduce((set: Set, predicate: string) => { - biolink + utils.biolink .getDescendantPredicates(utils.removeBioLinkPrefix(predicate)) .forEach((item) => set.add(`biolink:${utils.removeBioLinkPrefix(item)}`)); return set; @@ -162,13 +161,13 @@ export default class QEdge { ) : Array.from( new Set( - biolink + utils.biolink .getDescendantPredicates(utils.removeBioLinkPrefix(qualifier_value)) .map((item) => `biolink:${utils.removeBioLinkPrefix(item)}`), ), ) : Array.from( - new Set(biolink.getDescendantQualifiers(utils.removeBioLinkPrefix(qualifier_value as string))), + new Set(utils.biolink.getDescendantQualifiers(utils.removeBioLinkPrefix(qualifier_value as string))), ); return { @@ -575,6 +574,6 @@ export default class QEdge { } getReversedPredicate(predicate: string): string { - return predicate ? biolink.reverse(predicate) : undefined; + return predicate ? utils.biolink.reverse(predicate) : undefined; } } diff --git a/src/query_graph.ts b/src/query_graph.ts index 5b0f2b68..88b90210 100644 --- a/src/query_graph.ts +++ b/src/query_graph.ts @@ -1,12 +1,11 @@ import QEdge from './query_edge'; import InvalidQueryGraphError from './exceptions/invalid_query_graph_error'; +import * as utils from '@biothings-explorer/utils'; import { LogEntry, StampedLog } from '@biothings-explorer/utils'; import Debug from 'debug'; import QNode from './query_node'; -import biolink from './biolink'; import { resolveSRI } from 'biomedical_id_resolver'; import _ from 'lodash'; -import * as utils from './utils'; import { TrapiQueryGraph } from '@biothings-explorer/types'; import NotImplementedError from './exceptions/not_implemented_error'; @@ -226,7 +225,7 @@ export default class QueryGraph { } else { try { let finalCategories: string[] = []; - const tree = biolink.biolink.classTree.objects; + const tree = utils.biolink.biolink.classTree.objects; // get array of all unique categories for all curies const allCategories = [ diff --git a/src/query_node.ts b/src/query_node.ts index 98160026..01106d7a 100644 --- a/src/query_node.ts +++ b/src/query_node.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import _ from 'lodash'; -import * as utils from './utils'; -import biolink from './biolink'; +import * as utils from '@biothings-explorer/utils'; import Debug from 'debug'; import InvalidQueryGraphError from './exceptions/invalid_query_graph_error'; import { SRIBioEntity } from 'biomedical_id_resolver'; @@ -245,7 +244,7 @@ export default class QNode { categories.map((category) => { expanded_categories = [ ...expanded_categories, - ...(biolink.getDescendantClasses(utils.removeBioLinkPrefix(category)) || []), + ...(utils.biolink.getDescendantClasses(utils.removeBioLinkPrefix(category)) || []), ]; }); this.expandedCategories = utils.getUnique(expanded_categories); @@ -255,7 +254,7 @@ export default class QNode { // utils // .toArray(this.category) // .map((category) => utils.removeBioLinkPrefix(category)) - // .reduce((arr, category) => [...arr, ...biolink.getAncestorClasses(category)], []) + // .reduce((arr, category) => [...arr, ...utils.getAncestorClasses(category)], []) // .filter((category) => !utils.toArray(this.category).includes(`biolink:${category}`)), // ); let categories = utils.toArray(this.categories).map((category) => utils.removeBioLinkPrefix(category)); @@ -265,7 +264,7 @@ export default class QNode { this.expandedCategories = utils.getUnique( utils .getUnique(categories) - .reduce((arr, category) => [...arr, ...(biolink.getDescendantClasses(category) || [])], []), + .reduce((arr, category) => [...arr, ...(utils.biolink.getDescendantClasses(category) || [])], []), ); // .filter(category => !ancestors.has(category)); } diff --git a/src/results_assembly/pfocr.ts b/src/results_assembly/pfocr.ts index 5fab0980..ad0ec777 100644 --- a/src/results_assembly/pfocr.ts +++ b/src/results_assembly/pfocr.ts @@ -1,9 +1,8 @@ import axios from 'axios'; import Debug from 'debug'; const debug = Debug('bte:biothings-explorer-trapi:pfocr'); -import { intersection } from '../utils'; import _ from 'lodash'; -import { LogEntry, StampedLog } from '@biothings-explorer/utils'; +import { LogEntry, StampedLog, intersection } from '@biothings-explorer/utils'; import { TrapiResult, TrapiKGNode, TrapiResponse, TrapiKGEdge } from '@biothings-explorer/types'; import Graph from '../graph/graph'; diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index 1d999058..00000000 --- a/src/utils.ts +++ /dev/null @@ -1,52 +0,0 @@ -export function toArray(input: Type | Type[]): Type[] { - if (Array.isArray(input)) { - return input; - } - return [input]; -} - -export function getUnique(input: Type[]): Type[] { - return Array.from(new Set(input)); -} - -export function removeBioLinkPrefix(input: T): T { - if (Array.isArray(input)) { - return input.map((str: string) => str.replace('biolink:', '')) as T; - } else { - return input.replace('biolink:', '') as T; - } -} - -// This gets the intersection of two sets. -// Lodash _.intersection gets the intersection of two arrays. -// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set -export function intersection(setA: Set, setB: Set): Set { - const resultSet: Set = new Set(); - for (const elem of setB) { - if (setA.has(elem)) { - resultSet.add(elem); - } - } - return resultSet; -} - -// see https://stackoverflow.com/a/29585704 -export function cartesian(a: number[][]): number[][] { - // a = array of arrays - let i: number, j: number, l: number, m: number; - const o = []; - if (!a || a.length == 0) return a; - - const a1 = a.splice(0, 1)[0]; // the first array of a - a = cartesian(a); - for (i = 0, l = a1.length; i < l; i++) { - if (a && a.length) { - for (j = 0, m = a.length; j < m; j++) { - o.push([a1[i]].concat(a[j])); - } - } else { - o.push([a1[i]]); - } - } - return o; -} From 8ade72bf1bd8d69f63c92c86dc470a6294819f1e Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:17:00 -0400 Subject: [PATCH 2/3] test: fix tests --- __test__/integration/biolink.test.ts | 72 ------------------- __test__/integration/graph/graph.test.ts | 66 ++++++++--------- __test__/unittest/inferred_mode.test.ts | 29 ++++++++ .../unittest/pf_template_generator.test.ts | 39 ++++------ __test__/unittest/utils.test.ts | 42 ----------- 5 files changed, 74 insertions(+), 174 deletions(-) delete mode 100644 __test__/integration/biolink.test.ts delete mode 100644 __test__/unittest/utils.test.ts diff --git a/__test__/integration/biolink.test.ts b/__test__/integration/biolink.test.ts deleted file mode 100644 index be391761..00000000 --- a/__test__/integration/biolink.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import biolink from '../../src/biolink'; - -describe('Test BioLinkModel class', () => { - test('test reverse with correct predicate', () => { - const res = biolink.reverse('treats'); - expect(res).toBe('treated_by'); - }); - - test('test reverse with correct predicate if it contains underscore', () => { - const res = biolink.reverse('treated_by'); - expect(res).toBe('treats'); - }); - - test('test reverse with predicate having symmetric equal to true', () => { - const res = biolink.reverse('correlated_with'); - expect(res).toBe('correlated_with'); - }); - - test('test predicate with no inverse property and symmetric not equal to true', () => { - const res = biolink.reverse('has_phenotype'); - expect(res).toBe('phenotype_of'); - }); - - test('test predicate not exist in biolink model', () => { - const res = biolink.reverse('haha'); - expect(res).toBeUndefined(); - }); - - test('if input not string, return undefined', () => { - //@ts-expect-error: Explicitly testing for wrong type - const res = biolink.reverse(['dd']); - expect(res).toBeUndefined(); - }); - - describe('Test getDescendants function', () => { - test('if input is in biolink model, return all its desendants and itself', () => { - const res = biolink.getDescendantClasses('MolecularEntity'); - expect(res).toContain('SmallMolecule'); - expect(res).toContain('NucleicAcidEntity'); - expect(res).toContain('MolecularEntity'); - }); - - test("if input is in biolink model but doesn't have descendants, return itself", () => { - const res = biolink.getDescendantClasses('Gene'); - expect(res).toEqual(['Gene']); - }); - - test('if input is not in biolink, return itself', () => { - const res = biolink.getDescendantClasses('Gene1'); - expect(res).toEqual('Gene1'); - }); - }); - - describe('Test getDescendantPredicates function', () => { - test('if input is in biolink model, return all its desendants and itself', () => { - const res = biolink.getDescendantPredicates('related_to'); - expect(res).toContain('subclass_of'); - expect(res).toContain('superclass_of'); - expect(res).toContain('related_to'); - }); - - test("if input is in biolink model but doesn't have descendants, return itself", () => { - const res = biolink.getDescendantPredicates('subclass_of'); - expect(res).toEqual(['subclass_of']); - }); - - test('if input is not in biolink, return itself', () => { - const res = biolink.getDescendantPredicates('Gene1'); - expect(res).toEqual(['Gene1']); - }); - }); -}); diff --git a/__test__/integration/graph/graph.test.ts b/__test__/integration/graph/graph.test.ts index 0d650621..af88dfc9 100644 --- a/__test__/integration/graph/graph.test.ts +++ b/__test__/integration/graph/graph.test.ts @@ -109,11 +109,11 @@ describe('Test graph class', () => { expect(g.nodes['inputPrimaryCurie'].qNodeID).toEqual('qg1'); expect(Array.from(g.nodes['inputPrimaryCurie'].targetNodes)).toEqual(['outputPrimaryCurie']); expect(Array.from(g.nodes['inputPrimaryCurie'].targetQNodeIDs)).toEqual(['qg2']); - expect(g.edges).toHaveProperty('2c826c3663b91f65a1cba70f06c7fc65'); - expect(Array.from(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].apis)).toEqual(['API1']); - expect(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].sources).toHaveProperty('source1'); - expect(Array.from(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].publications)).toEqual(['PMID:1', 'PMID:2']); - expect(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].attributes).toHaveProperty('relation', new Set(['relation1'])); + expect(g.edges).toHaveProperty('3eb29a4cead0e5f3c3bdca4997bf215b'); + expect(Array.from(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].apis)).toEqual(['API1']); + expect(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].sources).toHaveProperty('source1'); + expect(Array.from(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].publications)).toEqual(['PMID:1', 'PMID:2']); + expect(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].attributes).toHaveProperty('relation', new Set(['relation1'])); }); test('Multiple query results are correctly updated for two edges having same input, predicate and output', () => { @@ -130,17 +130,17 @@ describe('Test graph class', () => { expect(Array.from(g.nodes['inputPrimaryCurie'].targetNodes)).toEqual(['outputPrimaryCurie']); expect(Array.from(g.nodes['inputPrimaryCurie'].targetQNodeIDs)).toEqual(['qg2']); - expect(g.edges).toHaveProperty('2c826c3663b91f65a1cba70f06c7fc65'); - expect(Array.from(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].apis)).toEqual(['API1']); - expect(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].sources).toHaveProperty('source1'); - expect(Array.from(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].publications)).toEqual(['PMID:1', 'PMID:2']); - expect(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].attributes).toHaveProperty('relation', new Set(['relation1'])); + expect(g.edges).toHaveProperty('3eb29a4cead0e5f3c3bdca4997bf215b'); + expect(Array.from(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].apis)).toEqual(['API1']); + expect(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].sources).toHaveProperty('source1'); + expect(Array.from(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].publications)).toEqual(['PMID:1', 'PMID:2']); + expect(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].attributes).toHaveProperty('relation', new Set(['relation1'])); - expect(g.edges).toHaveProperty('827c366e2e3088b3f4a90dd88a524f15'); - expect(Array.from(g.edges['827c366e2e3088b3f4a90dd88a524f15'].apis)).toEqual(['API2']); - expect(g.edges['827c366e2e3088b3f4a90dd88a524f15'].sources).toHaveProperty('source2'); - expect(Array.from(g.edges['827c366e2e3088b3f4a90dd88a524f15'].publications)).toEqual(['PMC:1', 'PMC:2']); - expect(g.edges['827c366e2e3088b3f4a90dd88a524f15'].attributes).toHaveProperty('relation', new Set(['relation2'])); + expect(g.edges).toHaveProperty('6930dcb2e9363817e9f6e736829ce278'); + expect(Array.from(g.edges['6930dcb2e9363817e9f6e736829ce278'].apis)).toEqual(['API2']); + expect(g.edges['6930dcb2e9363817e9f6e736829ce278'].sources).toHaveProperty('source2'); + expect(Array.from(g.edges['6930dcb2e9363817e9f6e736829ce278'].publications)).toEqual(['PMC:1', 'PMC:2']); + expect(g.edges['6930dcb2e9363817e9f6e736829ce278'].attributes).toHaveProperty('relation', new Set(['relation2'])); }); test('Multiple query results for different edges are correctly updated', () => { @@ -157,37 +157,37 @@ describe('Test graph class', () => { expect(Array.from(g.nodes['inputPrimaryCurie'].targetNodes)).toEqual(['outputPrimaryCurie']); expect(Array.from(g.nodes['inputPrimaryCurie'].targetQNodeIDs)).toEqual(['qg2']); - expect(g.edges).toHaveProperty('2c826c3663b91f65a1cba70f06c7fc65'); - expect(Array.from(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].apis)).toEqual(['API1']); - expect(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].sources).toHaveProperty('source1'); - expect(Array.from(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].publications)).toEqual(['PMID:1', 'PMID:2']); - expect(g.edges['2c826c3663b91f65a1cba70f06c7fc65'].attributes).toHaveProperty('relation', new Set(['relation1'])); + expect(g.edges).toHaveProperty('3eb29a4cead0e5f3c3bdca4997bf215b'); + expect(Array.from(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].apis)).toEqual(['API1']); + expect(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].sources).toHaveProperty('source1'); + expect(Array.from(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].publications)).toEqual(['PMID:1', 'PMID:2']); + expect(g.edges['3eb29a4cead0e5f3c3bdca4997bf215b'].attributes).toHaveProperty('relation', new Set(['relation1'])); - expect(g.edges).toHaveProperty('827c366e2e3088b3f4a90dd88a524f15'); - expect(Array.from(g.edges['827c366e2e3088b3f4a90dd88a524f15'].apis)).toEqual(['API2']); - expect(g.edges['827c366e2e3088b3f4a90dd88a524f15'].sources).toHaveProperty('source2'); - expect(Array.from(g.edges['827c366e2e3088b3f4a90dd88a524f15'].publications)).toEqual(['PMC:1', 'PMC:2']); - expect(g.edges['827c366e2e3088b3f4a90dd88a524f15'].attributes).toHaveProperty('relation', new Set(['relation2'])); + expect(g.edges).toHaveProperty('6930dcb2e9363817e9f6e736829ce278'); + expect(Array.from(g.edges['6930dcb2e9363817e9f6e736829ce278'].apis)).toEqual(['API2']); + expect(g.edges['6930dcb2e9363817e9f6e736829ce278'].sources).toHaveProperty('source2'); + expect(Array.from(g.edges['6930dcb2e9363817e9f6e736829ce278'].publications)).toEqual(['PMC:1', 'PMC:2']); + expect(g.edges['6930dcb2e9363817e9f6e736829ce278'].attributes).toHaveProperty('relation', new Set(['relation2'])); - expect(g.edges).toHaveProperty('3138ca0afca791770ed38c243dea2116'); - expect(Array.from(g.edges['3138ca0afca791770ed38c243dea2116'].apis)).toEqual(['API3']); - expect(g.edges['3138ca0afca791770ed38c243dea2116'].sources).toHaveProperty('source3'); - expect(Array.from(g.edges['3138ca0afca791770ed38c243dea2116'].publications)).toEqual(['PMC:3', 'PMC:4']); - expect(g.edges['3138ca0afca791770ed38c243dea2116'].attributes).toHaveProperty('relation', new Set(['relation3'])); + expect(g.edges).toHaveProperty('38e8cf1917452c83bb878c5a916ef86a'); + expect(Array.from(g.edges['38e8cf1917452c83bb878c5a916ef86a'].apis)).toEqual(['API3']); + expect(g.edges['38e8cf1917452c83bb878c5a916ef86a'].sources).toHaveProperty('source3'); + expect(Array.from(g.edges['38e8cf1917452c83bb878c5a916ef86a'].publications)).toEqual(['PMC:3', 'PMC:4']); + expect(g.edges['38e8cf1917452c83bb878c5a916ef86a'].attributes).toHaveProperty('relation', new Set(['relation3'])); }); test('Multiple attributes with the same name are merged', () => { const g = new graph(); g.update([record3, record3a]); - expect(g.edges).toHaveProperty('3138ca0afca791770ed38c243dea2116'); - expect(Array.from(g.edges['3138ca0afca791770ed38c243dea2116'].publications)).toEqual([ + expect(g.edges).toHaveProperty('38e8cf1917452c83bb878c5a916ef86a'); + expect(Array.from(g.edges['38e8cf1917452c83bb878c5a916ef86a'].publications)).toEqual([ 'PMC:3', 'PMC:4', 'PMC:6', 'PMC:7', ]); - expect(g.edges['3138ca0afca791770ed38c243dea2116'].attributes).toHaveProperty( + expect(g.edges['38e8cf1917452c83bb878c5a916ef86a'].attributes).toHaveProperty( 'relation', new Set(['relation3', 'relation3a', 'relation3b']), ); diff --git a/__test__/unittest/inferred_mode.test.ts b/__test__/unittest/inferred_mode.test.ts index 2a4e193d..3c95d449 100644 --- a/__test__/unittest/inferred_mode.test.ts +++ b/__test__/unittest/inferred_mode.test.ts @@ -351,11 +351,13 @@ describe('Test InferredQueryHandler', () => { creativeQuerySubject: [ { id: 'fakeCompound2', + attributes: [] }, ], creativeQueryObject: [ { id: 'fakeDisease1', + attributes: [] }, ], }, @@ -366,6 +368,7 @@ describe('Test InferredQueryHandler', () => { e0: [ { id: 'edgeHash1', + attributes: [] }, ], }, @@ -378,11 +381,13 @@ describe('Test InferredQueryHandler', () => { creativeQuerySubject: [ { id: 'fakeCompound1', + attributes: [] }, ], creativeQueryObject: [ { id: 'fakeDisease1', + attributes: [] }, ], }, @@ -393,6 +398,7 @@ describe('Test InferredQueryHandler', () => { e0: [ { id: 'edgeHash2', + attributes: [] }, ], }, @@ -405,11 +411,13 @@ describe('Test InferredQueryHandler', () => { creativeQuerySubject: [ { id: 'fakeCompound3', + attributes: [] }, ], creativeQueryObject: [ { id: 'fakeDisease1', + attributes: [] }, ], }, @@ -420,6 +428,7 @@ describe('Test InferredQueryHandler', () => { e0: [ { id: 'edgeHash3', + attributes: [] }, ], }, @@ -477,11 +486,13 @@ describe('Test InferredQueryHandler', () => { n01: [ { id: 'fakeCompound1', + attributes: [] }, ], n02: [ { id: 'fakeDisease1', + attributes: [] }, ], }, @@ -492,6 +503,7 @@ describe('Test InferredQueryHandler', () => { e01: [ { id: 'edgeHash1', + attributes: [] }, ], }, @@ -504,11 +516,13 @@ describe('Test InferredQueryHandler', () => { n01: [ { id: 'fakeCompound3', + attributes: [] }, ], n02: [ { id: 'fakeDisease1', + attributes: [] }, ], }, @@ -518,6 +532,7 @@ describe('Test InferredQueryHandler', () => { e01: [ { id: 'edgeHash2', + attributes: [] }, ], }, @@ -635,16 +650,19 @@ describe('Test InferredQueryHandler', () => { creativeQuerySubject: [ { id: 'fakeCompound4', + attributes: [] }, ], creativeQueryObject: [ { id: 'fakeDisease1', + attributes: [] }, ], n01: [ { id: 'fakeGene1', + attributes: [] }, ], }, @@ -655,11 +673,13 @@ describe('Test InferredQueryHandler', () => { e0: [ { id: 'edgeHash1', + attributes: [] }, ], e01: [ { id: 'edgeHash2', + attributes: [] }, ], }, @@ -672,11 +692,13 @@ describe('Test InferredQueryHandler', () => { creativeQuerySubject: [ { id: 'fakeCompound1', + attributes: [] }, ], creativeQueryObject: [ { id: 'fakeDisease1', + attributes: [] }, ], }, @@ -687,6 +709,7 @@ describe('Test InferredQueryHandler', () => { e0: [ { id: 'edgeHash3', + attributes: [] }, ], }, @@ -783,11 +806,13 @@ describe('Test InferredQueryHandler', () => { n01: [ { id: 'fakeCompound1', + attributes: [] }, ], n02: [ { id: 'fakeDisease1', + attributes: [] }, ], }, @@ -798,6 +823,7 @@ describe('Test InferredQueryHandler', () => { e01: [ { id: 'edgeHash1', + attributes: [] }, ], }, @@ -878,11 +904,13 @@ describe('Test InferredQueryHandler', () => { creativeQuerySubject: [ { id: 'creativeQuerySubject', + attributes: [] }, ], creativeQueryObject: [ { id: 'creativeQueryObject', + attributes: [] }, ], }, @@ -892,6 +920,7 @@ describe('Test InferredQueryHandler', () => { e01: [ { id: 'edgeHash1', + attributes: [] }, ], }, diff --git a/__test__/unittest/pf_template_generator.test.ts b/__test__/unittest/pf_template_generator.test.ts index 80aff452..8d8f3bba 100644 --- a/__test__/unittest/pf_template_generator.test.ts +++ b/__test__/unittest/pf_template_generator.test.ts @@ -39,12 +39,9 @@ describe('Test Pathfinder Template Generator', () => { "subject": "creativeQuerySubject", "object": "un", "predicates": [ - "biolink:regulates", - "biolink:regulated_by", "biolink:affects", - "biolink:affected_by", "biolink:interacts_with", - "biolink:associated_with" + "biolink:occurs_together_in_literature_with" ] }, "un_obj": { @@ -81,9 +78,7 @@ describe('Test Pathfinder Template Generator', () => { }, "nb": { "categories": [ - "biolink:AnatomicalEntity", - "biolink:BiologicalProcessOrActivity", - "biolink:ChemicalEntity" + "biolink:Cell" ] } }, @@ -92,37 +87,29 @@ describe('Test Pathfinder Template Generator', () => { "subject": "creativeQuerySubject", "object": "un", "predicates": [ - "biolink:regulates", - "biolink:regulated_by", "biolink:affects", - "biolink:affected_by", "biolink:interacts_with", - "biolink:associated_with" + "biolink:occurs_together_in_literature_with" ] }, "un_b": { "subject": "un", "object": "nb", "predicates": [ - "biolink:related_to_at_instance_level", "biolink:affects", - "biolink:contributes_to", - "biolink:participates_in", - "biolink:regulates", - "biolink:regulated_by", - "biolink:affected_by", - "biolink:interacts_with", - "biolink:correlated_with" + "biolink:produced_by", + "biolink:located_in", + "biolink:part_of", + "biolink:interacts_with" ] }, "b_obj": { "subject": "nb", "object": "creativeQueryObject", "predicates": [ - "biolink:related_to_at_instance_level", - "biolink:affects", + "biolink:location_of", "biolink:affected_by", - "biolink:occurs_in" + "biolink:interacts_with" ] } } @@ -158,12 +145,9 @@ describe('Test Pathfinder Template Generator', () => { "subject": "creativeQuerySubject", "object": "nc", "predicates": [ - "biolink:regulates", - "biolink:regulated_by", "biolink:affects", - "biolink:affected_by", "biolink:interacts_with", - "biolink:associated_with" + "biolink:occurs_together_in_literature_with" ] }, "c_un": { @@ -174,7 +158,8 @@ describe('Test Pathfinder Template Generator', () => { "biolink:regulated_by", "biolink:affects", "biolink:affected_by", - "biolink:interacts_with" + "biolink:interacts_with", + "biolink:occurs_together_in_literature_with" ] }, "un_obj": { diff --git a/__test__/unittest/utils.test.ts b/__test__/unittest/utils.test.ts deleted file mode 100644 index 36b5a41c..00000000 --- a/__test__/unittest/utils.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as utils from '../../src/utils'; - -describe('Test utility functions', () => { - describe('Test removeBioLinkPrefix function', () => { - test('String input with biolink prefix should be removed', () => { - const input = 'biolink:treats'; - const res = utils.removeBioLinkPrefix(input); - expect(res).toEqual('treats'); - }); - - test('String input without biolink prefix should be kept same', () => { - const input = 'treats'; - const res = utils.removeBioLinkPrefix(input); - expect(res).toEqual('treats'); - }); - }); - - describe('Test toArray function', () => { - test('Array input should return itself', () => { - const input = ['a']; - const res = utils.toArray(input); - expect(res).toEqual(['a']); - }); - - test('Non-Array input should return an array of one element being itself', () => { - const input = 'a'; - const res = utils.toArray(input); - expect(res).toEqual(['a']); - }); - }); - - test('intersection', () => { - const setA = new Set([1, 2, 3]); - const setB = new Set([2, 3, 4]); - const intersection = utils.intersection(setA, setB); - expect(intersection).toStrictEqual(new Set([2, 3])); - }); - - test('cartesian product', () => { - expect(utils.cartesian([[1, 2], [3, 4]])).toStrictEqual([[1, 3], [1, 4], [2, 3], [2, 4]]); - }); -}); From 8682d7829df1e78836f5d208728a6a133a392936 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:02:13 -0400 Subject: [PATCH 3/3] test: fix template log expectations --- __test__/unittest/pf_template_generator.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__test__/unittest/pf_template_generator.test.ts b/__test__/unittest/pf_template_generator.test.ts index 4310d477..8a0d24de 100644 --- a/__test__/unittest/pf_template_generator.test.ts +++ b/__test__/unittest/pf_template_generator.test.ts @@ -59,7 +59,7 @@ describe('Test Pathfinder Template Generator', () => { ] } }, - "log": "(subject) -(regulates,regulated_by,affects,affected_by,interacts_with,associated_with)-> (Gene) -(gene_associated_with_condition,biomarker_for,affects,contributes_to)-> (object)", + "log": "(subject) -(affects,interacts_with,occurs_together_in_literature_with)-> (Gene) -(gene_associated_with_condition,biomarker_for,affects,contributes_to)-> (object)", }); expect(templatesWithoutUnCat[0]).toEqual(templatesWithUnCat[0]); @@ -120,7 +120,7 @@ describe('Test Pathfinder Template Generator', () => { ] } }, - "log": "(subject) -(regulates,regulated_by,affects,affected_by,interacts_with,associated_with)-> (Gene) -(related_to_at_instance_level,affects,contributes_to,participates_in,regulates,regulated_by,affected_by,interacts_with,correlated_with)-> (AnatomicalEntity,BiologicalProcessOrActivity,ChemicalEntity) -(related_to_at_instance_level,affects,affected_by,occurs_in)-> (object)" + "log": "(subject) -(affects,interacts_with,occurs_together_in_literature_with)-> (Gene) -(affects,produced_by,located_in,part_of,interacts_with)-> (Cell) -(location_of,affected_by,interacts_with)-> (object)" }); expect(templatesWithoutUnCat[1]).toEqual(templatesWithUnCat[1]); @@ -183,7 +183,7 @@ describe('Test Pathfinder Template Generator', () => { ] } }, - "log": "(subject) -(regulates,regulated_by,affects,affected_by,interacts_with,associated_with)-> (Gene) -(regulates,regulated_by,affects,affected_by,interacts_with)-> (Gene) -(gene_associated_with_condition,biomarker_for,affects,contributes_to)-> (object)" + "log": "(subject) -(affects,interacts_with,occurs_together_in_literature_with)-> (Gene) -(regulates,regulated_by,affects,affected_by,interacts_with,occurs_together_in_literature_with)-> (Gene) -(gene_associated_with_condition,biomarker_for,affects,contributes_to)-> (object)" }); expect(templatesWithoutUnCat[2]).toEqual(templatesWithUnCat[2]); });