@standardnotes/analytics
Advanced tools
Comparing version 1.5.0 to 1.6.0
@@ -6,2 +6,13 @@ # Change Log | ||
# [1.6.0](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.5.0...@standardnotes/analytics@1.6.0) (2022-06-02) | ||
### Features | ||
* refactor analytics store to handle different periods of time ([00d4f3f](https://github.com/standardnotes/snjs/commit/00d4f3f2f742b0deb5ef4cd415c672574cb3a911)) | ||
# [1.5.0](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.4.1...@standardnotes/analytics@1.5.0) (2022-06-01) | ||
@@ -8,0 +19,0 @@ |
@@ -1,2 +0,6 @@ | ||
export * from './Service/AnalyticsActivity'; | ||
export * from './Service/AnalyticsStoreInterface'; | ||
export * from './Analytics/AnalyticsActivity'; | ||
export * from './Analytics/AnalyticsStoreInterface'; | ||
export * from './Statistics/StatisticsStoreInterface'; | ||
export * from './Time/Period'; | ||
export * from './Time/PeriodKeyGenerator'; | ||
export * from './Time/PeriodKeyGeneratorInterface'; |
@@ -17,3 +17,7 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__exportStar(require("./Service/AnalyticsActivity"), exports); | ||
__exportStar(require("./Service/AnalyticsStoreInterface"), exports); | ||
__exportStar(require("./Analytics/AnalyticsActivity"), exports); | ||
__exportStar(require("./Analytics/AnalyticsStoreInterface"), exports); | ||
__exportStar(require("./Statistics/StatisticsStoreInterface"), exports); | ||
__exportStar(require("./Time/Period"), exports); | ||
__exportStar(require("./Time/PeriodKeyGenerator"), exports); | ||
__exportStar(require("./Time/PeriodKeyGeneratorInterface"), exports); |
export * from './Redis/RedisAnalyticsStore'; | ||
export * from './Redis/RedisStatisticsStore'; |
@@ -18,1 +18,2 @@ "use strict"; | ||
__exportStar(require("./Redis/RedisAnalyticsStore"), exports); | ||
__exportStar(require("./Redis/RedisStatisticsStore"), exports); |
import * as IORedis from 'ioredis'; | ||
import { AnalyticsActivity } from '../../Domain'; | ||
import { AnalyticsStoreInterface } from '../../Domain/Service/AnalyticsStoreInterface'; | ||
import { Period } from '../../Domain/Time/Period'; | ||
import { PeriodKeyGeneratorInterface } from '../../Domain/Time/PeriodKeyGeneratorInterface'; | ||
import { AnalyticsActivity } from '../../Domain/Analytics/AnalyticsActivity'; | ||
import { AnalyticsStoreInterface } from '../../Domain/Analytics/AnalyticsStoreInterface'; | ||
export declare class RedisAnalyticsStore implements AnalyticsStoreInterface { | ||
private periodKeyGenerator; | ||
private redisClient; | ||
constructor(redisClient: IORedis.Redis); | ||
unmarkActivityForToday(activity: AnalyticsActivity, analyticsId: number): Promise<void>; | ||
unmarkActivitiesForToday(activities: AnalyticsActivity[], analyticsId: number): Promise<void>; | ||
unmarkActivityForYesterday(activity: AnalyticsActivity, analyticsId: number): Promise<void>; | ||
unmarkActivitiesForYesterday(activities: AnalyticsActivity[], analyticsId: number): Promise<void>; | ||
markActivityForToday(activity: AnalyticsActivity, analyticsId: number): Promise<void>; | ||
markActivitiesForToday(activities: AnalyticsActivity[], analyticsId: number): Promise<void>; | ||
calculateActivityTotalCountForYesterday(activity: AnalyticsActivity): Promise<number>; | ||
calculateActivityTotalCountForLastWeek(activity: AnalyticsActivity): Promise<number>; | ||
calculateActivityRetentionForYesterday(activity: AnalyticsActivity): Promise<number>; | ||
calculateActivityRetentionForLastWeek(activity: AnalyticsActivity): Promise<number>; | ||
wasActivityDoneYesterday(activity: AnalyticsActivity, analyticsId: number): Promise<boolean>; | ||
wasActivityDoneToday(activity: AnalyticsActivity, analyticsId: number): Promise<boolean>; | ||
wasActivityDoneLastWeek(activity: AnalyticsActivity, analyticsId: number): Promise<boolean>; | ||
wasActivityDoneThisWeek(activity: AnalyticsActivity, analyticsId: number): Promise<boolean>; | ||
getYesterdayOutOfSyncIncidents(): Promise<number>; | ||
incrementOutOfSyncIncidents(): Promise<void>; | ||
getYesterdaySNJSUsage(): Promise<{ | ||
version: string; | ||
count: number; | ||
}[]>; | ||
getYesterdayApplicationUsage(): Promise<{ | ||
version: string; | ||
count: number; | ||
}[]>; | ||
incrementApplicationVersionUsage(applicationVersion: string): Promise<void>; | ||
incrementSNJSVersionUsage(snjsVersion: string): Promise<void>; | ||
private getRequestCountPerVersion; | ||
private getMonthlyKey; | ||
private getDailyKey; | ||
private getWeeklyKey; | ||
private getYear; | ||
private getMonth; | ||
private getDayOfTheMonth; | ||
private getYesterdayDate; | ||
private getDayBeforeYesterdayDate; | ||
private getLastWeekDate; | ||
private getWeekBeforeLastWeekDate; | ||
constructor(periodKeyGenerator: PeriodKeyGeneratorInterface, redisClient: IORedis.Redis); | ||
markActivity(activities: AnalyticsActivity[], analyticsId: number, periods: Period[]): Promise<void>; | ||
unmarkActivity(activities: AnalyticsActivity[], analyticsId: number, periods: Period[]): Promise<void>; | ||
wasActivityDone(activity: AnalyticsActivity, analyticsId: number, period: Period): Promise<boolean>; | ||
calculateActivityRetention(activity: AnalyticsActivity, firstPeriod: Period, secondPeriod: Period): Promise<number>; | ||
calculateActivityTotalCount(activity: AnalyticsActivity, period: Period): Promise<number>; | ||
} |
@@ -14,21 +14,13 @@ "use strict"; | ||
class RedisAnalyticsStore { | ||
constructor(redisClient) { | ||
constructor(periodKeyGenerator, redisClient) { | ||
this.periodKeyGenerator = periodKeyGenerator; | ||
this.redisClient = redisClient; | ||
} | ||
unmarkActivityForToday(activity, analyticsId) { | ||
markActivity(activities, analyticsId, periods) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getMonthlyKey()}`, analyticsId, 0); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getWeeklyKey()}`, analyticsId, 0); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getDailyKey()}`, analyticsId, 0); | ||
yield pipeline.exec(); | ||
}); | ||
} | ||
unmarkActivitiesForToday(activities, analyticsId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
for (const activity of activities) { | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getMonthlyKey()}`, analyticsId, 0); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getWeeklyKey()}`, analyticsId, 0); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getDailyKey()}`, analyticsId, 0); | ||
for (const period of periods) { | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`, analyticsId, 1); | ||
} | ||
} | ||
@@ -38,18 +30,9 @@ yield pipeline.exec(); | ||
} | ||
unmarkActivityForYesterday(activity, analyticsId) { | ||
unmarkActivity(activities, analyticsId, periods) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getMonthlyKey(this.getYesterdayDate())}`, analyticsId, 0); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getWeeklyKey(this.getYesterdayDate())}`, analyticsId, 0); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getDailyKey(this.getYesterdayDate())}`, analyticsId, 0); | ||
yield pipeline.exec(); | ||
}); | ||
} | ||
unmarkActivitiesForYesterday(activities, analyticsId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
for (const activity of activities) { | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getMonthlyKey(this.getYesterdayDate())}`, analyticsId, 0); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getWeeklyKey(this.getYesterdayDate())}`, analyticsId, 0); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getDailyKey(this.getYesterdayDate())}`, analyticsId, 0); | ||
for (const period of periods) { | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`, analyticsId, 0); | ||
} | ||
} | ||
@@ -59,182 +42,25 @@ yield pipeline.exec(); | ||
} | ||
markActivityForToday(activity, analyticsId) { | ||
wasActivityDone(activity, analyticsId, period) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getMonthlyKey()}`, analyticsId, 1); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getWeeklyKey()}`, analyticsId, 1); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getDailyKey()}`, analyticsId, 1); | ||
yield pipeline.exec(); | ||
}); | ||
} | ||
markActivitiesForToday(activities, analyticsId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
for (const activity of activities) { | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getMonthlyKey()}`, analyticsId, 1); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getWeeklyKey()}`, analyticsId, 1); | ||
pipeline.setbit(`bitmap:action:${activity}:timespan:${this.getDailyKey()}`, analyticsId, 1); | ||
} | ||
yield pipeline.exec(); | ||
}); | ||
} | ||
calculateActivityTotalCountForYesterday(activity) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${this.getDailyKey(this.getYesterdayDate())}`); | ||
}); | ||
} | ||
calculateActivityTotalCountForLastWeek(activity) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${this.getWeeklyKey(this.getLastWeekDate())}`); | ||
}); | ||
} | ||
calculateActivityRetentionForYesterday(activity) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const dayBeforeYesterdayKey = this.getDailyKey(this.getDayBeforeYesterdayDate()); | ||
const yesterdayKey = this.getDailyKey(this.getYesterdayDate()); | ||
const diffKey = `bitmap:action:${activity}:timespan:${dayBeforeYesterdayKey}-${yesterdayKey}`; | ||
yield this.redisClient.send_command('BITOP', 'AND', diffKey, `bitmap:action:${activity}:timespan:${dayBeforeYesterdayKey}`, `bitmap:action:${activity}:timespan:${yesterdayKey}`); | ||
const yesterdayAndDayBeforeYesterdayTotalInActivity = yield this.redisClient.bitcount(diffKey); | ||
const dayBeforeYesterdayTotalInActivity = yield this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${dayBeforeYesterdayKey}`); | ||
return Math.ceil((yesterdayAndDayBeforeYesterdayTotalInActivity * 100) / dayBeforeYesterdayTotalInActivity); | ||
}); | ||
} | ||
calculateActivityRetentionForLastWeek(activity) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const weekBeforeLastWeekKey = this.getWeeklyKey(this.getWeekBeforeLastWeekDate()); | ||
const lastWeekKey = this.getWeeklyKey(this.getLastWeekDate()); | ||
const diffKey = `bitmap:action:${activity}:timespan:${weekBeforeLastWeekKey}-${lastWeekKey}`; | ||
yield this.redisClient.send_command('BITOP', 'AND', diffKey, `bitmap:action:${activity}:timespan:${weekBeforeLastWeekKey}`, `bitmap:action:${activity}:timespan:${lastWeekKey}`); | ||
const lastWeekAndWeekBeforeLastWeekTotalInActivity = yield this.redisClient.bitcount(diffKey); | ||
const weekBeforeLastWeekTotalInActivity = yield this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${weekBeforeLastWeekKey}`); | ||
return Math.ceil((lastWeekAndWeekBeforeLastWeekTotalInActivity * 100) / weekBeforeLastWeekTotalInActivity); | ||
}); | ||
} | ||
wasActivityDoneYesterday(activity, analyticsId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const bitValue = yield this.redisClient.getbit(`bitmap:action:${activity}:timespan:${this.getDailyKey(this.getYesterdayDate())}`, analyticsId); | ||
const bitValue = yield this.redisClient.getbit(`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`, analyticsId); | ||
return bitValue === 1; | ||
}); | ||
} | ||
wasActivityDoneToday(activity, analyticsId) { | ||
calculateActivityRetention(activity, firstPeriod, secondPeriod) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const bitValue = yield this.redisClient.getbit(`bitmap:action:${activity}:timespan:${this.getDailyKey()}`, analyticsId); | ||
return bitValue === 1; | ||
const initialPeriodKey = this.periodKeyGenerator.getPeriodKey(firstPeriod); | ||
const subsequentPeriodKey = this.periodKeyGenerator.getPeriodKey(secondPeriod); | ||
const diffKey = `bitmap:action:${activity}:timespan:${initialPeriodKey}-${subsequentPeriodKey}`; | ||
yield this.redisClient.send_command('BITOP', 'AND', diffKey, `bitmap:action:${activity}:timespan:${initialPeriodKey}`, `bitmap:action:${activity}:timespan:${subsequentPeriodKey}`); | ||
const retainedTotalInActivity = yield this.redisClient.bitcount(diffKey); | ||
const initialTotalInActivity = yield this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${initialPeriodKey}`); | ||
return Math.ceil((retainedTotalInActivity * 100) / initialTotalInActivity); | ||
}); | ||
} | ||
wasActivityDoneLastWeek(activity, analyticsId) { | ||
calculateActivityTotalCount(activity, period) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const bitValue = yield this.redisClient.getbit(`bitmap:action:${activity}:timespan:${this.getWeeklyKey(this.getLastWeekDate())}`, analyticsId); | ||
return bitValue === 1; | ||
return this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`); | ||
}); | ||
} | ||
wasActivityDoneThisWeek(activity, analyticsId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const bitValue = yield this.redisClient.getbit(`bitmap:action:${activity}:timespan:${this.getWeeklyKey()}`, analyticsId); | ||
return bitValue === 1; | ||
}); | ||
} | ||
getYesterdayOutOfSyncIncidents() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const count = yield this.redisClient.get(`count:action:out-of-sync:timespan:${this.getDailyKey(this.getYesterdayDate())}`); | ||
if (count === null) { | ||
return 0; | ||
} | ||
return +count; | ||
}); | ||
} | ||
incrementOutOfSyncIncidents() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
pipeline.incr(`count:action:out-of-sync:timespan:${this.getDailyKey()}`); | ||
pipeline.incr(`count:action:out-of-sync:timespan:${this.getMonthlyKey()}`); | ||
yield pipeline.exec(); | ||
}); | ||
} | ||
getYesterdaySNJSUsage() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const keys = yield this.redisClient.keys(`count:action:snjs-request:*:timespan:${this.getDailyKey(this.getYesterdayDate())}`); | ||
return this.getRequestCountPerVersion(keys); | ||
}); | ||
} | ||
getYesterdayApplicationUsage() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const keys = yield this.redisClient.keys(`count:action:application-request:*:timespan:${this.getDailyKey(this.getYesterdayDate())}`); | ||
return this.getRequestCountPerVersion(keys); | ||
}); | ||
} | ||
incrementApplicationVersionUsage(applicationVersion) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
pipeline.incr(`count:action:application-request:${applicationVersion}:timespan:${this.getDailyKey()}`); | ||
pipeline.incr(`count:action:application-request:${applicationVersion}:timespan:${this.getMonthlyKey()}`); | ||
yield pipeline.exec(); | ||
}); | ||
} | ||
incrementSNJSVersionUsage(snjsVersion) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const pipeline = this.redisClient.pipeline(); | ||
pipeline.incr(`count:action:snjs-request:${snjsVersion}:timespan:${this.getDailyKey()}`); | ||
pipeline.incr(`count:action:snjs-request:${snjsVersion}:timespan:${this.getMonthlyKey()}`); | ||
yield pipeline.exec(); | ||
}); | ||
} | ||
getRequestCountPerVersion(keys) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const statistics = []; | ||
for (const key of keys) { | ||
const count = yield this.redisClient.get(key); | ||
const version = key.split(':')[3]; | ||
statistics.push({ | ||
version, | ||
count: +count, | ||
}); | ||
} | ||
return statistics; | ||
}); | ||
} | ||
getMonthlyKey(date) { | ||
date = date !== null && date !== void 0 ? date : new Date(); | ||
return `${this.getYear(date)}-${this.getMonth(date)}`; | ||
} | ||
getDailyKey(date) { | ||
date = date !== null && date !== void 0 ? date : new Date(); | ||
return `${this.getYear(date)}-${this.getMonth(date)}-${this.getDayOfTheMonth(date)}`; | ||
} | ||
getWeeklyKey(date) { | ||
date = date !== null && date !== void 0 ? date : new Date(); | ||
const firstJanuary = new Date(date.getFullYear(), 0, 1); | ||
const numberOfDaysPassed = Math.floor((date.getTime() - firstJanuary.getTime()) / (24 * 60 * 60 * 1000)); | ||
const weekNumber = Math.ceil((date.getDay() + 1 + numberOfDaysPassed) / 7); | ||
return `${this.getYear(date)}-week-${weekNumber}`; | ||
} | ||
getYear(date) { | ||
return date.getFullYear().toString(); | ||
} | ||
getMonth(date) { | ||
return (date.getMonth() + 1).toString(); | ||
} | ||
getDayOfTheMonth(date) { | ||
return date.getDate().toString(); | ||
} | ||
getYesterdayDate() { | ||
const yesterday = new Date(); | ||
yesterday.setDate(new Date().getDate() - 1); | ||
return yesterday; | ||
} | ||
getDayBeforeYesterdayDate() { | ||
const dayBeforeYesterday = new Date(); | ||
dayBeforeYesterday.setDate(new Date().getDate() - 2); | ||
return dayBeforeYesterday; | ||
} | ||
getLastWeekDate() { | ||
const yesterday = new Date(); | ||
yesterday.setDate(new Date().getDate() - 7); | ||
return yesterday; | ||
} | ||
getWeekBeforeLastWeekDate() { | ||
const yesterday = new Date(); | ||
yesterday.setDate(new Date().getDate() - 14); | ||
return yesterday; | ||
} | ||
} | ||
exports.RedisAnalyticsStore = RedisAnalyticsStore; |
@@ -13,2 +13,3 @@ "use strict"; | ||
const Domain_1 = require("../../Domain"); | ||
const AnalyticsActivity_1 = require("../../Domain/Analytics/AnalyticsActivity"); | ||
const RedisAnalyticsStore_1 = require("./RedisAnalyticsStore"); | ||
@@ -18,3 +19,4 @@ describe('RedisAnalyticsStore', () => { | ||
let pipeline; | ||
const createStore = () => new RedisAnalyticsStore_1.RedisAnalyticsStore(redisClient); | ||
let periodKeyGenerator; | ||
const createStore = () => new RedisAnalyticsStore_1.RedisAnalyticsStore(periodKeyGenerator, redisClient); | ||
beforeEach(() => { | ||
@@ -31,187 +33,55 @@ pipeline = {}; | ||
redisClient.send_command = jest.fn(); | ||
periodKeyGenerator = {}; | ||
periodKeyGenerator.getPeriodKey = jest.fn().mockReturnValue('period-key'); | ||
}); | ||
it('should calculate total count of activities yesterday', () => __awaiter(void 0, void 0, void 0, function* () { | ||
it('should calculate total count of activities', () => __awaiter(void 0, void 0, void 0, function* () { | ||
redisClient.bitcount = jest.fn().mockReturnValue(70); | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
expect(yield createStore().calculateActivityTotalCountForYesterday(Domain_1.AnalyticsActivity.EditingItems)).toEqual(70); | ||
jest.useRealTimers(); | ||
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-5-23'); | ||
expect(yield createStore().calculateActivityTotalCount(AnalyticsActivity_1.AnalyticsActivity.EditingItems, Domain_1.Period.Yesterday)).toEqual(70); | ||
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:period-key'); | ||
})); | ||
it('should calculate total count of activities last week', () => __awaiter(void 0, void 0, void 0, function* () { | ||
redisClient.bitcount = jest.fn().mockReturnValue(70); | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
expect(yield createStore().calculateActivityTotalCountForLastWeek(Domain_1.AnalyticsActivity.EditingItems)).toEqual(70); | ||
jest.useRealTimers(); | ||
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-week-20'); | ||
})); | ||
it('should calculate activity retention for yesterday', () => __awaiter(void 0, void 0, void 0, function* () { | ||
it('should calculate activity retention', () => __awaiter(void 0, void 0, void 0, function* () { | ||
redisClient.bitcount = jest.fn().mockReturnValueOnce(7).mockReturnValueOnce(10); | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
expect(yield createStore().calculateActivityRetentionForYesterday(Domain_1.AnalyticsActivity.EditingItems)).toEqual(70); | ||
jest.useRealTimers(); | ||
expect(redisClient.send_command).toHaveBeenCalledWith('BITOP', 'AND', 'bitmap:action:editing-items:timespan:2022-5-22-2022-5-23', 'bitmap:action:editing-items:timespan:2022-5-22', 'bitmap:action:editing-items:timespan:2022-5-23'); | ||
expect(yield createStore().calculateActivityRetention(AnalyticsActivity_1.AnalyticsActivity.EditingItems, Domain_1.Period.DayBeforeYesterday, Domain_1.Period.Yesterday)).toEqual(70); | ||
expect(redisClient.send_command).toHaveBeenCalledWith('BITOP', 'AND', 'bitmap:action:editing-items:timespan:period-key-period-key', 'bitmap:action:editing-items:timespan:period-key', 'bitmap:action:editing-items:timespan:period-key'); | ||
})); | ||
it('should calculate activity retention for last week', () => __awaiter(void 0, void 0, void 0, function* () { | ||
redisClient.bitcount = jest.fn().mockReturnValueOnce(7).mockReturnValueOnce(10); | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
expect(yield createStore().calculateActivityRetentionForLastWeek(Domain_1.AnalyticsActivity.EditingItems)).toEqual(70); | ||
jest.useRealTimers(); | ||
expect(redisClient.send_command).toHaveBeenCalledWith('BITOP', 'AND', 'bitmap:action:editing-items:timespan:2022-week-19-2022-week-20', 'bitmap:action:editing-items:timespan:2022-week-19', 'bitmap:action:editing-items:timespan:2022-week-20'); | ||
it('shoud tell if activity was done', () => __awaiter(void 0, void 0, void 0, function* () { | ||
yield createStore().wasActivityDone(AnalyticsActivity_1.AnalyticsActivity.EditingItems, 123, Domain_1.Period.Yesterday); | ||
expect(redisClient.getbit).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:period-key', 123); | ||
})); | ||
it('shoud tell if activity was done yesterday', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().wasActivityDoneYesterday(Domain_1.AnalyticsActivity.EditingItems, 123); | ||
jest.useRealTimers(); | ||
expect(redisClient.getbit).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-5-23', 123); | ||
})); | ||
it('shoud tell if activity was done today', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().wasActivityDoneToday(Domain_1.AnalyticsActivity.EditingItems, 123); | ||
jest.useRealTimers(); | ||
expect(redisClient.getbit).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-5-24', 123); | ||
})); | ||
it('shoud tell if activity was done last week', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().wasActivityDoneLastWeek(Domain_1.AnalyticsActivity.EditingItems, 123); | ||
jest.useRealTimers(); | ||
expect(redisClient.getbit).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-week-20', 123); | ||
})); | ||
it('shoud tell if activity was done this week', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().wasActivityDoneThisWeek(Domain_1.AnalyticsActivity.EditingItems, 123); | ||
jest.useRealTimers(); | ||
expect(redisClient.getbit).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-week-21', 123); | ||
})); | ||
it('should mark analytics activity for today', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().markActivityForToday(Domain_1.AnalyticsActivity.EditingItems, 123); | ||
jest.useRealTimers(); | ||
expect(pipeline.setbit).toBeCalledTimes(3); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-5', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-week-21', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-5-24', 123, 1); | ||
it('should mark activity as done', () => __awaiter(void 0, void 0, void 0, function* () { | ||
yield createStore().markActivity([AnalyticsActivity_1.AnalyticsActivity.EditingItems], 123, [Domain_1.Period.Today]); | ||
expect(pipeline.setbit).toBeCalledTimes(1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 1); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
it('should mark analytics activities for today', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().markActivitiesForToday([Domain_1.AnalyticsActivity.EditingItems, Domain_1.AnalyticsActivity.EmailUnbackedUpData], 123); | ||
jest.useRealTimers(); | ||
expect(pipeline.setbit).toBeCalledTimes(6); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-5', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-week-21', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-5-24', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(4, 'bitmap:action:email-unbacked-up-data:timespan:2022-5', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(5, 'bitmap:action:email-unbacked-up-data:timespan:2022-week-21', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(6, 'bitmap:action:email-unbacked-up-data:timespan:2022-5-24', 123, 1); | ||
it('should mark activities as done', () => __awaiter(void 0, void 0, void 0, function* () { | ||
yield createStore().markActivity([AnalyticsActivity_1.AnalyticsActivity.EditingItems, AnalyticsActivity_1.AnalyticsActivity.EmailUnbackedUpData], 123, [ | ||
Domain_1.Period.Today, | ||
Domain_1.Period.ThisWeek, | ||
]); | ||
expect(pipeline.setbit).toBeCalledTimes(4); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:period-key', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(3, 'bitmap:action:email-unbacked-up-data:timespan:period-key', 123, 1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(4, 'bitmap:action:email-unbacked-up-data:timespan:period-key', 123, 1); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
it('should unmark analytics activity for today', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().unmarkActivityForToday(Domain_1.AnalyticsActivity.EditingItems, 123); | ||
jest.useRealTimers(); | ||
expect(pipeline.setbit).toBeCalledTimes(3); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-5', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-week-21', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-5-24', 123, 0); | ||
it('should unmark activity as done', () => __awaiter(void 0, void 0, void 0, function* () { | ||
yield createStore().unmarkActivity([AnalyticsActivity_1.AnalyticsActivity.EditingItems], 123, [Domain_1.Period.Today]); | ||
expect(pipeline.setbit).toBeCalledTimes(1); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 0); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
it('should unmark analytics activities for today', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().unmarkActivitiesForToday([Domain_1.AnalyticsActivity.EditingItems, Domain_1.AnalyticsActivity.EmailUnbackedUpData], 123); | ||
jest.useRealTimers(); | ||
expect(pipeline.setbit).toBeCalledTimes(6); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-5', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-week-21', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-5-24', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(4, 'bitmap:action:email-unbacked-up-data:timespan:2022-5', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(5, 'bitmap:action:email-unbacked-up-data:timespan:2022-week-21', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(6, 'bitmap:action:email-unbacked-up-data:timespan:2022-5-24', 123, 0); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
it('should unmark analytics activity for yesterday', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().unmarkActivityForYesterday(Domain_1.AnalyticsActivity.EditingItems, 123); | ||
jest.useRealTimers(); | ||
expect(pipeline.setbit).toBeCalledTimes(3); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-5', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-week-21', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-5-23', 123, 0); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
it('should unmark analytics activities for yesterday', () => __awaiter(void 0, void 0, void 0, function* () { | ||
jest.useFakeTimers('modern'); | ||
jest.setSystemTime(1653395155000); | ||
yield createStore().unmarkActivitiesForYesterday([Domain_1.AnalyticsActivity.EditingItems, Domain_1.AnalyticsActivity.EmailUnbackedUpData], 123); | ||
jest.useRealTimers(); | ||
expect(pipeline.setbit).toBeCalledTimes(6); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-5', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-week-21', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-5-23', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(4, 'bitmap:action:email-unbacked-up-data:timespan:2022-5', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(5, 'bitmap:action:email-unbacked-up-data:timespan:2022-week-21', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(6, 'bitmap:action:email-unbacked-up-data:timespan:2022-5-23', 123, 0); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
it('should get yesterday out of sync incidents', () => __awaiter(void 0, void 0, void 0, function* () { | ||
redisClient.get = jest.fn().mockReturnValue(1); | ||
expect(yield createStore().getYesterdayOutOfSyncIncidents()).toEqual(1); | ||
})); | ||
it('should default to 0 yesterday out of sync incidents', () => __awaiter(void 0, void 0, void 0, function* () { | ||
redisClient.get = jest.fn().mockReturnValue(null); | ||
expect(yield createStore().getYesterdayOutOfSyncIncidents()).toEqual(0); | ||
})); | ||
it('should get yesterday application version usage', () => __awaiter(void 0, void 0, void 0, function* () { | ||
redisClient.keys = jest | ||
.fn() | ||
.mockReturnValue([ | ||
'count:action:application-request:1.2.3:timespan:2022-3-10', | ||
'count:action:application-request:2.3.4:timespan:2022-3-10', | ||
it('should unmark activities as done', () => __awaiter(void 0, void 0, void 0, function* () { | ||
yield createStore().unmarkActivity([AnalyticsActivity_1.AnalyticsActivity.EditingItems, AnalyticsActivity_1.AnalyticsActivity.EmailUnbackedUpData], 123, [ | ||
Domain_1.Period.Today, | ||
Domain_1.Period.ThisWeek, | ||
]); | ||
redisClient.get = jest.fn().mockReturnValueOnce(3).mockReturnValueOnce(4); | ||
expect(yield createStore().getYesterdayApplicationUsage()).toEqual([ | ||
{ count: 3, version: '1.2.3' }, | ||
{ count: 4, version: '2.3.4' }, | ||
]); | ||
})); | ||
it('should get yesterday snjs version usage', () => __awaiter(void 0, void 0, void 0, function* () { | ||
redisClient.keys = jest | ||
.fn() | ||
.mockReturnValue([ | ||
'count:action:snjs-request:1.2.3:timespan:2022-3-10', | ||
'count:action:snjs-request:2.3.4:timespan:2022-3-10', | ||
]); | ||
redisClient.get = jest.fn().mockReturnValueOnce(3).mockReturnValueOnce(4); | ||
expect(yield createStore().getYesterdaySNJSUsage()).toEqual([ | ||
{ count: 3, version: '1.2.3' }, | ||
{ count: 4, version: '2.3.4' }, | ||
]); | ||
})); | ||
it('should increment application version usage', () => __awaiter(void 0, void 0, void 0, function* () { | ||
yield createStore().incrementApplicationVersionUsage('1.2.3'); | ||
expect(pipeline.incr).toHaveBeenCalled(); | ||
expect(pipeline.setbit).toBeCalledTimes(4); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:period-key', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(3, 'bitmap:action:email-unbacked-up-data:timespan:period-key', 123, 0); | ||
expect(pipeline.setbit).toHaveBeenNthCalledWith(4, 'bitmap:action:email-unbacked-up-data:timespan:period-key', 123, 0); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
it('should increment snjs version usage', () => __awaiter(void 0, void 0, void 0, function* () { | ||
yield createStore().incrementSNJSVersionUsage('1.2.3'); | ||
expect(pipeline.incr).toHaveBeenCalled(); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
it('should increment out of sync incedent count', () => __awaiter(void 0, void 0, void 0, function* () { | ||
yield createStore().incrementOutOfSyncIncidents(); | ||
expect(pipeline.incr).toHaveBeenCalled(); | ||
expect(pipeline.exec).toHaveBeenCalled(); | ||
})); | ||
}); |
{ | ||
"name": "@standardnotes/analytics", | ||
"version": "1.5.0", | ||
"version": "1.6.0", | ||
"engines": { | ||
@@ -39,3 +39,3 @@ "node": ">=14.0.0 <17.0.0" | ||
}, | ||
"gitHead": "c6682f600bbc40cff3af130dfde5085e2c8aef22" | ||
"gitHead": "b51630b6698ebbbaa71d235c7450b7db86187132" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30
633
37286
1