Skip to content

Commit 2aa8338

Browse files
committed
domestic data patch WIP
1 parent f754a95 commit 2aa8338

6 files changed

Lines changed: 282 additions & 23 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"type": "npm"
1212
},
1313
"scripts": {
14-
"test": "jest src/modules/dw/UnbundlingAid/unbundlingAid.test.ts",
14+
"test": "jest",
1515
"lint": "tslint -c tslint.json 'src/**/*.ts'",
1616
"test:watch": "npm test -- --watch",
1717
"codecov": "npm run build && jest -u && codecov",
Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`Utility functions test should create an aggregate sql query for a single year i.e unbundling aid 1`] = `
4-
"Object {
5-
\\"queryA\\": \\"SELECT to_di_id, year, sum(value) AS value from fact.oda_2015 WHERE value > 0 AND year = 2015 AND sector = 'banking-and-business' GROUP BY to_di_id, year\\",
6-
\\"queryB\\": \\"SELECT bundle, year, sum(value) AS value from fact.oda_2015 WHERE value > 0 AND from_di_id = 'afdb' AND to_di_id = 'UG' AND year = 2013 GROUP BY bundle, year\\",
7-
}"
8-
`;
9-
10-
exports[`Utility functions test should create an aggregate sql query for multiple years 1`] = `"\\"SELECT bundle, year, sum(value) AS value from fact.oda_2015 WHERE value > 0 AND from_di_id = 'afdb' AND to_di_id = 'UG' AND year >= 2013 AND year <= 2015 GROUP BY bundle, year\\""`;
11-
12-
exports[`Utility functions test should create human friendly numbers i.e 1.5k for 1500 1`] = `
13-
"Object {
14-
\\"formattedB\\": Array [
15-
\\"150\\",
16-
\\"1.5k\\",
17-
\\"15k\\",
18-
\\"200m\\",
3+
exports[`Utility functions test should make tree data 1`] = `
4+
"Array [
5+
Array [],
6+
Array [
7+
Object {
8+
\\"budget_type\\": \\"Actual\\",
9+
\\"color\\": \\"#5da3d9\\",
10+
\\"id\\": \\"NG\\",
11+
\\"levels\\": Array [
12+
\\"Total Expenditure\\",
13+
\\"Spending From Excess Crude Account /Sovereign Wealth Fund\\",
14+
\\"Other Excess Crude Account\\",
15+
],
16+
\\"uid\\": \\"Total ExpenditureSpending From Excess Crude Account /Sovereign Wealth FundOther Excess Crude Account\\",
17+
\\"value\\": 539768571.48,
18+
\\"value_ncu\\": 198000000000,
19+
\\"year\\": 2006,
20+
},
1921
],
20-
}"
22+
]"
2123
`;

src/modules/utils/index.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {isError} from '@devinit/prelude';
99
import {getBudgetLevels, IBudgetLevelRef} from '../refs/countryProfile';
1010
import {IGetIndicatorArgs, IGetIndicatorValueArgs, IhasDiId, IProcessedSimple,
1111
IRAW, IRAWDomestic, IToolTipArgs, ISpotlightGetIndicatorArgs,
12-
IGetIndicatorArgsSimple} from './types';
12+
IGetIndicatorArgsSimple, IMissingDomesticParent} from './types';
1313
import {approximate, toNumericFields, toId, getTableNameFromSql} from '@devinit/prelude';
1414

1515
export const RECIPIENT = 'recipient';
@@ -206,3 +206,52 @@ export const makeSqlAggregateQuery = (queryArgs: any, groupByField: string, tabl
206206
: `${query} ${field} = '${queryArgs[field]}' ${AND}`; // we need to enclose field values in quotes
207207
}, `SELECT ${groupByField}, year, sum(value) AS value from ${table} WHERE value > 0 AND`);
208208
};
209+
210+
// A patch of domestic data with missing parent entries
211+
// Ideally every entry in domestic table should have a parent entry i,e data of the form [l1: a, l2: b, l3:c]
212+
// l1: a, l2: b, l3:d] should have a corresponding entry with [l1: a, l2: b] as parent so to speak.
213+
// solution find data with missing parent levels, get that datas children and sum it up to create new parent entry
214+
215+
export const missingParentsData = (data: DH.IDomestic[]): DH.IDomestic[][] => {
216+
return [3, 4].map((level) => {
217+
const levelParentData = data.filter(obj => obj.levels.length === level - 1);
218+
const levelChildrenData = data.filter(obj => obj.levels.length === level);
219+
// parents that are missing in the raw data
220+
const missingParents = levelChildrenData.map(child => {
221+
// for each child confirm it has a standalone parent
222+
const childParent = levelParentData.filter(parent => {
223+
// the last parent item in level 2 should be the 2nd last item in level 3
224+
return R.last(parent.levels) === R.last(R.init(child.levels));
225+
});
226+
if (!childParent.length) {
227+
return {
228+
levels: R.init(child.levels),
229+
uid: R.init(child.levels).join(''),
230+
level: `l${level - 1}`,
231+
child
232+
};
233+
}
234+
return undefined;
235+
})
236+
.filter(item => item && item.level) as IMissingDomesticParent[];
237+
// create the missing parents
238+
return missingParents.reduce((acc, obj) => {
239+
const baseParent = {...obj.child, levels: obj.levels, uid: obj.uid};
240+
if (acc.length) {
241+
const similarParent = acc.find(parent => parent.uid === obj.uid);
242+
if (similarParent) {
243+
const joinedParent = {
244+
...similarParent,
245+
value: obj.child.value + similarParent.value,
246+
value_ncu: obj.child.value_ncu + similarParent.value_ncu
247+
};
248+
// remove previous parent from list
249+
const newParentsList = acc.filter(objP => objP.uid !== joinedParent.uid);
250+
return [...newParentsList, joinedParent];
251+
}
252+
return [...acc, baseParent];
253+
}
254+
return [baseParent];
255+
}, [] as DH.IDomestic[]);
256+
});
257+
};

src/modules/utils/testData/tree.ts

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
export default [{
2+
year: 2006,
3+
budget_type: 'Actual',
4+
value: 539768571.4,
5+
value_ncu: 198000000000,
6+
uid: 'BkMRW3iFH4Tf',
7+
levels: ['Total Expenditure',
8+
'Federal Government Exoenditure',
9+
'Federal Government Extrabudgetary Funds'
10+
],
11+
color: '#5da3d9'
12+
},
13+
{
14+
year: 2006,
15+
budget_type: 'Actual',
16+
17+
value: 1349421429,
18+
value_ncu: 495000000000,
19+
20+
uid: 'BJmCbniYrN6f',
21+
levels: ['Total Expenditure',
22+
'Federal Government Exoenditure',
23+
'Federal Government Capital Expenditure'
24+
],
25+
color: '#5da3d9'
26+
},
27+
{
28+
year: 2006,
29+
budget_type: 'Actual',
30+
value: 528864155.9,
31+
value_ncu: 194000000000,
32+
33+
uid: 'HyV0-2oYrNTz',
34+
levels: ['Total Expenditure',
35+
'Spending From Excess Crude Account /Sovereign Wealth Fund',
36+
'Other Excess Crude Account',
37+
'Shared Infrastructure And Social Spending'
38+
],
39+
color: '#5da3d9'
40+
},
41+
{
42+
year: 2006,
43+
budget_type: 'Actual',
44+
45+
value: 6439057403,
46+
value_ncu: 2360000000000,
47+
48+
uid: 'SJHAW2stBV6G',
49+
levels: ['Total Expenditure', 'State And Local Government'],
50+
color: '#5da3d9'
51+
},
52+
{
53+
year: 2006,
54+
budget_type: 'Actual',
55+
56+
value: 2153622078,
57+
value_ncu: 790000000000,
58+
59+
uid: 'SkLAZ2sYSV6G',
60+
levels: ['Total Expenditure', 'Other Expenditure'],
61+
color: '#e8443a'
62+
},
63+
{
64+
year: 2006,
65+
budget_type: 'Actual',
66+
67+
value: 577934026,
68+
value_ncu: 212000000000,
69+
70+
uid: 'HkPRb3jtHEpz',
71+
levels: ['Total Expenditure', 'Extrabudgetary Funds'],
72+
color: '#5da3d9'
73+
},
74+
{
75+
year: 2006,
76+
budget_type: 'Actual',
77+
78+
value: 10904415.58,
79+
value_ncu: 4000000000,
80+
81+
uid: 'HyuRZnjtHE6z',
82+
levels: ['Total Expenditure',
83+
'Spending From Excess Crude Account /Sovereign Wealth Fund',
84+
'Other Excess Crude Account',
85+
'Explicit Fuel Subsidy'
86+
],
87+
color: '#5da3d9'
88+
},
89+
{
90+
year: 2006,
91+
budget_type: 'Actual',
92+
93+
value: 14260249481,
94+
value_ncu: 5230000000000,
95+
96+
uid: 'BJF0ZnjKSEpf',
97+
levels: ['Total Expenditure'],
98+
color: '#7b3b89'
99+
},
100+
{
101+
year: 2006,
102+
budget_type: 'Actual',
103+
104+
value: 607921168.8,
105+
value_ncu: 223000000000,
106+
107+
uid: 'H19R-3oFBEaM',
108+
levels: ['Total Expenditure',
109+
'Federal Government Exoenditure',
110+
'Federal Government Recurrent Expenditure',
111+
'Overhead Cost'
112+
],
113+
color: '#5da3d9'
114+
},
115+
{
116+
year: 2006,
117+
budget_type: 'Actual',
118+
119+
value: 3200445974,
120+
value_ncu: 1170000000000,
121+
122+
uid: 'S1i0ZhjYBVpM',
123+
levels: ['Total Expenditure',
124+
'Federal Government Exoenditure',
125+
'Federal Government Recurrent Expenditure'
126+
],
127+
color: '#5da3d9'
128+
},
129+
{
130+
year: 2006,
131+
budget_type: 'Actual',
132+
133+
value: 509781428.6,
134+
value_ncu: 187000000000,
135+
136+
uid: 'H13RW3oKBV6G',
137+
levels: ['Total Expenditure',
138+
'Federal Government Exoenditure',
139+
'Federal Government Recurrent Expenditure',
140+
'Interest Payments'
141+
],
142+
color: '#5da3d9'
143+
},
144+
{
145+
year: 2006,
146+
budget_type: 'Actual',
147+
148+
value: 269884285.7,
149+
value_ncu: 99000000000,
150+
151+
uid: 'ByaAb3jFH4af',
152+
levels: ['Total Expenditure',
153+
'Federal Government Exoenditure',
154+
'Federal Government Recurrent Expenditure',
155+
'Transfers'
156+
],
157+
color: '#5da3d9'
158+
},
159+
{
160+
year: 2006,
161+
budget_type: 'Actual',
162+
163+
value: 5089635974,
164+
value_ncu: 1870000000000,
165+
166+
uid: 'SkA0-hjKHVaM',
167+
levels: ['Total Expenditure', 'Federal Government Exoenditure'],
168+
color: '#5da3d9'
169+
},
170+
{
171+
year: 2006,
172+
budget_type: 'Actual',
173+
174+
value: 1812859091,
175+
value_ncu: 665000000000,
176+
177+
uid: 'S11kMnsFS4Tz',
178+
levels: ['Total Expenditure',
179+
'Federal Government Exoenditure',
180+
'Federal Government Recurrent Expenditure',
181+
'Personnel'
182+
],
183+
color: '#5da3d9'
184+
}
185+
];

src/modules/utils/types.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import {IDB} from '@devinit/graphql-next/lib/db';
22

3+
export interface IMissingDomesticParent {
4+
level: string;
5+
levels: string[]; // for debugging
6+
child: DH.IDomestic;
7+
uid: string;
8+
}
9+
310
export interface IGetIndicatorArgs {
411
id?: string;
512
query: string;
@@ -84,10 +91,12 @@ export interface IRAWDomestic {
8491
di_id: string;
8592
year: string;
8693
budget_type: string;
94+
value: number;
95+
value_ncu: number;
8796
l1: string;
88-
l2: string;
89-
l3: string;
90-
l4: string;
97+
l2?: string;
98+
l3?: string;
99+
l4?: string;
91100
}
92101
export interface IToolTipArgs {
93102
query?: string;
@@ -112,3 +121,12 @@ export interface IGetIndicatorValueArgs {
112121
db: IDB;
113122
format: boolean;
114123
}
124+
125+
export interface IDomesticTree {
126+
id: string;
127+
year: string;
128+
budget_type: string;
129+
value: number;
130+
value_ncu: number;
131+
children: IDomesticTree[];
132+
}

src/modules/utils/utils.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import {makeSqlAggregateQuery, isDonor} from '.';
1+
import {makeSqlAggregateQuery, isDonor, missingParentsData} from '.';
22
import * as prettyFormat from 'pretty-format';
3+
import data from './testData/tree';
34
import {approximate, toId, getTotal, normalizeKeyName} from '@devinit/prelude';
45

56
const dataA = [
@@ -61,4 +62,8 @@ describe('Utility functions test', () => {
6162
expect(isDonorCountryA).toBe(false);
6263
expect(isDonorCountryB).toBe(true);
6364
}, 10000);
65+
it('should make tree data', () => {
66+
const result = missingParentsData(data);
67+
expect(prettyFormat(result)).toMatchSnapshot();
68+
});
6469
});

0 commit comments

Comments
 (0)