1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
#!/usr/bin/node
const R = require('ramda'),
Future = require('fluture'),
utils = require('./utils'),
api = require('./api');
// API data cleanup
const mapSideToTeam = (side) => side == 'left/blue' ? 'Left' : 'Right';
function loadFPayloads(config) {
const objOfPathsConfig = {
match: R.map(R.apply(utils.objOfPath), config.match),
roster: R.map(R.apply(utils.objOfPath), config.roster),
participant: R.map(R.apply(utils.objOfPath), config.participant),
}; // TODO Ramda-ify
/*
* 1 Pull API JSON
* 2 Extract Participant, Roster, Match, Assets
* 3.1 Transform Participant, Roster, Match to flat structure
* 3.2 Pull and filter Assets for Events
* 3.2.1 Transform Events: Add Match meta data
* 4 Join Events to flat structure
*/
const propIncludedFilterType = R.curry((type) =>
R.compose(R.filter(R.propEq('type', type)), R.prop('included'))
);
const extractJsonToAssets = propIncludedFilterType('asset');
const extractJsonToParticipants = propIncludedFilterType('participant');
const extractJsonToRosters = propIncludedFilterType('roster');
const extractJsonToMatches = R.prop('data');
const filterTypeEqTalentEquipped = R.pipe(
R.filter(R.propEq('type', 'TalentEquipped')),
R.map(R.prop('payload'))
);
const transformParticipantToPayload = R.converge(utils.mergeAllArgs,
R.concat(objOfPathsConfig.participant, [
utils.objOfPath('Actor', ['attributes', 'actor']),
utils.objOfPath('_participant_id', ['id']),
])
);
const transformRosterToPayload = R.converge(utils.mergeAllArgs,
R.concat(objOfPathsConfig.roster, [
R.pipe(
R.path(['attributes', 'stats', 'side']),
mapSideToTeam,
R.objOf('Team'),
),
utils.objOfPath('_roster_id', ['id']),
R.pipe(
R.path(['relationships', 'participants', 'data']),
R.map(R.prop('id')),
R.objOf('_participant_ids')
)
])
);
const transformMatchToPayload = R.converge(utils.mergeAllArgs,
R.concat(objOfPathsConfig.match, [
utils.objOfPath('_match_id', ['id']),
utils.objOfPath('_asset_id', ['relationships', 'assets', 'data', 0, 'id']),
R.pipe(
R.path(['relationships', 'rosters', 'data']),
R.map(R.prop('id')),
R.objOf('_roster_ids')
)
])
);
/* SQL style join using relationship info stored in _ attrs */
// TODO refactor
const joinParticipantPayloadToRosterPayload = R.pipe(
R.xprod,
R.filter(
R.converge(R.contains, [
R.path([0, '_participant_id']),
R.path([1, '_participant_ids'])
])
),
R.map(R.mergeAll)
);
const joinParticipantRosterPayloadToMatchPayload = R.pipe(
R.xprod,
R.filter(
R.converge(R.contains, [
R.path([0, '_roster_id']),
R.path([1, '_roster_ids'])
])
),
R.map(R.mergeAll)
);
// join participant -> roster -> match
const joinedParticipantRosterPayloads = R.converge(joinParticipantPayloadToRosterPayload, [
R.compose(R.map(transformParticipantToPayload), extractJsonToParticipants),
R.compose(R.map(transformRosterToPayload), extractJsonToRosters),
]);
const joinedParticipantRosterMatchPayloads = R.converge(joinParticipantRosterPayloadToMatchPayload, [
joinedParticipantRosterPayloads,
R.compose(R.map(transformMatchToPayload), extractJsonToMatches),
]);
// chain json -> constructed payload,
// wrap in future for compatibility with `loadFTelemetryPayloads`
const loadFParticipantRosterMatchPayloads = R.pipe(
joinedParticipantRosterMatchPayloads,
Future.of,
);
// join [telemetry, asset id] -> { telemetry, asset id }
const joinTelemetryPayloadsToId = R.pipe(
R.apply(R.xprod),
R.map(R.mergeAll),
);
// chain json -> api payload,
// add additional meta information to events
const loadFTelemetryPayloads = R.pipe(
extractJsonToAssets,
R.map(R.converge(R.pipe(
Future.both,
R.map(joinTelemetryPayloadsToId),
), [
R.pipe(
R.path(['attributes', 'URL']),
api.awsRequest,
R.map(filterTypeEqTalentEquipped),
),
R.pipe(
utils.objOfPath('_asset_id', ['id']),
R.of,
Future.of,
),
])),
Future.parallel(Infinity),
R.map(R.unnest),
);
// given an array of telemetry payloads and an array of constructed payloads,
// return merged telemetry + constructed payloads for identical players & matches
// problem: some do not have 'NoTalent' (5v5, 3v3 standard)! -> need right join not inner join
const joinParticipantRosterMatchPayloadsToTelemetryPayloads = R.pipe(
R.apply(utils.naturalJoinRight),
R.map(R.mergeAll),
);
const loadFParticipantRosterMatchTelemetryPayloads = R.pipe(
api.apiRequest,
R.chain(R.converge(R.pipe(
Future.both,
R.map(R.pipe(
joinParticipantRosterMatchPayloadsToTelemetryPayloads,
R.map(R.pipe(
R.omit(['_asset_id', '_participant_id', '_participant_ids', '_roster_id', '_roster_ids', '_match_id', 'Team']),
R.set(R.lensProp('Count'), 1),
)),
)),
), [
loadFParticipantRosterMatchPayloads,
loadFTelemetryPayloads,
]))
);
return loadFParticipantRosterMatchTelemetryPayloads;
}
module.exports = {
loadFPayloads,
};
|