make-mp-data 1.4.5 → 1.5.0

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.
@@ -1,4 +1,4 @@
1
- const generate = require('../core/index.js');
1
+ const generate = require('../index.js');
2
2
  const dayjs = require("dayjs");
3
3
  const utc = require("dayjs/plugin/utc");
4
4
  const fs = require('fs');
@@ -9,7 +9,7 @@ require('dotenv').config();
9
9
  /** @typedef {import('../types').Config} Config */
10
10
  /** @typedef {import('../types').EventConfig} EventConfig */
11
11
  /** @typedef {import('../types').ValueValid} ValueValid */
12
- /** @typedef {import('../types').EnrichedArray} hookArray */
12
+ /** @typedef {import('../types').HookedArray} hookArray */
13
13
  /** @typedef {import('../types').hookArrayOptions} hookArrayOptions */
14
14
  /** @typedef {import('../types').Person} Person */
15
15
  /** @typedef {import('../types').Funnel} Funnel */
@@ -32,7 +32,7 @@ const {
32
32
  range,
33
33
  pickAWinner,
34
34
  weighNumRange,
35
- hookArray,
35
+
36
36
  fixFirstAndLast,
37
37
  generateUser,
38
38
  openFinder,
@@ -51,13 +51,17 @@ const {
51
51
  getChance,
52
52
  initChance,
53
53
  validateEventConfig,
54
- validateTime,
54
+ validTime,
55
55
  interruptArray,
56
56
  optimizedBoxMuller,
57
- inferFunnels,
57
+
58
58
  datesBetween,
59
59
  weighChoices
60
- } = require('../core/utils.js');
60
+ } = require('../src/utils.js');
61
+
62
+ const main = require('../index.js');
63
+ //todo: test for funnel inference
64
+ const { hookArray, inferFunnels } = main.meta;
61
65
 
62
66
 
