11import { SupportedAggregation , SUPPORTED_AGGREGATIONS } from '../common' ;
2- import { Aggregations , NetworkAggregation , NumericAggregations } from '../types' ;
2+ import { Aggregations , NetworkAggregation , NumericAggregations , RemoteAggregation } from '../types' ;
3+
4+ type NetworkResult = {
5+ [ key : string ] : RemoteAggregation ;
6+ } ;
7+
8+ type ResolveAggregationInput = {
9+ networkResult : NetworkResult ;
10+ requestedAggregationFields : string [ ] ;
11+ accumulator : any ;
12+ } ;
313
414/**
5- * Pick each field from network result aggregations and reduce into single aggregation
15+ * Resolves returned aggregations from network queries into single accumulated aggregation
616 *
7- * @param networkResults
8- * @param rootQueryFields
17+ * @param
18+ * @returns number - Total bucket count for node
919 */
10- export const resolveAggregations = ( networkResults , rootQueryFields ) => {
11- const resolvedNetworkAggregations = rootQueryFields . map ( ( fieldName ) => {
12- const fieldAggregations = networkResults . map ( ( networkResult ) => {
13- const documentName = Object . keys ( networkResult ) [ 0 ] ;
14- return networkResult [ documentName ] [ fieldName ] ;
15- } ) ;
16- const aggregationType = fieldAggregations [ 0 ] . __typename ;
17- const resolvedAggregation = resolveToNetworkAggregation ( aggregationType , fieldAggregations ) ;
18- return { fieldName : fieldName , aggregation : resolvedAggregation } ;
19- } ) ;
20+ export const resolveAggregations = ( {
21+ networkResult,
22+ requestedAggregationFields,
23+ accumulator,
24+ } : ResolveAggregationInput ) : number => {
25+ const documentName = Object . keys ( networkResult ) [ 0 ] ;
26+
27+ const nodeBucketCount = requestedAggregationFields . reduce ( ( bucketCountAcc , fieldName ) => {
28+ const fieldAggregations = networkResult [ documentName ] [ fieldName ] ;
29+ const fieldBucketCount = fieldAggregations . bucket_count ;
30+ const aggregationType = fieldAggregations . __typename ;
2031
21- return resolvedNetworkAggregations ;
32+ const accumulatedFieldAggregations = accumulator [ fieldName ] ;
33+ const resolvedAggregation = resolveToNetworkAggregation ( aggregationType , [
34+ fieldAggregations ,
35+ accumulatedFieldAggregations ,
36+ ] ) ;
37+
38+ // mutation - updates accumulator
39+ accumulator [ fieldName ] = resolvedAggregation ;
40+ // returns total bucket count for node
41+ return bucketCountAcc + fieldBucketCount ;
42+ } , 0 ) ;
43+
44+ return nodeBucketCount ;
2245} ;
2346
2447/**
2548 * Resolve aggregation based on aggregation type
49+ *
2650 * @param type
2751 * @param aggregations
2852 */
@@ -41,48 +65,105 @@ export const resolveToNetworkAggregation = (
4165} ;
4266
4367/**
44- * Takes an array of the same aggregation type and computes the singular type
45- * eg. NumericAggregation => NetworkNumericAggregation
68+ * Mutation
69+ * Updates existing or adds additional bucket to computed buckets
4670 *
47- * Note for operations on Buckets - the size of the array can be large (e.g. total bucket count), complicating lookups, etc.
71+ * @param bucket - Bucket being processed
72+ * @param computedBuckets - Existing buckets
73+ */
74+ const updateComputedBuckets = ( bucket , computedBuckets ) => {
75+ /*
76+ * Unable to use lookup key eg. buckets[key]
77+ * "buckets": [
78+ * {
79+ * "doc_count": 140,
80+ * "key": "Dog"
81+ * },
82+ */
83+ const { key, doc_count } = bucket ;
84+ const existingBucketIndex = computedBuckets . findIndex ( ( bucket ) => bucket . key === key ) ;
85+ if ( existingBucketIndex !== - 1 ) {
86+ const existingBucket = computedBuckets [ existingBucketIndex ] ;
87+ if ( existingBucket ) {
88+ // update existing bucket
89+ computedBuckets [ existingBucketIndex ] = {
90+ ...existingBucket ,
91+ doc_count : existingBucket . doc_count + doc_count ,
92+ } ;
93+ }
94+ } else {
95+ computedBuckets . push ( bucket ) ;
96+ }
97+ } ;
98+
99+ /**
100+ * Resolves multiple aggregations into single
48101 *
49102 * @param aggregations
50103 * @returns
104+ *
105+ * @example
106+ * #### Input
107+ * ```javascript
108+ *[
109+ * {
110+ * bucket_count: 2,
111+ * buckets: [
112+ * {
113+ * key: 'Male',
114+ * doc_count: 15,
115+ * },
116+ * {
117+ * key: 'Female',
118+ * doc_count: 700,
119+ * },
120+ * {
121+ * key: 'Unknown',
122+ * doc_count: 5,
123+ * },
124+ * ],
125+ * },
126+ * {
127+ * bucket_count: 2,
128+ * buckets: [
129+ * {
130+ * key: 'Male',
131+ * doc_count: 25,
132+ * },
133+ * {
134+ * key: 'Female',
135+ * doc_count: 100,
136+ * },
137+ * ],
138+ * }];
139+ * ```
140+ *
141+ * #### Output
142+ * ```javascript
143+ * {
144+ * bucket_count: 3,
145+ * buckets: [
146+ * {
147+ * key: 'Male',
148+ * doc_count: 40,
149+ * },
150+ * {
151+ * key: 'Female',
152+ * doc_count: 800,
153+ * },
154+ * {
155+ * key: 'Unknown',
156+ * doc_count: 5,
157+ * }]
158+ * }
159+ * ```
51160 */
52161export const resolveAggregation = ( aggregations : Aggregations [ ] ) : NetworkAggregation => {
53- const emptyAggregation : NetworkAggregation = { bucket_count : 0 , buckets : [ ] } ;
54-
55162 const resolvedAggregation = aggregations . reduce ( ( resolvedAggregation , agg ) => {
56- const bucketCountAccumulator = resolvedAggregation . bucket_count + agg . bucket_count ;
57-
58- /*
59- * Unable to use lookup key eg. buckets[key]
60- * "buckets": [
61- * {
62- * "doc_count": 140,
63- * "key": "Dog"
64- * },
65- */
66163 const computedBuckets = resolvedAggregation . buckets ;
67-
68- agg . buckets . forEach ( ( bucket ) => {
69- const { key, doc_count } = bucket ;
70- const existingBucketIndex = computedBuckets . findIndex ( ( bucket ) => bucket . key === key ) ;
71- if ( existingBucketIndex !== - 1 ) {
72- const existingBucket = computedBuckets [ existingBucketIndex ] ;
73- if ( existingBucket ) {
74- // update existing bucket
75- computedBuckets [ existingBucketIndex ] = {
76- ...existingBucket ,
77- doc_count : existingBucket . doc_count + doc_count ,
78- } ;
79- }
80- } else {
81- computedBuckets . push ( bucket ) ;
82- }
83- } ) ;
84- return { bucket_count : bucketCountAccumulator , buckets : computedBuckets } ;
85- } , emptyAggregation ) ;
164+ agg . buckets . forEach ( ( bucket ) => updateComputedBuckets ( bucket , computedBuckets ) ) ;
165+ return { bucket_count : computedBuckets . length , buckets : computedBuckets } ;
166+ } ) ;
86167
87168 return resolvedAggregation ;
88169} ;
0 commit comments