285a684ef6
no issue The data generator went out of memory when trying to generate fake data for > 2M members. This adds some improvements to make sure it doesn't go out of memory. --------- Co-authored-by: Fabien "egg" O'Carroll <fabien@allou.is>
112 lines
4.6 KiB
JavaScript
112 lines
4.6 KiB
JavaScript
const TableImporter = require('./TableImporter');
|
|
const {faker} = require('@faker-js/faker');
|
|
const {faker: americanFaker} = require('@faker-js/faker/locale/en_US');
|
|
const {blogStartDate: startTime} = require('../utils/blog-info');
|
|
const generateEvents = require('../utils/event-generator');
|
|
const {luck} = require('../utils/random');
|
|
const dateToDatabaseString = require('../utils/database-date');
|
|
const debug = require('@tryghost/debug')('MembersImporter');
|
|
|
|
class MembersImporter extends TableImporter {
|
|
static table = 'members';
|
|
static dependencies = [];
|
|
defaultQuantity = faker.datatype.number({
|
|
min: 7000,
|
|
max: 8000
|
|
});
|
|
|
|
constructor(knex, transaction) {
|
|
super(MembersImporter.table, knex, transaction);
|
|
}
|
|
|
|
async import(quantity = this.defaultQuantity) {
|
|
const generateNow = Date.now();
|
|
|
|
this.timestamps = generateEvents({
|
|
shape: 'ease-in',
|
|
trend: 'positive',
|
|
total: quantity,
|
|
startTime,
|
|
endTime: new Date()
|
|
}).sort();
|
|
debug(`${this.name} generated ${this.timestamps.length} timestamps in ${Date.now() - generateNow}ms`);
|
|
|
|
await super.import(quantity);
|
|
}
|
|
|
|
/**
|
|
* Add open rate data to members table
|
|
*/
|
|
async finalise() {
|
|
const emailRecipients = await this.transaction.select('id', 'member_id', 'opened_at').from('email_recipients');
|
|
|
|
const memberData = {};
|
|
for (const emailRecipient of emailRecipients) {
|
|
if (!(emailRecipient.member_id in memberData)) {
|
|
memberData[emailRecipient.member_id] = {
|
|
emailCount: 1,
|
|
openedCount: emailRecipient.opened_at ? 1 : 0
|
|
};
|
|
} else {
|
|
memberData[emailRecipient.member_id].emailCount += 1;
|
|
if (emailRecipient.opened_at) {
|
|
memberData[emailRecipient.member_id].openedCount += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const [memberId, emailInfo] of Object.entries(memberData)) {
|
|
const openRate = Math.round(100 * (emailInfo.openedCount / emailInfo.emailCount));
|
|
await this.transaction('members').update({
|
|
email_count: emailInfo.emailCount,
|
|
email_opened_count: emailInfo.openedCount,
|
|
email_open_rate: emailInfo.emailCount >= 5 ? openRate : null
|
|
}).where({id: memberId});
|
|
}
|
|
}
|
|
|
|
generate() {
|
|
const id = this.fastFakeObjectId();
|
|
// Use name from American locale to reflect an English-speaking audience
|
|
const name = `${americanFaker.name.firstName()} ${americanFaker.name.lastName()}`;
|
|
const timestamp = this.timestamps.pop();
|
|
|
|
return {
|
|
id,
|
|
uuid: faker.datatype.uuid(),
|
|
transient_id: faker.datatype.uuid(),
|
|
email: `${name.replace(' ', '.').replace(/[^a-zA-Z0-9]/g, '').toLowerCase()}${faker.datatype.number({min: 0, max: 999999})}@example.com`,
|
|
status: luck(5) ? 'comped' : luck(15) ? 'paid' : 'free',
|
|
name: name,
|
|
expertise: luck(30) ? faker.name.jobTitle() : undefined,
|
|
geolocation: JSON.stringify({
|
|
organization_name: faker.company.name(),
|
|
region: faker.address.state(),
|
|
accuracy: 50,
|
|
asn: parseInt(faker.random.numeric(4)),
|
|
organization: `${faker.random.alpha({count: 2, casing: 'upper'})}${faker.random.numeric(4)} ${faker.company.name()}`,
|
|
timezone: faker.address.timeZone(),
|
|
longitude: faker.address.longitude(),
|
|
country_code3: faker.address.countryCode('alpha-3'),
|
|
area_code: '0',
|
|
ip: faker.internet.ipv4(),
|
|
city: faker.address.cityName(),
|
|
country: faker.address.country(),
|
|
continent_code: 'EU',
|
|
country_code: faker.address.countryCode('alpha-2'),
|
|
latitude: faker.address.latitude()
|
|
}),
|
|
email_count: 0, // Depends on number of emails sent since created_at, the newsletter they're a part of and subscription status
|
|
email_opened_count: 0,
|
|
email_open_rate: null,
|
|
// 40% of users logged in within a week, 60% sometime since registering
|
|
last_seen_at: luck(40) ? dateToDatabaseString(faker.date.recent(7)) : dateToDatabaseString(faker.date.between(timestamp, new Date())),
|
|
created_at: dateToDatabaseString(timestamp),
|
|
created_by: id,
|
|
updated_at: dateToDatabaseString(timestamp)
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = MembersImporter;
|