vaporous 0.0.9 → 0.0.11

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/Vaporous.js CHANGED
@@ -4,13 +4,17 @@ const By = require('./types/By');
4
4
  const Aggregation = require('./types/Aggregation');
5
5
  const Window = require('./types/Window')
6
6
 
7
- // Import mixins
8
- const utilsMixin = require('./src/utils');
9
- const transformationsMixin = require('./src/transformations');
10
- const fileOperationsMixin = require('./src/fileOperations');
11
- const statisticsMixin = require('./src/statistics');
12
- const checkpointsMixin = require('./src/checkpoints');
13
- const visualizationMixin = require('./src/visualization');
7
+ // Import mixin implementations
8
+ const core = require('./src/core');
9
+ const utils = require('./src/utils');
10
+ const transformations = require('./src/transformations');
11
+ const fileOperations = require('./src/fileOperations');
12
+ const statistics = require('./src/statistics');
13
+ const checkpoints = require('./src/checkpoints');
14
+ const visualization = require('./src/visualization');
15
+ const http = require('./src/http')
16
+ const processing = require('./src/processing')
17
+ const path = require('path')
14
18
 
15
19
  class Vaporous {
16
20
 
@@ -28,83 +32,484 @@ class Vaporous {
28
32
  this.loggers = loggers
29
33
  this.perf = null
30
34
  this.totalTime = 0
31
- }
32
35
 
33
- manageEntry() {
34
- if (this.loggers?.perf) {
35
- const [, , method, ...origination] = new Error().stack.split('\n')
36
- const invokedMethod = method.match(/Vaporous.(.+?) /)
36
+ this.intervals = []
37
+ this.processingQueue = []
37
38
 
38
- let orig = origination.find(orig => {
39
- const originator = orig.split("/").at(-1)
40
- return !originator.includes("Vaporous")
41
- })
39
+ this._isExecuting = false
42
40
 
43
- orig = orig.split("/").at(-1)
44
- const logLine = "(" + orig + " BEGIN " + invokedMethod[1]
45
- this.loggers.perf('info', logLine)
46
- this.perf = { time: new Date().valueOf(), logLine }
47
- }
48
- }
41
+ // Return a proxy that intercepts method calls
42
+ const proxy = new Proxy(this, {
43
+ get(target, prop, receiver) {
44
+
45
+ // If this is not a function then return actual value
46
+ if (typeof target[prop] !== 'function') return target[prop];
47
+
48
+ const value = target[prop]
49
49
 
50
- manageExit() {
51
- if (this.loggers?.perf) {
52
- let { logLine, time } = this.perf;
53
- const executionTime = new Date() - time
54
- this.totalTime += executionTime
50
+ // If it's a function we should queue it
51
+ if (typeof value === 'function'
52
+ && !target._isExecuting
53
+ && target._shouldQueue(prop)) {
54
+ return function (...args) {
55
+ let err = {}
56
+ Error.captureStackTrace(err, proxy);
57
+ err = err.stack.split('\n')[2]
58
+ err = path.parse(err).base.replace(")", "")
59
+ target.processingQueue.push([prop, args, { stack: err }])
60
+ return receiver // Return the proxy, not the target!
61
+ }
62
+ }
55
63
 
56
- const match = logLine.match(/^.*?BEGIN/);
57
- const prepend = "END"
58
- if (match) {
59
- const toReplace = match[0]; // the matched substring
60
- const spaces = " ".repeat(toReplace.length - prepend.length); // same length, all spaces
61
- logLine = spaces + prepend + logLine.replace(toReplace, "");
64
+ return target[prop]
62
65
  }
66
+ })
63
67
 
64
- this.loggers.perf('info', logLine + " (" + executionTime + "ms)")
65
- }
66
- return this
68
+ return proxy;
67
69
  }
68
70
 
69
- method(operation, name, options) {
70
- if (operation != 'retrieve') this.manageEntry()
71
- const operations = {
72
- create: () => {
73
- this.savedMethods[name] = options
74
- },
75
- retrieve: () => {
76
- this.savedMethods[name](this, options)
77
- },
78
- delete: () => {
79
- delete this.savedMethods[name]
80
- }
81
- }
71
+ _shouldQueue(methodName) {
72
+ const nonQueueable = ['begin', 'clone', 'serialise', 'destroy', '_shouldQueue', 'valueOf', 'toString']
73
+ return !nonQueueable.includes(methodName)
74
+ }
82
75
 
76
+ // ========================================
77
+ // Core methods
78
+ // ========================================
83
79
 
84
- operations[operation]()
85
- if (operation !== 'retrieve') return this.manageExit()
86
- return this;
80
+ /**
81
+ * Create, retrieve, or delete saved methods
82
+ * @param {string} operation - 'create', 'retrieve', or 'delete'
83
+ * @param {string} name - Method name
84
+ * @param {*} options - Method options or function
85
+ * @returns {Vaporous} - Returns this instance for chaining
86
+ */
87
+ method(operation, name, options) {
88
+ return processing.method.call(this, operation, name, options);
87
89
  }
88
90
 
91
+ /**
92
+ * Filter events using a predicate function
93
+ * @param {...*} args - Arguments to pass to Array.filter
94
+ * @returns {Vaporous} - Returns this instance for chaining
95
+ */
89
96
  filter(...args) {
90
- this.manageEntry()
91
- this.events = this.events.filter(...args)
92
- return this.manageExit()
97
+ return core.filter.call(this, ...args);
93
98
  }
94
99
 
100
+ /**
101
+ * Append new entities to events
102
+ * @param {Array} entities - Array of entities to append
103
+ * @returns {Vaporous} - Returns this instance for chaining
104
+ */
95
105
  append(entities) {
96
- this.manageEntry()
97
- this.events = this.events.concat(entities)
98
- return this.manageExit()
106
+ return core.append.call(this, entities);
107
+ }
108
+
109
+ /**
110
+ * Execute all queued operations
111
+ * @param {string} [stageName] - Optional stage name for logging
112
+ * @returns {Promise<Vaporous>} - Returns this instance for chaining
113
+ */
114
+ begin(stageName) {
115
+ return core.begin.call(this, stageName);
116
+ }
117
+
118
+ /**
119
+ * Serialize the Vaporous instance to a plain object
120
+ * @returns {Object} - Serialized instance data
121
+ */
122
+ serialise({ } = {}) {
123
+ return core.serialise.call(this);
124
+ }
125
+
126
+ /**
127
+ * Clone the Vaporous instance
128
+ * @param {Object} [options] - Clone options
129
+ * @param {boolean} [options.deep] - Whether to perform a deep clone
130
+ * @returns {Vaporous} - Returns cloned instance
131
+ */
132
+ clone({ deep } = {}) {
133
+ return core.clone.call(this, { deep });
134
+ }
135
+
136
+ /**
137
+ * Destroy the Vaporous instance and clean up resources
138
+ * @returns {Vaporous} - Returns this instance for chaining
139
+ */
140
+ destroy() {
141
+ return core.destroy.call(this);
142
+ }
143
+
144
+ // ========================================
145
+ // Utils methods
146
+ // ========================================
147
+
148
+ /**
149
+ * Sort events by specified keys
150
+ * @param {string} order - 'asc' or 'dsc'
151
+ * @param {...string} keys - Keys to sort by
152
+ * @returns {Vaporous} - Returns this instance for chaining
153
+ */
154
+ sort(order, ...keys) {
155
+ return utils.sort.call(this, order, ...keys);
156
+ }
157
+
158
+ /**
159
+ * Assert conditions on each event
160
+ * @param {Function} funct - Function that receives (event, index, {expect}) and performs assertions
161
+ * @returns {Vaporous} - Returns this instance for chaining
162
+ */
163
+ assert(funct) {
164
+ return utils.assert.call(this, funct);
165
+ }
166
+
167
+ // ========================================
168
+ // Transformation methods
169
+ // ========================================
170
+
171
+ /**
172
+ * Evaluate and modify each event
173
+ * @param {Function} modifier - Function that receives an event and returns modifications to apply
174
+ * @param {boolean} [discard] - Whether to discard the event if modifier returns falsy
175
+ * @returns {Vaporous} - Returns this instance for chaining
176
+ */
177
+ eval(modifier, discard) {
178
+ return transformations.eval.call(this, modifier, discard);
99
179
  }
100
- }
101
180
 
102
- // Apply mixins to Vaporous prototype
103
- Object.assign(Vaporous.prototype, utilsMixin);
104
- Object.assign(Vaporous.prototype, transformationsMixin);
105
- Object.assign(Vaporous.prototype, fileOperationsMixin);
106
- Object.assign(Vaporous.prototype, statisticsMixin);
107
- Object.assign(Vaporous.prototype, checkpointsMixin);
108
- Object.assign(Vaporous.prototype, visualizationMixin);
181
+ /**
182
+ * Internal table transformation helper
183
+ * @private
184
+ */
185
+ _table(modifier) {
186
+ return transformations._table.call(this, modifier);
187
+ }
188
+
189
+ /**
190
+ * Transform events into a table format
191
+ * @param {Function} modifier - Function that receives an event and returns the transformed row
192
+ * @returns {Vaporous} - Returns this instance for chaining
193
+ */
194
+ table(modifier) {
195
+ return transformations.table.call(this, modifier);
196
+ }
197
+
198
+ /**
199
+ * Rename fields in events
200
+ * @param {...Array} entities - Arrays of [from, to] field name pairs
201
+ * @returns {Vaporous} - Returns this instance for chaining
202
+ */
203
+ rename(...entities) {
204
+ return transformations.rename.call(this, ...entities);
205
+ }
206
+
207
+ /**
208
+ * Parse time fields into timestamps
209
+ * @param {string} value - Field name containing time value
210
+ * @param {string} [customFormat] - Optional custom time format
211
+ * @returns {Vaporous} - Returns this instance for chaining
212
+ */
213
+ parseTime(value, customFormat) {
214
+ return transformations.parseTime.call(this, value, customFormat);
215
+ }
216
+
217
+ /**
218
+ * Bin numeric values into intervals
219
+ * @param {string} value - Field name to bin
220
+ * @param {number} span - Bin size
221
+ * @returns {Vaporous} - Returns this instance for chaining
222
+ */
223
+ bin(value, span) {
224
+ return transformations.bin.call(this, value, span);
225
+ }
226
+
227
+ /**
228
+ * Flatten nested arrays in events
229
+ * @param {number} [depth=1] - Depth to flatten
230
+ * @returns {Vaporous} - Returns this instance for chaining
231
+ */
232
+ flatten(depth = 1) {
233
+ return transformations.flatten.call(this, depth);
234
+ }
235
+
236
+ /**
237
+ * Expand array field into multiple events
238
+ * @param {string} target - Field name containing array to expand
239
+ * @returns {Vaporous} - Returns this instance for chaining
240
+ */
241
+ mvexpand(target) {
242
+ return transformations.mvexpand.call(this, target);
243
+ }
244
+
245
+ // ========================================
246
+ // File operations methods
247
+ // ========================================
248
+
249
+ /**
250
+ * Internal file scan helper
251
+ * @private
252
+ */
253
+ _fileScan(directory) {
254
+ return fileOperations._fileScan.call(this, directory);
255
+ }
256
+
257
+ /**
258
+ * Internal file load helper
259
+ * @private
260
+ */
261
+ _fileLoad(events, delim, parser) {
262
+ return fileOperations._fileLoad.call(this, events, delim, parser);
263
+ }
264
+
265
+ /**
266
+ * Scan a directory for files
267
+ * @param {string} directory - Directory path to scan
268
+ * @returns {Vaporous} - Returns this instance for chaining
269
+ */
270
+ fileScan(directory) {
271
+ return fileOperations.fileScan.call(this, directory);
272
+ }
273
+
274
+ /**
275
+ * Load CSV files
276
+ * @param {Function} parser - Parser function for CSV rows
277
+ * @returns {Vaporous} - Returns this instance for chaining
278
+ */
279
+ csvLoad(parser) {
280
+ return fileOperations.csvLoad.call(this, parser);
281
+ }
282
+
283
+ /**
284
+ * Load files with custom delimiter and parser
285
+ * @param {string} delim - Delimiter for splitting file content
286
+ * @param {Function} parser - Parser function for lines
287
+ * @returns {Vaporous} - Returns this instance for chaining
288
+ */
289
+ fileLoad(delim, parser) {
290
+ return fileOperations.fileLoad.call(this, delim, parser);
291
+ }
292
+
293
+ /**
294
+ * Write events to file
295
+ * @param {string} title - File name to write to
296
+ * @returns {Vaporous} - Returns this instance for chaining
297
+ */
298
+ writeFile(title) {
299
+ return fileOperations.writeFile.call(this, title);
300
+ }
301
+
302
+ /**
303
+ * Output events to console or file
304
+ * @param {...string} [args] - Optional field names to output
305
+ * @returns {Vaporous} - Returns this instance for chaining
306
+ */
307
+ output(...args) {
308
+ return fileOperations.output.call(this, ...args);
309
+ }
310
+
311
+ // ========================================
312
+ // Statistics methods
313
+ // ========================================
314
+
315
+ /**
316
+ * Internal statistics calculation helper
317
+ * @private
318
+ */
319
+ _stats(args, events) {
320
+ return statistics._stats.call(this, args, events);
321
+ }
322
+
323
+ /**
324
+ * Calculate statistics with aggregations
325
+ * @param {...(Aggregation|By)} args - Aggregation and By objects for statistical operations
326
+ * @returns {Vaporous} - Returns this instance for chaining
327
+ */
328
+ stats(...args) {
329
+ return statistics.stats.call(this, ...args);
330
+ }
331
+
332
+ /**
333
+ * Add statistics to each event based on grouping
334
+ * @param {...(Aggregation|By)} args - Aggregation and By objects for statistical operations
335
+ * @returns {Vaporous} - Returns this instance for chaining
336
+ */
337
+ eventstats(...args) {
338
+ return statistics.eventstats.call(this, ...args);
339
+ }
340
+
341
+ /**
342
+ * Internal streaming statistics helper
343
+ * @private
344
+ */
345
+ _streamstats(...args) {
346
+ return statistics._streamstats.call(this, ...args);
347
+ }
348
+
349
+ /**
350
+ * Calculate cumulative statistics over a window
351
+ * @param {...(Aggregation|By|Window)} args - Aggregation, By, and Window objects
352
+ * @returns {Vaporous} - Returns this instance for chaining
353
+ */
354
+ streamstats(...args) {
355
+ return statistics.streamstats.call(this, ...args);
356
+ }
357
+
358
+ /**
359
+ * Calculate delta (range) between consecutive values
360
+ * @param {string} field - Field to calculate delta for
361
+ * @param {string} remapField - Output field name
362
+ * @param {...By} bys - Optional By objects for grouping
363
+ * @returns {Vaporous} - Returns this instance for chaining
364
+ */
365
+ delta(field, remapField, ...bys) {
366
+ return statistics.delta.call(this, field, remapField, ...bys);
367
+ }
368
+
369
+ // ========================================
370
+ // Checkpoint methods
371
+ // ========================================
372
+
373
+ /**
374
+ * Internal checkpoint operation helper
375
+ * @private
376
+ */
377
+ _checkpoint(operation, name, data, options) {
378
+ return checkpoints._checkpoint.call(this, operation, name, data, options);
379
+ }
380
+
381
+ /**
382
+ * Create, retrieve, or delete checkpoints
383
+ * @param {string} operation - 'create', 'retrieve', or 'delete'
384
+ * @param {string} name - Checkpoint name
385
+ * @param {Object} [options] - Optional configuration
386
+ * @returns {Vaporous} - Returns this instance for chaining
387
+ */
388
+ checkpoint(operation, name, options) {
389
+ return checkpoints.checkpoint.call(this, operation, name, options);
390
+ }
391
+
392
+ /**
393
+ * Filter events into a checkpoint
394
+ * @param {string} checkpointName - Name for the checkpoint
395
+ * @param {Function} funct - Filter function
396
+ * @param {Object} [options] - Optional configuration
397
+ * @returns {Vaporous} - Returns this instance for chaining
398
+ */
399
+ filterIntoCheckpoint(checkpointName, funct, options) {
400
+ return checkpoints.filterIntoCheckpoint.call(this, checkpointName, funct, options);
401
+ }
402
+
403
+ /**
404
+ * Store or retrieve checkpoints from disk
405
+ * @param {string} operation - 'create' or 'retrieve'
406
+ * @param {string} name - Checkpoint name
407
+ * @param {string} partitionBy - Field to partition by
408
+ * @returns {Vaporous} - Returns this instance for chaining
409
+ */
410
+ storedCheckpoint(operation, name, partitionBy) {
411
+ return checkpoints.storedCheckpoint.call(this, operation, name, partitionBy);
412
+ }
413
+
414
+ // ========================================
415
+ // Visualization methods
416
+ // ========================================
417
+
418
+ /**
419
+ * Prepare data for graph visualization
420
+ * @param {...string} keys - Keys to use for graph data
421
+ * @returns {Vaporous} - Returns this instance for chaining
422
+ */
423
+ toGraph(...keys) {
424
+ return visualization.toGraph.call(this, ...keys);
425
+ }
426
+
427
+ /**
428
+ * Build visualization with specified configuration
429
+ * @param {string} title - Visualization title
430
+ * @param {string} type - Visualization type
431
+ * @param {Object} [options] - Optional configuration
432
+ * @returns {Vaporous} - Returns this instance for chaining
433
+ */
434
+ build(title, type, options) {
435
+ return visualization.build.call(this, title, type, options);
436
+ }
437
+
438
+ /**
439
+ * Render visualizations
440
+ * @param {string} location - Location to render visualizations
441
+ * @param {Object} [options] - Optional render options
442
+ * @returns {Vaporous} - Returns this instance for chaining
443
+ */
444
+ render(location, options) {
445
+ return visualization.render.call(this, location, options);
446
+ }
447
+
448
+ // ========================================
449
+ // HTTP methods
450
+ // ========================================
451
+
452
+ /**
453
+ * Load data from HTTP requests
454
+ * @param {Object} [options] - Optional HTTP configuration
455
+ * @returns {Vaporous} - Returns this instance for chaining
456
+ */
457
+ load_http(options) {
458
+ return http.load_http.call(this, options);
459
+ }
460
+
461
+ // ========================================
462
+ // Processing methods
463
+ // ========================================
464
+
465
+ /**
466
+ * Process events at regular intervals
467
+ * @param {Function} callback - Function to call on each interval
468
+ * @param {number} ms - Interval in milliseconds
469
+ * @returns {Vaporous} - Returns this instance for chaining
470
+ */
471
+ interval(callback, ms) {
472
+ return processing.interval.call(this, callback, ms);
473
+ }
474
+
475
+ /**
476
+ * Process events in parallel
477
+ * @param {number} concurrency - Number of parallel operations
478
+ * @param {Function} callback - Function to execute for each batch
479
+ * @param {Object} [options] - Optional configuration
480
+ * @returns {Vaporous} - Returns this instance for chaining
481
+ */
482
+ parallel(concurrency, callback, options) {
483
+ return processing.parallel.call(this, concurrency, callback, options);
484
+ }
485
+
486
+ /**
487
+ * Recursively process events
488
+ * @param {Function} callback - Function to execute recursively
489
+ * @returns {Vaporous} - Returns this instance for chaining
490
+ */
491
+ recurse(callback) {
492
+ return processing.recurse.call(this, callback);
493
+ }
494
+
495
+ /**
496
+ * Debug events by executing a callback
497
+ * @param {Function} callback - Debug callback function
498
+ * @returns {Vaporous} - Returns this instance for chaining
499
+ */
500
+ debug(callback) {
501
+ return core.debug.call(this, callback);
502
+ }
503
+
504
+ /**
505
+ * Conditionally execute a callback
506
+ * @param {Function|boolean} condition - Condition to evaluate or boolean value
507
+ * @param {Function} callback - Function to execute if condition is true
508
+ * @returns {Vaporous} - Returns this instance for chaining
509
+ */
510
+ doIf(condition, callback) {
511
+ return processing.doIf.call(this, condition, callback);
512
+ }
513
+ }
109
514
 
110
515
  module.exports = { Vaporous, Aggregation, By, Window }