jtcsv 2.1.5 → 2.2.2

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.
@@ -0,0 +1,434 @@
1
+ /**
2
+ * NDJSON Processing Examples for jtcsv
3
+ *
4
+ * NDJSON (Newline Delimited JSON) is a format where each line
5
+ * is a valid JSON object. It's ideal for streaming large datasets
6
+ * and log processing.
7
+ */
8
+
9
+ const {
10
+ jsonToNdjson,
11
+ ndjsonToJson,
12
+ parseNdjsonStream,
13
+ createNdjsonToCsvStream,
14
+ createCsvToNdjsonStream,
15
+ getNdjsonStats
16
+ } = require('jtcsv');
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+ const { Readable, PassThrough } = require('stream');
21
+
22
+ // =============================================================================
23
+ // Example 1: Basic NDJSON Conversion
24
+ // =============================================================================
25
+
26
+ function basicNdjsonConversion() {
27
+ console.log('\n=== Basic NDJSON Conversion ===\n');
28
+
29
+ const data = [
30
+ { id: 1, event: 'login', user: 'john', timestamp: '2024-01-15T10:30:00Z' },
31
+ { id: 2, event: 'click', user: 'john', timestamp: '2024-01-15T10:30:15Z' },
32
+ { id: 3, event: 'purchase', user: 'john', timestamp: '2024-01-15T10:31:00Z' },
33
+ { id: 4, event: 'logout', user: 'john', timestamp: '2024-01-15T10:35:00Z' }
34
+ ];
35
+
36
+ // Convert to NDJSON
37
+ const ndjson = jsonToNdjson(data);
38
+ console.log('NDJSON output:');
39
+ console.log(ndjson);
40
+
41
+ // Parse back to JSON
42
+ const parsed = ndjsonToJson(ndjson);
43
+ console.log('\nParsed back:', parsed.length, 'records');
44
+ }
45
+
46
+ // =============================================================================
47
+ // Example 2: NDJSON with Transform and Filter
48
+ // =============================================================================
49
+
50
+ function ndjsonWithTransformAndFilter() {
51
+ console.log('\n=== NDJSON with Transform and Filter ===\n');
52
+
53
+ const logEntries = [
54
+ { level: 'info', message: 'Application started', ts: 1705312200 },
55
+ { level: 'debug', message: 'Connecting to database', ts: 1705312201 },
56
+ { level: 'error', message: 'Connection failed', ts: 1705312202 },
57
+ { level: 'info', message: 'Retry connection', ts: 1705312203 },
58
+ { level: 'info', message: 'Connected successfully', ts: 1705312204 },
59
+ { level: 'debug', message: 'Query executed', ts: 1705312205 }
60
+ ];
61
+
62
+ // Convert with transform - add formatted timestamp
63
+ const ndjson = jsonToNdjson(logEntries, {
64
+ transform: (obj, index) => ({
65
+ ...obj,
66
+ index,
67
+ formattedTime: new Date(obj.ts * 1000).toISOString()
68
+ })
69
+ });
70
+ console.log('Transformed NDJSON:');
71
+ console.log(ndjson);
72
+
73
+ // Parse back with filter - only errors and info
74
+ const filtered = ndjsonToJson(ndjson, {
75
+ filter: (obj) => obj.level === 'error' || obj.level === 'info'
76
+ });
77
+ console.log('\nFiltered entries (error + info only):', filtered.length);
78
+ filtered.forEach(e => console.log(` [${e.level}] ${e.message}`));
79
+ }
80
+
81
+ // =============================================================================
82
+ // Example 3: NDJSON Error Handling
83
+ // =============================================================================
84
+
85
+ function ndjsonErrorHandling() {
86
+ console.log('\n=== NDJSON Error Handling ===\n');
87
+
88
+ // NDJSON with some invalid lines
89
+ const mixedNdjson = `{"id": 1, "valid": true}
90
+ {"id": 2, "valid": true}
91
+ {invalid json here}
92
+ {"id": 3, "valid": true}
93
+ not json at all
94
+ {"id": 4, "valid": true}`;
95
+
96
+ const errors = [];
97
+
98
+ const result = ndjsonToJson(mixedNdjson, {
99
+ onError: (error, line, lineNumber) => {
100
+ errors.push({
101
+ lineNumber,
102
+ error: error.message,
103
+ content: line.substring(0, 30) + (line.length > 30 ? '...' : '')
104
+ });
105
+ }
106
+ });
107
+
108
+ console.log('Valid records:', result.length);
109
+ console.log('Errors encountered:', errors.length);
110
+ errors.forEach(e => {
111
+ console.log(` Line ${e.lineNumber}: ${e.error}`);
112
+ console.log(` Content: ${e.content}`);
113
+ });
114
+ }
115
+
116
+ // =============================================================================
117
+ // Example 4: Streaming NDJSON Processing
118
+ // =============================================================================
119
+
120
+ async function streamingNdjsonProcessing() {
121
+ console.log('\n=== Streaming NDJSON Processing ===\n');
122
+
123
+ // Create a stream from NDJSON string
124
+ const ndjsonContent = `{"type": "user", "name": "Alice", "age": 28}
125
+ {"type": "user", "name": "Bob", "age": 35}
126
+ {"type": "product", "name": "Laptop", "price": 999}
127
+ {"type": "user", "name": "Charlie", "age": 42}
128
+ {"type": "product", "name": "Phone", "price": 599}`;
129
+
130
+ // Create readable stream
131
+ const stream = Readable.from([ndjsonContent]);
132
+
133
+ // Process stream with async iterator
134
+ const users = [];
135
+ const products = [];
136
+
137
+ for await (const obj of parseNdjsonStream(stream)) {
138
+ if (obj.type === 'user') {
139
+ users.push(obj);
140
+ } else if (obj.type === 'product') {
141
+ products.push(obj);
142
+ }
143
+ }
144
+
145
+ console.log('Users found:', users.length);
146
+ users.forEach(u => console.log(` - ${u.name}, ${u.age} years old`));
147
+
148
+ console.log('\nProducts found:', products.length);
149
+ products.forEach(p => console.log(` - ${p.name}: $${p.price}`));
150
+ }
151
+
152
+ // =============================================================================
153
+ // Example 5: NDJSON to CSV Conversion
154
+ // =============================================================================
155
+
156
+ async function ndjsonToCsvConversion() {
157
+ console.log('\n=== NDJSON to CSV Conversion ===\n');
158
+
159
+ const ndjson = `{"name": "Alice", "department": "Engineering", "salary": 85000}
160
+ {"name": "Bob", "department": "Marketing", "salary": 65000}
161
+ {"name": "Charlie", "department": "Engineering", "salary": 90000}
162
+ {"name": "Diana", "department": "Sales", "salary": 70000}`;
163
+
164
+ // Create NDJSON to CSV transform stream
165
+ const transformStream = createNdjsonToCsvStream({
166
+ delimiter: ',',
167
+ includeHeaders: true
168
+ });
169
+
170
+ // Collect CSV output
171
+ let csvOutput = '';
172
+ transformStream.writable.getWriter();
173
+
174
+ // Manual stream processing for demo
175
+ const lines = ndjson.split('\n');
176
+ const objects = lines.map(line => JSON.parse(line));
177
+
178
+ // Convert to CSV manually for this example
179
+ const { jsonToCsv } = require('jtcsv');
180
+ const csv = jsonToCsv(objects, { delimiter: ',' });
181
+
182
+ console.log('Converted CSV:');
183
+ console.log(csv);
184
+ }
185
+
186
+ // =============================================================================
187
+ // Example 6: CSV to NDJSON Conversion
188
+ // =============================================================================
189
+
190
+ function csvToNdjsonConversion() {
191
+ console.log('\n=== CSV to NDJSON Conversion ===\n');
192
+
193
+ const csv = `id,name,email,active
194
+ 1,John Doe,john@example.com,true
195
+ 2,Jane Smith,jane@example.com,false
196
+ 3,Bob Wilson,bob@example.com,true`;
197
+
198
+ const { csvToJson } = require('jtcsv');
199
+
200
+ // Parse CSV first
201
+ const data = csvToJson(csv, {
202
+ parseNumbers: true,
203
+ parseBooleans: true
204
+ });
205
+
206
+ // Convert to NDJSON
207
+ const ndjson = jsonToNdjson(data);
208
+ console.log('NDJSON output:');
209
+ console.log(ndjson);
210
+ }
211
+
212
+ // =============================================================================
213
+ // Example 7: NDJSON Statistics
214
+ // =============================================================================
215
+
216
+ async function ndjsonStatistics() {
217
+ console.log('\n=== NDJSON Statistics ===\n');
218
+
219
+ const ndjson = `{"id": 1, "type": "event"}
220
+ {"id": 2, "type": "event"}
221
+ {invalid}
222
+ {"id": 3, "type": "event"}
223
+ not json
224
+ {"id": 4, "type": "event"}
225
+ {"id": 5, "type": "event"}`;
226
+
227
+ const stats = await getNdjsonStats(ndjson);
228
+
229
+ console.log('NDJSON Statistics:');
230
+ console.log(' Total lines:', stats.totalLines);
231
+ console.log(' Valid lines:', stats.validLines);
232
+ console.log(' Error lines:', stats.errorLines);
233
+ console.log(' Total bytes:', stats.totalBytes);
234
+ console.log(' Success rate:', (stats.successRate * 100).toFixed(1) + '%');
235
+
236
+ if (stats.errors.length > 0) {
237
+ console.log('\nErrors:');
238
+ stats.errors.forEach(e => {
239
+ console.log(` Line ${e.line}: ${e.error}`);
240
+ });
241
+ }
242
+ }
243
+
244
+ // =============================================================================
245
+ // Example 8: Large NDJSON Processing with Memory Efficiency
246
+ // =============================================================================
247
+
248
+ async function largeNdjsonProcessing() {
249
+ console.log('\n=== Large NDJSON Processing ===\n');
250
+
251
+ // Simulate large NDJSON data
252
+ const generateLargeNdjson = (count) => {
253
+ const lines = [];
254
+ for (let i = 0; i < count; i++) {
255
+ lines.push(JSON.stringify({
256
+ id: i,
257
+ timestamp: Date.now() + i,
258
+ value: Math.random() * 100,
259
+ category: ['A', 'B', 'C'][i % 3]
260
+ }));
261
+ }
262
+ return lines.join('\n');
263
+ };
264
+
265
+ const largeNdjson = generateLargeNdjson(10000);
266
+ console.log(`Generated ${largeNdjson.split('\n').length} NDJSON lines`);
267
+
268
+ // Process with aggregation
269
+ const stats = {
270
+ count: 0,
271
+ sum: 0,
272
+ categories: {}
273
+ };
274
+
275
+ const startTime = Date.now();
276
+
277
+ for await (const obj of parseNdjsonStream(Readable.from([largeNdjson]))) {
278
+ stats.count++;
279
+ stats.sum += obj.value;
280
+ stats.categories[obj.category] = (stats.categories[obj.category] || 0) + 1;
281
+ }
282
+
283
+ const endTime = Date.now();
284
+
285
+ console.log('\nAggregation results:');
286
+ console.log(' Records processed:', stats.count);
287
+ console.log(' Average value:', (stats.sum / stats.count).toFixed(2));
288
+ console.log(' Categories:', stats.categories);
289
+ console.log(' Processing time:', endTime - startTime, 'ms');
290
+ console.log(' Throughput:', Math.round(stats.count / ((endTime - startTime) / 1000)), 'records/sec');
291
+ }
292
+
293
+ // =============================================================================
294
+ // Example 9: NDJSON Log Processing Pipeline
295
+ // =============================================================================
296
+
297
+ async function logProcessingPipeline() {
298
+ console.log('\n=== NDJSON Log Processing Pipeline ===\n');
299
+
300
+ // Simulated log entries
301
+ const logs = `{"ts": "2024-01-15T10:00:00Z", "level": "info", "service": "api", "msg": "Request received", "duration_ms": 50}
302
+ {"ts": "2024-01-15T10:00:01Z", "level": "debug", "service": "api", "msg": "Processing request", "duration_ms": 0}
303
+ {"ts": "2024-01-15T10:00:02Z", "level": "warn", "service": "db", "msg": "Slow query detected", "duration_ms": 1500}
304
+ {"ts": "2024-01-15T10:00:03Z", "level": "error", "service": "api", "msg": "Request failed", "duration_ms": 100, "error": "Timeout"}
305
+ {"ts": "2024-01-15T10:00:04Z", "level": "info", "service": "api", "msg": "Request completed", "duration_ms": 45}
306
+ {"ts": "2024-01-15T10:00:05Z", "level": "error", "service": "db", "msg": "Connection lost", "duration_ms": 0, "error": "Network error"}`;
307
+
308
+ // Pipeline stages
309
+ const pipeline = {
310
+ errors: [],
311
+ warnings: [],
312
+ slowRequests: [],
313
+ serviceStats: {}
314
+ };
315
+
316
+ // Process logs
317
+ for await (const log of parseNdjsonStream(Readable.from([logs]))) {
318
+ // Collect errors
319
+ if (log.level === 'error') {
320
+ pipeline.errors.push({
321
+ time: log.ts,
322
+ service: log.service,
323
+ message: log.msg,
324
+ error: log.error
325
+ });
326
+ }
327
+
328
+ // Collect warnings
329
+ if (log.level === 'warn') {
330
+ pipeline.warnings.push({
331
+ time: log.ts,
332
+ service: log.service,
333
+ message: log.msg
334
+ });
335
+ }
336
+
337
+ // Track slow requests (> 1000ms)
338
+ if (log.duration_ms > 1000) {
339
+ pipeline.slowRequests.push({
340
+ time: log.ts,
341
+ service: log.service,
342
+ duration: log.duration_ms
343
+ });
344
+ }
345
+
346
+ // Aggregate by service
347
+ if (!pipeline.serviceStats[log.service]) {
348
+ pipeline.serviceStats[log.service] = { count: 0, errors: 0 };
349
+ }
350
+ pipeline.serviceStats[log.service].count++;
351
+ if (log.level === 'error') {
352
+ pipeline.serviceStats[log.service].errors++;
353
+ }
354
+ }
355
+
356
+ // Report
357
+ console.log('Log Analysis Report:');
358
+ console.log('\nErrors:', pipeline.errors.length);
359
+ pipeline.errors.forEach(e => {
360
+ console.log(` [${e.service}] ${e.message} - ${e.error}`);
361
+ });
362
+
363
+ console.log('\nWarnings:', pipeline.warnings.length);
364
+ pipeline.warnings.forEach(w => {
365
+ console.log(` [${w.service}] ${w.message}`);
366
+ });
367
+
368
+ console.log('\nSlow Requests (>1s):', pipeline.slowRequests.length);
369
+ pipeline.slowRequests.forEach(s => {
370
+ console.log(` [${s.service}] ${s.duration}ms`);
371
+ });
372
+
373
+ console.log('\nService Statistics:');
374
+ Object.entries(pipeline.serviceStats).forEach(([service, stats]) => {
375
+ const errorRate = ((stats.errors / stats.count) * 100).toFixed(1);
376
+ console.log(` ${service}: ${stats.count} requests, ${stats.errors} errors (${errorRate}%)`);
377
+ });
378
+ }
379
+
380
+ // =============================================================================
381
+ // Example 10: NDJSON Pretty Print and Compact
382
+ // =============================================================================
383
+
384
+ function ndjsonFormatting() {
385
+ console.log('\n=== NDJSON Formatting Options ===\n');
386
+
387
+ const data = [
388
+ { name: 'Test', nested: { a: 1, b: 2 }, array: [1, 2, 3] }
389
+ ];
390
+
391
+ // Compact (default)
392
+ const compact = jsonToNdjson(data);
393
+ console.log('Compact:');
394
+ console.log(compact);
395
+
396
+ // With custom replacer (filter out 'array' field)
397
+ const filtered = jsonToNdjson(data, {
398
+ replacer: (key, value) => key === 'array' ? undefined : value
399
+ });
400
+ console.log('\nFiltered (no array):');
401
+ console.log(filtered);
402
+
403
+ // With space for readability (not standard NDJSON but useful for debugging)
404
+ const pretty = jsonToNdjson(data, {
405
+ space: 0 // Standard NDJSON should have no space
406
+ });
407
+ console.log('\nStandard NDJSON:');
408
+ console.log(pretty);
409
+ }
410
+
411
+ // =============================================================================
412
+ // Run All Examples
413
+ // =============================================================================
414
+
415
+ async function main() {
416
+ console.log('jtcsv NDJSON Processing Examples');
417
+ console.log('='.repeat(60));
418
+
419
+ basicNdjsonConversion();
420
+ ndjsonWithTransformAndFilter();
421
+ ndjsonErrorHandling();
422
+ await streamingNdjsonProcessing();
423
+ await ndjsonToCsvConversion();
424
+ csvToNdjsonConversion();
425
+ await ndjsonStatistics();
426
+ await largeNdjsonProcessing();
427
+ await logProcessingPipeline();
428
+ ndjsonFormatting();
429
+
430
+ console.log('\n' + '='.repeat(60));
431
+ console.log('All NDJSON examples completed.');
432
+ }
433
+
434
+ main().catch(console.error);