node-red-contrib-questdb 0.2.0 → 0.3.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,908 +0,0 @@
1
- [
2
- {
3
- "id": "questdb-comprehensive-tab",
4
- "type": "tab",
5
- "label": "QuestDB Comprehensive Tests",
6
- "disabled": false,
7
- "info": "Comprehensive test flows covering all data types and scenarios"
8
- },
9
- {
10
- "id": "comment-header",
11
- "type": "comment",
12
- "z": "questdb-comprehensive-tab",
13
- "name": "=== QuestDB Comprehensive Test Suite ===",
14
- "info": "Tests all data types, formats, and edge cases.\nMake sure QuestDB is running on localhost:9000",
15
- "x": 220,
16
- "y": 40
17
- },
18
- {
19
- "id": "comment-datatypes",
20
- "type": "comment",
21
- "z": "questdb-comprehensive-tab",
22
- "name": "--- Data Types Test ---",
23
- "info": "",
24
- "x": 140,
25
- "y": 100
26
- },
27
- {
28
- "id": "inject-all-types",
29
- "type": "inject",
30
- "z": "questdb-comprehensive-tab",
31
- "name": "All data types",
32
- "props": [
33
- {"p": "payload"},
34
- {"p": "topic", "vt": "str"}
35
- ],
36
- "repeat": "",
37
- "crontab": "",
38
- "once": false,
39
- "onceDelay": 0.1,
40
- "topic": "all_types_test",
41
- "payload": "{}",
42
- "payloadType": "json",
43
- "x": 140,
44
- "y": 160,
45
- "wires": [["function-all-types"]]
46
- },
47
- {
48
- "id": "function-all-types",
49
- "type": "function",
50
- "z": "questdb-comprehensive-tab",
51
- "name": "Generate all data types",
52
- "func": "msg.payload = {\n symbols: {\n device_id: \"device_001\",\n location: \"building_a\",\n type: \"sensor\",\n status: \"active\"\n },\n columns: {\n // Float types\n temperature: 23.456789,\n humidity: 65.5,\n pressure: 1013.25,\n voltage: 3.3,\n current: 0.125,\n power: 0.4125,\n latitude: 51.5074,\n longitude: -0.1278,\n \n // Integer types (will be stored as float in QuestDB ILP)\n count: 42,\n error_count: 0,\n sequence: 12345,\n \n // Boolean types\n is_online: true,\n alarm_active: false,\n maintenance_mode: false,\n \n // String types\n firmware_version: \"v2.1.3\",\n last_error: \"none\",\n description: \"Main temperature sensor in warehouse\",\n serial_number: \"SN-2024-001234\",\n \n // Timestamp column (as ISO string)\n last_calibration: \"2024-06-15T10:30:00.000Z\",\n \n // Special numeric values\n percentage: 85.5,\n ratio: 0.95\n },\n timestamp: Date.now()\n};\nreturn msg;",
53
- "outputs": 1,
54
- "x": 380,
55
- "y": 160,
56
- "wires": [["questdb-write-types", "debug-types"]]
57
- },
58
- {
59
- "id": "questdb-write-types",
60
- "type": "questdb",
61
- "z": "questdb-comprehensive-tab",
62
- "name": "Write all types",
63
- "questdb": "questdb-config-test",
64
- "autoFlush": true,
65
- "flushInterval": 1000,
66
- "x": 620,
67
- "y": 160,
68
- "wires": [["debug-types-result"]]
69
- },
70
- {
71
- "id": "debug-types",
72
- "type": "debug",
73
- "z": "questdb-comprehensive-tab",
74
- "name": "Payload",
75
- "active": true,
76
- "tosidebar": true,
77
- "console": false,
78
- "tostatus": false,
79
- "complete": "payload",
80
- "targetType": "msg",
81
- "x": 620,
82
- "y": 120
83
- },
84
- {
85
- "id": "debug-types-result",
86
- "type": "debug",
87
- "z": "questdb-comprehensive-tab",
88
- "name": "Result",
89
- "active": true,
90
- "tosidebar": true,
91
- "console": false,
92
- "tostatus": true,
93
- "complete": "payload",
94
- "targetType": "msg",
95
- "statusVal": "payload.success",
96
- "statusType": "auto",
97
- "x": 810,
98
- "y": 160
99
- },
100
- {
101
- "id": "comment-timestamps",
102
- "type": "comment",
103
- "z": "questdb-comprehensive-tab",
104
- "name": "--- Timestamp Formats Test ---",
105
- "info": "",
106
- "x": 170,
107
- "y": 240
108
- },
109
- {
110
- "id": "inject-ts-milliseconds",
111
- "type": "inject",
112
- "z": "questdb-comprehensive-tab",
113
- "name": "Timestamp: milliseconds",
114
- "props": [
115
- {"p": "payload"},
116
- {"p": "topic", "vt": "str"}
117
- ],
118
- "repeat": "",
119
- "crontab": "",
120
- "once": false,
121
- "onceDelay": 0.1,
122
- "topic": "timestamp_test",
123
- "payload": "{}",
124
- "payloadType": "json",
125
- "x": 170,
126
- "y": 300,
127
- "wires": [["function-ts-ms"]]
128
- },
129
- {
130
- "id": "function-ts-ms",
131
- "type": "function",
132
- "z": "questdb-comprehensive-tab",
133
- "name": "Milliseconds timestamp",
134
- "func": "msg.payload = {\n symbols: { format: \"milliseconds\" },\n columns: { value: 100 },\n timestamp: Date.now() // milliseconds since epoch\n};\nreturn msg;",
135
- "outputs": 1,
136
- "x": 410,
137
- "y": 300,
138
- "wires": [["questdb-write-ts"]]
139
- },
140
- {
141
- "id": "inject-ts-iso",
142
- "type": "inject",
143
- "z": "questdb-comprehensive-tab",
144
- "name": "Timestamp: ISO string",
145
- "props": [
146
- {"p": "payload"},
147
- {"p": "topic", "vt": "str"}
148
- ],
149
- "repeat": "",
150
- "crontab": "",
151
- "once": false,
152
- "onceDelay": 0.1,
153
- "topic": "timestamp_test",
154
- "payload": "{}",
155
- "payloadType": "json",
156
- "x": 160,
157
- "y": 340,
158
- "wires": [["function-ts-iso"]]
159
- },
160
- {
161
- "id": "function-ts-iso",
162
- "type": "function",
163
- "z": "questdb-comprehensive-tab",
164
- "name": "ISO string timestamp",
165
- "func": "msg.payload = {\n symbols: { format: \"iso_string\" },\n columns: { value: 200 },\n timestamp: new Date().toISOString() // ISO 8601 string\n};\nreturn msg;",
166
- "outputs": 1,
167
- "x": 410,
168
- "y": 340,
169
- "wires": [["questdb-write-ts"]]
170
- },
171
- {
172
- "id": "inject-ts-date",
173
- "type": "inject",
174
- "z": "questdb-comprehensive-tab",
175
- "name": "Timestamp: Date object",
176
- "props": [
177
- {"p": "payload"},
178
- {"p": "topic", "vt": "str"}
179
- ],
180
- "repeat": "",
181
- "crontab": "",
182
- "once": false,
183
- "onceDelay": 0.1,
184
- "topic": "timestamp_test",
185
- "payload": "{}",
186
- "payloadType": "json",
187
- "x": 170,
188
- "y": 380,
189
- "wires": [["function-ts-date"]]
190
- },
191
- {
192
- "id": "function-ts-date",
193
- "type": "function",
194
- "z": "questdb-comprehensive-tab",
195
- "name": "Date object timestamp",
196
- "func": "msg.payload = {\n symbols: { format: \"date_object\" },\n columns: { value: 300 },\n timestamp: new Date() // Date object\n};\nreturn msg;",
197
- "outputs": 1,
198
- "x": 410,
199
- "y": 380,
200
- "wires": [["questdb-write-ts"]]
201
- },
202
- {
203
- "id": "inject-ts-none",
204
- "type": "inject",
205
- "z": "questdb-comprehensive-tab",
206
- "name": "Timestamp: auto (now)",
207
- "props": [
208
- {"p": "payload"},
209
- {"p": "topic", "vt": "str"}
210
- ],
211
- "repeat": "",
212
- "crontab": "",
213
- "once": false,
214
- "onceDelay": 0.1,
215
- "topic": "timestamp_test",
216
- "payload": "{}",
217
- "payloadType": "json",
218
- "x": 170,
219
- "y": 420,
220
- "wires": [["function-ts-none"]]
221
- },
222
- {
223
- "id": "function-ts-none",
224
- "type": "function",
225
- "z": "questdb-comprehensive-tab",
226
- "name": "No timestamp (use now)",
227
- "func": "msg.payload = {\n symbols: { format: \"auto_now\" },\n columns: { value: 400 }\n // No timestamp - will use server time\n};\nreturn msg;",
228
- "outputs": 1,
229
- "x": 420,
230
- "y": 420,
231
- "wires": [["questdb-write-ts"]]
232
- },
233
- {
234
- "id": "questdb-write-ts",
235
- "type": "questdb",
236
- "z": "questdb-comprehensive-tab",
237
- "name": "Write timestamp test",
238
- "questdb": "questdb-config-test",
239
- "autoFlush": true,
240
- "flushInterval": 1000,
241
- "x": 670,
242
- "y": 360,
243
- "wires": [["debug-ts-result"]]
244
- },
245
- {
246
- "id": "debug-ts-result",
247
- "type": "debug",
248
- "z": "questdb-comprehensive-tab",
249
- "name": "TS Result",
250
- "active": true,
251
- "tosidebar": true,
252
- "console": false,
253
- "tostatus": true,
254
- "complete": "payload",
255
- "targetType": "msg",
256
- "statusVal": "payload.success",
257
- "statusType": "auto",
258
- "x": 870,
259
- "y": 360
260
- },
261
- {
262
- "id": "comment-mapper",
263
- "type": "comment",
264
- "z": "questdb-comprehensive-tab",
265
- "name": "--- Mapper Node Tests ---",
266
- "info": "",
267
- "x": 150,
268
- "y": 500
269
- },
270
- {
271
- "id": "inject-mapper-nested",
272
- "type": "inject",
273
- "z": "questdb-comprehensive-tab",
274
- "name": "Nested object data",
275
- "props": [
276
- {"p": "payload"},
277
- {"p": "topic", "vt": "str"}
278
- ],
279
- "repeat": "",
280
- "crontab": "",
281
- "once": false,
282
- "onceDelay": 0.1,
283
- "topic": "nested_data",
284
- "payload": "{\"device\":{\"id\":\"dev_001\",\"type\":\"thermostat\"},\"readings\":{\"temp\":22.5,\"setpoint\":21.0,\"mode\":\"heat\"},\"meta\":{\"ts\":0,\"battery\":95}}",
285
- "payloadType": "json",
286
- "x": 160,
287
- "y": 560,
288
- "wires": [["function-add-ts-nested"]]
289
- },
290
- {
291
- "id": "function-add-ts-nested",
292
- "type": "function",
293
- "z": "questdb-comprehensive-tab",
294
- "name": "Add timestamp",
295
- "func": "msg.payload.meta.ts = Date.now();\nreturn msg;",
296
- "outputs": 1,
297
- "x": 360,
298
- "y": 560,
299
- "wires": [["mapper-nested"]]
300
- },
301
- {
302
- "id": "mapper-nested",
303
- "type": "questdb-mapper",
304
- "z": "questdb-comprehensive-tab",
305
- "name": "Map nested data",
306
- "tableName": "thermostat_data",
307
- "timestampField": "payload.meta.ts",
308
- "symbolMappings": [
309
- {"source": "payload.device.id", "target": "device_id"},
310
- {"source": "payload.device.type", "target": "device_type"}
311
- ],
312
- "columnMappings": [
313
- {"source": "payload.readings.temp", "target": "temperature", "type": "float"},
314
- {"source": "payload.readings.setpoint", "target": "setpoint", "type": "float"},
315
- {"source": "payload.readings.mode", "target": "mode", "type": "string"},
316
- {"source": "payload.meta.battery", "target": "battery", "type": "integer"}
317
- ],
318
- "x": 560,
319
- "y": 560,
320
- "wires": [["debug-mapper-out", "questdb-write-mapper"]]
321
- },
322
- {
323
- "id": "debug-mapper-out",
324
- "type": "debug",
325
- "z": "questdb-comprehensive-tab",
326
- "name": "Mapped output",
327
- "active": true,
328
- "tosidebar": true,
329
- "console": false,
330
- "tostatus": false,
331
- "complete": "true",
332
- "targetType": "full",
333
- "x": 770,
334
- "y": 520
335
- },
336
- {
337
- "id": "questdb-write-mapper",
338
- "type": "questdb",
339
- "z": "questdb-comprehensive-tab",
340
- "name": "Write mapped",
341
- "questdb": "questdb-config-test",
342
- "autoFlush": true,
343
- "flushInterval": 1000,
344
- "x": 770,
345
- "y": 560,
346
- "wires": [["debug-mapper-result"]]
347
- },
348
- {
349
- "id": "debug-mapper-result",
350
- "type": "debug",
351
- "z": "questdb-comprehensive-tab",
352
- "name": "Mapper Result",
353
- "active": true,
354
- "tosidebar": true,
355
- "console": false,
356
- "tostatus": true,
357
- "complete": "payload",
358
- "targetType": "msg",
359
- "statusVal": "payload.success",
360
- "statusType": "auto",
361
- "x": 980,
362
- "y": 560
363
- },
364
- {
365
- "id": "inject-mapper-array",
366
- "type": "inject",
367
- "z": "questdb-comprehensive-tab",
368
- "name": "Array data",
369
- "props": [
370
- {"p": "payload"},
371
- {"p": "topic", "vt": "str"}
372
- ],
373
- "repeat": "",
374
- "crontab": "",
375
- "once": false,
376
- "onceDelay": 0.1,
377
- "topic": "array_data",
378
- "payload": "{\"sensors\":[{\"name\":\"temp\",\"value\":25.5},{\"name\":\"humidity\",\"value\":60}],\"timestamp\":0}",
379
- "payloadType": "json",
380
- "x": 140,
381
- "y": 620,
382
- "wires": [["function-add-ts-array"]]
383
- },
384
- {
385
- "id": "function-add-ts-array",
386
- "type": "function",
387
- "z": "questdb-comprehensive-tab",
388
- "name": "Add timestamp",
389
- "func": "msg.payload.timestamp = Date.now();\nreturn msg;",
390
- "outputs": 1,
391
- "x": 360,
392
- "y": 620,
393
- "wires": [["mapper-array"]]
394
- },
395
- {
396
- "id": "mapper-array",
397
- "type": "questdb-mapper",
398
- "z": "questdb-comprehensive-tab",
399
- "name": "Map array access",
400
- "tableName": "sensor_array_test",
401
- "timestampField": "payload.timestamp",
402
- "symbolMappings": [
403
- {"source": "payload.sensors[0].name", "target": "sensor1_name"},
404
- {"source": "payload.sensors[1].name", "target": "sensor2_name"}
405
- ],
406
- "columnMappings": [
407
- {"source": "payload.sensors[0].value", "target": "sensor1_value", "type": "float"},
408
- {"source": "payload.sensors[1].value", "target": "sensor2_value", "type": "float"}
409
- ],
410
- "x": 560,
411
- "y": 620,
412
- "wires": [["questdb-write-mapper"]]
413
- },
414
- {
415
- "id": "comment-iot",
416
- "type": "comment",
417
- "z": "questdb-comprehensive-tab",
418
- "name": "--- IoT Scenarios ---",
419
- "info": "",
420
- "x": 140,
421
- "y": 700
422
- },
423
- {
424
- "id": "inject-mqtt-style",
425
- "type": "inject",
426
- "z": "questdb-comprehensive-tab",
427
- "name": "MQTT-style message",
428
- "props": [
429
- {"p": "payload"},
430
- {"p": "topic", "vt": "str"}
431
- ],
432
- "repeat": "",
433
- "crontab": "",
434
- "once": false,
435
- "onceDelay": 0.1,
436
- "topic": "home/livingroom/temperature",
437
- "payload": "22.5",
438
- "payloadType": "num",
439
- "x": 170,
440
- "y": 760,
441
- "wires": [["function-mqtt-transform"]]
442
- },
443
- {
444
- "id": "function-mqtt-transform",
445
- "type": "function",
446
- "z": "questdb-comprehensive-tab",
447
- "name": "Transform MQTT to ILP",
448
- "func": "// Parse MQTT topic: home/livingroom/temperature\nconst parts = msg.topic.split('/');\nconst location = parts[1] || 'unknown';\nconst measurement = parts[2] || 'value';\n\nmsg.topic = 'mqtt_sensors'; // Table name\nmsg.payload = {\n symbols: {\n location: location,\n measurement_type: measurement\n },\n columns: {\n value: msg.payload\n },\n timestamp: Date.now()\n};\nreturn msg;",
449
- "outputs": 1,
450
- "x": 420,
451
- "y": 760,
452
- "wires": [["questdb-write-iot", "debug-iot"]]
453
- },
454
- {
455
- "id": "inject-modbus-style",
456
- "type": "inject",
457
- "z": "questdb-comprehensive-tab",
458
- "name": "Modbus-style registers",
459
- "props": [
460
- {"p": "payload"},
461
- {"p": "topic", "vt": "str"}
462
- ],
463
- "repeat": "",
464
- "crontab": "",
465
- "once": false,
466
- "onceDelay": 0.1,
467
- "topic": "plc_data",
468
- "payload": "{\"unitId\":1,\"registers\":[100,200,300,400],\"address\":40001}",
469
- "payloadType": "json",
470
- "x": 170,
471
- "y": 820,
472
- "wires": [["function-modbus-transform"]]
473
- },
474
- {
475
- "id": "function-modbus-transform",
476
- "type": "function",
477
- "z": "questdb-comprehensive-tab",
478
- "name": "Transform Modbus to ILP",
479
- "func": "const regs = msg.payload.registers;\nmsg.topic = 'modbus_data';\nmsg.payload = {\n symbols: {\n unit_id: String(msg.payload.unitId),\n base_address: String(msg.payload.address)\n },\n columns: {\n register_0: regs[0],\n register_1: regs[1],\n register_2: regs[2],\n register_3: regs[3],\n register_count: regs.length\n },\n timestamp: Date.now()\n};\nreturn msg;",
480
- "outputs": 1,
481
- "x": 430,
482
- "y": 820,
483
- "wires": [["questdb-write-iot", "debug-iot"]]
484
- },
485
- {
486
- "id": "inject-opc-style",
487
- "type": "inject",
488
- "z": "questdb-comprehensive-tab",
489
- "name": "OPC UA-style data",
490
- "props": [
491
- {"p": "payload"},
492
- {"p": "topic", "vt": "str"}
493
- ],
494
- "repeat": "",
495
- "crontab": "",
496
- "once": false,
497
- "onceDelay": 0.1,
498
- "topic": "opc_data",
499
- "payload": "{\"nodeId\":\"ns=2;s=Temperature\",\"value\":{\"value\":75.5,\"statusCode\":0,\"sourceTimestamp\":\"2024-01-15T12:30:00.000Z\"},\"browseName\":\"Temperature\"}",
500
- "payloadType": "json",
501
- "x": 160,
502
- "y": 880,
503
- "wires": [["function-opc-transform"]]
504
- },
505
- {
506
- "id": "function-opc-transform",
507
- "type": "function",
508
- "z": "questdb-comprehensive-tab",
509
- "name": "Transform OPC to ILP",
510
- "func": "msg.topic = 'opc_ua_data';\nmsg.payload = {\n symbols: {\n node_id: msg.payload.nodeId,\n browse_name: msg.payload.browseName\n },\n columns: {\n value: msg.payload.value.value,\n status_code: msg.payload.value.statusCode,\n quality_good: msg.payload.value.statusCode === 0\n },\n timestamp: msg.payload.value.sourceTimestamp\n};\nreturn msg;",
511
- "outputs": 1,
512
- "x": 420,
513
- "y": 880,
514
- "wires": [["questdb-write-iot", "debug-iot"]]
515
- },
516
- {
517
- "id": "questdb-write-iot",
518
- "type": "questdb",
519
- "z": "questdb-comprehensive-tab",
520
- "name": "Write IoT data",
521
- "questdb": "questdb-config-test",
522
- "autoFlush": true,
523
- "flushInterval": 1000,
524
- "x": 680,
525
- "y": 820,
526
- "wires": [["debug-iot-result"]]
527
- },
528
- {
529
- "id": "debug-iot",
530
- "type": "debug",
531
- "z": "questdb-comprehensive-tab",
532
- "name": "Transformed",
533
- "active": true,
534
- "tosidebar": true,
535
- "console": false,
536
- "tostatus": false,
537
- "complete": "payload",
538
- "targetType": "msg",
539
- "x": 680,
540
- "y": 760
541
- },
542
- {
543
- "id": "debug-iot-result",
544
- "type": "debug",
545
- "z": "questdb-comprehensive-tab",
546
- "name": "IoT Result",
547
- "active": true,
548
- "tosidebar": true,
549
- "console": false,
550
- "tostatus": true,
551
- "complete": "payload",
552
- "targetType": "msg",
553
- "statusVal": "payload.success",
554
- "statusType": "auto",
555
- "x": 870,
556
- "y": 820
557
- },
558
- {
559
- "id": "comment-batch",
560
- "type": "comment",
561
- "z": "questdb-comprehensive-tab",
562
- "name": "--- Batch & High Volume Tests ---",
563
- "info": "",
564
- "x": 180,
565
- "y": 960
566
- },
567
- {
568
- "id": "inject-batch-10",
569
- "type": "inject",
570
- "z": "questdb-comprehensive-tab",
571
- "name": "Send 10 records",
572
- "props": [
573
- {"p": "payload"},
574
- {"p": "topic", "vt": "str"}
575
- ],
576
- "repeat": "",
577
- "crontab": "",
578
- "once": false,
579
- "onceDelay": 0.1,
580
- "topic": "batch_test",
581
- "payload": "10",
582
- "payloadType": "num",
583
- "x": 160,
584
- "y": 1020,
585
- "wires": [["function-batch"]]
586
- },
587
- {
588
- "id": "inject-batch-100",
589
- "type": "inject",
590
- "z": "questdb-comprehensive-tab",
591
- "name": "Send 100 records",
592
- "props": [
593
- {"p": "payload"},
594
- {"p": "topic", "vt": "str"}
595
- ],
596
- "repeat": "",
597
- "crontab": "",
598
- "once": false,
599
- "onceDelay": 0.1,
600
- "topic": "batch_test",
601
- "payload": "100",
602
- "payloadType": "num",
603
- "x": 160,
604
- "y": 1060,
605
- "wires": [["function-batch"]]
606
- },
607
- {
608
- "id": "inject-batch-1000",
609
- "type": "inject",
610
- "z": "questdb-comprehensive-tab",
611
- "name": "Send 1000 records",
612
- "props": [
613
- {"p": "payload"},
614
- {"p": "topic", "vt": "str"}
615
- ],
616
- "repeat": "",
617
- "crontab": "",
618
- "once": false,
619
- "onceDelay": 0.1,
620
- "topic": "batch_test",
621
- "payload": "1000",
622
- "payloadType": "num",
623
- "x": 170,
624
- "y": 1100,
625
- "wires": [["function-batch"]]
626
- },
627
- {
628
- "id": "function-batch",
629
- "type": "function",
630
- "z": "questdb-comprehensive-tab",
631
- "name": "Generate batch messages",
632
- "func": "const count = msg.payload;\nconst messages = [];\nconst baseTime = Date.now();\n\nfor (let i = 0; i < count; i++) {\n messages.push({\n topic: msg.topic,\n payload: {\n symbols: {\n batch_id: node.id,\n source: \"batch_generator\"\n },\n columns: {\n sequence: i,\n value: Math.random() * 100,\n temperature: 20 + Math.random() * 10,\n humidity: 40 + Math.random() * 40\n },\n timestamp: baseTime + i // 1ms apart\n }\n });\n}\n\nnode.status({text: `Sending ${count} records...`});\nreturn [messages];",
633
- "outputs": 1,
634
- "x": 430,
635
- "y": 1060,
636
- "wires": [["questdb-write-batch"]]
637
- },
638
- {
639
- "id": "questdb-write-batch",
640
- "type": "questdb",
641
- "z": "questdb-comprehensive-tab",
642
- "name": "Write batch",
643
- "questdb": "questdb-config-test",
644
- "autoFlush": true,
645
- "flushInterval": 1000,
646
- "x": 670,
647
- "y": 1060,
648
- "wires": [["function-count-batch"]]
649
- },
650
- {
651
- "id": "function-count-batch",
652
- "type": "function",
653
- "z": "questdb-comprehensive-tab",
654
- "name": "Count results",
655
- "func": "// Initialize counter in context\nlet count = context.get('count') || 0;\nlet success = context.get('success') || 0;\nlet failed = context.get('failed') || 0;\n\ncount++;\nif (msg.payload.success) {\n success++;\n} else {\n failed++;\n}\n\ncontext.set('count', count);\ncontext.set('success', success);\ncontext.set('failed', failed);\n\nmsg.batchStats = {\n total: count,\n success: success,\n failed: failed\n};\n\nnode.status({text: `${success}/${count} OK`});\n\n// Reset after 5 seconds of no messages\nif (context.get('resetTimer')) {\n clearTimeout(context.get('resetTimer'));\n}\ncontext.set('resetTimer', setTimeout(() => {\n context.set('count', 0);\n context.set('success', 0);\n context.set('failed', 0);\n}, 5000));\n\nreturn msg;",
656
- "outputs": 1,
657
- "x": 870,
658
- "y": 1060,
659
- "wires": [["debug-batch-result"]]
660
- },
661
- {
662
- "id": "debug-batch-result",
663
- "type": "debug",
664
- "z": "questdb-comprehensive-tab",
665
- "name": "Batch Stats",
666
- "active": false,
667
- "tosidebar": true,
668
- "console": false,
669
- "tostatus": true,
670
- "complete": "batchStats",
671
- "targetType": "msg",
672
- "statusVal": "batchStats.success",
673
- "statusType": "auto",
674
- "x": 1070,
675
- "y": 1060
676
- },
677
- {
678
- "id": "comment-edge",
679
- "type": "comment",
680
- "z": "questdb-comprehensive-tab",
681
- "name": "--- Edge Cases & Special Values ---",
682
- "info": "",
683
- "x": 190,
684
- "y": 1180
685
- },
686
- {
687
- "id": "inject-edge-null",
688
- "type": "inject",
689
- "z": "questdb-comprehensive-tab",
690
- "name": "Null/undefined values",
691
- "props": [
692
- {"p": "payload"},
693
- {"p": "topic", "vt": "str"}
694
- ],
695
- "repeat": "",
696
- "crontab": "",
697
- "once": false,
698
- "onceDelay": 0.1,
699
- "topic": "edge_cases",
700
- "payload": "{}",
701
- "payloadType": "json",
702
- "x": 170,
703
- "y": 1240,
704
- "wires": [["function-edge-null"]]
705
- },
706
- {
707
- "id": "function-edge-null",
708
- "type": "function",
709
- "z": "questdb-comprehensive-tab",
710
- "name": "Test null handling",
711
- "func": "msg.payload = {\n symbols: {\n test_type: \"null_values\",\n nullable_symbol: null, // Should be skipped\n valid_symbol: \"present\"\n },\n columns: {\n valid_value: 42,\n null_value: null, // Should be skipped\n undefined_value: undefined, // Should be skipped\n zero_value: 0, // Should be included\n empty_string: \"\", // Should be included\n false_boolean: false // Should be included\n },\n timestamp: Date.now()\n};\nreturn msg;",
712
- "outputs": 1,
713
- "x": 410,
714
- "y": 1240,
715
- "wires": [["questdb-write-edge", "debug-edge"]]
716
- },
717
- {
718
- "id": "inject-edge-special",
719
- "type": "inject",
720
- "z": "questdb-comprehensive-tab",
721
- "name": "Special numeric values",
722
- "props": [
723
- {"p": "payload"},
724
- {"p": "topic", "vt": "str"}
725
- ],
726
- "repeat": "",
727
- "crontab": "",
728
- "once": false,
729
- "onceDelay": 0.1,
730
- "topic": "edge_cases",
731
- "payload": "{}",
732
- "payloadType": "json",
733
- "x": 170,
734
- "y": 1300,
735
- "wires": [["function-edge-special"]]
736
- },
737
- {
738
- "id": "function-edge-special",
739
- "type": "function",
740
- "z": "questdb-comprehensive-tab",
741
- "name": "Test special numbers",
742
- "func": "msg.payload = {\n symbols: {\n test_type: \"special_numbers\"\n },\n columns: {\n zero: 0,\n negative_zero: -0,\n small_positive: 0.000001,\n small_negative: -0.000001,\n large_positive: 999999999.999,\n large_negative: -999999999.999,\n max_safe_int: Number.MAX_SAFE_INTEGER,\n min_safe_int: Number.MIN_SAFE_INTEGER\n // Note: Infinity and NaN are skipped automatically\n },\n timestamp: Date.now()\n};\nreturn msg;",
743
- "outputs": 1,
744
- "x": 420,
745
- "y": 1300,
746
- "wires": [["questdb-write-edge", "debug-edge"]]
747
- },
748
- {
749
- "id": "inject-edge-strings",
750
- "type": "inject",
751
- "z": "questdb-comprehensive-tab",
752
- "name": "Special strings",
753
- "props": [
754
- {"p": "payload"},
755
- {"p": "topic", "vt": "str"}
756
- ],
757
- "repeat": "",
758
- "crontab": "",
759
- "once": false,
760
- "onceDelay": 0.1,
761
- "topic": "edge_cases",
762
- "payload": "{}",
763
- "payloadType": "json",
764
- "x": 150,
765
- "y": 1360,
766
- "wires": [["function-edge-strings"]]
767
- },
768
- {
769
- "id": "function-edge-strings",
770
- "type": "function",
771
- "z": "questdb-comprehensive-tab",
772
- "name": "Test special strings",
773
- "func": "msg.payload = {\n symbols: {\n test_type: \"special_strings\",\n unicode_symbol: \"温度传感器\",\n emoji_symbol: \"sensor_🌡️\"\n },\n columns: {\n normal_string: \"Hello World\",\n unicode_string: \"Température: 25°C\",\n json_string: '{\"nested\": \"json\"}',\n multiline_string: \"Line 1\\nLine 2\\nLine 3\",\n special_chars: \"Tab:\\tQuote:\\\"Backslash:\\\\\",\n empty_string: \"\",\n numeric_string: \"12345\"\n },\n timestamp: Date.now()\n};\nreturn msg;",
774
- "outputs": 1,
775
- "x": 420,
776
- "y": 1360,
777
- "wires": [["questdb-write-edge", "debug-edge"]]
778
- },
779
- {
780
- "id": "questdb-write-edge",
781
- "type": "questdb",
782
- "z": "questdb-comprehensive-tab",
783
- "name": "Write edge cases",
784
- "questdb": "questdb-config-test",
785
- "autoFlush": true,
786
- "flushInterval": 1000,
787
- "x": 680,
788
- "y": 1300,
789
- "wires": [["debug-edge-result"]]
790
- },
791
- {
792
- "id": "debug-edge",
793
- "type": "debug",
794
- "z": "questdb-comprehensive-tab",
795
- "name": "Edge payload",
796
- "active": true,
797
- "tosidebar": true,
798
- "console": false,
799
- "tostatus": false,
800
- "complete": "payload",
801
- "targetType": "msg",
802
- "x": 680,
803
- "y": 1240
804
- },
805
- {
806
- "id": "debug-edge-result",
807
- "type": "debug",
808
- "z": "questdb-comprehensive-tab",
809
- "name": "Edge Result",
810
- "active": true,
811
- "tosidebar": true,
812
- "console": false,
813
- "tostatus": true,
814
- "complete": "payload",
815
- "targetType": "msg",
816
- "statusVal": "payload.success",
817
- "statusType": "auto",
818
- "x": 890,
819
- "y": 1300
820
- },
821
- {
822
- "id": "comment-multi-table",
823
- "type": "comment",
824
- "z": "questdb-comprehensive-tab",
825
- "name": "--- Multi-Table Scenario ---",
826
- "info": "",
827
- "x": 160,
828
- "y": 1440
829
- },
830
- {
831
- "id": "inject-multi",
832
- "type": "inject",
833
- "z": "questdb-comprehensive-tab",
834
- "name": "Trigger multi-table write",
835
- "props": [
836
- {"p": "payload"},
837
- {"p": "topic", "vt": "str"}
838
- ],
839
- "repeat": "",
840
- "crontab": "",
841
- "once": false,
842
- "onceDelay": 0.1,
843
- "topic": "",
844
- "payload": "",
845
- "payloadType": "date",
846
- "x": 180,
847
- "y": 1500,
848
- "wires": [["function-multi-split"]]
849
- },
850
- {
851
- "id": "function-multi-split",
852
- "type": "function",
853
- "z": "questdb-comprehensive-tab",
854
- "name": "Generate multi-table data",
855
- "func": "const now = Date.now();\n\n// Simulate a device sending to multiple tables\nconst messages = [\n {\n topic: 'device_status',\n payload: {\n symbols: { device_id: 'dev_001' },\n columns: {\n online: true,\n uptime_seconds: 86400,\n cpu_usage: 45.2,\n memory_usage: 62.8\n },\n timestamp: now\n }\n },\n {\n topic: 'temperature_log',\n payload: {\n symbols: { device_id: 'dev_001', sensor: 'internal' },\n columns: { temperature: 42.5 },\n timestamp: now\n }\n },\n {\n topic: 'temperature_log',\n payload: {\n symbols: { device_id: 'dev_001', sensor: 'external' },\n columns: { temperature: 22.1 },\n timestamp: now\n }\n },\n {\n topic: 'network_stats',\n payload: {\n symbols: { device_id: 'dev_001', interface: 'eth0' },\n columns: {\n bytes_in: 1234567890,\n bytes_out: 987654321,\n packets_in: 12345,\n packets_out: 9876\n },\n timestamp: now\n }\n },\n {\n topic: 'event_log',\n payload: {\n symbols: {\n device_id: 'dev_001',\n event_type: 'info',\n severity: 'low'\n },\n columns: {\n message: 'Periodic health check completed',\n event_code: 1001\n },\n timestamp: now\n }\n }\n];\n\nreturn [messages];",
856
- "outputs": 1,
857
- "x": 440,
858
- "y": 1500,
859
- "wires": [["questdb-write-multi"]]
860
- },
861
- {
862
- "id": "questdb-write-multi",
863
- "type": "questdb",
864
- "z": "questdb-comprehensive-tab",
865
- "name": "Write to multiple tables",
866
- "questdb": "questdb-config-test",
867
- "autoFlush": true,
868
- "flushInterval": 1000,
869
- "x": 710,
870
- "y": 1500,
871
- "wires": [["debug-multi-result"]]
872
- },
873
- {
874
- "id": "debug-multi-result",
875
- "type": "debug",
876
- "z": "questdb-comprehensive-tab",
877
- "name": "Multi Result",
878
- "active": true,
879
- "tosidebar": true,
880
- "console": false,
881
- "tostatus": true,
882
- "complete": "payload",
883
- "targetType": "msg",
884
- "statusVal": "payload.table",
885
- "statusType": "auto",
886
- "x": 930,
887
- "y": 1500
888
- },
889
- {
890
- "id": "questdb-config-test",
891
- "type": "questdb-config",
892
- "name": "Test QuestDB",
893
- "protocol": "http",
894
- "host": "localhost",
895
- "port": "9000",
896
- "tlsVerify": true,
897
- "tlsCa": "",
898
- "autoFlush": true,
899
- "autoFlushRows": "75000",
900
- "autoFlushInterval": "1000",
901
- "requestTimeout": "10000",
902
- "retryTimeout": "10000",
903
- "initBufSize": "65536",
904
- "maxBufSize": "104857600",
905
- "useAuth": false,
906
- "authType": "basic"
907
- }
908
- ]