const fs = require('fs') const cosineSimilarity = require('compute-cosine-similarity') const mockOutputPath = './db/_generated.js' // Insert here how many users you would like to generate: const total = 10 let extraProfilesToGenerate = 0 // Amount of responses for a complete survey const questions = 13 // Seekers per 100 profiles const percentageOfSeekers = 90 // Values for responses const possibleResponses = { not_important: '120', some_what_important: '140', important: '160', very_important: '180', extremely_important: '200', mandatory: '400', } const possibleZipcodes = [ '90065', // Glassel '90012', // Chinatown '90240', // Downey '91030', // South Pasadena '91201', // Glendale '91399', // Woodland Hills '91401', // Van Nuys '90840', // Long Beach '91001', // Altadena '91011', // La Canada Flintridge '97075', // Beaverton ] // Helper functions const randomNumber = max => { return Math.floor(Math.random() * max) < 1 ? 1 : Math.floor(Math.random() * max) } const randomValFrom = arr => arr[randomNumber(arr.length)] const randomEmail = (length = 5) => { let chars = 'abcdefghijklmnopqrstuvwxyz-_abcdefghijklmnopqrstuvwxyz0123456789' let str = '' for (let i = 0; i < length + randomNumber(9); i++) { str += chars.charAt(Math.floor(Math.random() * chars.length)) } const suffixs = [ '@gmail.com', '@aol.com', '@yahoo.com', '@apple.com', '@hotmail.com', '@rocket-mail.com', '@mail.com', ] return str + randomValFrom(suffixs) } const randomName = (length = 4) => { let chars = 'aeiouaeiouabcdefghijklmnoprstuvwyabcdefghijklmnopqrstuvwxyz' let str = '' for (let i = 0; i < length + randomNumber(9); i++) { str += chars.charAt(Math.floor(Math.random() * chars.length)) } return str } const generate = (classObj, amount, meta) => { const instances = [] for (let i = 0; i < amount; i++) { instances.push(new classObj(i + 1, meta)) } return instances } class User { constructor(id) { this.user_id = id this.user_name = '' this.user_email = '' this.is_admin = false this.is_poster = false } } class Profile { constructor(id, override) { this.user_id = override ? override.user_id : id this.profile_id = override ? override.profile_id + id : id } } class Response { constructor(id) { this.response_id = id this.profile_id = null this.response_key_id = null this.val = null } } const users = generate(User, total) users.forEach(user => { user.is_poster = randomNumber(100) > percentageOfSeekers ? 1 : 0 if (user.is_poster) { extraProfilesToGenerate = extraProfilesToGenerate + randomNumber(2) } user.user_name = randomName() + ' ' + randomName() user.user_email = randomEmail() }) let jobPosterIds = users .filter(user => user.is_poster > 0) .map(user => user.user_id) // Guarentee ONE job poster if (!jobPosterIds.length) { randomValFrom(users).is_poster = 1 jobPosterIds = users .filter(user => user.is_poster > 0) .map(user => user.user_id) } const profiles = generate(Profile, total) // Generate extra job posting profiles // attributed to random user.is_poster === true // TODO: Clean this up. Hard to read... if (extraProfilesToGenerate > 0) { let extras = [] for (let l = 0; l < extraProfilesToGenerate; l++) { const generatedExtraProfiles = generate(Profile, 1, { user_id: jobPosterIds.length > 1 ? randomValFrom(jobPosterIds) : jobPosterIds[0], profile_id: profiles.length + l, }) extras = [...extras, ...generatedExtraProfiles] } extras.forEach(profile => profiles.push(profile)) } // Generate responses, then fill in details const responses = generate( Response, (total + extraProfilesToGenerate) * questions, ) profiles.forEach((profile, i) => { const startingIndex = i * questions for (let k = 0; k < questions; k++) { const resToEdit = responses[startingIndex + k] resToEdit.response_key_id = k + 1 resToEdit.profile_id = profile.profile_id resToEdit.val = k + 1 == questions ? randomValFrom(possibleZipcodes) : randomValFrom(Object.values(possibleResponses)) } }) /** * Score all the profiles! */ const scoreResponses = (seeker, potentialMatch) => { const seekerResponses = responses .filter(response => response.profile_id == seeker.profile_id) .filter(response => response.val.length < 4) const potentialMatchResponses = responses .filter(response => response.profile_id == potentialMatch.profile_id) .filter(response => response.val.length < 4) const checkValCb = res => { const val = parseInt(res.val) return isNaN(val) ? 0 : val } return Math.floor( cosineSimilarity( seekerResponses.map(checkValCb), potentialMatchResponses.map(checkValCb), ) * 1000, ) } const scoreProfile = (profile, potentialMatchList) => { const scored = potentialMatchList.map(profileToCompare => { return { match_queue_id: null, profile_id: profile.profile_id, target_id: profileToCompare.profile_id, is_deleted: false, score: scoreResponses(profile, profileToCompare), } }) return scored.sort((a, b) => a.score - b.score) } const scoreAll = () => { let scores = [] const posterProfiles = profiles.filter(profile => jobPosterIds.includes(profile.user_id), ) const seekerProfiles = profiles.filter( profile => !jobPosterIds.includes(profile.user_id), ) seekerProfiles.forEach(seeker => { const scored = scoreProfile(seeker, posterProfiles) scores = [...scored, ...scores] }) posterProfiles.forEach(poster => { const scored = scoreProfile(poster, seekerProfiles) scores = [...scored, ...scores] }) return scores.reverse() } const match_queues = scoreAll().map((score, i) => { score.match_queue_id = i + 1 // Comment out to see the score delete score.score return score }) /** * Our output format */ const outputDataObject = { users, profiles, responses, match_queues } const jobPostings = profiles.filter(profile => jobPosterIds.includes(profile.user_id), ).length const jobPosters = users.filter(user => user.is_poster > 0).length const header = `/** * GENERATED MOCK SIIMEE DATA * Generated at: ${Date.now()} * --- * ${jobPostings} positions listed by ${jobPosters} job posters * ${total + extraProfilesToGenerate - jobPostings} candidate profiles by ${ total + extraProfilesToGenerate - jobPostings } job seekers * --- * ${total + extraProfilesToGenerate} Profiles * ${total} Users */ ` const write = async () => { await fs.writeFile(mockOutputPath, '', () => {}) fs.appendFile( mockOutputPath, header + 'module.exports = ' + JSON.stringify(outputDataObject), err => { if (err) { console.error(err) return } }, ) } write()