Files
openstapps/src/app/modules/data/data-facets.provider.ts
2021-07-08 15:32:07 +02:00

171 lines
5.0 KiB
TypeScript

/*
* Copyright (C) 2018, 2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Injectable} from '@angular/core';
import {
SCBackendAggregationConfiguration,
SCFacet,
SCFacetBucket,
SCThing,
} from '@openstapps/core';
/**
* TODO
*/
@Injectable()
export class DataFacetsProvider {
// eslint-disable-next-line no-empty, @typescript-eslint/no-empty-function
constructor() {}
/**
* Adds buckets to a map of buckets (e.g. if a buckets array is [{foo: 1}, {bar: 3}],
* its bucketsMap is {foo: 1, bar: 3}), if a field 'bar' is added to it it becomes:
* {foo: 1, bar: 4}
*
* @param bucketsMap Buckets array transformed into a map
* @param fields A field that should be added to buckets (its map)
*/
// eslint-disable-next-line class-methods-use-this
addBuckets(
bucketsMap: {[key: string]: number},
fields: string[],
): {[key: string]: number} {
for (const field of fields) {
if (typeof bucketsMap[field] !== 'undefined') {
bucketsMap[field] = bucketsMap[field] + 1;
} else {
bucketsMap[field] = 1;
}
}
return bucketsMap;
}
/**
* Converts a buckets array to a map
*
* @param buckets Buckets from a facet
*/
// eslint-disable-next-line class-methods-use-this
bucketsToMap(buckets: SCFacetBucket[]): {[key: string]: number} {
const bucketsMap: {[key: string]: number} = {};
for (const bucket of buckets) {
bucketsMap[bucket.key] = bucket.count;
}
return bucketsMap;
}
/**
* Extract facets from data items, optionally combine them with a list of existing facets
*
* @param items Items to extract facets from
* @param aggregations Aggregations configuration(s) from backend
* @param facets Existing facets to be combined with the facets from the items
*/
extractFacets(
items: SCThing[],
aggregations: SCBackendAggregationConfiguration[],
facets: SCFacet[] = [],
): SCFacet[] {
if (items.length === 0) {
if (facets.length === 0) {
return [];
}
return facets;
}
const combinedFacetsMap: {[key: string]: {[key: string]: number}} =
this.facetsToMap(facets);
for (const item of items) {
for (const aggregation of aggregations) {
let fieldValues = item[aggregation.fieldName as keyof SCThing] as
| string
| string[]
| undefined;
if (typeof fieldValues === 'undefined') {
continue;
}
if (typeof fieldValues === 'string') {
fieldValues = [fieldValues];
}
if (typeof aggregation.onlyOnTypes === 'undefined') {
combinedFacetsMap[aggregation.fieldName] = this.addBuckets(
combinedFacetsMap[aggregation.fieldName] || {},
fieldValues,
);
} else if (aggregation.onlyOnTypes.includes(item.type)) {
combinedFacetsMap[aggregation.fieldName] = this.addBuckets(
combinedFacetsMap[aggregation.fieldName] || {},
fieldValues,
);
}
}
}
return this.mapToFacets(combinedFacetsMap);
}
/**
* Converts facets array into a map (for quicker operations with facets)
*
* @param facets Array of facets
*/
facetsToMap(facets: SCFacet[]): {[key: string]: {[key: string]: number}} {
const facetsMap: {[key: string]: {[key: string]: number}} = {};
for (const facet of facets) {
facetsMap[facet.field] = this.bucketsToMap(facet.buckets);
}
return facetsMap;
}
/**
* Converts a buckets map into buckets array (as it is inside of a facet)
*
* @param bucketsMap A map from a buckets array
*/
// eslint-disable-next-line class-methods-use-this
mapToBuckets(bucketsMap: {[key: string]: number}): SCFacetBucket[] {
const buckets: SCFacetBucket[] = [];
for (const key in bucketsMap) {
if (bucketsMap.hasOwnProperty(key)) {
const bucket: SCFacetBucket = {key: key, count: bucketsMap[key]};
buckets.push(bucket);
}
}
return buckets;
}
/**
* Converts facets map into an array of facets (as they are provided by backend)
*
* @param facetsMap A map from facets array
*/
mapToFacets(facetsMap: {[key: string]: {[key: string]: number}}): SCFacet[] {
const facets: SCFacet[] = [];
for (const key in facetsMap) {
if (facetsMap.hasOwnProperty(key)) {
const facet: SCFacet = {buckets: [], field: ''};
facet.field = key;
facet.buckets = this.mapToBuckets(facetsMap[key]);
facets.push(facet);
}
}
return facets;
}
}