@engine9-io/input-tools 1.7.8 → 1.7.9
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/file/tools.js +70 -40
- package/index.js +27 -33
- package/package.json +1 -1
- package/test/processing/forEach.js +55 -0
- package/test/packet/forEach.js +0 -63
- /package/test/{packet → processing}/bigDataMessage.js +0 -0
- /package/test/{packet → processing}/message.js +0 -0
- /package/test/{packet → processing}/zip.js +0 -0
package/file/tools.js
CHANGED
|
@@ -14,16 +14,9 @@ const unzipper = require('unzipper');
|
|
|
14
14
|
|
|
15
15
|
const dayjs = require('dayjs');
|
|
16
16
|
|
|
17
|
-
const {
|
|
18
|
-
S3Client,
|
|
19
|
-
HeadObjectCommand,
|
|
20
|
-
GetObjectCommand,
|
|
21
|
-
} = require('@aws-sdk/client-s3');
|
|
17
|
+
const { S3Client, HeadObjectCommand, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
const {
|
|
25
|
-
v7: uuidv7,
|
|
26
|
-
} = require('uuid');
|
|
19
|
+
const { v7: uuidv7 } = require('uuid');
|
|
27
20
|
|
|
28
21
|
async function getTempDir({ accountId = 'engine9' }) {
|
|
29
22
|
const dir = [os.tmpdir(), accountId, new Date().toISOString().substring(0, 10)].join(path.sep);
|
|
@@ -52,7 +45,10 @@ async function getTempFilename(options) {
|
|
|
52
45
|
}
|
|
53
46
|
|
|
54
47
|
// make a distinct directory, so we don't overwrite the file
|
|
55
|
-
dir = `${dir}/${new Date()
|
|
48
|
+
dir = `${dir}/${new Date()
|
|
49
|
+
.toISOString()
|
|
50
|
+
.slice(0, -6)
|
|
51
|
+
.replace(/[^0-9]/g, '_')}`;
|
|
56
52
|
|
|
57
53
|
const newDir = await mkdirp(dir);
|
|
58
54
|
|
|
@@ -97,8 +93,8 @@ async function getPacketFiles({ packet }) {
|
|
|
97
93
|
const info = await s3Client.send(
|
|
98
94
|
new HeadObjectCommand({
|
|
99
95
|
Bucket,
|
|
100
|
-
Key
|
|
101
|
-
})
|
|
96
|
+
Key
|
|
97
|
+
})
|
|
102
98
|
);
|
|
103
99
|
size = info.ContentLength;
|
|
104
100
|
progress(`Retrieving file of size ${size / (1024 * 1024)} MB`);
|
|
@@ -107,13 +103,14 @@ async function getPacketFiles({ packet }) {
|
|
|
107
103
|
|
|
108
104
|
stream(offset, length) {
|
|
109
105
|
const ptStream = new PassThrough();
|
|
110
|
-
s3Client
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
106
|
+
s3Client
|
|
107
|
+
.send(
|
|
108
|
+
new GetObjectCommand({
|
|
109
|
+
Bucket,
|
|
110
|
+
Key,
|
|
111
|
+
Range: `bytes=${offset}-${length ?? ''}`
|
|
112
|
+
})
|
|
113
|
+
)
|
|
117
114
|
.then((response) => {
|
|
118
115
|
response.Body.pipe(ptStream);
|
|
119
116
|
})
|
|
@@ -122,7 +119,7 @@ async function getPacketFiles({ packet }) {
|
|
|
122
119
|
});
|
|
123
120
|
|
|
124
121
|
return ptStream;
|
|
125
|
-
}
|
|
122
|
+
}
|
|
126
123
|
});
|
|
127
124
|
|
|
128
125
|
return directory;
|
|
@@ -131,7 +128,6 @@ async function getPacketFiles({ packet }) {
|
|
|
131
128
|
return directory;
|
|
132
129
|
}
|
|
133
130
|
|
|
134
|
-
|
|
135
131
|
async function getManifest({ packet }) {
|
|
136
132
|
if (!packet) throw new Error('no packet option specififed');
|
|
137
133
|
const { files } = await getPacketFiles({ packet });
|
|
@@ -156,8 +152,8 @@ function getBatchTransform({ batchSize = 100 }) {
|
|
|
156
152
|
flush(cb) {
|
|
157
153
|
if (this.buffer?.length > 0) this.push(this.buffer);
|
|
158
154
|
cb();
|
|
159
|
-
}
|
|
160
|
-
})
|
|
155
|
+
}
|
|
156
|
+
})
|
|
161
157
|
};
|
|
162
158
|
}
|
|
163
159
|
function getDebatchTransform() {
|
|
@@ -167,8 +163,8 @@ function getDebatchTransform() {
|
|
|
167
163
|
transform(chunk, encoding, cb) {
|
|
168
164
|
chunk.forEach((c) => this.push(c));
|
|
169
165
|
cb();
|
|
170
|
-
}
|
|
171
|
-
})
|
|
166
|
+
}
|
|
167
|
+
})
|
|
172
168
|
};
|
|
173
169
|
}
|
|
174
170
|
|
|
@@ -218,7 +214,8 @@ async function downloadFile({ packet, type = 'person' }) {
|
|
|
218
214
|
const filename = await getTempFilename({ targetFilename: filePath.split('/').pop() });
|
|
219
215
|
|
|
220
216
|
return new Promise((resolve, reject) => {
|
|
221
|
-
fileStream
|
|
217
|
+
fileStream
|
|
218
|
+
.pipe(fs.createWriteStream(filename))
|
|
222
219
|
.on('error', reject)
|
|
223
220
|
.on('finish', () => {
|
|
224
221
|
resolve({ filename });
|
|
@@ -228,12 +225,12 @@ async function downloadFile({ packet, type = 'person' }) {
|
|
|
228
225
|
|
|
229
226
|
function isValidDate(d) {
|
|
230
227
|
// we WANT to use isNaN, not the Number.isNaN -- we're checking the date type
|
|
231
|
-
|
|
228
|
+
|
|
232
229
|
return d instanceof Date && !isNaN(d);
|
|
233
230
|
}
|
|
234
231
|
|
|
235
232
|
function bool(x, _defaultVal) {
|
|
236
|
-
const defaultVal =
|
|
233
|
+
const defaultVal = _defaultVal === undefined ? false : _defaultVal;
|
|
237
234
|
if (x === undefined || x === null || x === '') return defaultVal;
|
|
238
235
|
if (typeof x !== 'string') return !!x;
|
|
239
236
|
if (x === '1') return true; // 0 will return false, but '1' is true
|
|
@@ -255,7 +252,7 @@ function relativeDate(s, _initialDate) {
|
|
|
255
252
|
if (!s || s === 'none') return null;
|
|
256
253
|
if (typeof s.getMonth === 'function') return s;
|
|
257
254
|
// We actually want a double equals here to test strings as well
|
|
258
|
-
|
|
255
|
+
|
|
259
256
|
if (parseInt(s, 10) == s) {
|
|
260
257
|
const r = new Date(parseInt(s, 10));
|
|
261
258
|
if (!isValidDate(r)) throw new Error(`Invalid integer date:${s}`);
|
|
@@ -274,15 +271,31 @@ function relativeDate(s, _initialDate) {
|
|
|
274
271
|
let period = null;
|
|
275
272
|
switch (r[3]) {
|
|
276
273
|
case 'Y':
|
|
277
|
-
case 'y':
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
case '
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
case '
|
|
285
|
-
|
|
274
|
+
case 'y':
|
|
275
|
+
period = 'years';
|
|
276
|
+
break;
|
|
277
|
+
|
|
278
|
+
case 'M':
|
|
279
|
+
period = 'months';
|
|
280
|
+
break;
|
|
281
|
+
case 'w':
|
|
282
|
+
period = 'weeks';
|
|
283
|
+
break;
|
|
284
|
+
case 'd':
|
|
285
|
+
period = 'days';
|
|
286
|
+
break;
|
|
287
|
+
case 'h':
|
|
288
|
+
period = 'hours';
|
|
289
|
+
break;
|
|
290
|
+
case 'm':
|
|
291
|
+
period = 'minutes';
|
|
292
|
+
break;
|
|
293
|
+
case 's':
|
|
294
|
+
period = 'seconds';
|
|
295
|
+
break;
|
|
296
|
+
default:
|
|
297
|
+
period = 'minutes';
|
|
298
|
+
break;
|
|
286
299
|
}
|
|
287
300
|
|
|
288
301
|
let d = dayjs(initialDate);
|
|
@@ -317,12 +330,29 @@ function relativeDate(s, _initialDate) {
|
|
|
317
330
|
*/
|
|
318
331
|
function makeStrings(o) {
|
|
319
332
|
return Object.entries(o).reduce((a, [k, v]) => {
|
|
320
|
-
a[k] =
|
|
333
|
+
a[k] = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
321
334
|
return a;
|
|
322
335
|
}, {});
|
|
323
336
|
}
|
|
337
|
+
function appendPostfix(filename, postfix) {
|
|
338
|
+
const filenameParts = filename.split('/');
|
|
339
|
+
const fileParts = filenameParts
|
|
340
|
+
.slice(-1)[0]
|
|
341
|
+
.split('.')
|
|
342
|
+
.filter(Boolean)
|
|
343
|
+
.filter((d) => d !== postfix);
|
|
344
|
+
|
|
345
|
+
let targetFile = null;
|
|
346
|
+
if (fileParts.slice(-1)[0] === 'gz') {
|
|
347
|
+
targetFile = fileParts.slice(0, -2).concat(postfix).concat(fileParts.slice(-2)).join('.');
|
|
348
|
+
} else {
|
|
349
|
+
targetFile = fileParts.slice(0, -1).concat(postfix).concat(fileParts.slice(-1)).join('.');
|
|
350
|
+
}
|
|
351
|
+
return filenameParts.slice(0, -1).concat(targetFile).join('/');
|
|
352
|
+
}
|
|
324
353
|
|
|
325
354
|
module.exports = {
|
|
355
|
+
appendPostfix,
|
|
326
356
|
bool,
|
|
327
357
|
downloadFile,
|
|
328
358
|
getTempFilename,
|
|
@@ -336,5 +366,5 @@ module.exports = {
|
|
|
336
366
|
makeStrings,
|
|
337
367
|
relativeDate,
|
|
338
368
|
streamPacket,
|
|
339
|
-
writeTempFile
|
|
369
|
+
writeTempFile
|
|
340
370
|
};
|
package/index.js
CHANGED
|
@@ -6,15 +6,14 @@ const dayjs = require('dayjs');
|
|
|
6
6
|
const debug = require('debug')('@engine9/input-tools');
|
|
7
7
|
|
|
8
8
|
const unzipper = require('unzipper');
|
|
9
|
-
const {
|
|
10
|
-
v4: uuidv4, v5: uuidv5, v7: uuidv7, validate: uuidIsValid,
|
|
11
|
-
} = require('uuid');
|
|
9
|
+
const { v4: uuidv4, v5: uuidv5, v7: uuidv7, validate: uuidIsValid } = require('uuid');
|
|
12
10
|
const archiver = require('archiver');
|
|
13
11
|
const handlebars = require('handlebars');
|
|
14
12
|
|
|
15
13
|
const FileUtilities = require('./file/FileUtilities');
|
|
16
14
|
|
|
17
15
|
const {
|
|
16
|
+
appendPostfix,
|
|
18
17
|
bool,
|
|
19
18
|
getManifest,
|
|
20
19
|
getFile,
|
|
@@ -29,7 +28,7 @@ const {
|
|
|
29
28
|
getDebatchTransform,
|
|
30
29
|
getStringArray,
|
|
31
30
|
makeStrings,
|
|
32
|
-
writeTempFile
|
|
31
|
+
writeTempFile
|
|
33
32
|
} = require('./file/tools');
|
|
34
33
|
|
|
35
34
|
const ForEachEntry = require('./ForEachEntry');
|
|
@@ -45,7 +44,7 @@ function getFormattedDate(dateObject, format = 'MMM DD,YYYY') {
|
|
|
45
44
|
|
|
46
45
|
handlebars.registerHelper('date', (d, f) => {
|
|
47
46
|
let format;
|
|
48
|
-
if (typeof f === 'string')format = f;
|
|
47
|
+
if (typeof f === 'string') format = f;
|
|
49
48
|
return getFormattedDate(d, format);
|
|
50
49
|
});
|
|
51
50
|
handlebars.registerHelper('json', (d) => JSON.stringify(d));
|
|
@@ -60,11 +59,7 @@ async function list(_path) {
|
|
|
60
59
|
const directory = await unzipper.Open.file(_path);
|
|
61
60
|
|
|
62
61
|
return new Promise((resolve, reject) => {
|
|
63
|
-
directory.files[0]
|
|
64
|
-
.stream()
|
|
65
|
-
.pipe(fs.createWriteStream('firstFile'))
|
|
66
|
-
.on('error', reject)
|
|
67
|
-
.on('finish', resolve);
|
|
62
|
+
directory.files[0].stream().pipe(fs.createWriteStream('firstFile')).on('error', reject).on('finish', resolve);
|
|
68
63
|
});
|
|
69
64
|
}
|
|
70
65
|
|
|
@@ -74,11 +69,7 @@ async function extract(_path, _file) {
|
|
|
74
69
|
const file = directory.files.find((d) => d.path === _file);
|
|
75
70
|
const tempFilename = await getTempFilename({ source: _file });
|
|
76
71
|
return new Promise((resolve, reject) => {
|
|
77
|
-
file
|
|
78
|
-
.stream()
|
|
79
|
-
.pipe(fs.createWriteStream(tempFilename))
|
|
80
|
-
.on('error', reject)
|
|
81
|
-
.on('finish', resolve);
|
|
72
|
+
file.stream().pipe(fs.createWriteStream(tempFilename)).on('error', reject).on('finish', resolve);
|
|
82
73
|
});
|
|
83
74
|
}
|
|
84
75
|
|
|
@@ -87,7 +78,7 @@ function appendFiles(existingFiles, _newFiles, options) {
|
|
|
87
78
|
if (newFiles.length === 0) return;
|
|
88
79
|
let { type, dateCreated } = options || {};
|
|
89
80
|
if (!type) type = 'unknown';
|
|
90
|
-
if (!dateCreated)dateCreated = new Date().toISOString();
|
|
81
|
+
if (!dateCreated) dateCreated = new Date().toISOString();
|
|
91
82
|
let arr = newFiles;
|
|
92
83
|
if (!Array.isArray(newFiles)) arr = [arr];
|
|
93
84
|
|
|
@@ -96,7 +87,7 @@ function appendFiles(existingFiles, _newFiles, options) {
|
|
|
96
87
|
type,
|
|
97
88
|
originalFilename: '',
|
|
98
89
|
isNew: true,
|
|
99
|
-
dateCreated
|
|
90
|
+
dateCreated
|
|
100
91
|
};
|
|
101
92
|
|
|
102
93
|
if (typeof p === 'string') {
|
|
@@ -121,7 +112,7 @@ async function create(options) {
|
|
|
121
112
|
messageFiles = [], // file with contents of message, used for delivery
|
|
122
113
|
personFiles = [], // files with data on people
|
|
123
114
|
timelineFiles = [], // activity entry
|
|
124
|
-
statisticsFiles = []
|
|
115
|
+
statisticsFiles = [] // files with aggregate statistics
|
|
125
116
|
} = options;
|
|
126
117
|
if (options.peopleFiles) throw new Error('Unknown option: peopleFiles, did you mean personFiles?');
|
|
127
118
|
|
|
@@ -132,21 +123,21 @@ async function create(options) {
|
|
|
132
123
|
appendFiles(files, timelineFiles, { type: 'timeline', dateCreated });
|
|
133
124
|
appendFiles(files, statisticsFiles, { type: 'statistics', dateCreated });
|
|
134
125
|
|
|
135
|
-
const zipFilename = target || await getTempFilename({ postfix: '.packet.zip' });
|
|
126
|
+
const zipFilename = target || (await getTempFilename({ postfix: '.packet.zip' }));
|
|
136
127
|
|
|
137
128
|
const manifest = {
|
|
138
129
|
accountId,
|
|
139
130
|
source: {
|
|
140
|
-
pluginId
|
|
131
|
+
pluginId
|
|
141
132
|
},
|
|
142
133
|
dateCreated,
|
|
143
|
-
files
|
|
134
|
+
files
|
|
144
135
|
};
|
|
145
136
|
|
|
146
137
|
// create a file to stream archive data to.
|
|
147
138
|
const output = fs.createWriteStream(zipFilename);
|
|
148
139
|
const archive = archiver('zip', {
|
|
149
|
-
zlib: { level: 9 }
|
|
140
|
+
zlib: { level: 9 } // Sets the compression level.
|
|
150
141
|
});
|
|
151
142
|
return new Promise((resolve, reject) => {
|
|
152
143
|
debug(`Setting up write stream to ${zipFilename}`);
|
|
@@ -157,7 +148,7 @@ async function create(options) {
|
|
|
157
148
|
debug(zipFilename);
|
|
158
149
|
return resolve({
|
|
159
150
|
filename: zipFilename,
|
|
160
|
-
bytes: archive.pointer()
|
|
151
|
+
bytes: archive.pointer()
|
|
161
152
|
});
|
|
162
153
|
});
|
|
163
154
|
|
|
@@ -196,7 +187,6 @@ function intToByteArray(_v) {
|
|
|
196
187
|
const byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
|
|
197
188
|
let v = _v;
|
|
198
189
|
for (let index = 0; index < byteArray.length; index += 1) {
|
|
199
|
-
// eslint-disable-next-line no-bitwise
|
|
200
190
|
const byte = v & 0xff;
|
|
201
191
|
byteArray[index] = byte;
|
|
202
192
|
v = (v - byte) / 256;
|
|
@@ -226,23 +216,26 @@ function getInputUUID(a, b) {
|
|
|
226
216
|
return uuidv5(`${pluginId}:${rid}`, '3d0e5d99-6ba9-4fab-9bb2-c32304d3df8e');
|
|
227
217
|
}
|
|
228
218
|
|
|
229
|
-
function getUUIDv7(date, inputUuid) {
|
|
219
|
+
function getUUIDv7(date, inputUuid) {
|
|
220
|
+
/* optional date and input UUID */
|
|
230
221
|
const uuid = inputUuid || uuidv7();
|
|
231
222
|
const bytes = Buffer.from(uuid.replace(/-/g, ''), 'hex');
|
|
232
223
|
if (date !== undefined) {
|
|
233
224
|
const d = new Date(date);
|
|
234
225
|
// isNaN behaves differently than Number.isNaN -- we're actually going for the
|
|
235
226
|
// attempted conversion here
|
|
236
|
-
|
|
227
|
+
|
|
237
228
|
if (isNaN(d)) throw new Error(`getUUIDv7 got an invalid date:${date || '<blank>'}`);
|
|
238
229
|
const dateBytes = intToByteArray(d.getTime()).reverse();
|
|
239
|
-
dateBytes.slice(2, 8).forEach((b, i) => {
|
|
230
|
+
dateBytes.slice(2, 8).forEach((b, i) => {
|
|
231
|
+
bytes[i] = b;
|
|
232
|
+
});
|
|
240
233
|
}
|
|
241
234
|
return uuidv4({ random: bytes });
|
|
242
235
|
}
|
|
243
236
|
/* Returns a date from a given uuid (assumed to be a v7, otherwise the results are ... weird */
|
|
244
237
|
function getUUIDTimestamp(uuid) {
|
|
245
|
-
const ts = parseInt(
|
|
238
|
+
const ts = parseInt(`${uuid}`.replace(/-/g, '').slice(0, 12), 16);
|
|
246
239
|
return new Date(ts);
|
|
247
240
|
}
|
|
248
241
|
|
|
@@ -266,7 +259,8 @@ function getTimelineEntryUUID(inputObject, { defaults = {} } = {}) {
|
|
|
266
259
|
|
|
267
260
|
if (o.remote_entry_id) {
|
|
268
261
|
// get a temp ID
|
|
269
|
-
if (!o.input_id)
|
|
262
|
+
if (!o.input_id)
|
|
263
|
+
throw new Error('Error generating timeline entry uuid -- remote_entry_id specified, but no input_id');
|
|
270
264
|
const uuid = uuidv5(o.remote_entry_id, o.input_id);
|
|
271
265
|
// Change out the ts to match the v7 sorting.
|
|
272
266
|
// But because outside specified remote_entry_uuid
|
|
@@ -274,14 +268,13 @@ function getTimelineEntryUUID(inputObject, { defaults = {} } = {}) {
|
|
|
274
268
|
return getUUIDv7(o.ts, uuid);
|
|
275
269
|
}
|
|
276
270
|
|
|
277
|
-
const missing = requiredTimelineEntryFields
|
|
278
|
-
.filter((d) => o[d] === undefined);// 0 could be an entry type value
|
|
271
|
+
const missing = requiredTimelineEntryFields.filter((d) => o[d] === undefined); // 0 could be an entry type value
|
|
279
272
|
|
|
280
273
|
if (missing.length > 0) throw new Error(`Missing required fields to append an entry_id:${missing.join(',')}`);
|
|
281
274
|
const ts = new Date(o.ts);
|
|
282
275
|
// isNaN behaves differently than Number.isNaN -- we're actually going for the
|
|
283
276
|
// attempted conversion here
|
|
284
|
-
|
|
277
|
+
|
|
285
278
|
if (isNaN(ts)) throw new Error(`getTimelineEntryUUID got an invalid date:${o.ts || '<blank>'}`);
|
|
286
279
|
const idString = `${ts.toISOString()}-${o.person_id}-${o.entry_type_id}-${o.source_code_id || 0}`;
|
|
287
280
|
|
|
@@ -308,6 +301,7 @@ function getEntryTypeId(o, { defaults = {} } = {}) {
|
|
|
308
301
|
}
|
|
309
302
|
|
|
310
303
|
module.exports = {
|
|
304
|
+
appendPostfix,
|
|
311
305
|
bool,
|
|
312
306
|
create,
|
|
313
307
|
list,
|
|
@@ -339,5 +333,5 @@ module.exports = {
|
|
|
339
333
|
uuidIsValid,
|
|
340
334
|
uuidv4,
|
|
341
335
|
uuidv5,
|
|
342
|
-
uuidv7
|
|
336
|
+
uuidv7
|
|
343
337
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const { describe, it } = require('node:test');
|
|
2
|
+
const assert = require('node:assert');
|
|
3
|
+
const debug = require('debug')('test/forEach');
|
|
4
|
+
|
|
5
|
+
const { ForEachEntry } = require('../../index');
|
|
6
|
+
|
|
7
|
+
describe('Test Person File For Each', async () => {
|
|
8
|
+
it('forEachPerson Should loop through 1000 sample people', async () => {
|
|
9
|
+
let counter = 0;
|
|
10
|
+
const forEach = new ForEachEntry();
|
|
11
|
+
const result = await forEach.process({
|
|
12
|
+
packet: 'test/sample/1000_message.packet.zip',
|
|
13
|
+
batchSize: 50,
|
|
14
|
+
bindings: {
|
|
15
|
+
timelineOutputFileStream: {
|
|
16
|
+
path: 'output.timeline',
|
|
17
|
+
options: {
|
|
18
|
+
entry_type: 'ENTRY_OPTION'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
sampleOutputFileStream: {
|
|
22
|
+
path: 'output.stream'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
async transform(props) {
|
|
26
|
+
const { batch, timelineOutputFileStream, sampleOutputFileStream } = props;
|
|
27
|
+
|
|
28
|
+
batch.forEach((p) => {
|
|
29
|
+
if (Math.random() > 0.9) {
|
|
30
|
+
sampleOutputFileStream.push({
|
|
31
|
+
// for testing we don't need real person_ids
|
|
32
|
+
person_id: p.person_id || Math.floor(Math.random() * 1000000),
|
|
33
|
+
email: p.email,
|
|
34
|
+
entry_type: 'SAMPLE_OUTPUT'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
timelineOutputFileStream.push({
|
|
38
|
+
// for testing we don't need real person_ids
|
|
39
|
+
person_id: p.person_id || Math.floor(Math.random() * 1000000),
|
|
40
|
+
email: p.email,
|
|
41
|
+
entry_type: 'EMAIL_DELIVERED'
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
batch.forEach(() => {
|
|
46
|
+
counter += 1;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
assert(result.outputFiles?.timelineOutputFileStream?.[0]?.records);
|
|
51
|
+
assert(result.outputFiles?.sampleOutputFileStream?.[0]?.records);
|
|
52
|
+
assert.equal(counter, 1000, `Expected to loop through 1000 people, actual:${counter}`);
|
|
53
|
+
});
|
|
54
|
+
debug('Completed tests');
|
|
55
|
+
});
|
package/test/packet/forEach.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
describe, it,
|
|
3
|
-
} = require('node:test');
|
|
4
|
-
const assert = require('node:assert');
|
|
5
|
-
const debug = require('debug')('test/forEach');
|
|
6
|
-
|
|
7
|
-
const { ForEachEntry } = require('../../index');
|
|
8
|
-
|
|
9
|
-
describe('Test Person Packet For Each', async () => {
|
|
10
|
-
it('forEachPerson Should loop through 1000 sample people', async () => {
|
|
11
|
-
let counter = 0;
|
|
12
|
-
const forEach = new ForEachEntry();
|
|
13
|
-
const result = await forEach.process(
|
|
14
|
-
{
|
|
15
|
-
packet: 'test/sample/1000_message.packet.zip',
|
|
16
|
-
batchSize: 50,
|
|
17
|
-
bindings: {
|
|
18
|
-
timelineOutputFileStream: {
|
|
19
|
-
path: 'output.timeline',
|
|
20
|
-
options: {
|
|
21
|
-
entry_type: 'ENTRY_OPTION',
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
sampleOutputFileStream: {
|
|
25
|
-
path: 'output.stream',
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
async transform(props) {
|
|
29
|
-
const {
|
|
30
|
-
batch,
|
|
31
|
-
timelineOutputFileStream,
|
|
32
|
-
sampleOutputFileStream,
|
|
33
|
-
} = props;
|
|
34
|
-
|
|
35
|
-
batch.forEach((p) => {
|
|
36
|
-
if (Math.random() > 0.9) {
|
|
37
|
-
sampleOutputFileStream.push({
|
|
38
|
-
// for testing we don't need real person_ids
|
|
39
|
-
person_id: p.person_id || Math.floor(Math.random() * 1000000),
|
|
40
|
-
email: p.email,
|
|
41
|
-
entry_type: 'SAMPLE_OUTPUT',
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
timelineOutputFileStream.push(
|
|
45
|
-
{
|
|
46
|
-
// for testing we don't need real person_ids
|
|
47
|
-
person_id: p.person_id || Math.floor(Math.random() * 1000000),
|
|
48
|
-
email: p.email,
|
|
49
|
-
entry_type: 'EMAIL_DELIVERED',
|
|
50
|
-
},
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
batch.forEach(() => { counter += 1; });
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
);
|
|
58
|
-
assert(result.outputFiles?.timelineOutputFileStream?.[0]?.records);
|
|
59
|
-
assert(result.outputFiles?.sampleOutputFileStream?.[0]?.records);
|
|
60
|
-
assert.equal(counter, 1000, `Expected to loop through 1000 people, actual:${counter}`);
|
|
61
|
-
});
|
|
62
|
-
debug('Completed tests');
|
|
63
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|