n8n-nodes-databar 0.1.4 → 0.2.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.
@@ -20,9 +20,8 @@
20
20
  * Resources & Operations:
21
21
  * - User: Get account info
22
22
  * - Enrichment: Run, Bulk Run (with async polling)
23
- * - Waterfall: List, Get, Run
24
- *
25
- * Note: Table operations are temporarily hidden but can be re-enabled in the code
23
+ * - Table: Insert Rows, Upsert Rows
24
+ * - Waterfall: Run (with async polling)
26
25
  */
27
26
  Object.defineProperty(exports, "__esModule", { value: true });
28
27
  exports.Databar = void 0;
@@ -107,15 +106,14 @@ class Databar {
107
106
  name: 'Enrichment',
108
107
  value: 'enrichment',
109
108
  },
109
+ {
110
+ name: 'Table',
111
+ value: 'table',
112
+ },
110
113
  {
111
114
  name: 'Waterfall',
112
115
  value: 'waterfall',
113
116
  },
114
- // Table resource temporarily hidden - can be re-enabled later
115
- // {
116
- // name: 'Table',
117
- // value: 'table',
118
- // },
119
117
  {
120
118
  name: 'Other',
121
119
  value: 'user',
@@ -166,102 +164,29 @@ class Databar {
166
164
  description: 'Run an enrichment task',
167
165
  action: 'Run enrichment',
168
166
  },
169
- {
170
- name: 'Bulk Run',
171
- value: 'bulkRun',
172
- description: 'Run enrichment on multiple records',
173
- action: 'Bulk run enrichment',
174
- },
167
+ // Bulk Run hidden for v1 - re-add to enable:
168
+ // { name: 'Bulk Run', value: 'bulkRun', description: 'Run enrichment on multiple records', action: 'Bulk run enrichment' },
175
169
  ],
176
170
  default: 'run',
177
171
  },
178
- // Enrichment: Selection Mode
179
- {
180
- displayName: 'Enrichment Selection',
181
- name: 'enrichmentSelectionMode',
182
- type: 'options',
183
- options: [
184
- {
185
- name: 'From List',
186
- value: 'list',
187
- description: 'Select from available enrichments',
188
- },
189
- {
190
- name: 'By ID',
191
- value: 'id',
192
- description: 'Enter enrichment ID manually',
193
- },
194
- ],
195
- displayOptions: {
196
- show: {
197
- resource: ['enrichment'],
198
- operation: ['run', 'bulkRun'],
199
- },
200
- },
201
- default: 'list',
202
- description: 'How to select the enrichment',
203
- },
204
- // Enrichment: Run/BulkRun - Enrichment Selection from List
172
+ // Enrichment: Run/BulkRun - Enrichment Selection
205
173
  {
206
174
  displayName: 'Enrichment',
207
175
  name: 'enrichmentId',
208
176
  type: 'options',
209
177
  typeOptions: {
210
178
  loadOptionsMethod: 'getEnrichments',
211
- searchable: true, // Enable client-side search
179
+ searchable: true,
212
180
  },
213
181
  displayOptions: {
214
182
  show: {
215
183
  resource: ['enrichment'],
216
184
  operation: ['run', 'bulkRun'],
217
- enrichmentSelectionMode: ['list'],
218
185
  },
219
186
  },
220
187
  default: '',
221
188
  required: true,
222
- description: 'Select the enrichment to use. If this dropdown is empty, switch to "By ID" mode above.',
223
- },
224
- // Enrichment: Run/BulkRun - Enrichment ID Manual Entry
225
- {
226
- displayName: 'Enrichment ID',
227
- name: 'enrichmentId',
228
- type: 'number',
229
- displayOptions: {
230
- show: {
231
- resource: ['enrichment'],
232
- operation: ['run', 'bulkRun'],
233
- enrichmentSelectionMode: ['id'],
234
- },
235
- },
236
- default: 0,
237
- required: true,
238
- description: 'Enter the enrichment ID (e.g., 1220 for Email Verifier)',
239
- },
240
- // Enrichment: Run - Parameter Input Mode
241
- {
242
- displayName: 'Parameter Input Mode',
243
- name: 'parameterMode',
244
- type: 'options',
245
- options: [
246
- {
247
- name: 'Guided Fields',
248
- value: 'fields',
249
- description: 'Fill in parameters using individual fields',
250
- },
251
- {
252
- name: 'Raw JSON',
253
- value: 'json',
254
- description: 'Enter parameters as JSON object',
255
- },
256
- ],
257
- displayOptions: {
258
- show: {
259
- resource: ['enrichment'],
260
- operation: ['run'],
261
- },
262
- },
263
- default: 'fields',
264
- description: 'Choose how to input enrichment parameters',
189
+ description: 'Select the enrichment to use. Switch to Expression mode to pass a dynamic enrichment ID.',
265
190
  },
266
191
  // Enrichment: Run - Parameters as Resource Mapper (Guided Fields)
