From d90dccafa7fb66cc88188efb136b2480049ecccb Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:17:27 -0400 Subject: [PATCH 1/6] chore: add utils dependency --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 1fe7a93..810457b 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "@babel/runtime": "^7.23.2", "@commitlint/cli": "^17.8.1", "@commitlint/config-conventional": "^11.0.0", + "@biothings-explorer/utils": "workspace:../utils", "axios": "^0.21.4", "camelcase": "^6.3.0", "core-js": "^3.33.1", From 80a6d866eadeb4cc377b3322b06bf50550a5d665 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:17:42 -0400 Subject: [PATCH 2/6] feat: inject flipped metaEdges based on config --- .../sync_operations_builder_with_reasoner.ts | 79 ++++++++++++++++--- src/types.ts | 1 + 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/operations_builder/sync_operations_builder_with_reasoner.ts b/src/operations_builder/sync_operations_builder_with_reasoner.ts index 7fe6c31..1151a88 100644 --- a/src/operations_builder/sync_operations_builder_with_reasoner.ts +++ b/src/operations_builder/sync_operations_builder_with_reasoner.ts @@ -7,6 +7,7 @@ import { PredicatesMetadata } from "../types"; import Debug from "debug"; const debug = Debug("bte:smartapi-kg:SyncOperationsBuilderWithReasoner"); import { SmartAPISpec } from "../parser/types"; +import { biolink } from "@biothings-explorer/utils"; declare global { var missingAPIs: SmartAPISpec[]; @@ -49,7 +50,7 @@ export default class SyncOperationsBuilderWithReasoner extends BaseOperationsBui Object.keys(metadata.predicates[obj]).map(sbj => { if (Array.isArray(metadata.predicates[obj][sbj])) { metadata.predicates[obj][sbj].map(pred => { - ops.push({ + const op = { association: { input_type: this.removeBioLinkPrefix(sbj), input_id: metadata?.nodes?.[sbj]?.id_prefixes, @@ -64,11 +65,11 @@ export default class SyncOperationsBuilderWithReasoner extends BaseOperationsBui typeof pred === "string" || !pred.qualifiers ? undefined : Object.fromEntries( - pred.qualifiers.map((q: any) => [ - this.removeBioLinkPrefix(q.qualifier_type_id), - q.applicable_values.map(this.removeBioLinkPrefix), - ]), - ), + pred.qualifiers.map((q: any) => [ + this.removeBioLinkPrefix(q.qualifier_type_id), + q.applicable_values.map(this.removeBioLinkPrefix), + ]), + ), "x-translator": metadata.association["x-translator"], "x-trapi": metadata.association["x-trapi"], }, @@ -84,7 +85,65 @@ export default class SyncOperationsBuilderWithReasoner extends BaseOperationsBui inputSeparator: ",", tags: [...metadata.tags, ...["bte-trapi"]], }, - }); + }; + ops.push(op); + if ( + !this._options.apiList || + !this._options.apiList.include.find( + api => api.id === metadata.association.smartapi.id, + )?.includeFlipped + ) { + return; + } + // Add inverse metaEdge if includeFlipped is true + const inverse_op = { + ...op, + association: { + ...op.association, + input_type: this.removeBioLinkPrefix(obj), + input_id: metadata?.nodes?.[obj]?.id_prefixes, + output_type: this.removeBioLinkPrefix(sbj), + output_id: metadata?.nodes?.[sbj]?.id_prefixes, + predicate: biolink.reverse( + this.removeBioLinkPrefix( + typeof pred === "string" ? pred : pred.predicate, + ), + ), + qualifiers: + typeof pred === "string" || !pred.qualifiers + ? undefined + : Object.fromEntries( + pred.qualifiers.map((q: any) => { + let newQualifierType: string = q.qualifier_type_id; + let newQualifier: string[] = q.applicable_values.map( + this.removeBioLinkPrefix, + ); + if (newQualifierType.includes("predicate")) { + newQualifier = newQualifier.map(biolink.reverse); + } + if (newQualifierType.includes("subject")) { + newQualifierType = newQualifierType.replace( + "subject", + "object", + ); + } else if (newQualifierType.includes("object")) { + newQualifierType = newQualifierType.replace( + "object", + "subject", + ); + } + + return [newQualifierType, newQualifier]; + }), + ), + }, + }; + if (inverse_op.association.predicate) { + ops.push(inverse_op); + debug( + `Injected reverse MetaEdge for ${op.association.api_name} ( ${inverse_op.association.input_type} -> ${inverse_op.association.predicate} -> ${inverse_op.association.output_type} )`, + ); + } }); } }); @@ -150,7 +209,7 @@ export default class SyncOperationsBuilderWithReasoner extends BaseOperationsBui private fetch(): PredicatesMetadata[] { if (this._options.predicates) { - return this._options.predicates; + return this._options.predicates; } const file = fs.readFileSync(this._predicates_file_path, "utf-8"); @@ -166,7 +225,7 @@ export default class SyncOperationsBuilderWithReasoner extends BaseOperationsBui this._options.component, this._options.apiList, this._file_path, - this._options.smartapiSpecs + this._options.smartapiSpecs, ); const nonTRAPIOps = this.loadOpsFromSpecs(specs); const predicatesMetadata = this.fetch(); @@ -177,7 +236,7 @@ export default class SyncOperationsBuilderWithReasoner extends BaseOperationsBui undefined, undefined, this._file_path, - this._options.smartapiSpecs + this._options.smartapiSpecs, ).filter( spec => "info" in spec && diff --git a/src/types.ts b/src/types.ts index c7b7c08..8344c79 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,6 +9,7 @@ export interface apiListItem { id?: string; infores?: string; name: string; + includeFlipped?: boolean; // Automatically generate flipped MetaEdges (TRAPI only) } export interface apiListObject { From f98454c3d139705b1f5421334620397e402df149 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:35:41 -0400 Subject: [PATCH 3/6] chore: smaller log for injected operations --- .../sync_operations_builder_with_reasoner.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/operations_builder/sync_operations_builder_with_reasoner.ts b/src/operations_builder/sync_operations_builder_with_reasoner.ts index 1151a88..586115a 100644 --- a/src/operations_builder/sync_operations_builder_with_reasoner.ts +++ b/src/operations_builder/sync_operations_builder_with_reasoner.ts @@ -46,6 +46,7 @@ export default class SyncOperationsBuilderWithReasoner extends BaseOperationsBui } //predicates are store as OBJ:{SUBJ:[predicates]} //parses each layer accordingly + let injectedOps = 0; Object.keys(metadata.predicates).map(obj => { Object.keys(metadata.predicates[obj]).map(sbj => { if (Array.isArray(metadata.predicates[obj][sbj])) { @@ -140,14 +141,15 @@ export default class SyncOperationsBuilderWithReasoner extends BaseOperationsBui }; if (inverse_op.association.predicate) { ops.push(inverse_op); - debug( - `Injected reverse MetaEdge for ${op.association.api_name} ( ${inverse_op.association.input_type} -> ${inverse_op.association.predicate} -> ${inverse_op.association.output_type} )`, - ); + injectedOps += 1; } }); } }); }); + if (injectedOps) { + debug(`Injected ${injectedOps} inverse operations for ${metadata.association.api_name}`); + } if (!(typeof this._options.apiList === "undefined")) { return ops.filter(op => { const includeSmartAPI = this._options.apiList.include.find( From 2ae29553d3c940ad4a774e977c51ef638a56b00a Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:42:54 -0400 Subject: [PATCH 4/6] test: update test workflow --- .github/workflows/test_cov.yml | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_cov.yml b/.github/workflows/test_cov.yml index 4b78d5d..4a4c876 100644 --- a/.github/workflows/test_cov.yml +++ b/.github/workflows/test_cov.yml @@ -1,6 +1,6 @@ on: ["push", "pull_request"] -name: Test Codecov +name: Test in workspace jobs: @@ -9,7 +9,24 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - name: Get branch name + id: branch-name + uses: tj-actions/branch-names@v6 + + - name: Checkout to specific branch + uses: actions/checkout@v3 + id: specific-checkout + continue-on-error: true + with: + repository: biothings/biothings_explorer + ref: ${{ steps.branch-name.outputs.current_branch }} + + - name: Checkout to main if above failed + if: steps.specific-checkout.outcome == 'failure' + uses: actions/checkout@v3 + with: + repository: biothings/biothings_explorer + ref: main - name: Use Node.js 18.x uses: actions/setup-node@v3 @@ -23,10 +40,14 @@ jobs: - name: pnpm install, generate coverage report run: | + pnpm run clone + pnpm run git checkout ${{ steps.branch-name.outputs.current_branch }} pnpm i - pnpm run test-cov + pnpm --filter smartapi-kg test-cov - name: Send coverage report to codecov for visualization uses: codecov/codecov-action@v3 with: + working-directory: ./packages/@biothings-explorer/query_graph_handler + files: ./coverage/lcov.info verbose: true From 1d190d862a4c8a106aa038e2de58e10d1345480b Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:47:07 -0400 Subject: [PATCH 5/6] test: workflow fixes --- .github/workflows/test_cov.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_cov.yml b/.github/workflows/test_cov.yml index 4a4c876..7f9ed92 100644 --- a/.github/workflows/test_cov.yml +++ b/.github/workflows/test_cov.yml @@ -11,7 +11,7 @@ jobs: - name: Get branch name id: branch-name - uses: tj-actions/branch-names@v6 + uses: tj-actions/branch-names@v7.0.7 - name: Checkout to specific branch uses: actions/checkout@v3 @@ -48,6 +48,6 @@ jobs: - name: Send coverage report to codecov for visualization uses: codecov/codecov-action@v3 with: - working-directory: ./packages/@biothings-explorer/query_graph_handler + working-directory: ./packages/@biothings-explorer/smartapi-kg files: ./coverage/lcov.info verbose: true From f79674d80f8f1595dea4fab14f4e99c86d8c0e39 Mon Sep 17 00:00:00 2001 From: tokebe <43009413+tokebe@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:55:44 -0400 Subject: [PATCH 6/6] build: update tsconfig --- tsconfig.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 286159b..12fe01c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,10 @@ "esModuleInterop": true, "resolveJsonModule": true, "strict": false, - "noImplicitAny": false + "noImplicitAny": false, + "paths": { + "@biothings-explorer/utils": ["../utils"], + } }, "include": [ "./src/**/*", @@ -23,5 +26,10 @@ "exclude": [ "node_modules", "__tests__/" + ], + "references": [ + { + "path": "../utils" + } ] }