Extracted stats aggregation function to util
ref https://linear.app/tryghost/issue/SLO-168/rangeerror-maximum-call-stack-size-exceeded - this extracts a function to a util so we can unit test it - this function is about to be optimized but having unit tests allows us to make the change with confidence
This commit is contained in:
parent
019f417c7d
commit
43bb83f7bb
@ -3,6 +3,8 @@ import moment from 'moment-timezone';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
import mergeStatsByDate from 'ghost-admin/utils/merge-stats-by-date';
|
||||
|
||||
/**
|
||||
* @typedef MrrStat
|
||||
* @type {Object}
|
||||
@ -461,39 +463,7 @@ export default class DashboardStatsService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
function mergeDates(list, entry) {
|
||||
const [current, ...rest] = list;
|
||||
|
||||
if (!current) {
|
||||
return entry ? [entry] : [];
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
return mergeDates(rest, {
|
||||
date: current.date,
|
||||
count: current.count,
|
||||
positiveDelta: current.positive_delta,
|
||||
negativeDelta: current.negative_delta,
|
||||
signups: current.signups,
|
||||
cancellations: current.cancellations
|
||||
});
|
||||
}
|
||||
|
||||
if (current.date === entry.date) {
|
||||
return mergeDates(rest, {
|
||||
date: entry.date,
|
||||
count: entry.count + current.count,
|
||||
positiveDelta: entry.positiveDelta + current.positive_delta,
|
||||
negativeDelta: entry.negativeDelta + current.negative_delta,
|
||||
signups: entry.signups + current.signups,
|
||||
cancellations: entry.cancellations + current.cancellations
|
||||
});
|
||||
}
|
||||
|
||||
return [entry].concat(mergeDates(list));
|
||||
}
|
||||
|
||||
const subscriptionCountStats = mergeDates(result.stats);
|
||||
const subscriptionCountStats = mergeStatsByDate(result.stats);
|
||||
|
||||
this.paidMembersByCadence = paidMembersByCadence;
|
||||
this.paidMembersByTier = paidMembersByTier;
|
||||
@ -524,7 +494,7 @@ export default class DashboardStatsService extends Service {
|
||||
this.memberCountStats = this.dashboardMocks.memberCountStats;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const stats = yield this.membersStats.fetchMemberCount();
|
||||
this.memberCountStats = stats.stats.map((d) => {
|
||||
return {
|
||||
|
31
ghost/admin/app/utils/merge-stats-by-date.js
Normal file
31
ghost/admin/app/utils/merge-stats-by-date.js
Normal file
@ -0,0 +1,31 @@
|
||||
export default function mergeDates(list, entry) {
|
||||
const [current, ...rest] = list;
|
||||
|
||||
if (!current) {
|
||||
return entry ? [entry] : [];
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
return mergeDates(rest, {
|
||||
date: current.date,
|
||||
count: current.count,
|
||||
positiveDelta: current.positive_delta,
|
||||
negativeDelta: current.negative_delta,
|
||||
signups: current.signups,
|
||||
cancellations: current.cancellations
|
||||
});
|
||||
}
|
||||
|
||||
if (current.date === entry.date) {
|
||||
return mergeDates(rest, {
|
||||
date: entry.date,
|
||||
count: entry.count + current.count,
|
||||
positiveDelta: entry.positiveDelta + current.positive_delta,
|
||||
negativeDelta: entry.negativeDelta + current.negative_delta,
|
||||
signups: entry.signups + current.signups,
|
||||
cancellations: entry.cancellations + current.cancellations
|
||||
});
|
||||
}
|
||||
|
||||
return [entry].concat(mergeDates(list));
|
||||
}
|
184
ghost/admin/tests/unit/utils/merge-stats-by-date-test.js
Normal file
184
ghost/admin/tests/unit/utils/merge-stats-by-date-test.js
Normal file
@ -0,0 +1,184 @@
|
||||
import mergeStatsByDate from 'ghost-admin/utils/merge-stats-by-date';
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
|
||||
const STATS_DATA = [
|
||||
{
|
||||
date: '2024-06-22',
|
||||
tier: '111111111111111111111111',
|
||||
cadence: 'month',
|
||||
positive_delta: 0,
|
||||
negative_delta: 0,
|
||||
signups: 0,
|
||||
cancellations: 0,
|
||||
count: 456
|
||||
},
|
||||
{
|
||||
date: '2024-06-22',
|
||||
tier: '111111111111111111111111',
|
||||
cadence: 'year',
|
||||
positive_delta: 1,
|
||||
negative_delta: 1,
|
||||
signups: 0,
|
||||
cancellations: 0,
|
||||
count: 1354
|
||||
},
|
||||
{
|
||||
date: '2024-06-23',
|
||||
tier: '111111111111111111111111',
|
||||
cadence: 'month',
|
||||
positive_delta: 0,
|
||||
negative_delta: 0,
|
||||
signups: 0,
|
||||
cancellations: 0,
|
||||
count: 456
|
||||
},
|
||||
{
|
||||
date: '2024-06-23',
|
||||
tier: '111111111111111111111111',
|
||||
cadence: 'year',
|
||||
positive_delta: 1,
|
||||
negative_delta: 1,
|
||||
signups: 0,
|
||||
cancellations: 0,
|
||||
count: 1354
|
||||
},
|
||||
{
|
||||
date: '2024-06-23',
|
||||
tier: '111111111111111111111113',
|
||||
cadence: 'year',
|
||||
positive_delta: 0,
|
||||
negative_delta: 0,
|
||||
signups: 0,
|
||||
cancellations: 0,
|
||||
count: 400
|
||||
},
|
||||
{
|
||||
date: '2024-06-24',
|
||||
tier: '111111111111111111111111',
|
||||
cadence: 'year',
|
||||
positive_delta: 3,
|
||||
negative_delta: 2,
|
||||
signups: 1,
|
||||
cancellations: 0,
|
||||
count: 1355
|
||||
},
|
||||
{
|
||||
date: '2024-06-24',
|
||||
tier: '111111111111111111111113',
|
||||
cadence: 'year',
|
||||
positive_delta: 2,
|
||||
negative_delta: 1,
|
||||
signups: 2,
|
||||
cancellations: 1,
|
||||
count: 401
|
||||
},
|
||||
{
|
||||
date: '2024-06-24',
|
||||
tier: '111111111111111111111112',
|
||||
cadence: 'year',
|
||||
positive_delta: 1,
|
||||
negative_delta: 0,
|
||||
signups: 1,
|
||||
cancellations: 0,
|
||||
count: 55
|
||||
},
|
||||
{
|
||||
date: '2024-06-25',
|
||||
tier: '111111111111111111111111',
|
||||
cadence: 'month',
|
||||
positive_delta: 0,
|
||||
negative_delta: 1,
|
||||
signups: 0,
|
||||
cancellations: 1,
|
||||
count: 455
|
||||
},
|
||||
{
|
||||
date: '2024-06-25',
|
||||
tier: '111111111111111111111111',
|
||||
cadence: 'year',
|
||||
positive_delta: 2,
|
||||
negative_delta: 5,
|
||||
signups: 1,
|
||||
cancellations: 4,
|
||||
count: 1352
|
||||
},
|
||||
{
|
||||
date: '2024-06-25',
|
||||
tier: '111111111111111111111113',
|
||||
cadence: 'year',
|
||||
positive_delta: 1,
|
||||
negative_delta: 2,
|
||||
signups: 1,
|
||||
cancellations: 2,
|
||||
count: 400
|
||||
},
|
||||
{
|
||||
date: '2024-06-26',
|
||||
tier: '111111111111111111111111',
|
||||
cadence: 'year',
|
||||
positive_delta: 2,
|
||||
negative_delta: 2,
|
||||
signups: 0,
|
||||
cancellations: 0,
|
||||
count: 1352
|
||||
},
|
||||
{
|
||||
date: '2024-06-26',
|
||||
tier: '111111111111111111111113',
|
||||
cadence: 'year',
|
||||
positive_delta: 0,
|
||||
negative_delta: 0,
|
||||
signups: 0,
|
||||
cancellations: 0,
|
||||
count: 400
|
||||
}
|
||||
];
|
||||
|
||||
describe('mergeStatsByDate', function () {
|
||||
it('merges stats as expected', function () {
|
||||
const result = mergeStatsByDate(STATS_DATA);
|
||||
expect(result).to.deep.equal([
|
||||
{
|
||||
date: '2024-06-22',
|
||||
count: 1810,
|
||||
positiveDelta: 1,
|
||||
negativeDelta: 1,
|
||||
signups: 0,
|
||||
cancellations: 0
|
||||
},
|
||||
{
|
||||
date: '2024-06-23',
|
||||
count: 2210,
|
||||
positiveDelta: 1,
|
||||
negativeDelta: 1,
|
||||
signups: 0,
|
||||
cancellations: 0
|
||||
},
|
||||
{
|
||||
date: '2024-06-24',
|
||||
count: 1811,
|
||||
positiveDelta: 6,
|
||||
negativeDelta: 3,
|
||||
signups: 4,
|
||||
cancellations: 1
|
||||
},
|
||||
{
|
||||
date: '2024-06-25',
|
||||
count: 2207,
|
||||
positiveDelta: 3,
|
||||
negativeDelta: 8,
|
||||
signups: 2,
|
||||
cancellations: 7
|
||||
},
|
||||
{
|
||||
date: '2024-06-26',
|
||||
count: 1752,
|
||||
positiveDelta: 2,
|
||||
negativeDelta: 2,
|
||||
signups: 0,
|
||||
cancellations: 0
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user