63
67
  describe('timesoup', () => {
@@ -264,19 +268,19 @@ describe('generation', () => {
264
268
  test('user: works', () => {
265
269
  const uuid = { guid: jest.fn().mockReturnValue('uuid-123') };
266
270
  const numDays = 30;
267
- const user = generateUser(numDays);
271
+ const user = generateUser('123', { numDays });
268
272
  expect(user).toHaveProperty('distinct_id');
269
273
  expect(user).toHaveProperty('name');
270
274
  expect(user).toHaveProperty('email');
271
- expect(user).toHaveProperty('avatar');
275
+ expect(user).not.toHaveProperty('avatar');
272
276
  expect(user).toHaveProperty('created');
273
- expect(user).toHaveProperty('anonymousIds');
274
- expect(user).toHaveProperty('sessionIds');
277
+ expect(user).not.toHaveProperty('anonymousIds');
278
+ expect(user).not.toHaveProperty('sessionIds');
275
279
  });
276
280
 
277
281
  test('user: in time range', () => {
278
282
  const numDays = 30;
279
- const user = generateUser('uuid-123', numDays);
283
+ const user = generateUser('uuid-123', { numDays });
280
284
  const createdDate = dayjs(user.created, 'YYYY-MM-DD');
281
285
  expect(createdDate.isValid()).toBeTruthy();
282
286
  expect(createdDate.isBefore(dayjs.unix(global.NOW))).toBeTruthy();
@@ -290,10 +294,10 @@ describe('generation', () => {
290
294
  expect(user.distinct_id).toBe('uuid-123');
291
295
  expect(user).toHaveProperty('name');
292
296
  expect(user).toHaveProperty('email');
293
- expect(user).toHaveProperty('avatar');
297
+ expect(user).not.toHaveProperty('avatar');
294
298
  expect(user).toHaveProperty('created');
295
- expect(user).toHaveProperty('anonymousIds');
296
- expect(user).toHaveProperty('sessionIds');
299
+ expect(user).not.toHaveProperty('anonymousIds');
300
+ expect(user).not.toHaveProperty('sessionIds');
297
301
  });
298
302
 
299
303
  test('person: anon', () => {
@@ -301,13 +305,13 @@ describe('generation', () => {
301
305
  const user = person('uuid-123', numDays, true);
302
306
  expect(user).toHaveProperty('distinct_id');
303
307
  expect(user).toHaveProperty('name');
304
- expect(user.name).toBe('Anonymous User')
308
+ expect(user.name).toBe('Anonymous User');
305
309
  expect(user).toHaveProperty('email');
306
310
  expect(user.email.includes('*')).toBeTruthy();
307
311
  expect(user).not.toHaveProperty('avatar');
308
312
  expect(user).toHaveProperty('created');
309
- expect(user).toHaveProperty('anonymousIds');
310
- expect(user).toHaveProperty('sessionIds');
313
+ expect(user).not.toHaveProperty('anonymousIds');
314
+ expect(user).not.toHaveProperty('sessionIds');
311
315
  });
312
316
 
313
317
 
@@ -437,64 +441,64 @@ describe('validation', () => {
437
441
  const chosenTime = global.NOW - (60 * 60 * 24 * 15); // 15 days ago
438
442
  const earliestTime = global.NOW - (60 * 60 * 24 * 30); // 30 days ago
439
443
  const latestTime = global.NOW;
440
- expect(validateTime(chosenTime, earliestTime, latestTime)).toBe(true);
444
+ expect(validTime(chosenTime, earliestTime, latestTime)).toBe(true);
441
445
  });
442
446
 
443
447
  test('time: outside earliest', () => {
444
448
  const chosenTime = global.NOW - (60 * 60 * 24 * 31); // 31 days ago
445
449
  const earliestTime = global.NOW - (60 * 60 * 24 * 30); // 30 days ago
446
450
  const latestTime = global.NOW;
447
- expect(validateTime(chosenTime, earliestTime, latestTime)).toBe(false);
451
+ expect(validTime(chosenTime, earliestTime, latestTime)).toBe(false);
448
452
  });
449
453
 
450
454
  test('time: outside latest', () => {
451
455
  const chosenTime = -1;
452
456
  const earliestTime = global.NOW - (60 * 60 * 24 * 30); // 30 days ago
453
457
  const latestTime = global.NOW;
454
- expect(validateTime(chosenTime, earliestTime, latestTime)).toBe(false);
458
+ expect(validTime(chosenTime, earliestTime, latestTime)).toBe(false);
455
459
  });
456
460
 
457
461
  test('time: inference in', () => {
458
462
  const chosenTime = global.NOW - (60 * 60 * 24 * 15); // 15 days ago
459
- expect(validateTime(chosenTime)).toBe(true);
463
+ expect(validTime(chosenTime)).toBe(true);
460
464
  });
461
465
 
462
466
  test('time: inference out', () => {
463
467
  const chosenTime = global.NOW - (60 * 60 * 24 * 31); // 31 days ago
464
- expect(validateTime(chosenTime)).toBe(false);
468
+ expect(validTime(chosenTime)).toBe(false);
465
469
  });
466
470
  });
467
471
 
468
472
  describe('enrichment', () => {
469
473
 
470
- test('hooks: noop', () => {
474
+ test('hooks: noop', async () => {
471
475
  const arr = [];
472
- const enrichedArray = hookArray(arr);
473
- enrichedArray.hookPush(1);
474
- enrichedArray.hookPush(2);
476
+ const enrichedArray = await hookArray(arr);
477
+ await enrichedArray.hookPush(1);
478
+ await enrichedArray.hookPush(2);
475
479
  const match = JSON.stringify(enrichedArray) === JSON.stringify([1, 2]);
476
480
  expect(match).toEqual(true);
477
481
  });
478
482
 
479
- test('hook: double', () => {
483
+ test('hook: double', async () => {
480
484
  const arr = [];
481
485
  const hook = (item) => item * 2;
482
- const enrichedArray = hookArray(arr, { hook });
483
- enrichedArray.hookPush(1);
484
- enrichedArray.hookPush(2);
486
+ const enrichedArray = await hookArray(arr, { hook });
487
+ await enrichedArray.hookPush(1);
488
+ await enrichedArray.hookPush(2);
485
489
  expect(enrichedArray.includes(2)).toBeTruthy();
486
490
  expect(enrichedArray.includes(4)).toBeTruthy();
487
491
  });
488
492
 
489
- test('hooks: filter', () => {
493
+ test('hooks: filter', async () => {
490
494
  const arr = [];
491
495
  const hook = (item) => item ? item.toString() : item;
492
- const enrichedArray = hookArray(arr, { hook });
493
- enrichedArray.hookPush(null);
494
- enrichedArray.hookPush(undefined);
495
- enrichedArray.hookPush({});
496
- enrichedArray.hookPush({ a: 1 });
497
- enrichedArray.hookPush([1, 2]);
496
+ const enrichedArray = await hookArray(arr, { hook });
497
+ await enrichedArray.hookPush(null);
498
+ await enrichedArray.hookPush(undefined);
499
+ await enrichedArray.hookPush({});
500
+ await enrichedArray.hookPush({ a: 1 });
501
+ await enrichedArray.hookPush([1, 2]);
498
502
  expect(enrichedArray).toHaveLength(3);
499
503
  expect(enrichedArray.includes('null')).toBeFalsy();
500
504
  expect(enrichedArray.includes('undefined')).toBeFalsy();
@@ -664,7 +668,7 @@ describe('utilities', () => {
664
668
  });
665
669
 
666
670
  test('range: works', () => {
667
- const result = range(1,5);
671
+ const result = range(1, 5);
668
672
  expect(result).toEqual([1, 2, 3, 4, 5]);
669
673
  });
670
674
 
package/tsconfig.json CHANGED
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "include": [
13
13
  "**/*.js"
14
- , "soupTemplates.mjs", "tests/testSoup.mjs", "tests/testCases.mjs" ],
14
+ , "soupTemplates.mjs", "tests/testSoup.mjs", "tests/testCases.mjs", "tests/benchmark/concurrency.mjs" ],
15
15
  "exclude": [
16
16
  "node_modules"
17
17
  ]
package/types.d.ts CHANGED
@@ -13,6 +13,7 @@ declare namespace main {
13
13
  * main config object for the entire data generation
14
14
  */
15
15
  export interface Config {
16
+ // constants
16
17
  token?: string;
17
18
  seed?: string;
18
19
  numDays?: number;
@@ -20,9 +21,18 @@ declare namespace main {
20
21
  epochEnd?: number;
21
22
  numEvents?: number;
22
23
  numUsers?: number;
24
+ format?: "csv" | "json" | string;
25
+ region?: "US" | "EU";
26
+ concurrency?: number;
27
+ batchSize?: number;
28
+
29
+ // ids
30
+ simulationName?: string;
31
+ name?: string;
23
32
 
24
33
  //switches
25
34
  isAnonymous?: boolean;
35
+ hasAvatar?: boolean;
26
36
  hasLocation?: boolean;
27
37
  hasCampaigns?: boolean;
28
38
  hasAdSpend?: boolean;
@@ -30,10 +40,14 @@ declare namespace main {
30
40
  hasAndroidDevices?: boolean;
31
41
  hasDesktopDevices?: boolean;
32
42
  hasBrowser?: boolean;
43
+ writeToDisk?: boolean | string;
44
+ verbose?: boolean;
45
+ hasAnonIds?: boolean;
46
+ hasSessionIds?: boolean;
47
+ makeChart?: boolean | string;
33
48
 
34
- format?: "csv" | "json";
35
- region?: "US" | "EU";
36
- events?: EventConfig[]; //can also be a array of strings
49
+ //models
50
+ events?: EventConfig[]; //| string[]; //can also be a array of strings
37
51
  superProps?: Record<string, ValueValid>;
38
52
  funnels?: Funnel[];
39
53
  userProps?: Record<string, ValueValid>;
@@ -42,14 +56,11 @@ declare namespace main {
42
56
  groupKeys?: [string, number][] | [string, number, string[]][]; // [key, numGroups, [events]]
43
57
  groupProps?: Record<string, Record<string, ValueValid>>;
44
58
  lookupTables?: LookupTableSchema[];
45
- writeToDisk?: boolean;
46
- simulationName?: string;
47
- verbose?: boolean;
48
- anonIds?: boolean;
49
- sessionIds?: boolean;
50
- makeChart?: boolean | string;
51
59
  soup?: soup;
52
60
  hook?: Hook<any>;
61
+
62
+ //allow anything to be on the config
63
+ [key: string]: any;
53
64
  }
54
65
 
55
66
  /**
@@ -85,14 +96,42 @@ declare namespace main {
85
96
  export interface hookArrayOptions<T> {
86
97
  hook?: Hook<T>;
87
98
  type?: hookTypes;
99
+ filename?: string;
100
+ format?: "csv" | "json" | string;
101
+ concurrency?: number;
88
102
  [key: string]: any;
89
103
  }
90
104
 
91
105
  /**
92
106
  * an enriched array is an array that has a hookPush method that can be used to transform-then-push items into the array
93
107
  */
94
- export interface EnrichedArray<T> extends Array<T> {
95
- hookPush: (item: T) => boolean;
108
+ export interface HookedArray<T> extends Array<T> {
109
+ hookPush: (item: T | T[]) => any;
110
+ flush: () => void;
111
+ getWriteDir: () => string;
112
+ getWritePath: () => string;
113
+ [key: string]: any;
114
+ }
115
+
116
+ export type AllData =
117
+ | HookedArray<EventSchema>
118
+ | HookedArray<UserProfile>
119
+ | HookedArray<GroupProfileSchema>
120
+ | HookedArray<LookupTableSchema>
121
+ | HookedArray<SCDSchema>
122
+ | any[];
123
+
124
+ /**
125
+ * the storage object is a key-value store that holds arrays of data
126
+ */
127
+ export interface Storage {
128
+ eventData?: HookedArray<EventSchema>;
129
+ mirrorEventData?: HookedArray<EventSchema>;
130
+ userProfilesData?: HookedArray<UserProfile>;
131
+ adSpendData?: HookedArray<EventSchema>;
132
+ groupProfilesData?: HookedArray<GroupProfileSchema>[];
133
+ lookupTableData?: HookedArray<LookupTableSchema>[];
134
+ scdTableData?: HookedArray<SCDSchema>[];
96
135
  }
97
136
 
98
137
  /**
@@ -107,6 +146,20 @@ declare namespace main {
107
146
  relativeTimeMs?: number;
108
147
  }
109
148
 
149
+ /**
150
+ * the generated event data
151
+ */
152
+ export interface EventSchema {
153
+ event: string;
154
+ time: string;
155
+ source: string;
156
+ insert_id: string;
157
+ device_id?: string;
158
+ session_id?: string;
159
+ user_id?: string;
160
+ [key: string]: ValueValid;
161
+ }
162
+
110
163
  /**
111
164
  * how we define funnels and their properties
112
165
  */
@@ -133,13 +186,15 @@ declare namespace main {
133
186
  * how the events in the funnel are ordered for each user
134
187
  */
135
188
  order?:
189
+ | string
136
190
  | "sequential"
137
191
  | "first-fixed"
138
192
  | "last-fixed"
139
193
  | "random" //totally shuffled
140
194
  | "first-and-last-fixed"
141
195
  | "middle-fixed"
142
- | "interrupted"; //todo: explain this
196
+ | "interrupted";
197
+
143
198
  /**
144
199
  * todo: implement this
145
200
  * if set, the funnel might be the last thing the user does
@@ -178,29 +233,10 @@ declare namespace main {
178
233
  */
179
234
  strategy?: "create" | "update" | "fill" | "delete" | "";
180
235
  values?: ValueValid[];
181
- }
182
-
183
- /**
184
- * the generated event data
185
- */
186
- export interface EventSchema {
187
- event: string;
188
- time: string;
189
- insert_id: string;
190
- device_id?: string;
191
- session_id?: string;
192
- user_id?: string;
193
- [key: string]: ValueValid;
194
- }
195
-
196
- export interface EventData {
197
- event: string;
198
- source: string;
199
- time: string;
200
- device_id?: string;
201
- session_id?: string;
202
- user_id?: string;
203
- [key: string]: any;
236
+ /**
237
+ * optional: for 'fill' mode, daysUnfilled will dictate where the cutoff is in the unfilled data
238
+ */
239
+ daysUnfilled?: number;
204
240
  }
205
241
 
206
242
  export interface UserProfile {
@@ -214,8 +250,8 @@ declare namespace main {
214
250
 
215
251
  export interface Person {
216
252
  name: string;
217
- email: string;
218
- avatar: string;
253
+ email?: string;
254
+ avatar?: string;
219
255
  created: string | undefined;
220
256
  anonymousIds: string[];
221
257
  sessionIds: string[];
@@ -262,14 +298,21 @@ declare namespace main {
262
298
  * the end result of the data generation
263
299
  */
264
300
  export type Result = {
265
- eventData: EventData[];
301
+ eventData: EventSchema[];
302
+ mirrorEventData: EventSchema[];
266
303
  userProfilesData: any[];
267
304
  scdTableData: any[];
268
- adSpendData: EventData[];
305
+ adSpendData: EventSchema[];
269
306
  groupProfilesData: GroupProfileSchema[];
270
307
  lookupTableData: LookupTableData[];
271
308
  importResults?: ImportResults;
272
309
  files?: string[];
310
+ time?: {
311
+ start: number;
312
+ end: number;
313
+ delta: number;
314
+ human: string;
315
+ };
273
316
  };
274
317
  }
275
318