make-mp-data 1.2.2 → 1.2.21
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/README.md +24 -4
- package/index.js +22 -15
- package/package.json +3 -3
- package/scripts/go.sh +1 -1
- package/tests/unit.test.js +1 -3
- package/utils.js +38 -26
package/README.md
CHANGED
|
@@ -5,13 +5,33 @@ a quick and dirty CLI in node.js to generate fake data for mixpanel.
|
|
|
5
5
|
|
|
6
6
|
## tldr;
|
|
7
7
|
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx make-mp-data
|
|
11
|
+
```
|
|
12
|
+
- makes events + users (and writes them to CSVs)
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx make-mp-data --numUsers 100 --numEvents 10000 --days 90 --format json
|
|
16
|
+
```
|
|
17
|
+
- makes ~10k events + 100 users from the last 90 days (but writes JSON)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx make-mp-data --complex
|
|
22
|
+
```
|
|
23
|
+
- makes events + users + groups + scd + lookup tables
|
|
24
|
+
- this includes every type of data that mixpanel supports
|
|
25
|
+
|
|
8
26
|
```bash
|
|
9
27
|
npx make-mp-data --token 1234
|
|
10
28
|
```
|
|
11
|
-
- makes events
|
|
12
|
-
- makes lookup tables and SCD type 2 exported as CSVs
|
|
29
|
+
- makes events + users (and send them to mixpanel)
|
|
13
30
|
|
|
14
|
-
|
|
31
|
+
```bash
|
|
32
|
+
npx make-mp-data --help
|
|
33
|
+
```
|
|
34
|
+
- explains all the options you can specify
|
|
15
35
|
|
|
16
36
|
## customization
|
|
17
37
|
|
|
@@ -26,5 +46,5 @@ npx make-mp-data ecommSpec.js --token 1234 --numDays 30 --numUsers 1000 --numEve
|
|
|
26
46
|
|
|
27
47
|
see `--help` for a full list of options
|
|
28
48
|
|
|
29
|
-
see `./models/` for a few `dataModel.js
|
|
49
|
+
see `./models/` for a few `dataModel.js` examples...
|
|
30
50
|
|
package/index.js
CHANGED
|
@@ -61,7 +61,7 @@ async function main(config) {
|
|
|
61
61
|
const uuidChance = new Chance(seed);
|
|
62
62
|
log(`------------------SETUP------------------`);
|
|
63
63
|
log(`\nyour data simulation will heretofore be known as: \n\n\t${config.simulationName.toUpperCase()}...\n`);
|
|
64
|
-
log(`and your configuration is:\n`, JSON.stringify({ seed, numEvents, numUsers, numDays, format, token, region, writeToDisk }, null, 2));
|
|
64
|
+
log(`and your configuration is:\n\n`, JSON.stringify({ seed, numEvents, numUsers, numDays, format, token, region, writeToDisk }, null, 2));
|
|
65
65
|
log(`------------------SETUP------------------`, "\n");
|
|
66
66
|
|
|
67
67
|
|
|
@@ -116,7 +116,7 @@ async function main(config) {
|
|
|
116
116
|
const numEventsThisUser = Math.round(
|
|
117
117
|
chance.normal({ mean: avgEvPerUser, dev: avgEvPerUser / u.integer(3, 7) })
|
|
118
118
|
);
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
if (firstEvents.length) {
|
|
121
121
|
eventData.push(
|
|
122
122
|
makeEvent(
|
|
@@ -147,6 +147,7 @@ async function main(config) {
|
|
|
147
147
|
);
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
+
|
|
150
151
|
//flatten SCD
|
|
151
152
|
scdTableData = scdTableData.flat();
|
|
152
153
|
|
|
@@ -193,7 +194,8 @@ async function main(config) {
|
|
|
193
194
|
[groupFiles, groupProfilesData],
|
|
194
195
|
[lookupFiles, lookupTableData],
|
|
195
196
|
];
|
|
196
|
-
log("\n"
|
|
197
|
+
log("\n")
|
|
198
|
+
log(`---------------SIMULATION----------------`, "\n");
|
|
197
199
|
|
|
198
200
|
if (!writeToDisk && !token) {
|
|
199
201
|
return {
|
|
@@ -202,12 +204,14 @@ async function main(config) {
|
|
|
202
204
|
scdTableData,
|
|
203
205
|
groupProfilesData,
|
|
204
206
|
lookupTableData,
|
|
207
|
+
import: {},
|
|
208
|
+
files: []
|
|
205
209
|
};
|
|
206
210
|
}
|
|
207
211
|
log(`-----------------WRITES------------------`, `\n\n`);
|
|
208
212
|
//write the files
|
|
209
213
|
if (writeToDisk) {
|
|
210
|
-
if (verbose) log(`writing files... for ${config.simulationName}
|
|
214
|
+
if (verbose) log(`writing files... for ${config.simulationName}`);
|
|
211
215
|
loopFiles: for (const pair of pairs) {
|
|
212
216
|
const [paths, data] = pair;
|
|
213
217
|
if (!data.length) continue loopFiles;
|
|
@@ -218,7 +222,7 @@ async function main(config) {
|
|
|
218
222
|
for (const writeData of datasetsToWrite) {
|
|
219
223
|
//if it's a lookup table, it's always a CSV
|
|
220
224
|
if (format === "csv" || path.includes("-LOOKUP.csv")) {
|
|
221
|
-
log(
|
|
225
|
+
log(`\twriting ${path}`);
|
|
222
226
|
const columns = u.getUniqueKeys(writeData);
|
|
223
227
|
//papa parse needs nested JSON stringified
|
|
224
228
|
writeData.forEach((e) => {
|
|
@@ -228,7 +232,6 @@ async function main(config) {
|
|
|
228
232
|
});
|
|
229
233
|
const csv = Papa.unparse(writeData, { columns });
|
|
230
234
|
await touch(path, csv);
|
|
231
|
-
log(`\tdone\n`);
|
|
232
235
|
} else {
|
|
233
236
|
const ndjson = data.map((d) => JSON.stringify(d)).join("\n");
|
|
234
237
|
await touch(path, ndjson, false);
|
|
@@ -293,7 +296,7 @@ async function main(config) {
|
|
|
293
296
|
}
|
|
294
297
|
|
|
295
298
|
}
|
|
296
|
-
log(
|
|
299
|
+
log(`\n-----------------WRITES------------------`, "\n");
|
|
297
300
|
return {
|
|
298
301
|
import: importResults,
|
|
299
302
|
files: [eventFiles, userFiles, scdFiles, groupFiles, lookupFiles, folder],
|
|
@@ -311,7 +314,7 @@ function makeProfile(props, defaults) {
|
|
|
311
314
|
|
|
312
315
|
for (const key in props) {
|
|
313
316
|
try {
|
|
314
|
-
profile[key] = choose(props[key]);
|
|
317
|
+
profile[key] = u.choose(props[key]);
|
|
315
318
|
} catch (e) {
|
|
316
319
|
// debugger;
|
|
317
320
|
}
|
|
@@ -451,20 +454,22 @@ if (require.main === module) {
|
|
|
451
454
|
const suppliedConfig = args._[0];
|
|
452
455
|
|
|
453
456
|
//if the user specifics an separate config file
|
|
457
|
+
//todo this text isn't displaying
|
|
454
458
|
let config = null;
|
|
455
459
|
if (suppliedConfig) {
|
|
456
|
-
log(`using ${suppliedConfig} for data\n`);
|
|
460
|
+
console.log(`using ${suppliedConfig} for data\n`);
|
|
457
461
|
config = require(path.resolve(suppliedConfig));
|
|
458
462
|
}
|
|
459
463
|
else {
|
|
460
464
|
if (complex) {
|
|
461
|
-
log(`... using default COMPLEX configuration [everything] ...\n`);
|
|
462
|
-
log(`... for more simple data, don't use the --complex flag ...\n`);
|
|
465
|
+
console.log(`... using default COMPLEX configuration [everything] ...\n`);
|
|
466
|
+
console.log(`... for more simple data, don't use the --complex flag ...\n`);
|
|
467
|
+
console.log(`... or specify your own js config file (see docs or --help) ...\n`);
|
|
463
468
|
config = require(path.resolve(__dirname, "./models/complex.js"));
|
|
464
469
|
}
|
|
465
470
|
else {
|
|
466
|
-
log(`... using default SIMPLE configuration [events + users] ...\n`);
|
|
467
|
-
log(`... for more complex data, use the --complex flag ...\n`);
|
|
471
|
+
console.log(`... using default SIMPLE configuration [events + users] ...\n`);
|
|
472
|
+
console.log(`... for more complex data, use the --complex flag ...\n`);
|
|
468
473
|
config = require(path.resolve(__dirname, "./models/simple.js"));
|
|
469
474
|
}
|
|
470
475
|
}
|
|
@@ -484,7 +489,9 @@ if (require.main === module) {
|
|
|
484
489
|
main(config)
|
|
485
490
|
.then((data) => {
|
|
486
491
|
log(`-----------------SUMMARY-----------------`);
|
|
487
|
-
const {
|
|
492
|
+
const d = {success: 0, bytes: 0};
|
|
493
|
+
const darr = [d]
|
|
494
|
+
const { events = d, groups = darr, users = d } = data.import;
|
|
488
495
|
const files = data.files;
|
|
489
496
|
const folder = files?.pop();
|
|
490
497
|
const groupBytes = groups.reduce((acc, group) => {
|
|
@@ -501,7 +508,7 @@ if (require.main === module) {
|
|
|
501
508
|
bytes: bytesHuman(bytes || 0),
|
|
502
509
|
};
|
|
503
510
|
if (bytes > 0) console.table(stats);
|
|
504
|
-
log(`\nfiles written to ${folder} ...`);
|
|
511
|
+
log(`\nfiles written to ${folder || "no where; we didn't write anything"} ...`);
|
|
505
512
|
log(" " + files?.flat().join("\n "));
|
|
506
513
|
log(`\n----------------SUMMARY-----------------\n\n\n`);
|
|
507
514
|
})
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "make-mp-data",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.21",
|
|
4
4
|
"description": "builds all mixpanel primitives for a given project",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "node index.js",
|
|
9
|
-
|
|
10
|
-
"
|
|
9
|
+
"dev": "./scripts/go.sh",
|
|
10
|
+
"prune": "rm ./data/*",
|
|
11
11
|
"post": "npm publish",
|
|
12
12
|
"test": "jest --runInBand",
|
|
13
13
|
"deps": "sh ./scripts/deps.sh"
|
package/scripts/go.sh
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
RUNTIME=local
|
|
2
|
+
RUNTIME=local nodemon --inspect index.js --writeToDisk false -u 100 -e 10000
|
package/tests/unit.test.js
CHANGED
|
@@ -70,9 +70,7 @@ describe('utils', () => {
|
|
|
70
70
|
const generatedPerson = person();
|
|
71
71
|
expect(generatedPerson).toHaveProperty('$name');
|
|
72
72
|
expect(generatedPerson).toHaveProperty('$email');
|
|
73
|
-
expect(generatedPerson).toHaveProperty('$avatar');
|
|
74
|
-
expect(generatedPerson).toHaveProperty('anonymousIds');
|
|
75
|
-
expect(generatedPerson.anonymousIds).toBeInstanceOf(Array);
|
|
73
|
+
expect(generatedPerson).toHaveProperty('$avatar');
|
|
76
74
|
});
|
|
77
75
|
|
|
78
76
|
|
package/utils.js
CHANGED
|
@@ -81,16 +81,24 @@ function day(start, end) {
|
|
|
81
81
|
};
|
|
82
82
|
|
|
83
83
|
function choose(value) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
84
|
+
try {
|
|
85
|
+
// Keep resolving the value if it's a function
|
|
86
|
+
while (typeof value === 'function') {
|
|
87
|
+
value = value();
|
|
88
|
+
}
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
// Now, if the resolved value is an array, use chance.pickone
|
|
91
|
+
if (Array.isArray(value)) {
|
|
92
|
+
return chance.pickone(value);
|
|
93
|
+
}
|
|
93
94
|
|
|
95
|
+
// If it's not a function or array, return it as is
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
94
102
|
function exhaust(arr) {
|
|
95
103
|
return function () {
|
|
96
104
|
return arr.shift();
|
|
@@ -285,30 +293,34 @@ function person(bornDaysAgo = 30) {
|
|
|
285
293
|
const $avatar = avatarPrefix + avPath;
|
|
286
294
|
const $created = date(bornDaysAgo, true, null)();
|
|
287
295
|
|
|
296
|
+
const user = {
|
|
297
|
+
$name,
|
|
298
|
+
$email,
|
|
299
|
+
$avatar,
|
|
300
|
+
$created,
|
|
301
|
+
};
|
|
302
|
+
|
|
288
303
|
//anon Ids
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
304
|
+
if (global.MP_SIMULATION_CONFIG?.anonIds) {
|
|
305
|
+
const anonymousIds = [];
|
|
306
|
+
const clusterSize = integer(2, 10);
|
|
307
|
+
for (let i = 0; i < clusterSize; i++) {
|
|
308
|
+
anonymousIds.push(uid(42));
|
|
309
|
+
}
|
|
310
|
+
user.anonymousIds = anonymousIds;
|
|
293
311
|
}
|
|
294
312
|
|
|
295
313
|
//session Ids
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
314
|
+
if (global.MP_SIMULATION_CONFIG?.sessionIds) {
|
|
315
|
+
const sessionIds = [];
|
|
316
|
+
const sessionSize = integer(5, 30);
|
|
317
|
+
for (let i = 0; i < sessionSize; i++) {
|
|
318
|
+
sessionIds.push([uid(5), uid(5), uid(5), uid(5)].join("-"));
|
|
319
|
+
}
|
|
320
|
+
user.sessionIds = sessionIds;
|
|
300
321
|
}
|
|
301
322
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
return {
|
|
305
|
-
$name,
|
|
306
|
-
$email,
|
|
307
|
-
$avatar,
|
|
308
|
-
$created,
|
|
309
|
-
anonymousIds,
|
|
310
|
-
sessionIds
|
|
311
|
-
};
|
|
323
|
+
return user;
|
|
312
324
|
};
|
|
313
325
|
|
|
314
326
|
|