Skip to content

Commit

Permalink
faucetsdn#756-created distinct queries for each field
Browse files Browse the repository at this point in the history
  • Loading branch information
Marc Spratt committed May 16, 2022
1 parent 546126a commit 5d734aa
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 62 deletions.
24 changes: 1 addition & 23 deletions udmif/api/src/device/dao/mongodb/MongoDeviceDAO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ export class MongoDeviceDAO implements DeviceDAO {
async getDevices(searchOptions: SearchOptions): Promise<Device[]> {
return this.db
.collection<Device>('device')
.aggregate(this.getAggregate(searchOptions))
.find(this.getFilter(searchOptions))
.sort(this.getSort(searchOptions))
.skip(searchOptions.offset)
.limit(searchOptions.batchSize)
.map((device) => <Device>device)
.toArray();
}

Expand Down Expand Up @@ -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<string[]> {
return this.db
.collection<Device>('device')
Expand Down
1 change: 0 additions & 1 deletion udmif/api/src/device/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export interface SearchOptions {
offset?: number;
sortOptions?: SortOptions;
filter?: string;
uniqueBy?: string;
}

export interface ValidatedCommonSearchOptions {
Expand Down
3 changes: 0 additions & 3 deletions udmif/api/src/device/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ input SearchOptions {
sortOptions: SortOptions
# the search filter
filter: String
# the field to consider uniqueness on
uniqueBy: String
}

input DeviceNamesSearchOptions {
Expand Down Expand Up @@ -69,7 +67,6 @@ type DevicesResponse {
totalFilteredCount: Int!
}


type Point{
# the ID of the point
id: ID!
Expand Down
2 changes: 0 additions & 2 deletions udmif/web/src/app/devices/devices.component.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<app-search-filter
serviceName="DevicesService"
serviceMethod="getDevices"
[fields]="searchFields"
itemsPath="devices.devices"
[limit]="15"
[handleFilterChange]="filterData"
></app-search-filter>
Expand Down
8 changes: 7 additions & 1 deletion udmif/web/src/app/devices/devices.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string> = {
name: 'getDeviceNames',
make: 'getDeviceMakes',
model: 'getDeviceModels',
site: 'getDeviceSites',
section: 'getDeviceSections',
};

constructor(private devicesService: DevicesService) {}

Expand Down
30 changes: 29 additions & 1 deletion udmif/web/src/app/devices/devices.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export interface SearchOptions {
offset?: number;
sortOptions?: SortOptions;
filter?: string;
uniqueBy?: string;
}

export interface SortOptions {
Expand All @@ -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[];
};
30 changes: 30 additions & 0 deletions udmif/web/src/app/devices/devices.gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
`;
118 changes: 112 additions & 6 deletions udmif/web/src/app/devices/devices.service.ts
Original file line number Diff line number Diff line change
@@ -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({
Expand All @@ -18,8 +36,7 @@ export class DevicesService {
offset?: number,
batchSize: number = 10,
sortOptions?: SortOptions,
filter?: string,
uniqueBy?: string
filter?: string
): Observable<ApolloQueryResult<DevicesQueryResponse>> {
this.devicesQuery = this.apollo.watchQuery<DevicesQueryResponse, DevicesQueryVariables>({
notifyOnNetworkStatusChange: true, // to update the loading flag on next batch fetched
Expand All @@ -31,7 +48,6 @@ export class DevicesService {
batchSize,
sortOptions,
filter,
uniqueBy,
},
},
});
Expand All @@ -49,4 +65,94 @@ export class DevicesService {
},
});
}

getDeviceNames(term?: string, limit?: number): Observable<DeviceDistinctQueryResult> {
return this.apollo
.watchQuery<DeviceNamesQueryResponse, DeviceDistinctQueryVariables>({
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<DeviceDistinctQueryResult> {
return this.apollo
.watchQuery<DeviceMakesQueryResponse, DeviceDistinctQueryVariables>({
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<DeviceDistinctQueryResult> {
return this.apollo
.watchQuery<DeviceModelsQueryResponse, DeviceDistinctQueryVariables>({
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<DeviceDistinctQueryResult> {
return this.apollo
.watchQuery<DeviceSitesQueryResponse, DeviceDistinctQueryVariables>({
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<DeviceDistinctQueryResult> {
return this.apollo
.watchQuery<DeviceSectionsQueryResponse, DeviceDistinctQueryVariables>({
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 };
})
);
}
}
32 changes: 7 additions & 25 deletions udmif/web/src/app/search-filter/search-filter.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@ 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
})
export class SearchFilterComponent implements OnInit {
serviceName!: string;
serviceMethod!: string;
fields!: string[];
itemsPath!: string;
fields!: Record<string, string>;
limit: number = 5;
handleFilterChange = (_filters: SearchFilterItem[]): void => {};
filterEntry: SearchFilterItem = {}; // chip cache
Expand All @@ -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.
<Observable<any>>this.injector
<Observable<ChipItem[]>>this.injector
.get<any>(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;
})
),
Expand All @@ -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;
}

Expand Down

0 comments on commit 5d734aa

Please sign in to comment.