From 5d734aa1d91644b914db439aeba3984e3fbe7a07 Mon Sep 17 00:00:00 2001 From: Marc Spratt Date: Tue, 10 May 2022 16:26:08 -0400 Subject: [PATCH] #756-created distinct queries for each field --- .../src/device/dao/mongodb/MongoDeviceDAO.ts | 24 +--- udmif/api/src/device/model.ts | 1 - udmif/api/src/device/schema.graphql | 3 - .../src/app/devices/devices.component.html | 2 - .../web/src/app/devices/devices.component.ts | 8 +- udmif/web/src/app/devices/devices.d.ts | 30 ++++- udmif/web/src/app/devices/devices.gql.ts | 30 +++++ udmif/web/src/app/devices/devices.service.ts | 118 +++++++++++++++++- .../search-filter/search-filter.component.ts | 32 ++--- 9 files changed, 186 insertions(+), 62 deletions(-) diff --git a/udmif/api/src/device/dao/mongodb/MongoDeviceDAO.ts b/udmif/api/src/device/dao/mongodb/MongoDeviceDAO.ts index 5716a01b2a..33734f2566 100644 --- a/udmif/api/src/device/dao/mongodb/MongoDeviceDAO.ts +++ b/udmif/api/src/device/dao/mongodb/MongoDeviceDAO.ts @@ -23,11 +23,10 @@ export class MongoDeviceDAO implements DeviceDAO { async getDevices(searchOptions: SearchOptions): Promise { return this.db .collection('device') - .aggregate(this.getAggregate(searchOptions)) + .find(this.getFilter(searchOptions)) .sort(this.getSort(searchOptions)) .skip(searchOptions.offset) .limit(searchOptions.batchSize) - .map((device) => device) .toArray(); } @@ -76,27 +75,6 @@ export class MongoDeviceDAO implements DeviceDAO { return searchOptions.sortOptions ? getSort(searchOptions.sortOptions) : { _id: 1 }; } - private getAggregate(searchOptions: SearchOptions): any { - const aggregate: any[] = [{ $match: this.getFilter(searchOptions) }]; - - // Return unique results based on a certain field. - return searchOptions.uniqueBy - ? aggregate.concat( - { - $group: { - _id: `$${searchOptions.uniqueBy}`, - doc: { $first: '$$ROOT' }, - }, - }, - { - $replaceRoot: { - newRoot: '$doc', - }, - } - ) - : aggregate; - } - private async getDistinct(field: string, searchOptions: ValidatedCommonSearchOptions): Promise { return this.db .collection('device') diff --git a/udmif/api/src/device/model.ts b/udmif/api/src/device/model.ts index 9cafe3f14a..c93f6276b3 100644 --- a/udmif/api/src/device/model.ts +++ b/udmif/api/src/device/model.ts @@ -9,7 +9,6 @@ export interface SearchOptions { offset?: number; sortOptions?: SortOptions; filter?: string; - uniqueBy?: string; } export interface ValidatedCommonSearchOptions { diff --git a/udmif/api/src/device/schema.graphql b/udmif/api/src/device/schema.graphql index 6967d4a4bd..f0fda7aec3 100644 --- a/udmif/api/src/device/schema.graphql +++ b/udmif/api/src/device/schema.graphql @@ -7,8 +7,6 @@ input SearchOptions { sortOptions: SortOptions # the search filter filter: String - # the field to consider uniqueness on - uniqueBy: String } input DeviceNamesSearchOptions { @@ -69,7 +67,6 @@ type DevicesResponse { totalFilteredCount: Int! } - type Point{ # the ID of the point id: ID! diff --git a/udmif/web/src/app/devices/devices.component.html b/udmif/web/src/app/devices/devices.component.html index e0cf407c92..9e8306f3a3 100644 --- a/udmif/web/src/app/devices/devices.component.html +++ b/udmif/web/src/app/devices/devices.component.html @@ -1,8 +1,6 @@ diff --git a/udmif/web/src/app/devices/devices.component.ts b/udmif/web/src/app/devices/devices.component.ts index d15d8e4991..0647fd825f 100644 --- a/udmif/web/src/app/devices/devices.component.ts +++ b/udmif/web/src/app/devices/devices.component.ts @@ -30,7 +30,13 @@ export class DevicesComponent implements OnInit { pageSizeOptions: number[] = [10, 25, 50, 100]; sortOptions: SortOptions | undefined; filter: string | undefined; - searchFields: string[] = ['name', 'make', 'model', 'site', 'section']; + searchFields: Record = { + name: 'getDeviceNames', + make: 'getDeviceMakes', + model: 'getDeviceModels', + site: 'getDeviceSites', + section: 'getDeviceSections', + }; constructor(private devicesService: DevicesService) {} diff --git a/udmif/web/src/app/devices/devices.d.ts b/udmif/web/src/app/devices/devices.d.ts index d8db926739..02c007f247 100644 --- a/udmif/web/src/app/devices/devices.d.ts +++ b/udmif/web/src/app/devices/devices.d.ts @@ -5,7 +5,6 @@ export interface SearchOptions { offset?: number; sortOptions?: SortOptions; filter?: string; - uniqueBy?: string; } export interface SortOptions { @@ -24,3 +23,32 @@ export type DevicesQueryResponse = { export type DevicesQueryVariables = { searchOptions: SearchOptions; }; + +export type DeviceNamesQueryResponse = { + deviceNames: string[]; +}; + +export type DeviceMakesQueryResponse = { + deviceMakes: string[]; +}; + +export type DeviceModelsQueryResponse = { + deviceModels: string[]; +}; + +export type DeviceSitesQueryResponse = { + deviceSites: string[]; +}; + +export type DeviceSectionsQueryResponse = { + deviceSections: string[]; +}; + +export type DeviceDistinctQueryVariables = { + term?: string; + limit?: number; +}; + +export type DeviceDistinctQueryResult = { + values: string[]; +}; diff --git a/udmif/web/src/app/devices/devices.gql.ts b/udmif/web/src/app/devices/devices.gql.ts index 5d4100ce7e..4c86927307 100644 --- a/udmif/web/src/app/devices/devices.gql.ts +++ b/udmif/web/src/app/devices/devices.gql.ts @@ -13,3 +13,33 @@ export const GET_DEVICES = gql` } ${fragments.device} `; + +export const GET_DEVICE_NAMES = gql` + query GetDeviceNames($term: String, $limit: Int) { + deviceNames(term: $term, limit: $limit) + } +`; + +export const GET_DEVICE_MAKES = gql` + query GetDeviceMakes($term: String, $limit: Int) { + deviceMakes(term: $term, limit: $limit) + } +`; + +export const GET_DEVICE_MODELS = gql` + query GetDeviceModels($term: String, $limit: Int) { + deviceModels(term: $term, limit: $limit) + } +`; + +export const GET_DEVICE_SITES = gql` + query GetDeviceSites($term: String, $limit: Int) { + deviceSites(term: $term, limit: $limit) + } +`; + +export const GET_DEVICE_SECTIONS = gql` + query GetDeviceSections($term: String, $limit: Int) { + deviceSections(term: $term, limit: $limit) + } +`; diff --git a/udmif/web/src/app/devices/devices.service.ts b/udmif/web/src/app/devices/devices.service.ts index 098644f92b..23094afb0e 100644 --- a/udmif/web/src/app/devices/devices.service.ts +++ b/udmif/web/src/app/devices/devices.service.ts @@ -1,9 +1,27 @@ import { Injectable } from '@angular/core'; import { Apollo } from 'apollo-angular'; -import { GET_DEVICES } from './devices.gql'; +import { + GET_DEVICES, + GET_DEVICE_MAKES, + GET_DEVICE_MODELS, + GET_DEVICE_NAMES, + GET_DEVICE_SECTIONS, + GET_DEVICE_SITES, +} from './devices.gql'; import { QueryRef } from 'apollo-angular'; -import { DevicesQueryResponse, DevicesQueryVariables, SortOptions } from './devices'; -import { Observable } from 'rxjs'; +import { + DeviceDistinctQueryResult, + DeviceDistinctQueryVariables, + DeviceMakesQueryResponse, + DeviceModelsQueryResponse, + DeviceNamesQueryResponse, + DeviceSectionsQueryResponse, + DeviceSitesQueryResponse, + DevicesQueryResponse, + DevicesQueryVariables, + SortOptions, +} from './devices'; +import { map, Observable } from 'rxjs'; import { ApolloQueryResult } from '@apollo/client/core'; @Injectable({ @@ -18,8 +36,7 @@ export class DevicesService { offset?: number, batchSize: number = 10, sortOptions?: SortOptions, - filter?: string, - uniqueBy?: string + filter?: string ): Observable> { this.devicesQuery = this.apollo.watchQuery({ notifyOnNetworkStatusChange: true, // to update the loading flag on next batch fetched @@ -31,7 +48,6 @@ export class DevicesService { batchSize, sortOptions, filter, - uniqueBy, }, }, }); @@ -49,4 +65,94 @@ export class DevicesService { }, }); } + + getDeviceNames(term?: string, limit?: number): Observable { + return this.apollo + .watchQuery({ + notifyOnNetworkStatusChange: true, // to update the loading flag on next batch fetched + query: GET_DEVICE_NAMES, + fetchPolicy: 'network-only', + variables: { + term, + limit, + }, + }) + .valueChanges.pipe( + map(({ data }) => { + return { values: data.deviceNames }; + }) + ); + } + + getDeviceMakes(term?: string, limit?: number): Observable { + return this.apollo + .watchQuery({ + notifyOnNetworkStatusChange: true, // to update the loading flag on next batch fetched + query: GET_DEVICE_MAKES, + fetchPolicy: 'network-only', + variables: { + term, + limit, + }, + }) + .valueChanges.pipe( + map(({ data }) => { + return { values: data.deviceMakes }; + }) + ); + } + + getDeviceModels(term?: string, limit?: number): Observable { + return this.apollo + .watchQuery({ + notifyOnNetworkStatusChange: true, // to update the loading flag on next batch fetched + query: GET_DEVICE_MODELS, + fetchPolicy: 'network-only', + variables: { + term, + limit, + }, + }) + .valueChanges.pipe( + map(({ data }) => { + return { values: data.deviceModels }; + }) + ); + } + + getDeviceSites(term?: string, limit?: number): Observable { + return this.apollo + .watchQuery({ + notifyOnNetworkStatusChange: true, // to update the loading flag on next batch fetched + query: GET_DEVICE_SITES, + fetchPolicy: 'network-only', + variables: { + term, + limit, + }, + }) + .valueChanges.pipe( + map(({ data }) => { + return { values: data.deviceSites }; + }) + ); + } + + getDeviceSections(term?: string, limit?: number): Observable { + return this.apollo + .watchQuery({ + notifyOnNetworkStatusChange: true, // to update the loading flag on next batch fetched + query: GET_DEVICE_SECTIONS, + fetchPolicy: 'network-only', + variables: { + term, + limit, + }, + }) + .valueChanges.pipe( + map(({ data }) => { + return { values: data.deviceSections }; + }) + ); + } } diff --git a/udmif/web/src/app/search-filter/search-filter.component.ts b/udmif/web/src/app/search-filter/search-filter.component.ts index 780643c401..7d27c39a97 100644 --- a/udmif/web/src/app/search-filter/search-filter.component.ts +++ b/udmif/web/src/app/search-filter/search-filter.component.ts @@ -14,7 +14,7 @@ const services: any = { @Component({ selector: 'app-search-filter', - inputs: ['serviceName', 'serviceMethod', 'fields', 'itemsPath', 'limit', 'handleFilterChange'], + inputs: ['serviceName', 'fields', 'limit', 'handleFilterChange'], templateUrl: './search-filter.component.html', styleUrls: ['./search-filter.component.scss'], providers: [DevicesService], // scoped instances @@ -22,8 +22,7 @@ const services: any = { export class SearchFilterComponent implements OnInit { serviceName!: string; serviceMethod!: string; - fields!: string[]; - itemsPath!: string; + fields!: Record; limit: number = 5; handleFilterChange = (_filters: SearchFilterItem[]): void => {}; filterEntry: SearchFilterItem = {}; // chip cache @@ -45,29 +44,12 @@ export class SearchFilterComponent implements OnInit { iif( () => this.filterEntry.operator === '=' && !some(this.allItems, (item) => term === item.value), // avoid calling the backend again with the populated search term when the value is selected // Auto-complete on suggested values when we've chosen the equals operator on a field. - >this.injector + >this.injector .get(services[this.serviceName]) - [this.serviceMethod]( - 0, - this.limit, - { direction: 'ASC', field: this.filterEntry.field }, - JSON.stringify([ - { - field: this.filterEntry.field, - operator: '~', // contains - value: term, - }, - ]), - this.filterEntry.field - ) + [this.fields[this.filterEntry.field]]?.(term, this.limit) .pipe( - map(({ data }) => { - this.allItems = - get(data, this.itemsPath)?.map((item: any): ChipItem => { - const value: string = item?.[this.filterEntry.field]; - - return { label: value, value }; - }) || []; + map(({ values }) => { + this.allItems = values.map((value: string): ChipItem => ({ label: value, value })); return this.allItems; }) ), @@ -79,7 +61,7 @@ export class SearchFilterComponent implements OnInit { } ngOnInit(): void { - this.allItems = this.fields.map((chipValue) => ({ label: startCase(chipValue), value: chipValue })); + this.allItems = Object.keys(this.fields).map((chipValue) => ({ label: startCase(chipValue), value: chipValue })); this.fieldItems = this.allItems; }