267
192
  {
@@ -282,54 +207,17 @@ class Databar {
282
207
  valuesLabel: 'Parameters',
283
208
  addAllFields: true,
284
209
  multiKeyMatch: false,
210
+ supportAutoMap: false,
285
211
  },
286
212
  },
287
213
  displayOptions: {
288
214
  show: {
289
215
  resource: ['enrichment'],
290
216
  operation: ['run'],
291
- parameterMode: ['fields'],
292
217
  },
293
218
  },
294
219
  description: 'Fill in the enrichment parameters',
295
220
  },
296
- // Enrichment: Run - Template Helper for JSON Mode (Hidden field that loads template)
297
- {
298
- displayName: 'Template',
299
- name: 'jsonTemplateHelper',
300
- type: 'options',
301
- typeOptions: {
302
- loadOptionsMethod: 'getEnrichmentTemplate',
303
- loadOptionsDependsOn: ['enrichmentId'],
304
- },
305
- displayOptions: {
306
- show: {
307
- resource: ['enrichment'],
308
- operation: ['run'],
309
- parameterMode: ['json'],
310
- },
311
- },
312
- default: '{}',
313
- description: 'Click to see the parameter template, then copy it into the field below',
314
- },
315
- // Enrichment: Run - Parameters as JSON (Raw JSON)
316
- {
317
- displayName: 'Parameters (JSON)',
318
- name: 'paramsJson',
319
- type: 'json',
320
- displayOptions: {
321
- show: {
322
- resource: ['enrichment'],
323
- operation: ['run'],
324
- parameterMode: ['json'],
325
- },
326
- },
327
- default: '={{ $parameter["jsonTemplateHelper"] }}',
328
- placeholder: '{"email": "test@example.com"}',
329
- hint: '✨ Auto-filled from template above! Replace <text> placeholders with your actual data.',
330
- description: 'Parameters automatically populated from template. Replace placeholders with real values.',
331
- required: true,
332
- },
333
221
  // Enrichment: Bulk Run - Parameters JSON
