/* * 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 . */ 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; } }