make-mp-data 1.1.11 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/default.js CHANGED
@@ -19,6 +19,8 @@ const config = {
19
19
  numUsers: 1000, //how many users
20
20
  format: 'csv', //csv or json
21
21
  region: "US",
22
+ anonIds: true, //if true, anonymousIds are created for each user
23
+ sessionIds: true, //if true, sessionIds are created for each user
22
24
 
23
25
  events: [
24
26
  {
package/e2e.test.js CHANGED
@@ -36,14 +36,60 @@ describe('e2e', () => {
36
36
 
37
37
  test('sends data to mixpanel', async () => {
38
38
  console.log('NETWORK TEST');
39
- const results = await generate({ writeToDisk: false, numEvents: 1100, numUsers: 100, seed: "deal with it", token: testToken});
40
- const {events, users, groups } = results.import;
39
+ const results = await generate({ writeToDisk: false, numEvents: 1100, numUsers: 100, seed: "deal with it", token: testToken });
40
+ const { events, users, groups } = results.import;
41
41
  expect(events.success).toBeGreaterThan(980);
42
42
  expect(users.success).toBe(100);
43
- expect(groups.length).toBe(0);
43
+ expect(groups.length).toBe(0);
44
+ }, timeout);
45
+
46
+ test('every record is valid', async () => {
47
+ console.log('VALIDATION TEST');
48
+ const results = await generate({ writeToDisk: false, numEvents: 10000, numUsers: 500 });
49
+ const { eventData, userProfilesData } = results;
50
+ const areEventsValid = eventData.every(validateEvent);
51
+ const areUsersValid = userProfilesData.every(validateUser);
52
+
53
+ const invalidEvents = eventData.filter(e => !validateEvent(e));
54
+ const invalidUsers = userProfilesData.filter(u => !validateUser(u));
55
+
56
+ expect(areEventsValid).toBe(true);
57
+ expect(areUsersValid).toBe(true);
58
+ }, timeout);
59
+
60
+
61
+ });
62
+
63
+ describe('options + tweaks', () => {
64
+ test('creates sessionIds', async () => {
65
+ const results = await generate({ writeToDisk: false, numEvents: 1000, numUsers: 100, sessionIds: true });
66
+ const { eventData } = results;
67
+ const sessionIds = eventData.map(a => a.$session_id).filter(a => a);
68
+ expect(sessionIds.length).toBe(eventData.length);
69
+ }, timeout);
44
70
 
71
+ test('no sessionIds', async () => {
72
+ const results = await generate({ writeToDisk: false, numEvents: 1000, numUsers: 100, sessionIds: false });
73
+ const { eventData } = results;
74
+ const sessionIds = eventData.map(a => a.$session_id).filter(a => a);
75
+ expect(sessionIds.length).toBe(0);
76
+ }, timeout);
77
+
78
+ test('creates anonymousIds', async () => {
79
+ const results = await generate({ writeToDisk: false, numEvents: 1000, numUsers: 100, anonIds: true });
80
+ const { eventData } = results;
81
+ const anonIds = eventData.map(a => a.$device_id).filter(a => a);
82
+ const userIds = eventData.map(a => a.$user_id).filter(a => a);
83
+ expect(anonIds.length).toBe(eventData.length);
84
+ expect(userIds.length).toBeLessThan(anonIds.length);
85
+ }, timeout);
86
+
87
+ test('no anonymousIds', async () => {
88
+ const results = await generate({ writeToDisk: false, numEvents: 1000, numUsers: 100, anonIds: false });
89
+ const { eventData } = results;
90
+ const anonIds = eventData.map(a => a.$device_id).filter(a => a);
91
+ expect(anonIds.length).toBe(0);
45
92
  }, timeout);
46
-
47
93
 
48
94
 
49
95
  });
@@ -55,7 +101,31 @@ afterEach(() => {
55
101
  });
56
102
 
57
103
  afterAll(() => {
58
- console.log('clearing...');
59
- execSync(`npm run prune`);
60
- console.log('...files cleared 👍');
61
- });
104
+ try {
105
+ console.log('clearing...');
106
+ execSync(`npm run prune`);
107
+ console.log('...files cleared 👍');
108
+ }
109
+ catch (err) {
110
+ console.log('error clearing files');
111
+ }
112
+ });
113
+
114
+ //helpers
115
+
116
+ function validateEvent(event) {
117
+ if (!event.event) return false;
118
+ if (!event.$device_id && !event.$user_id) return false;
119
+ if (!event.time) return false;
120
+ if (!event.$insert_id) return false;
121
+ return true;
122
+ }
123
+
124
+
125
+ function validateUser(user) {
126
+ if (!user.distinct_id) return false;
127
+ if (!user.$name) return false;
128
+ if (!user.$email) return false;
129
+ if (!user.$created) return false;
130
+ return true;
131
+ }
package/index.js CHANGED
@@ -35,7 +35,7 @@ const dayjs = require("dayjs");
35
35
  const utc = require("dayjs/plugin/utc");
36
36
  dayjs.extend(utc);
37
37
  const cliParams = require("./cli.js");
38
- const { makeName } = require('ak-tools');
38
+ const { makeName, md5 } = require('ak-tools');
39
39
 
40
40
  Array.prototype.pickOne = pick;
41
41
  const NOW = dayjs().unix();
@@ -78,6 +78,8 @@ async function main(config) {
78
78
  groupKeys = [],
79
79
  groupProps = {},
80
80
  lookupTables = [],
81
+ anonIds = true,
82
+ sessionIds = true,
81
83
  format = "csv",
82
84
  token = null,
83
85
  region = "US",
@@ -86,6 +88,7 @@ async function main(config) {
86
88
  } = config;
87
89
  VERBOSE = verbose;
88
90
  config.simulationName = makeName();
91
+ global.config = config;
89
92
  const uuidChance = new Chance(seed);
90
93
  log(`------------------SETUP------------------`);
91
94
  log(`\nyour data simulation will heretofore be known as: \n\n\t${config.simulationName.toUpperCase()}...\n`);
@@ -93,8 +96,8 @@ async function main(config) {
93
96
  log(`------------------SETUP------------------`, "\n");
94
97
 
95
98
 
96
- //the function which generates $distinct_id + $created, skewing towards the present
97
- function uuid() {
99
+ //the function which generates $distinct_id + $anonymoud_ids, $session_ids, and $created, skewing towards the present
100
+ function generateUser() {
98
101
  const distinct_id = uuidChance.guid();
99
102
  let z = boxMullerRandom();
100
103
  const skew = chance.normal({ mean: 10, dev: 3 });
@@ -136,8 +139,8 @@ async function main(config) {
136
139
  log(`---------------SIMULATION----------------`, `\n\n`);
137
140
  for (let i = 1; i < numUsers + 1; i++) {
138
141
  progress("users", i);
139
- const user = uuid();
140
- const { distinct_id, $created, anonymousIds } = user;
142
+ const user = generateUser();
143
+ const { distinct_id, $created, anonymousIds, sessionIds } = user;
141
144
  userProfilesData.push(makeProfile(userProps, user));
142
145
  const mutations = chance.integer({ min: 1, max: 10 });
143
146
  scdTableData.push(makeSCD(scdProps, distinct_id, mutations, $created));
@@ -150,6 +153,7 @@ async function main(config) {
150
153
  makeEvent(
151
154
  distinct_id,
152
155
  anonymousIds,
156
+ sessionIds,
153
157
  dayjs($created).unix(),
154
158
  firstEvents,
155
159
  superProps,
@@ -165,6 +169,7 @@ async function main(config) {
165
169
  makeEvent(
166
170
  distinct_id,
167
171
  anonymousIds,
172
+ sessionIds,
168
173
  dayjs($created).unix(),
169
174
  weightedEvents,
170
175
  superProps,
@@ -220,7 +225,7 @@ async function main(config) {
220
225
  [lookupFiles, lookupTableData],
221
226
  ];
222
227
  log("\n", `---------------SIMULATION----------------`, "\n");
223
-
228
+
224
229
  if (!writeToDisk && !token) {
225
230
  return {
226
231
  eventData,
@@ -255,7 +260,7 @@ async function main(config) {
255
260
  log(`\tdone\n`);
256
261
  } else {
257
262
  const ndjson = data.map((d) => JSON.stringify(d)).join("\n");
258
- await touch(path, ndjson, true);
263
+ await touch(path, ndjson, false);
259
264
  }
260
265
  }
261
266
  }
@@ -365,29 +370,41 @@ function makeSCD(props, distinct_id, mutations, $created) {
365
370
  * creates a random event
366
371
  * @param {string} distinct_id
367
372
  * @param {string[]} anonymousIds
373
+ * @param {string[]} sessionIds
368
374
  * @param {number} earliestTime
369
375
  * @param {Object[]} events
370
376
  * @param {Object} superProps
371
377
  * @param {Object} groupKeys
372
378
  * @param {Boolean} isFirstEvent=false
373
379
  */
374
- function makeEvent(distinct_id, anonymousIds, earliestTime, events, superProps, groupKeys, isFirstEvent = false) {
375
-
380
+ function makeEvent(distinct_id, anonymousIds, sessionIds, earliestTime, events, superProps, groupKeys, isFirstEvent = false) {
376
381
  let chosenEvent = events.pickOne();
377
- if (typeof chosenEvent === "string")
382
+
383
+ //allow for a string shorthand
384
+ if (typeof chosenEvent === "string") {
378
385
  chosenEvent = { event: chosenEvent, properties: {} };
386
+ }
387
+
388
+ //event model
379
389
  const event = {
380
390
  event: chosenEvent.event,
381
- $device_id: chance.pickone(anonymousIds), // always have a $device_id
382
391
  $source: "AKsTimeSoup",
383
392
  };
384
393
 
394
+ //event time
385
395
  if (isFirstEvent) event.time = dayjs.unix(earliestTime).toISOString();
386
396
  if (!isFirstEvent) event.time = AKsTimeSoup(earliestTime, NOW, PEAK_DAYS);
387
397
 
398
+ // anonymous and session ids
399
+ if (global?.config.anonIds) event.$device_id = chance.pickone(anonymousIds);
400
+ if (global?.config.sessionIds) event.$session_id = chance.pickone(sessionIds);
401
+
388
402
  //sometimes have a $user_id
389
403
  if (!isFirstEvent && chance.bool({ likelihood: 42 })) event.$user_id = distinct_id;
390
404
 
405
+ // ensure that there is a $user_id or $device_id
406
+ if (!event.$user_id && !event.$device_id) event.$user_id = distinct_id;
407
+
391
408
  const props = { ...chosenEvent.properties, ...superProps };
392
409
 
393
410
  //iterate through custom properties
@@ -408,6 +425,9 @@ function makeEvent(distinct_id, anonymousIds, earliestTime, events, superProps,
408
425
  event[groupKey] = weightedRange(1, groupCardinality).pickOne();
409
426
  }
410
427
 
428
+ //make $insert_id
429
+ event.$insert_id = md5(JSON.stringify(event));
430
+
411
431
  return event;
412
432
  }
413
433
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "make-mp-data",
3
- "version": "1.1.11",
3
+ "version": "1.1.13",
4
4
  "description": "builds all mixpanel primitives for a given project",
5
5
  "main": "index.js",
6
6
  "types": "types.d.ts",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "homepage": "https://github.com/ak--47/make-mp-data#readme",
40
40
  "dependencies": {
41
- "ak-tools": "^1.0.52",
41
+ "ak-tools": "^1.0.53",
42
42
  "chance": "^1.1.7",
43
43
  "dayjs": "^1.11.10",
44
44
  "mixpanel-import": "^2.5.5",
package/types.d.ts CHANGED
@@ -21,6 +21,8 @@ export interface Config {
21
21
  writeToDisk?: boolean;
22
22
  simulationName?: string;
23
23
  verbose?: boolean;
24
+ anonIds?: boolean;
25
+ sessionIds?: boolean;
24
26
  }
25
27
 
26
28
  interface EventConfig {
package/utils.js CHANGED
@@ -231,18 +231,30 @@ function person(bornDaysAgo = 30) {
231
231
  const avPath = gender === 'male' ? `/men/${randomAvatarNumber}.jpg` : `/women/${randomAvatarNumber}.jpg`;
232
232
  const $avatar = avatarPrefix + avPath;
233
233
  const $created = date(bornDaysAgo, true, null)();
234
+
235
+ //anon Ids
234
236
  const anonymousIds = [];
235
237
  const clusterSize = integer(2, 10);
236
238
  for (let i = 0; i < clusterSize; i++) {
237
239
  anonymousIds.push(uid(42));
238
240
  }
239
241
 
242
+ //session Ids
243
+ const sessionIds = [];
244
+ const sessionSize = integer(5, 30);
245
+ for (let i = 0; i < sessionSize; i++) {
246
+ sessionIds.push([uid(5), uid(5), uid(5), uid(5)].join("-"));
247
+ }
248
+
249
+
250
+
240
251
  return {
241
252
  $name,
242
253
  $email,
243
254
  $avatar,
244
255
  $created,
245
- anonymousIds
256
+ anonymousIds,
257
+ sessionIds
246
258
  };
247
259
  }
248
260
 
@@ -333,7 +345,7 @@ function generateName() {
333
345
  "splintering", "crescendoing", "whirling", "bursting", "shining", "gushing", "emerging", "revealing",
334
346
  "emerging", "unfolding", "unveiling", "emerging", "surrounding", "unveiling", "materializing", "revealing"
335
347
  ];
336
-
348
+
337
349
  var adverbs = [
338
350
  "gracefully", "softly", "smoothly", "gently", "tenderly", "quietly", "serenely", "peacefully",
339
351
  "delicately", "effortlessly", "subtly", "tranquilly", "majestically", "silently", "calmly", "harmoniously",
@@ -343,16 +355,16 @@ function generateName() {
343
355
  "seductively", "envelopingly", "ensnaringly", "entrancingly", "intoxicatingly", "irresistibly", "transcendentally",
344
356
  "envelopingly", "rapturously", "intimately", "intensely", "tangibly", "vividly", "intensely", "deeply"
345
357
  ];
346
-
358
+
347
359
 
348
360
  // ? http://stackoverflow.com/a/17516862/103058
349
- var adj = adjs[Math.floor(Math.random() * adjs.length)];
361
+ var adj = adjs[Math.floor(Math.random() * adjs.length)];
350
362
  var noun = nouns[Math.floor(Math.random() * nouns.length)];
351
363
  var verb = verbs[Math.floor(Math.random() * verbs.length)];
352
364
  var adverb = adverbs[Math.floor(Math.random() * adverbs.length)];
353
-
354
-
355
- return adj + '-' + noun + '-' + verb + '-' + adverb
365
+
366
+
367
+ return adj + '-' + noun + '-' + verb + '-' + adverb;
356
368
 
357
369
  }
358
370