334
222
  {
335
223
  displayName: 'Parameters (Array of Objects)',
@@ -395,115 +283,6 @@ class Databar {
395
283
  // ====================================
396
284
  // TABLE OPERATIONS
397
285
  // ====================================
398
- // Table operations temporarily hidden - can be re-enabled later
399
- // {
400
- // displayName: 'Operation',
401
- // name: 'operation',
402
- // type: 'options',
403
- // noDataExpression: true,
404
- // displayOptions: {
405
- // show: {
406
- // resource: ['table'],
407
- // },
408
- // },
409
- // options: [
410
- // {
411
- // name: 'Create',
412
- // value: 'create',
413
- // description: 'Create a new table',
414
- // action: 'Create table',
415
- // },
416
- // {
417
- // name: 'List',
418
- // value: 'list',
419
- // description: 'Get all workspace tables',
420
- // action: 'List tables',
421
- // },
422
- // {
423
- // name: 'Get Rows',
424
- // value: 'getRows',
425
- // description: 'Get table rows',
426
- // action: 'Get table rows',
427
- // },
428
- // {
429
- // name: 'Get Columns',
430
- // value: 'getColumns',
431
- // description: 'Get table columns',
432
- // action: 'Get table columns',
433
- // },
434
- // {
435
- // name: 'Run Enrichment',
436
- // value: 'runEnrichment',
437
- // description: 'Run table enrichment',
438
- // action: 'Run table enrichment',
439
- // },
440
- // ],
441
- // default: 'list',
442
- // },
443
- // Table: Get Rows/Columns/Run - Table Selection
444
- // {
445
- // displayName: 'Table',
446
- // name: 'tableUuid',
447
- // type: 'options',
448
- // typeOptions: {
449
- // loadOptionsMethod: 'getTables',
450
- // searchable: true,
451
- // },
452
- // displayOptions: {
453
- // show: {
454
- // resource: ['table'],
455
- // operation: ['getRows', 'getColumns', 'runEnrichment'],
456
- // },
457
- // },
458
- // default: '',
459
- // required: true,
460
- // description: 'Select the table to use',
461
- // },
462
- // Table: Get Rows - Pagination
463
- // {
464
- // displayName: 'Per Page',
465
- // name: 'perPage',
466
- // type: 'number',
467
- // displayOptions: {
468
- // show: {
469
- // resource: ['table'],
470
- // operation: ['getRows'],
471
- // },
472
- // },
473
- // default: 1000,
474
- // description: 'Number of items to return per page',
475
- // },
476
- // {
477
- // displayName: 'Page',
478
- // name: 'page',
479
- // type: 'number',
480
- // displayOptions: {
481
- // show: {
482
- // resource: ['table'],
483
- // operation: ['getRows'],
484
- // },
485
- // },
486
- // default: 1,
487
- // description: 'Page number to retrieve',
488
- // },
489
- // Table: Run Enrichment - Enrichment ID
490
- // {
491
- // displayName: 'Enrichment ID',
492
- // name: 'tableEnrichmentId',
493
- // type: 'string',
494
- // displayOptions: {
495
- // show: {
496
- // resource: ['table'],
497
- // operation: ['runEnrichment'],
498
- // },
499
- // },
500
- // default: '',
501
- // required: true,
502
- // description: 'The ID of the enrichment to run',
503
- // },
504
- // ====================================
505
- // WATERFALL OPERATIONS
506
- // ====================================
507
286
  {
508
287
  displayName: 'Operation',
509
288
  name: 'operation',
@@ -511,87 +290,155 @@ class Databar {
511
290
  noDataExpression: true,
512
291
  displayOptions: {
513
292
  show: {
514
- resource: ['waterfall'],
293
+ resource: ['table'],
515
294
  },
516
295
  },
517
296
  options: [
518
297
  {
519
- name: 'List',
520
- value: 'list',
521
- description: 'Get all available waterfalls',
522
- action: 'List waterfalls',
298
+ name: 'Insert Rows',
299
+ value: 'insertRows',
300
+ description: 'Insert one or more rows into a table',
301
+ action: 'Insert rows into table',
523
302
  },
524
303
  {
525
- name: 'Get',
526
- value: 'get',
527
- description: 'Get details of a specific waterfall',
528
- action: 'Get waterfall',
304
+ name: 'Upsert Rows',
305
+ value: 'upsertRows',
306
+ description: 'Update rows by key or create new ones if no match is found',
307
+ action: 'Upsert rows in table',
529
308
  },
530
- {
531
- name: 'Run',
532
- value: 'run',
533
- description: 'Run a waterfall task',
534
- action: 'Run waterfall',
535
- },
536
- // Bulk Run temporarily removed - can be re-added later if needed
537
- // {
538
- // name: 'Bulk Run',
539
- // value: 'bulkRun',
540
- // description: 'Run waterfall on multiple records',
541
- // action: 'Bulk run waterfall',
542
- // },
543
309
  ],
544
- default: 'list',
310
+ default: 'insertRows',
545
311
  },
546
- // Waterfall: Get/Run - Waterfall Selection
312
+ // Table: Selection from List
547
313
  {
548
- displayName: 'Waterfall',
549
- name: 'waterfallIdentifier',
314
+ displayName: 'Table',
315
+ name: 'tableId',
550
316
  type: 'options',
551
317
  typeOptions: {
552
- loadOptionsMethod: 'getWaterfalls',
318
+ loadOptionsMethod: 'getTables',
553
319
  searchable: true,
554
320
  },
555
321
  displayOptions: {
556
322
  show: {
557
- resource: ['waterfall'],
558
- operation: ['get', 'run'],
323
+ resource: ['table'],
559
324
  },
560
325
  },
561
326
  default: '',
562
327
  required: true,
563
- description: 'Select the waterfall to use',
328
+ description: 'Select the table to use. Switch to Expression mode to pass a dynamic table ID.',
564
329
  },
565
- // Waterfall: Run - Parameter Input Mode
330
+ // Table: Insert Rows - Fields (Resource Mapper)
566
331
  {
567
- displayName: 'Parameter Input Mode',
568
- name: 'waterfallParameterMode',
569
- type: 'options',
332
+ displayName: 'Fields',
333
+ name: 'rowFields',
334
+ type: 'resourceMapper',
335
+ noDataExpression: true,
336
+ default: {
337
+ mappingMode: 'defineBelow',
338
+ value: null,
339
+ },
340
+ required: true,
341
+ typeOptions: {
342
+ loadOptionsDependsOn: ['tableId'],
343
+ resourceMapper: {
344
+ resourceMapperMethod: 'getTableFields',
345
+ mode: 'add',
346
+ valuesLabel: 'Column',
347
+ addAllFields: true,
348
+ multiKeyMatch: false,
349
+ supportAutoMap: false,
350
+ },
351
+ },
352
+ displayOptions: {
353
+ show: {
354
+ resource: ['table'],
355
+ operation: ['insertRows'],
356
+ },
357
+ },
358
+ description: 'Column values for the row to insert. Each input item creates one row.',
359
+ },
360
+ // Table: Insert Rows - Additional Options
361
+ {
362
+ displayName: 'Options',
363
+ name: 'insertOptions',
364
+ type: 'collection',
365
+ placeholder: 'Add Option',
366
+ default: {},
367
+ displayOptions: {
368
+ show: {
369
+ resource: ['table'],
370
+ operation: ['insertRows'],
371
+ },
372
+ },
570
373
  options: [
571
374
  {
572
- name: 'Guided Fields',
573
- value: 'fields',
574
- description: 'Fill in parameters using individual fields',
375
+ displayName: 'Allow New Columns',
376
+ name: 'allowNewColumns',
377
+ type: 'boolean',
378
+ default: false,
379
+ description: 'Whether to automatically create columns that don\'t exist yet (created as text columns)',
575
380
  },
576
381
  {
577
- name: 'Raw JSON',
578
- value: 'json',
579
- description: 'Enter parameters as JSON object',
382
+ displayName: 'Dedupe',
383
+ name: 'dedupeEnabled',
384
+ type: 'boolean',
385
+ default: false,
386
+ description: 'Whether to skip rows that match existing rows on the specified keys',
387
+ },
388
+ {
389
+ displayName: 'Dedupe Keys',
390
+ name: 'dedupeKeys',
391
+ type: 'string',
392
+ default: '',
393
+ placeholder: 'domain, email',
394
+ description: 'Comma-separated column names used for duplicate detection',
395
+ displayOptions: {
396
+ show: {
397
+ dedupeEnabled: [true],
398
+ },
399
+ },
580
400
  },
581
401
  ],
402
+ },
403
+ // Table: Upsert Rows - Key Column
404
+ {
405
+ displayName: 'Column to Match On',
406
+ name: 'upsertKeyColumn',
407
+ type: 'options',
408
+ typeOptions: {
409
+ loadOptionsMethod: 'getTableColumns',
410
+ loadOptionsDependsOn: ['tableId'],
411
+ },
582
412
  displayOptions: {
583
413
  show: {
584
- resource: ['waterfall'],
585
- operation: ['run'],
414
+ resource: ['table'],
415
+ operation: ['upsertRows'],
586
416
  },
587
417
  },
588
- default: 'fields',
589
- description: 'Choose how to input waterfall parameters',
418
+ default: '',
419
+ required: true,
420
+ description: 'The column used to find an existing row. If a match is found, that row is updated; otherwise a new row is created.',
590
421
  },
591
- // Waterfall: Run - Parameters as Resource Mapper (Guided Fields)
422
+ // Table: Upsert Rows - Value to Search
592
423
  {
593
- displayName: 'Parameters',
594
- name: 'waterfallParamsFields',
424
+ displayName: 'Value to Search',
425
+ name: 'upsertKeyValue',
426
+ type: 'string',
427
+ displayOptions: {
428
+ show: {
429
+ resource: ['table'],
430
+ operation: ['upsertRows'],
431
+ },
432
+ },
433
+ default: '',
434
+ required: true,
435
+ placeholder: 'e.g. openai.com',
436
+ description: 'The value to look for in the selected column. Databar will search for a row where the column matches this value exactly. If found, that row\'s fields are updated; if not, a new row is inserted with this value and the fields you provide.',
437
+ },
438
+ // Table: Upsert Rows - Fields (Resource Mapper)
439
+ {
440
+ displayName: 'Fields',
441
+ name: 'upsertFields',
595
442
  type: 'resourceMapper',
596
443
  noDataExpression: true,
597
444
  default: {
@@ -600,60 +447,95 @@ class Databar {
600
447
  },
601
448
  required: true,
602
449
  typeOptions: {
603
- loadOptionsDependsOn: ['waterfallIdentifier'],
450
+ loadOptionsDependsOn: ['tableId'],
604
451
  resourceMapper: {
605
- resourceMapperMethod: 'getWaterfallFields',
452
+ resourceMapperMethod: 'getTableFields',
606
453
  mode: 'add',
607
- valuesLabel: 'Parameters',
454
+ valuesLabel: 'Column',
608
455
  addAllFields: true,
609
456
  multiKeyMatch: false,
457
+ supportAutoMap: false,
610
458
  },
611
459
  },
460
+ displayOptions: {
461
+ show: {
462
+ resource: ['table'],
463
+ operation: ['upsertRows'],
464
+ },
465
+ },
466
+ description: 'Column values to set on the matched or newly created row',
467
+ },
468
+ // ====================================
469
+ // WATERFALL OPERATIONS
470
+ // ====================================
471
+ {
472
+ displayName: 'Operation',
473
+ name: 'operation',
474
+ type: 'options',
475
+ noDataExpression: true,
612
476
  displayOptions: {
613
477
  show: {
614
478
  resource: ['waterfall'],
615
- operation: ['run'],
616
- waterfallParameterMode: ['fields'],
617
479
  },
618
480
  },
619
- description: 'Fill in the waterfall parameters',
481
+ options: [
482
+ {
483
+ name: 'Run',
484
+ value: 'run',
485
+ description: 'Run a waterfall task',
486
+ action: 'Run waterfall',
487
+ },
488
+ ],
489
+ default: 'run',
620
490
  },
621
- // Waterfall: Run - Template Helper for JSON Mode
491
+ // Waterfall: Run - Waterfall Selection
622
492
  {
623
- displayName: 'Template',
624
- name: 'waterfallJsonTemplateHelper',
493
+ displayName: 'Waterfall',
494
+ name: 'waterfallIdentifier',
625
495
  type: 'options',
626
496
  typeOptions: {
627
- loadOptionsMethod: 'getWaterfallTemplate',
628
- loadOptionsDependsOn: ['waterfallIdentifier'],
497
+ loadOptionsMethod: 'getWaterfalls',
498
+ searchable: true,
629
499
  },
630
500
  displayOptions: {
631
501
  show: {
632
502
  resource: ['waterfall'],
633
503
  operation: ['run'],
634
- waterfallParameterMode: ['json'],
635
504
  },
636
505
  },
637
- default: '{}',
638
- description: 'Click to see the parameter template, then copy it into the field below',
506
+ default: '',
507
+ required: true,
508
+ description: 'Select the waterfall to use',
639
509
  },
640
- // Waterfall: Run - Parameters as JSON (Raw JSON)
510
+ // Waterfall: Run - Parameters as Resource Mapper (Guided Fields)
641
511
  {
642
- displayName: 'Parameters (JSON)',
643
- name: 'params',
644
- type: 'json',
512
+ displayName: 'Parameters',
513
+ name: 'waterfallParamsFields',
514
+ type: 'resourceMapper',
515
+ noDataExpression: true,
516
+ default: {
517
+ mappingMode: 'defineBelow',
518
+ value: null,
519
+ },
520
+ required: true,
521
+ typeOptions: {
522
+ loadOptionsDependsOn: ['waterfallIdentifier'],
523
+ resourceMapper: {
524
+ resourceMapperMethod: 'getWaterfallFields',
525
+ mode: 'add',
526
+ valuesLabel: 'Parameters',
527
+ addAllFields: true,
528
+ multiKeyMatch: false,
529
+ supportAutoMap: false,
530
+ },
531
+ },
645
532
  displayOptions: {
646
533
  show: {
647
534
  resource: ['waterfall'],
648
535
  operation: ['run'],
649
- waterfallParameterMode: ['json'],
650
536
  },
651
537
  },
652
- default: '={{ $parameter["waterfallJsonTemplateHelper"] }}',
653
- placeholder: '{"first_name": "John", "last_name": "Doe", "company": "example.com"}',
654
- hint: '✨ Auto-filled from template above! Replace <text> placeholders with your actual data.',
655
- description: 'Parameters automatically populated from template. Replace placeholders with real values.',
656
- required: true,
538
+ description: 'Fill in the waterfall parameters',
657
539
  },
658
540
  // Waterfall: Run - Enrichments (Multi-select)
659
541
  {
@@ -671,6 +553,7 @@ class Databar {
671
553
  },
672
554
  },
673
555
  default: [],
556
+ required: true,
674
557
  description: 'Select which data providers to use in the waterfall. The waterfall will try each provider in order until a successful result is returned.',
675
558
  },
676
559
  // Waterfall: Run - Wait for Completion
@@ -763,9 +646,9 @@ class Databar {
763
646
  // Return error as an option so user knows what went wrong
764
647
  const errorMessage = error instanceof Error ? error.message : 'Failed to load enrichments';
765
648
  returnData.push({
766
- name: `⚠️ Error: ${errorMessage}`,
649
+ name: `Error: ${errorMessage}`,
767
650
  value: '',
768
- description: 'Switch to "By ID" mode to enter enrichment ID manually',
651
+ description: 'Could not load enrichments. Check your API key and try again.',
769
652
  });
770
653
  }
771
654
  return returnData;
@@ -827,7 +710,7 @@ class Databar {
827
710
  const availableEnrichments = waterfallData.available_enrichments || [];
828
711
  if (availableEnrichments.length === 0) {
829
712
  return [{
830
- name: '⚠️ No Data Providers Available',
713
+ name: 'No Data Providers Available',
831
714
  value: '',
832
715
  description: 'This waterfall has no available data providers configured.',
833
716
  }];
@@ -850,42 +733,88 @@ class Databar {
850
733
  catch (error) {
851
734
  const errorMessage = error instanceof Error ? error.message : String(error);
852
735
  return [{
853
- name: '⚠️ Error Loading Data Providers',
736
+ name: 'Error Loading Data Providers',
854
737
  value: '',
855
738
  description: `Could not fetch waterfall data providers. Error: ${errorMessage}`,
856
739
  }];
857
740
  }
858
741
  return returnData;
859
742
  },
860
- // Load tables - temporarily hidden, can be re-enabled later
861
- // async getTables(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
862
- // const returnData: INodePropertyOptions[] = [];
863
- // try {
864
- // const tables = await this.helpers.httpRequestWithAuthentication.call(
865
- // this,
866
- // 'databarApi',
867
- // {
868
- // method: 'GET',
869
- // url: 'https://api.databar.ai/v1/table/',
870
- // },
871
- // );
872
- // if (Array.isArray(tables)) {
873
- // for (const table of tables) {
874
- // const tableData = table as IDataObject;
875
- // returnData.push({
876
- // name: tableData.name as string,
877
- // value: tableData.identifier as string,
878
- // description: `Created: ${tableData.created_at}`,
879
- // });
880
- // }
881
- // }
882
- // // Sort by name
883
- // returnData.sort((a, b) => a.name.localeCompare(b.name));
884
- // } catch (error) {
885
- // // Silently fail
886
- // }
887
- // return returnData;
888
- // },
743
+ async getTables() {
744
+ const returnData = [];
745
+ try {
746
+ const tables = await this.helpers.httpRequestWithAuthentication.call(this, 'databarApi', {
747
+ method: 'GET',
748
+ url: 'https://api.databar.ai/v1/table/',
749
+ });
750
+ if (Array.isArray(tables)) {
751
+ for (const table of tables) {
752
+ const tableData = table;
753
+ returnData.push({
754
+ name: tableData.name,
755
+ value: tableData.identifier,
756
+ description: `Created: ${tableData.created_at}`,
757
+ });
758
+ }
759
+ }
760
+ returnData.sort((a, b) => a.name.localeCompare(b.name));
761
+ }
762
+ catch (error) {
763
+ const errorMessage = error instanceof Error ? error.message : 'Failed to load tables';
764
+ returnData.push({
765
+ name: `Error: ${errorMessage}`,
766
+ value: '',
767
+ description: 'Could not load tables. Check your API key and try again.',
768
+ });
769
+ }
770
+ return returnData;
771
+ },
772
+ async getTableColumns() {
773
+ const returnData = [];
774
+ try {
775
+ let tableId;
776
+ try {
777
+ const tableIdRaw = this.getCurrentNodeParameter('tableId');
778
+ if (tableIdRaw) {
779
+ tableId = tableIdRaw;
780
+ }
781
+ }
782
+ catch (error) {
783
+ // Parameter might not be set yet
784
+ }
785
+ if (!tableId) {
786
+ return [{
787
+ name: 'Select a Table First',
788
+ value: '',
789
+ }];
790
+ }
791
+ const columns = await this.helpers.httpRequestWithAuthentication.call(this, 'databarApi', {
792
+ method: 'GET',
793
+ url: `https://api.databar.ai/v1/table/${tableId}/columns`,
794
+ });
795
+ if (Array.isArray(columns)) {
796
+ for (const column of columns) {
797
+ const colData = column;
798
+ if (colData.data_processor_id)
799
+ continue;
800
+ returnData.push({
801
+ name: colData.name,
802
+ value: colData.internal_name,
803
+ description: `Type: ${colData.type_of_value || 'unknown'}`,
804
+ });
805
+ }
806
+ }
807
+ returnData.sort((a, b) => a.name.localeCompare(b.name));
808
+ }
809
+ catch (error) {
810
+ const errorMessage = error instanceof Error ? error.message : 'Failed to load columns';
811
+ returnData.push({
812
+ name: `Error: ${errorMessage}`,
813
+ value: '',
814
+ });
815
+ }
816
+ return returnData;
817
+ },
889
818
  /**
890
819
  * Get parameter template for selected enrichment
891
820
  *
@@ -945,17 +874,17 @@ class Databar {
945
874
  const singleLineJson = JSON.stringify(template); // Single line for expression
946
875
  const paramList = paramDescriptions.join('\n');
947
876
  return [{
948
- name: '📋 Template Loaded',
877
+ name: 'Template Loaded',
949
878
  value: singleLineJson,
950
- description: `Required Parameters:\n${paramList}\n\n📝 JSON Template:\n${templateJson}`,
879
+ description: `Required Parameters:\n${paramList}\n\nJSON Template:\n${templateJson}`,
951
880
  }];
952
881
  }
953
882
  catch (error) {
954
883
  const errorMessage = error instanceof Error ? error.message : String(error);
955
884
  return [{
956
- name: '⚠️ Error Loading Template',
885
+ name: 'Error Loading Template',
957
886
  value: '{}',
958
- description: `Could not fetch enrichment parameters. Error: ${errorMessage}\n\nTry:\n• Verify the enrichment ID is valid\n• Check your API key has access\n• Use the "Get" operation to see parameters manually`,
887
+ description: `Could not fetch enrichment parameters: ${errorMessage}`,
959
888
  }];
960
889
  }
961
890
  },
@@ -1018,22 +947,83 @@ class Databar {
1018
947
  const singleLineJson = JSON.stringify(template); // Single line for expression
1019
948
  const paramList = paramDescriptions.join('\n');
1020
949
  return [{
1021
- name: '📋 Template Loaded',
950
+ name: 'Template Loaded',
1022
951
  value: singleLineJson,
1023
- description: `Required Parameters:\n${paramList}\n\n📝 JSON Template:\n${templateJson}`,
952
+ description: `Required Parameters:\n${paramList}\n\nJSON Template:\n${templateJson}`,
1024
953
  }];
1025
954
  }
1026
955
  catch (error) {
1027
956
  const errorMessage = error instanceof Error ? error.message : String(error);
1028
957
  return [{
1029
- name: '⚠️ Error Loading Template',
958
+ name: 'Error Loading Template',
1030
959
  value: '{}',
1031
- description: `Could not fetch waterfall parameters. Error: ${errorMessage}\n\nTry:\n• Verify the waterfall identifier is valid\n• Check your API key has access\n• Use the "Get" operation to see parameters manually`,
960
+ description: `Could not fetch waterfall parameters: ${errorMessage}`,
1032
961
  }];
1033
962
  }
1034
963
  },
1035
964
  },
1036
965
  resourceMapping: {
966
+ /**
967
+ * Get table column definitions for the resource mapper.
968
+ * Fetches columns from the API and maps them to ResourceMapperField entries
969
+ * so n8n renders a per-column form UI.
970
+ */
971
+ async getTableFields() {
972
+ try {
973
+ let tableId;
974
+ try {
975
+ const tableIdRaw = this.getCurrentNodeParameter('tableId');
976
+ if (tableIdRaw) {
977
+ tableId = tableIdRaw;
978
+ }
979
+ }
980
+ catch (_error) {
981
+ // Parameter might not be set yet
982
+ }
983
+ if (!tableId) {
984
+ return { fields: [] };
985
+ }
986
+ const columns = await this.helpers.httpRequestWithAuthentication.call(this, 'databarApi', {
987
+ method: 'GET',
988
+ url: `https://api.databar.ai/v1/table/${tableId}/columns`,
989
+ });
990
+ if (!Array.isArray(columns) || columns.length === 0) {
991
+ return { fields: [] };
992
+ }
993
+ const typeMap = {
994
+ text: 'string',
995
+ longtext: 'string',
996
+ number: 'number',
997
+ integer: 'number',
998
+ float: 'number',
999
+ boolean: 'boolean',
1000
+ bool: 'boolean',
1001
+ };
1002
+ const userColumns = columns.filter((column) => {
1003
+ const col = column;
1004
+ return !col.data_processor_id;
1005
+ });
1006
+ const fields = userColumns.map((column) => {
1007
+ const col = column;
1008
+ const internalName = col.internal_name;
1009
+ const displayName = col.name;
1010
+ const colType = col.type_of_value || 'text';
1011
+ return {
1012
+ id: internalName,
1013
+ displayName: `${displayName} (${colType})`,
1014
+ required: false,
1015
+ defaultMatch: false,
1016
+ display: true,
1017
+ type: typeMap[colType] || 'string',
1018
+ canBeUsedToMatch: true,
1019
+ };
1020
+ });
1021
+ return { fields };
1022
+ }
1023
+ catch (_error) {
1024
+ return { fields: [] };
1025
+ }
1026
+ },
1037
1027
  /**
1038
1028
  * Get enrichment fields for resource mapper
1039
1029
  *
@@ -1250,26 +1240,9 @@ class Databar {
1250
1240
  if (!enrichmentId || isNaN(enrichmentId)) {
1251
1241
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Please provide a valid enrichment ID', { itemIndex: i });
1252
1242
  }
1253
- const parameterMode = this.getNodeParameter('parameterMode', i, 'fields');
1254
1243
  const waitForCompletion = this.getNodeParameter('waitForCompletion', i, true);
1255
- // Get parameters based on input mode
1256
- let params;
1257
- if (parameterMode === 'fields') {
1258
- // Resource mapper mode - get structured fields
1259
- const paramsFields = this.getNodeParameter('paramsFields', i);
1260
- // Resource mapper returns an object with 'value' containing the actual data
1261
- params = paramsFields.value || {};
1262
- }
1263
- else {
1264
- // Raw JSON mode - parse JSON string
1265
- const paramsJson = this.getNodeParameter('paramsJson', i);
1266
- try {
1267
- params = JSON.parse(paramsJson);
1268
- }
1269
- catch (error) {
1270
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Parameters must be valid JSON object', { itemIndex: i });
1271
- }
1272
- }
1244
+ const paramsFields = this.getNodeParameter('paramsFields', i);
1245
+ const params = paramsFields.value || {};
1273
1246
  const response = await this.helpers.httpRequestWithAuthentication.call(this, 'databarApi', {
1274
1247
  method: 'POST',
1275
1248
  url: `https://api.databar.ai/v1/enrichments/${enrichmentId}/run`,
@@ -1337,63 +1310,76 @@ class Databar {
1337
1310
  }
1338
1311
  }
1339
1312
  // ====================================
1340
- // WATERFALL OPERATIONS
1313
+ // TABLE OPERATIONS
1341
1314
  // ====================================
1342
- else if (resource === 'waterfall') {
1343
- if (operation === 'list') {
1344
- const response = await this.helpers.httpRequestWithAuthentication.call(this, 'databarApi', {
1345
- method: 'GET',
1346
- url: 'https://api.databar.ai/v1/waterfalls/',
1347
- });
1348
- if (Array.isArray(response)) {
1349
- for (const item of response) {
1350
- returnData.push({
1351
- json: item,
1352
- pairedItem: { item: i },
1353
- });
1354
- }
1315
+ else if (resource === 'table') {
1316
+ const tableId = this.getNodeParameter('tableId', i);
1317
+ if (!tableId) {
1318
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Please provide a valid table ID', { itemIndex: i });
1319
+ }
1320
+ if (operation === 'insertRows') {
1321
+ const rowFieldsMapper = this.getNodeParameter('rowFields', i);
1322
+ const insertOptions = this.getNodeParameter('insertOptions', i, {});
1323
+ const fields = rowFieldsMapper.value || {};
1324
+ const row = { fields };
1325
+ const options = {};
1326
+ if (insertOptions.allowNewColumns !== undefined) {
1327
+ options.allow_new_columns = insertOptions.allowNewColumns;
1355
1328
  }
1356
- else {
1357
- returnData.push({
1358
- json: response,
1359
- pairedItem: { item: i },
1360
- });
1329
+ if (insertOptions.dedupeEnabled) {
1330
+ const keysStr = insertOptions.dedupeKeys || '';
1331
+ options.dedupe = {
1332
+ enabled: true,
1333
+ keys: keysStr.split(',').map((k) => k.trim()).filter((k) => k),
1334
+ };
1335
+ }
1336
+ const body = { rows: [row] };
1337
+ if (Object.keys(options).length > 0) {
1338
+ body.options = options;
1361
1339
  }
1340
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'databarApi', {
1341
+ method: 'POST',
1342
+ url: `https://api.databar.ai/v1/table/${tableId}/rows`,
1343
+ body,
1344
+ });
1345
+ returnData.push({
1346
+ json: response,
1347
+ pairedItem: { item: i },
1348
+ });
1362
1349
  }
1363
- else if (operation === 'get') {
1364
- const waterfallIdentifier = this.getNodeParameter('waterfallIdentifier', i);
1350
+ else if (operation === 'upsertRows') {
1351
+ const keyColumn = this.getNodeParameter('upsertKeyColumn', i);
1352
+ const keyValue = this.getNodeParameter('upsertKeyValue', i);
1353
+ const upsertFieldsMapper = this.getNodeParameter('upsertFields', i);
1354
+ if (!keyColumn) {
1355
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Please provide a key column name', { itemIndex: i });
1356
+ }
1357
+ const fields = upsertFieldsMapper.value || {};
1358
+ const row = {
1359
+ key: { [keyColumn]: keyValue },
1360
+ fields,
1361
+ };
1365
1362
  const response = await this.helpers.httpRequestWithAuthentication.call(this, 'databarApi', {
1366
- method: 'GET',
1367
- url: `https://api.databar.ai/v1/waterfalls/${waterfallIdentifier}`,
1363
+ method: 'POST',
1364
+ url: `https://api.databar.ai/v1/table/${tableId}/rows/upsert`,
1365
+ body: { rows: [row] },
1368
1366
  });
1369
1367
  returnData.push({
1370
1368
  json: response,
1371
1369
  pairedItem: { item: i },
1372
1370
  });
1373
1371
  }
1374
- else if (operation === 'run') {
1372
+ }
1373
+ // ====================================
1374
+ // WATERFALL OPERATIONS
1375
+ // ====================================
1376
+ else if (resource === 'waterfall') {
1377
+ if (operation === 'run') {
1375
1378
  const waterfallIdentifier = this.getNodeParameter('waterfallIdentifier', i);
1376
- const parameterMode = this.getNodeParameter('waterfallParameterMode', i, 'fields');
1377
1379
  const enrichmentsRaw = this.getNodeParameter('enrichments', i, []);
1378
1380
  const waitForCompletion = this.getNodeParameter('waitForCompletion', i, true);
1379
- // Get parameters based on input mode
1380
- let params;
1381
- if (parameterMode === 'fields') {
1382
- // Resource mapper mode - get structured fields
1383
- const paramsFields = this.getNodeParameter('waterfallParamsFields', i);
1384
- // Resource mapper returns an object with 'value' containing the actual data
1385
- params = paramsFields.value || {};
1386
- }
1387
- else {
1388
- // Raw JSON mode - parse JSON string
1389
- const paramsJson = this.getNodeParameter('params', i);
1390
- try {
1391
- params = JSON.parse(paramsJson);
1392
- }
1393
- catch (error) {
1394
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Parameters must be valid JSON object', { itemIndex: i });
1395
- }
1396
- }
1381
+ const paramsFields = this.getNodeParameter('waterfallParamsFields', i);
1382
+ const params = paramsFields.value || {};
1397
1383
  // Convert enrichment IDs to numbers (multiOptions returns array of selected values)
1398
1384
  const enrichments = enrichmentsRaw.map((id) => {
1399
1385
  return typeof id === 'string' ? parseInt(id, 10) : id;