From b527ca8ba52f37fee07536f48c74281d9a5c4c8c Mon Sep 17 00:00:00 2001 From: edlu77 Date: Mon, 29 Jan 2024 18:15:45 -0500 Subject: [PATCH 1/7] Use hybrid database for fetching requests --- projects/ccf-database/src/lib/ccf-database.ts | 6 +- .../data-source/data-source.service.ts | 11 ++- .../src/app/core/store/data/data.state.ts | 23 +----- .../filters-content.component.ts | 2 +- .../data-source/api-endpoint.service.ts | 19 ++--- .../data-source/ccf-database.service.ts | 79 +++++++++++++++++-- 6 files changed, 100 insertions(+), 40 deletions(-) diff --git a/projects/ccf-database/src/lib/ccf-database.ts b/projects/ccf-database/src/lib/ccf-database.ts index 0a2dc92c6..1f5263c64 100644 --- a/projects/ccf-database/src/lib/ccf-database.ts +++ b/projects/ccf-database/src/lib/ccf-database.ts @@ -8,7 +8,6 @@ import { import { CCFSpatialGraph } from './ccf-spatial-graph'; import { CCFSpatialScene, SpatialSceneNode } from './ccf-spatial-scene'; -import { searchXConsortia } from './xconsortia/xconsortia-data-import'; import { AggregateResult, DatabaseStatus, Filter, OntologyTreeModel, TissueBlockResult } from './interfaces'; import { getAggregateResults, getDatasetTechnologyNames, getProviderNames } from './queries/aggregate-results-n3'; import { findIds } from './queries/find-ids-n3'; @@ -18,9 +17,10 @@ import { getSpatialEntityForEntity } from './queries/spatial-result-n3'; import { getTissueBlockResult } from './queries/tissue-block-result-n3'; import { FlatSpatialPlacement, SpatialEntity } from './spatial-types'; import { CCFDatabaseStatusTracker } from './util/ccf-database-status-tracker'; -import { patchJsonLd } from './util/patch-jsonld'; -import { enrichRuiLocations } from './util/enrich-rui-locations'; import { getBmLocatedInAs } from './util/enrich-bm-located-in-as'; +import { enrichRuiLocations } from './util/enrich-rui-locations'; +import { patchJsonLd } from './util/patch-jsonld'; +import { searchXConsortia } from './xconsortia/xconsortia-data-import'; const { delMany, get, setMany } = idb; diff --git a/projects/ccf-eui/src/app/core/services/data-source/data-source.service.ts b/projects/ccf-eui/src/app/core/services/data-source/data-source.service.ts index 40420567c..fd812bbca 100644 --- a/projects/ccf-eui/src/app/core/services/data-source/data-source.service.ts +++ b/projects/ccf-eui/src/app/core/services/data-source/data-source.service.ts @@ -1,6 +1,6 @@ import { Injectable, ProviderToken } from '@angular/core'; import { - ApiEndpointDataSourceService, CCFDatabaseDataSourceService, DataSourceLike, InjectorDelegateDataSourceService, + ApiEndpointDataSourceService, CCFDatabaseDataSourceService, DataSourceLike, InjectorDelegateDataSourceService, MixedCCfDatabaseDatasourceService } from 'ccf-shared'; import { environment } from '../../../../environments/environment'; @@ -8,6 +8,7 @@ import { WorkerDataSourceService } from './worker-data-source.service'; export interface DelegateDataSourceOptions { + dataSources?: []; useRemoteApi?: boolean; remoteApiEndpoint?: string; } @@ -18,10 +19,14 @@ export interface DelegateDataSourceOptions { }) export class DelegateDataSourceService extends InjectorDelegateDataSourceService { protected selectToken(config: DelegateDataSourceOptions): ProviderToken { - const { useRemoteApi, remoteApiEndpoint } = config; + const { dataSources, useRemoteApi, remoteApiEndpoint } = config; if (useRemoteApi && !!remoteApiEndpoint) { - return ApiEndpointDataSourceService; + if (dataSources && dataSources.length > 0) { + return MixedCCfDatabaseDatasourceService; + } else { + return ApiEndpointDataSourceService; + } } else if (typeof Worker !== 'undefined' && !environment.disableDbWorker) { return WorkerDataSourceService; } else { diff --git a/projects/ccf-eui/src/app/core/store/data/data.state.ts b/projects/ccf-eui/src/app/core/store/data/data.state.ts index 2ff45d134..27c52d572 100644 --- a/projects/ccf-eui/src/app/core/store/data/data.state.ts +++ b/projects/ccf-eui/src/app/core/store/data/data.state.ts @@ -1,32 +1,17 @@ /* eslint-disable no-underscore-dangle */ /* eslint-disable @typescript-eslint/member-ordering */ /* eslint-disable @typescript-eslint/naming-convention */ -import { Injectable } from '@angular/core'; import { DataAction, Payload, StateRepository } from '@angular-ru/ngxs/decorators'; import { NgxsDataRepository } from '@angular-ru/ngxs/repositories'; +import { Injectable } from '@angular/core'; import { Action, NgxsOnInit, State } from '@ngxs/store'; import { bind } from 'bind-decorator'; import { AggregateResult, DatabaseStatus, Filter, OntologyTreeModel, SpatialSceneNode, TissueBlockResult } from 'ccf-database'; -import { DataSourceService } from 'ccf-shared'; -import { combineLatest, defer, ObservableInput, ObservedValueOf, OperatorFunction, ReplaySubject, Subject } from 'rxjs'; -import { delay, distinct, filter as rxjsFilter, map, publishReplay, refCount, repeat, switchMap, take, takeWhile, tap } from 'rxjs/operators'; +import { DEFAULT_FILTER, DataSourceService } from 'ccf-shared'; +import { ObservableInput, ObservedValueOf, OperatorFunction, ReplaySubject, Subject, combineLatest, defer } from 'rxjs'; +import { delay, distinct, map, publishReplay, refCount, repeat, filter as rxjsFilter, switchMap, take, takeWhile, tap } from 'rxjs/operators'; import { UpdateFilter } from './data.actions'; - -/** Default values for filters. */ -export const DEFAULT_FILTER: Filter = { - sex: 'Both', - ageRange: [1, 110], - bmiRange: [13, 83], - consortiums: [], - tmc: [], - technologies: [], - ontologyTerms: ['http://purl.obolibrary.org/obo/UBERON_0013702'], - cellTypeTerms: ['http://purl.obolibrary.org/obo/CL_0000000'], - biomarkerTerms: ['http://purl.org/ccf/biomarkers'], - spatialSearches: [] -}; - /** Current state of data queries. */ // eslint-disable-next-line no-shadow export enum DataQueryState { diff --git a/projects/ccf-eui/src/app/modules/filters/filters-content/filters-content.component.ts b/projects/ccf-eui/src/app/modules/filters/filters-content/filters-content.component.ts index be549c908..809ee0668 100644 --- a/projects/ccf-eui/src/app/modules/filters/filters-content/filters-content.component.ts +++ b/projects/ccf-eui/src/app/modules/filters/filters-content/filters-content.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { GoogleAnalyticsService } from 'ngx-google-analytics'; -import { DEFAULT_FILTER } from '../../../core/store/data/data.state'; +import { DEFAULT_FILTER } from 'ccf-shared'; import { SpatialSearchFilterItem } from '../../../core/store/spatial-search-filter/spatial-search-filter.state'; import { Sex } from '../../../shared/components/spatial-search-config/spatial-search-config.component'; diff --git a/projects/ccf-shared/src/lib/services/data-source/api-endpoint.service.ts b/projects/ccf-shared/src/lib/services/data-source/api-endpoint.service.ts index 189416da0..ef99813dd 100644 --- a/projects/ccf-shared/src/lib/services/data-source/api-endpoint.service.ts +++ b/projects/ccf-shared/src/lib/services/data-source/api-endpoint.service.ts @@ -1,10 +1,11 @@ import { Injectable } from '@angular/core'; import { Matrix4 } from '@math.gl/core'; import { - AggregateResult, Filter, OntologyTreeModel, OntologyTreeNode, SpatialEntity, SpatialSceneNode, TissueBlockResult, + AggregateResult, Filter, OntologyTreeModel, + SpatialEntity, SpatialSceneNode, TissueBlockResult } from 'ccf-database'; -import { DatabaseStatus, DefaultService, MinMax, SpatialSearch, SpatialSceneNode as RawSpatialSceneNode } from 'ccf-openapi/angular-client'; -import { combineLatest, Observable, of, Subject } from 'rxjs'; +import { DatabaseStatus, DefaultService, MinMax, SpatialSceneNode as RawSpatialSceneNode, SpatialSearch } from 'ccf-openapi/angular-client'; +import { Observable, Subject, combineLatest } from 'rxjs'; import { map, switchMap, take, tap } from 'rxjs/operators'; import { Cacheable } from 'ts-cacheable'; @@ -20,14 +21,14 @@ export interface ApiEndpointDataSourceOptions { // Not exported from ts-cacheable!? type IObservableCacheConfig = NonNullable[0]>; -type RequestMethod = (params: P) => Observable; -type DataReviver = (data: T) => U; +export type RequestMethod = (params: P) => Observable; +export type DataReviver = (data: T) => U; -interface DefaultParams { +export interface DefaultParams { token?: string; } -interface FilterParams { +export interface FilterParams { age?: MinMax; ageRange?: string; bmi?: MinMax; @@ -61,7 +62,7 @@ function cast(): (data: unknown) => T { return data => data as T; } -function rangeToMinMax( +export function rangeToMinMax( range: [number, number] | undefined, low: number, high: number ): MinMax | undefined { @@ -71,7 +72,7 @@ function rangeToMinMax( } : undefined; } -function filterToParams(filter?: Filter): FilterParams { +export function filterToParams(filter?: Filter): FilterParams { return { age: rangeToMinMax(filter?.ageRange, 1, 110), bmi: rangeToMinMax(filter?.bmiRange, 13, 83), diff --git a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts index cff07ed47..9d132fd94 100644 --- a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts +++ b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts @@ -1,13 +1,27 @@ import { Injectable, isDevMode } from '@angular/core'; -import { CCFDatabase, CCFDatabaseOptions } from 'ccf-database'; -import { releaseProxy, Remote, wrap } from 'comlink'; -import { Observable, Unsubscribable, using } from 'rxjs'; +import { CCFDatabase, CCFDatabaseOptions, Filter } from 'ccf-database'; +import { Remote, releaseProxy, wrap } from 'comlink'; +import { Observable, ObservableInput, Unsubscribable, using } from 'rxjs'; import { filter, map, shareReplay, switchMap } from 'rxjs/operators'; import { GlobalConfigState } from '../../config/global-config.state'; -import { DataSourceLike, DelegateDataSource } from './data-source'; - +import { ApiEndpointDataSourceService } from './api-endpoint.service'; +import { DataSource, DataSourceDataType, DataSourceLike, DataSourceMethod, DelegateDataSource, ForwardingDataSource } from './data-source'; +import _ from 'lodash'; +/** Default values for filters. */ +export const DEFAULT_FILTER: Filter = { + sex: 'Both', + ageRange: [1, 110], + bmiRange: [13, 83], + consortiums: [], + tmc: [], + technologies: [], + ontologyTerms: ['http://purl.obolibrary.org/obo/UBERON_0013702'], + cellTypeTerms: ['http://purl.obolibrary.org/obo/CL_0000000'], + biomarkerTerms: ['http://purl.org/ccf/biomarkers'], + spatialSearches: [] +}; interface CCFDatabaseManager extends Unsubscribable { database: CCFDatabase | Remote; @@ -75,3 +89,58 @@ export abstract class WorkerCCFDatabaseDataSourceService extends CCFDatabaseData }; } } + +const REMOTE_METHODS: (keyof DataSource)[] = [ + 'getProviderNames', + 'getDatasetTechnologyNames', + 'getOntologyTreeModel', + 'getCellTypeTreeModel', + 'getBiomarkerTreeModel', + 'getReferenceOrgans', +]; +const FILTER_METHODS_ARG_0: (keyof DataSource)[] = [ + 'getTissueBlockResults', + 'getAggregateResults', + 'getOntologyTermOccurences', + 'getCellTypeTermOccurences', + 'getBiomarkerTermOccurences', + 'getScene', +]; +const FILTER_METHODS_ARG_1: (keyof DataSource)[] = [ + 'getReferenceOrganScene', +]; + +@Injectable({ + providedIn: 'root' +}) +export class MixedCCfDatabaseDatasourceService extends ForwardingDataSource { + constructor( + private readonly remote: ApiEndpointDataSourceService, + private readonly local: CCFDatabaseDataSourceService, + ) { + super(); + } + + protected forwardCall( + method: K, ...args: Parameters> + ): Observable> { + type AnyFunction = (...rest: unknown[]) => ObservableInput; + type Res = Observable>; + const source = this.isRemoteCall(method, args) ? this.remote : this.local; + return (source[method] as AnyFunction)(...args) as Res; + } + + private isRemoteCall(method: keyof DataSource, args: unknown[]): boolean { + return ( + REMOTE_METHODS.includes(method) || + (FILTER_METHODS_ARG_0.includes(method) && this.isDefaultFilter(args[0] as Filter)) || + (FILTER_METHODS_ARG_1.includes(method) && this.isDefaultFilter(args[1] as Filter)) + ); + } + + private isDefaultFilter(value?: Filter): boolean { + return _.isEqual(value, DEFAULT_FILTER); + } +} + + From a97ba49d6d15386e148ca2522c467a42e4307be2 Mon Sep 17 00:00:00 2001 From: edlu77 Date: Mon, 29 Jan 2024 18:30:00 -0500 Subject: [PATCH 2/7] Linting --- .../src/lib/services/data-source/ccf-database.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts index 9d132fd94..73d3b16c5 100644 --- a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts +++ b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts @@ -7,7 +7,7 @@ import { filter, map, shareReplay, switchMap } from 'rxjs/operators'; import { GlobalConfigState } from '../../config/global-config.state'; import { ApiEndpointDataSourceService } from './api-endpoint.service'; import { DataSource, DataSourceDataType, DataSourceLike, DataSourceMethod, DelegateDataSource, ForwardingDataSource } from './data-source'; -import _ from 'lodash'; +import isEqual from 'lodash/isEqual'; /** Default values for filters. */ export const DEFAULT_FILTER: Filter = { @@ -139,7 +139,7 @@ export class MixedCCfDatabaseDatasourceService extends ForwardingDataSource { } private isDefaultFilter(value?: Filter): boolean { - return _.isEqual(value, DEFAULT_FILTER); + return isEqual(value, DEFAULT_FILTER); } } From 0367520d0597dbcf07ccbbe57c4a3ab9bc2727ab Mon Sep 17 00:00:00 2001 From: edlu77 Date: Mon, 29 Jan 2024 18:31:01 -0500 Subject: [PATCH 3/7] Formatting --- .../src/lib/services/data-source/ccf-database.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts index 73d3b16c5..e76528d7b 100644 --- a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts +++ b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts @@ -7,7 +7,7 @@ import { filter, map, shareReplay, switchMap } from 'rxjs/operators'; import { GlobalConfigState } from '../../config/global-config.state'; import { ApiEndpointDataSourceService } from './api-endpoint.service'; import { DataSource, DataSourceDataType, DataSourceLike, DataSourceMethod, DelegateDataSource, ForwardingDataSource } from './data-source'; -import isEqual from 'lodash/isEqual'; +import { isEqual } from 'lodash'; /** Default values for filters. */ export const DEFAULT_FILTER: Filter = { From c0415a42dabe5b0c981d41c43c503b233ca55ee6 Mon Sep 17 00:00:00 2001 From: edlu77 Date: Mon, 29 Jan 2024 18:39:17 -0500 Subject: [PATCH 4/7] Fix test --- projects/ccf-eui/src/app/core/store/data/data.state.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts b/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts index 049991ba6..67cfbb404 100644 --- a/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts +++ b/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts @@ -1,9 +1,9 @@ import { TestBed } from '@angular/core/testing'; import { NgxsDataPluginModule } from '@angular-ru/ngxs'; import { NgxsModule } from '@ngxs/store'; -import { CCFDatabaseDataSourceService, DataSourceService, GlobalConfigState } from 'ccf-shared'; +import { CCFDatabaseDataSourceService, DataSourceService, GlobalConfigState, DEFAULT_FILTER } from 'ccf-shared'; -import { DataState, DEFAULT_FILTER } from './data.state'; +import { DataState } from './data.state'; describe('DataState', () => { let dataState: DataState; From 333fe8c755bd8609b8a6510d35cd2ac2fc73dd58 Mon Sep 17 00:00:00 2001 From: edlu77 Date: Tue, 30 Jan 2024 17:37:14 -0500 Subject: [PATCH 5/7] Tweaks --- .../services/data-source/data-source.service.ts | 6 ++++-- .../src/app/core/store/data/data.state.spec.ts | 4 ++-- .../src/environments/environment.prod.ts | 8 ++++---- .../src/environments/environment.staging.ts | 8 ++++---- .../ccf-eui/src/environments/environment.ts | 8 ++++---- .../data-source/api-endpoint.service.ts | 14 +++++++------- .../data-source/ccf-database.service.ts | 17 +++++------------ 7 files changed, 30 insertions(+), 35 deletions(-) diff --git a/projects/ccf-eui/src/app/core/services/data-source/data-source.service.ts b/projects/ccf-eui/src/app/core/services/data-source/data-source.service.ts index fd812bbca..cf45f490f 100644 --- a/projects/ccf-eui/src/app/core/services/data-source/data-source.service.ts +++ b/projects/ccf-eui/src/app/core/services/data-source/data-source.service.ts @@ -1,6 +1,8 @@ import { Injectable, ProviderToken } from '@angular/core'; import { - ApiEndpointDataSourceService, CCFDatabaseDataSourceService, DataSourceLike, InjectorDelegateDataSourceService, MixedCCfDatabaseDatasourceService + ApiEndpointDataSourceService, CCFDatabaseDataSourceService, DataSourceLike, + HybridCCfDatabaseDatasourceService, + InjectorDelegateDataSourceService } from 'ccf-shared'; import { environment } from '../../../../environments/environment'; @@ -23,7 +25,7 @@ export class DelegateDataSourceService extends InjectorDelegateDataSourceService if (useRemoteApi && !!remoteApiEndpoint) { if (dataSources && dataSources.length > 0) { - return MixedCCfDatabaseDatasourceService; + return HybridCCfDatabaseDatasourceService; } else { return ApiEndpointDataSourceService; } diff --git a/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts b/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts index 67cfbb404..7c89e2eaa 100644 --- a/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts +++ b/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts @@ -1,7 +1,7 @@ -import { TestBed } from '@angular/core/testing'; import { NgxsDataPluginModule } from '@angular-ru/ngxs'; +import { TestBed } from '@angular/core/testing'; import { NgxsModule } from '@ngxs/store'; -import { CCFDatabaseDataSourceService, DataSourceService, GlobalConfigState, DEFAULT_FILTER } from 'ccf-shared'; +import { CCFDatabaseDataSourceService, DEFAULT_FILTER, DataSourceService, GlobalConfigState } from 'ccf-shared'; import { DataState } from './data.state'; diff --git a/projects/ccf-eui/src/environments/environment.prod.ts b/projects/ccf-eui/src/environments/environment.prod.ts index f594e22a0..8c4d9987e 100644 --- a/projects/ccf-eui/src/environments/environment.prod.ts +++ b/projects/ccf-eui/src/environments/environment.prod.ts @@ -10,10 +10,10 @@ export const environment = { dbOptions: { ccfOwlUrl: 'https://apps.humanatlas.io/hra-api/v1/ccf.owl.n3store.json', ccfContextUrl: 'https://hubmapconsortium.github.io/ccf-ontology/ccf-context.jsonld', - dataSources: [ - 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', - 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' - ], + // dataSources: [ + // 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', + // 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' + // ], hubmapDataService: 'search-api', hubmapDataUrl: 'https://search.api.hubmapconsortium.org/v3/entities/search', hubmapToken: localStorage.getItem('HUBMAP_TOKEN') ?? '', diff --git a/projects/ccf-eui/src/environments/environment.staging.ts b/projects/ccf-eui/src/environments/environment.staging.ts index 1e8a90893..b2ce07a11 100644 --- a/projects/ccf-eui/src/environments/environment.staging.ts +++ b/projects/ccf-eui/src/environments/environment.staging.ts @@ -10,10 +10,10 @@ export const environment = { dbOptions: { ccfOwlUrl: 'https://apps.humanatlas.io/hra-api--staging/v1/ccf.owl.n3store.json', ccfContextUrl: 'https://hubmapconsortium.github.io/ccf-ontology/ccf-context.jsonld', - dataSources: [ - 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', - 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' - ], + // dataSources: [ + // 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', + // 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' + // ], hubmapDataService: 'search-api', hubmapDataUrl: 'https://search.api.hubmapconsortium.org/v3/entities/search', hubmapToken: localStorage.getItem('HUBMAP_TOKEN') ?? '', diff --git a/projects/ccf-eui/src/environments/environment.ts b/projects/ccf-eui/src/environments/environment.ts index 6377e78e0..d4da1f2d2 100644 --- a/projects/ccf-eui/src/environments/environment.ts +++ b/projects/ccf-eui/src/environments/environment.ts @@ -15,10 +15,10 @@ export const environment = { dbOptions: { ccfOwlUrl: 'assets/ccf.owl.n3store.json', ccfContextUrl: 'https://hubmapconsortium.github.io/ccf-ontology/ccf-context.jsonld', - dataSources: [ - 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', - 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' - ], + // dataSources: [ + // 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', + // 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' + // ], hubmapDataService: 'search-api', hubmapDataUrl: 'https://search.api.hubmapconsortium.org/v3/entities/search', hubmapToken: localStorage.getItem('HUBMAP_TOKEN') ?? '', diff --git a/projects/ccf-shared/src/lib/services/data-source/api-endpoint.service.ts b/projects/ccf-shared/src/lib/services/data-source/api-endpoint.service.ts index ef99813dd..5e044eef7 100644 --- a/projects/ccf-shared/src/lib/services/data-source/api-endpoint.service.ts +++ b/projects/ccf-shared/src/lib/services/data-source/api-endpoint.service.ts @@ -13,7 +13,7 @@ import { GlobalConfigState } from '../../config/global-config.state'; import { DataSource } from './data-source'; -export interface ApiEndpointDataSourceOptions { +interface ApiEndpointDataSourceOptions { remoteApiEndpoint: string; hubmapToken?: string; } @@ -21,14 +21,14 @@ export interface ApiEndpointDataSourceOptions { // Not exported from ts-cacheable!? type IObservableCacheConfig = NonNullable[0]>; -export type RequestMethod = (params: P) => Observable; -export type DataReviver = (data: T) => U; +type RequestMethod = (params: P) => Observable; +type DataReviver = (data: T) => U; -export interface DefaultParams { +interface DefaultParams { token?: string; } -export interface FilterParams { +interface FilterParams { age?: MinMax; ageRange?: string; bmi?: MinMax; @@ -62,7 +62,7 @@ function cast(): (data: unknown) => T { return data => data as T; } -export function rangeToMinMax( +function rangeToMinMax( range: [number, number] | undefined, low: number, high: number ): MinMax | undefined { @@ -72,7 +72,7 @@ export function rangeToMinMax( } : undefined; } -export function filterToParams(filter?: Filter): FilterParams { +function filterToParams(filter?: Filter): FilterParams { return { age: rangeToMinMax(filter?.ageRange, 1, 110), bmi: rangeToMinMax(filter?.bmiRange, 13, 83), diff --git a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts index e76528d7b..92bc60c98 100644 --- a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts +++ b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts @@ -7,7 +7,6 @@ import { filter, map, shareReplay, switchMap } from 'rxjs/operators'; import { GlobalConfigState } from '../../config/global-config.state'; import { ApiEndpointDataSourceService } from './api-endpoint.service'; import { DataSource, DataSourceDataType, DataSourceLike, DataSourceMethod, DelegateDataSource, ForwardingDataSource } from './data-source'; -import { isEqual } from 'lodash'; /** Default values for filters. */ export const DEFAULT_FILTER: Filter = { @@ -91,8 +90,6 @@ export abstract class WorkerCCFDatabaseDataSourceService extends CCFDatabaseData } const REMOTE_METHODS: (keyof DataSource)[] = [ - 'getProviderNames', - 'getDatasetTechnologyNames', 'getOntologyTreeModel', 'getCellTypeTreeModel', 'getBiomarkerTreeModel', @@ -113,7 +110,7 @@ const FILTER_METHODS_ARG_1: (keyof DataSource)[] = [ @Injectable({ providedIn: 'root' }) -export class MixedCCfDatabaseDatasourceService extends ForwardingDataSource { +export class HybridCCfDatabaseDatasourceService extends ForwardingDataSource { constructor( private readonly remote: ApiEndpointDataSourceService, private readonly local: CCFDatabaseDataSourceService, @@ -126,21 +123,17 @@ export class MixedCCfDatabaseDatasourceService extends ForwardingDataSource { ): Observable> { type AnyFunction = (...rest: unknown[]) => ObservableInput; type Res = Observable>; - const source = this.isRemoteCall(method, args) ? this.remote : this.local; + const source = this.isRemoteCall(method) ? this.remote : this.local; return (source[method] as AnyFunction)(...args) as Res; } - private isRemoteCall(method: keyof DataSource, args: unknown[]): boolean { + private isRemoteCall(method: keyof DataSource): boolean { return ( REMOTE_METHODS.includes(method) || - (FILTER_METHODS_ARG_0.includes(method) && this.isDefaultFilter(args[0] as Filter)) || - (FILTER_METHODS_ARG_1.includes(method) && this.isDefaultFilter(args[1] as Filter)) + (FILTER_METHODS_ARG_0.includes(method)) || + (FILTER_METHODS_ARG_1.includes(method)) ); } - - private isDefaultFilter(value?: Filter): boolean { - return isEqual(value, DEFAULT_FILTER); - } } From 969739fd33b58f5798d2aca526b3b70d6656245c Mon Sep 17 00:00:00 2001 From: edlu77 Date: Mon, 5 Feb 2024 13:59:35 -0500 Subject: [PATCH 6/7] Minor tweaks --- .../app/core/store/data/data.state.spec.ts | 4 +-- .../src/app/core/store/data/data.state.ts | 17 +++++++++- .../src/environments/environment.prod.ts | 4 --- .../src/environments/environment.staging.ts | 4 --- .../ccf-eui/src/environments/environment.ts | 9 +---- .../data-source/ccf-database.service.ts | 33 ++----------------- 6 files changed, 21 insertions(+), 50 deletions(-) diff --git a/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts b/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts index 7c89e2eaa..11631f32a 100644 --- a/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts +++ b/projects/ccf-eui/src/app/core/store/data/data.state.spec.ts @@ -1,9 +1,9 @@ import { NgxsDataPluginModule } from '@angular-ru/ngxs'; import { TestBed } from '@angular/core/testing'; import { NgxsModule } from '@ngxs/store'; -import { CCFDatabaseDataSourceService, DEFAULT_FILTER, DataSourceService, GlobalConfigState } from 'ccf-shared'; +import { CCFDatabaseDataSourceService, DataSourceService, GlobalConfigState } from 'ccf-shared'; -import { DataState } from './data.state'; +import { DataState, DEFAULT_FILTER } from './data.state'; describe('DataState', () => { let dataState: DataState; diff --git a/projects/ccf-eui/src/app/core/store/data/data.state.ts b/projects/ccf-eui/src/app/core/store/data/data.state.ts index 27c52d572..3fb219c03 100644 --- a/projects/ccf-eui/src/app/core/store/data/data.state.ts +++ b/projects/ccf-eui/src/app/core/store/data/data.state.ts @@ -7,11 +7,26 @@ import { Injectable } from '@angular/core'; import { Action, NgxsOnInit, State } from '@ngxs/store'; import { bind } from 'bind-decorator'; import { AggregateResult, DatabaseStatus, Filter, OntologyTreeModel, SpatialSceneNode, TissueBlockResult } from 'ccf-database'; -import { DEFAULT_FILTER, DataSourceService } from 'ccf-shared'; +import { DataSourceService } from 'ccf-shared'; import { ObservableInput, ObservedValueOf, OperatorFunction, ReplaySubject, Subject, combineLatest, defer } from 'rxjs'; import { delay, distinct, map, publishReplay, refCount, repeat, filter as rxjsFilter, switchMap, take, takeWhile, tap } from 'rxjs/operators'; import { UpdateFilter } from './data.actions'; + +/** Default values for filters. */ +export const DEFAULT_FILTER: Filter = { + sex: 'Both', + ageRange: [1, 110], + bmiRange: [13, 83], + consortiums: [], + tmc: [], + technologies: [], + ontologyTerms: ['http://purl.obolibrary.org/obo/UBERON_0013702'], + cellTypeTerms: ['http://purl.obolibrary.org/obo/CL_0000000'], + biomarkerTerms: ['http://purl.org/ccf/biomarkers'], + spatialSearches: [] +}; + /** Current state of data queries. */ // eslint-disable-next-line no-shadow export enum DataQueryState { diff --git a/projects/ccf-eui/src/environments/environment.prod.ts b/projects/ccf-eui/src/environments/environment.prod.ts index 8c4d9987e..e4de43b48 100644 --- a/projects/ccf-eui/src/environments/environment.prod.ts +++ b/projects/ccf-eui/src/environments/environment.prod.ts @@ -10,10 +10,6 @@ export const environment = { dbOptions: { ccfOwlUrl: 'https://apps.humanatlas.io/hra-api/v1/ccf.owl.n3store.json', ccfContextUrl: 'https://hubmapconsortium.github.io/ccf-ontology/ccf-context.jsonld', - // dataSources: [ - // 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', - // 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' - // ], hubmapDataService: 'search-api', hubmapDataUrl: 'https://search.api.hubmapconsortium.org/v3/entities/search', hubmapToken: localStorage.getItem('HUBMAP_TOKEN') ?? '', diff --git a/projects/ccf-eui/src/environments/environment.staging.ts b/projects/ccf-eui/src/environments/environment.staging.ts index b2ce07a11..3a0b0cd01 100644 --- a/projects/ccf-eui/src/environments/environment.staging.ts +++ b/projects/ccf-eui/src/environments/environment.staging.ts @@ -10,10 +10,6 @@ export const environment = { dbOptions: { ccfOwlUrl: 'https://apps.humanatlas.io/hra-api--staging/v1/ccf.owl.n3store.json', ccfContextUrl: 'https://hubmapconsortium.github.io/ccf-ontology/ccf-context.jsonld', - // dataSources: [ - // 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', - // 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' - // ], hubmapDataService: 'search-api', hubmapDataUrl: 'https://search.api.hubmapconsortium.org/v3/entities/search', hubmapToken: localStorage.getItem('HUBMAP_TOKEN') ?? '', diff --git a/projects/ccf-eui/src/environments/environment.ts b/projects/ccf-eui/src/environments/environment.ts index d4da1f2d2..98dcd61ff 100644 --- a/projects/ccf-eui/src/environments/environment.ts +++ b/projects/ccf-eui/src/environments/environment.ts @@ -15,26 +15,19 @@ export const environment = { dbOptions: { ccfOwlUrl: 'assets/ccf.owl.n3store.json', ccfContextUrl: 'https://hubmapconsortium.github.io/ccf-ontology/ccf-context.jsonld', - // dataSources: [ - // 'https://hubmapconsortium.github.io/hra-registrations/federated/rui_locations.jsonld', - // 'https://apps.humanatlas.io/hra-api/v1/gtex/rui_locations.jsonld' - // ], hubmapDataService: 'search-api', hubmapDataUrl: 'https://search.api.hubmapconsortium.org/v3/entities/search', hubmapToken: localStorage.getItem('HUBMAP_TOKEN') ?? '', useRemoteApi: false, remoteApiEndpoint: 'https://apps.humanatlas.io/hra-api--staging/v1' - // remoteApiEndpoint: 'https://apps.humanatlas.io/hra-api/v1' - // remoteApiEndpoint: 'http://localhost:8080/v1' }, customization: { theme: 'default', header: true, homeUrl: 'https://portal.hubmapconsortium.org/', logoTooltip: 'Human BioMolecular Atlas Project', - loginDisabled: false, - // filter: { sex: 'Male' } + loginDisabled: false }, googleAnalyticsToken: 'G-B3DT7XPMRT' }; diff --git a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts index 92bc60c98..1f41f280c 100644 --- a/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts +++ b/projects/ccf-shared/src/lib/services/data-source/ccf-database.service.ts @@ -1,5 +1,5 @@ import { Injectable, isDevMode } from '@angular/core'; -import { CCFDatabase, CCFDatabaseOptions, Filter } from 'ccf-database'; +import { CCFDatabase, CCFDatabaseOptions } from 'ccf-database'; import { Remote, releaseProxy, wrap } from 'comlink'; import { Observable, ObservableInput, Unsubscribable, using } from 'rxjs'; import { filter, map, shareReplay, switchMap } from 'rxjs/operators'; @@ -8,20 +8,6 @@ import { GlobalConfigState } from '../../config/global-config.state'; import { ApiEndpointDataSourceService } from './api-endpoint.service'; import { DataSource, DataSourceDataType, DataSourceLike, DataSourceMethod, DelegateDataSource, ForwardingDataSource } from './data-source'; -/** Default values for filters. */ -export const DEFAULT_FILTER: Filter = { - sex: 'Both', - ageRange: [1, 110], - bmiRange: [13, 83], - consortiums: [], - tmc: [], - technologies: [], - ontologyTerms: ['http://purl.obolibrary.org/obo/UBERON_0013702'], - cellTypeTerms: ['http://purl.obolibrary.org/obo/CL_0000000'], - biomarkerTerms: ['http://purl.org/ccf/biomarkers'], - spatialSearches: [] -}; - interface CCFDatabaseManager extends Unsubscribable { database: CCFDatabase | Remote; } @@ -95,17 +81,6 @@ const REMOTE_METHODS: (keyof DataSource)[] = [ 'getBiomarkerTreeModel', 'getReferenceOrgans', ]; -const FILTER_METHODS_ARG_0: (keyof DataSource)[] = [ - 'getTissueBlockResults', - 'getAggregateResults', - 'getOntologyTermOccurences', - 'getCellTypeTermOccurences', - 'getBiomarkerTermOccurences', - 'getScene', -]; -const FILTER_METHODS_ARG_1: (keyof DataSource)[] = [ - 'getReferenceOrganScene', -]; @Injectable({ providedIn: 'root' @@ -128,11 +103,7 @@ export class HybridCCfDatabaseDatasourceService extends ForwardingDataSource { } private isRemoteCall(method: keyof DataSource): boolean { - return ( - REMOTE_METHODS.includes(method) || - (FILTER_METHODS_ARG_0.includes(method)) || - (FILTER_METHODS_ARG_1.includes(method)) - ); + return REMOTE_METHODS.includes(method); } } From aac69074341ef7fde8e33c301e1908a306dba418 Mon Sep 17 00:00:00 2001 From: edlu77 Date: Mon, 5 Feb 2024 14:05:28 -0500 Subject: [PATCH 7/7] Fix import --- .../filters/filters-content/filters-content.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/ccf-eui/src/app/modules/filters/filters-content/filters-content.component.ts b/projects/ccf-eui/src/app/modules/filters/filters-content/filters-content.component.ts index 809ee0668..be549c908 100644 --- a/projects/ccf-eui/src/app/modules/filters/filters-content/filters-content.component.ts +++ b/projects/ccf-eui/src/app/modules/filters/filters-content/filters-content.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { GoogleAnalyticsService } from 'ngx-google-analytics'; -import { DEFAULT_FILTER } from 'ccf-shared'; +import { DEFAULT_FILTER } from '../../../core/store/data/data.state'; import { SpatialSearchFilterItem } from '../../../core/store/spatial-search-filter/spatial-search-filter.state'; import { Sex } from '../../../shared/components/spatial-search-config/spatial-search-config.component';