Skip to content

Commit

Permalink
Improve performance
Browse files Browse the repository at this point in the history
Implement caching to improve performance

Closes #330
  • Loading branch information
imaustink committed Sep 22, 2017
1 parent df05ec1 commit 148dded
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 68 deletions.
2 changes: 1 addition & 1 deletion public/components/page-dashboard/payouts/payouts.stache
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<tr>
<th>&nbsp;</th>
<td class="total">
<span>{{formatDollarAmount(contributionMonths.getTotalForAllPayouts(contributionMonth))}}</span>
<span>{{formatDollarAmount(contributionMonth.totalPayouts)}}</span>
</td>
{{#each contributionMonth.sortedMonthlyOSProjects}}
{{#payoutFor(null, osProjectRef)}}
Expand Down
4 changes: 2 additions & 2 deletions public/components/page-dashboard/payouts/payouts_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ QUnit.test('viewModel.OSProjectContributionsMap', function(assert){
ContributionMonth.get("1").then(month => {
vm = new ViewModel({ contributionMonth: month });
vm.on('contributionMonths', () => {
QUnit.equal(vm.contributionMonths.OSProjectContributionsMap(month)['1-CanJS'].contributors['1-JustinMeyer'].points, 10, 'has a contributor for CanJS');
QUnit.equal(vm.contributionMonths.OSProjectContributionsMap(month)['1-CanJS'].totalPoints, 40, 'has totalPoints for CanJS as 40');
QUnit.equal(vm.contributionMonths.osProjectContributionsMap(month)['1-CanJS'].contributors['1-JustinMeyer'].points, 10, 'has a contributor for CanJS');
QUnit.equal(vm.contributionMonths.osProjectContributionsMap(month)['1-CanJS'].totalPoints, 40, 'has totalPoints for CanJS as 40');
done();
});
});
Expand Down
166 changes: 101 additions & 65 deletions public/models/contribution-month/contribution-month.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import OSProject from "../os-project";
import Contributor from "../contributor";

import set from "can-set";
import memoize from "can-compute-memoize";
import DefineMap from "can-define/map/";
import DefineList from "can-define/list/";
import superModel from '../../lib/super-model';
Expand Down Expand Up @@ -77,6 +78,23 @@ var ContributionMonth = DefineMap.extend("ContributionMonth", { seal: false }, {
return this.monthlyContributors.slice(0).sort(sortByRefField('contributorRef', 'name'));
}
},
totalPayouts: {
type: 'number',
get: function() {
let total = 0;

this.monthlyOSProjects.forEach( osProject => {
if (osProject.commissioned) {
const totalAmountForOSProject = this.calculations.osProjects[osProject.osProjectRef._id];
if (totalAmountForOSProject !== undefined){
total += totalAmountForOSProject;
}
}
});

return total;
}
},
calculations: {
get: function() {
var calculations = {
Expand Down Expand Up @@ -285,103 +303,119 @@ var ContributionMonth = DefineMap.extend("ContributionMonth", { seal: false }, {

ContributionMonth.List = DefineList.extend("ContributionMonthList", {
"#": ContributionMonth,
OSProjectContributionsMap(currentContributionMonth) {
var OSProjectContributionsMap = {};
osProjectContributionsMap(currentContributionMonth) {
var osProjectContributionsMap = {};

this.forEach(contributionMonth => {
if(moment(contributionMonth.date).isBefore(moment(currentContributionMonth.date).add(1, 'day'))) {
if (moment(contributionMonth.date).isBefore(moment(currentContributionMonth.date).add(1, 'day'))) {
contributionMonth.monthlyContributions.forEach(monthlyContribution => {
if (currentContributionMonth.contributorsMap[monthlyContribution.contributorRef._id]) {
if( ! OSProjectContributionsMap[monthlyContribution.osProjectRef._id] ) {
OSProjectContributionsMap[monthlyContribution.osProjectRef._id] = {
if (!osProjectContributionsMap[monthlyContribution.osProjectRef._id]) {
osProjectContributionsMap[monthlyContribution.osProjectRef._id] = {
contributors: {},
totalPoints: 0
};
}

if( ! OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id] ) {
OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id] = {
if (!osProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id]) {
osProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id] = {
points: 0
};
}

OSProjectContributionsMap[monthlyContribution.osProjectRef._id].totalPoints += monthlyContribution.points;
OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id].points += monthlyContribution.points;
osProjectContributionsMap[monthlyContribution.osProjectRef._id].totalPoints += monthlyContribution.points;
osProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id].points += monthlyContribution.points;
}
});
}
});

return OSProjectContributionsMap;
return osProjectContributionsMap;
},
getOSProjectPayoutTotal(monthlyOSProject, contributor, contributionMonth) {
let total = 0;

const contributorsMap = this.OSProjectContributionsMap(contributionMonth);

if(contributorsMap[monthlyOSProject.osProjectRef._id] && contributorsMap[monthlyOSProject.osProjectRef._id].contributors[contributor.contributorRef._id] ) {
const contributorData = contributorsMap[monthlyOSProject.osProjectRef._id].contributors[contributor.contributorRef._id];
const points = contributorData.points;
const totalPoints = contributorsMap[monthlyOSProject.osProjectRef._id].totalPoints;
const totalAmountForOSProject = contributionMonth.calculations.osProjects[monthlyOSProject.osProjectRef._id];

total = (points / totalPoints) * totalAmountForOSProject;
}

return total;
},
getTotalForAllPayouts(contributionMonth) {
let total = 0;

const projectMap = this.OSProjectContributionsMap(contributionMonth);
for (const osProjectID in projectMap) {
const totalAmountForOSProject = contributionMonth.calculations.osProjects[osProjectID];
if (totalAmountForOSProject !== undefined){
total += totalAmountForOSProject;
const cachedOSProjectPayouts = memoize(this, 'osProjectsPayout', [contributionMonth], function(contributionMonth){
const contributorsMap = this.osProjectContributionsMap(contributionMonth);
const payouts = {};
for(const projectRef in contributorsMap){
if(!payouts[projectRef]){
payouts[projectRef] = {};
}
for(const contributorRef in contributorsMap[projectRef].contributors){
if(!payouts[projectRef][contributorRef]){
payouts[projectRef][contributorRef] = 0;
}
const contributorData = contributorsMap[projectRef].contributors[contributorRef];
const points = contributorData.points;
const totalPoints = contributorsMap[projectRef].totalPoints;
const totalAmountForOSProject = contributionMonth.calculations.osProjects[projectRef];

payouts[projectRef][contributorRef] = (points / totalPoints) * totalAmountForOSProject;
}
}
}
return payouts;
});

return total;
const payouts = cachedOSProjectPayouts();

return payouts[monthlyOSProject.osProjectRef._id] && payouts[monthlyOSProject.osProjectRef._id][contributor.contributorRef._id] || 0;
},
getTotalForAllPayoutsForContributor(contributorRef, contributionMonth) {
let total = 0;

const contributorsMap = this.OSProjectContributionsMap(contributionMonth);

for (const osProjectID in contributorsMap) {
const projectContributors = contributorsMap[osProjectID].contributors;

if(projectContributors[contributorRef._id]) {
const contributorData = contributorsMap[osProjectID].contributors[contributorRef._id];
const points = contributorData.points;
const totalPoints = contributorsMap[osProjectID].totalPoints;
const totalAmountForOSProject = contributionMonth.calculations.osProjects[osProjectID];

// TODO: figure out what to do with `OSProjectContributionsMap` if an `OSProject` gets removed from a month:
// since `OSProjectContributionsMap` will still have the removed project whereas `contributionMonth.calculations.osProjects` won't
// which will cause NaN for total. For now just ignore undefined for calculation:
if (totalAmountForOSProject !== undefined){
total = total + ( (points / totalPoints) * totalAmountForOSProject );
const cachedTotals = memoize(this, 'totalForAllPayoutsForContributor', [contributionMonth], function(contributionMonth){
const totals = {};
const contributorsMap = this.osProjectContributionsMap(contributionMonth);
for (const osProjectID in contributorsMap) {
const projectContributors = contributorsMap[osProjectID].contributors;
for (const contributor in projectContributors) {
if (totals[contributor] === undefined) {
totals[contributor] = 0;
}

const contributorData = projectContributors[contributor];
const points = contributorData.points;
const totalPoints = contributorsMap[osProjectID].totalPoints;
const totalAmountForOSProject = contributionMonth.calculations.osProjects[osProjectID];

// TODO: figure out what to do with `osProjectContributionsMap` if an `OSProject` gets removed from a month:
// since `osProjectContributionsMap` will still have the removed project whereas `contributionMonth.calculations.osProjects` won't
// which will cause NaN for total. For now just ignore undefined for calculation:
if (totalAmountForOSProject !== undefined){
totals[contributor] = totals[contributor] + ((points / totalPoints) * totalAmountForOSProject);
}
}
}
}
return totals;
});

return total;
return cachedTotals()[contributorRef._id] || 0;
},
getOwnershipPercentageForContributor(monthlyOSProject, contributor, contributionMonth) {
let total = 0;

const contributorsMap = this.OSProjectContributionsMap(contributionMonth);
const cachedOwershipPercentages = memoize(this, 'ownershipPercentageForContributor', [contributionMonth], function(contributionMonth){
const percentages = {};

const contributorsMap = this.osProjectContributionsMap(contributionMonth);

for(const projectRef in contributorsMap){
if(!percentages[projectRef]){
percentages[projectRef] = {};
}
for(const contributorRef in contributorsMap[projectRef].contributors){
if(!percentages[projectRef][contributorRef]){
percentages[projectRef][contributorRef] = 0;
}
const contributorData = contributorsMap[projectRef].contributors[contributorRef];
const points = contributorData.points;
const totalPoints = contributorsMap[projectRef].totalPoints;

if(contributorsMap[monthlyOSProject.osProjectRef._id] && contributorsMap[monthlyOSProject.osProjectRef._id].contributors[contributor.contributorRef._id] ) {
const contributorData = contributorsMap[monthlyOSProject.osProjectRef._id].contributors[contributor.contributorRef._id];
const points = contributorData.points;
const totalPoints = contributorsMap[monthlyOSProject.osProjectRef._id].totalPoints;
percentages[projectRef][contributorRef] = points / totalPoints;
}
}

return percentages;
});

total = (points / totalPoints);
}
const percentages = cachedOwershipPercentages();

return total;
return percentages[monthlyOSProject.osProjectRef._id] && percentages[monthlyOSProject.osProjectRef._id][contributor.contributorRef._id] || 0;
},
/**
* @property getMonthlyPayouts
Expand Down Expand Up @@ -432,6 +466,8 @@ ContributionMonth.List = DefineList.extend("ContributionMonthList", {
});
});

const contributorsMap = this.osProjectContributionsMap(currentMonth);

Object.keys(uniqueContributors).forEach(contributorId => {
let contributorPayout =
Object.assign({ }, uniqueContributors[contributorId]);
Expand Down
1 change: 1 addition & 0 deletions public/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"bootstrap": "^3.3.7",
"can-cid": "^1.0.0",
"can-component": "^3.0.2",
"can-compute-memoize": "^0.1.0",
"can-connect": "^1.3.6",
"can-connect-feathers": "3.5.0",
"can-define": "^1.0.10",
Expand Down

0 comments on commit 148dded

Please sign in to comment.