@fachkraftfreund/n8n-nodes-supabase 1.2.22 → 1.2.23

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.
@@ -527,6 +527,58 @@ class Supabase {
527
527
  },
528
528
  },
529
529
  },
530
+ {
531
+ displayName: 'Joins',
532
+ name: 'joins',
533
+ type: 'fixedCollection',
534
+ typeOptions: {
535
+ multipleValues: true,
536
+ },
537
+ default: {},
538
+ placeholder: 'Add Join',
539
+ description: 'Join related tables via foreign keys (PostgREST resource embedding)',
540
+ displayOptions: {
541
+ show: {
542
+ resource: ['database'],
543
+ operation: ['read'],
544
+ },
545
+ },
546
+ options: [
547
+ {
548
+ displayName: 'Join',
549
+ name: 'join',
550
+ values: [
551
+ {
552
+ displayName: 'Table',
553
+ name: 'table',
554
+ type: 'string',
555
+ default: '',
556
+ placeholder: 'company_email',
557
+ description: 'Related table to join',
558
+ },
559
+ {
560
+ displayName: 'Columns',
561
+ name: 'columns',
562
+ type: 'string',
563
+ default: '*',
564
+ placeholder: 'email,verified',
565
+ description: 'Comma-separated columns to select from the joined table (* for all)',
566
+ },
567
+ {
568
+ displayName: 'Join Type',
569
+ name: 'joinType',
570
+ type: 'options',
571
+ options: [
572
+ { name: 'Left Join', value: 'left' },
573
+ { name: 'Inner Join', value: 'inner' },
574
+ ],
575
+ default: 'left',
576
+ description: 'Left returns all rows even without a match; Inner only returns rows with a match',
577
+ },
578
+ ],
579
+ },
580
+ ],
581
+ },
530
582
  {
531
583
  displayName: 'Sort',
532
584
  name: 'sort',
@@ -196,16 +196,26 @@ async function handleRead(supabase, itemIndex, hostUrl) {
196
196
  (0, supabaseClient_1.validateTableName)(table);
197
197
  const returnFields = this.getNodeParameter('returnFields', itemIndex, '*');
198
198
  const returnAll = this.getNodeParameter('returnAll', itemIndex, false);
199
+ const singleItem = this.getNodeParameter('singleItem', itemIndex, false);
199
200
  const filters = getFilters(this, itemIndex);
200
201
  const sort = this.getNodeParameter('sort.sortField', itemIndex, []);
202
+ const joins = this.getNodeParameter('joins.join', itemIndex, []);
203
+ let selectWithJoins = returnFields;
204
+ for (const j of joins) {
205
+ if (!j.table)
206
+ continue;
207
+ const cols = j.columns || '*';
208
+ const hint = j.joinType === 'inner' ? `${j.table}!inner` : j.table;
209
+ selectWithJoins += `,${hint}(${cols})`;
210
+ }
201
211
  for (const f of filters) {
202
212
  const valType = Array.isArray(f.value) ? `array[${f.value.length}]` : typeof f.value;
203
213
  const valLen = typeof f.value === 'string' ? f.value.length : Array.isArray(f.value) ? f.value.length : 0;
204
214
  console.log(`[Supabase READ] item=${itemIndex} filter: ${f.column} ${f.operator} (${valType}, len=${valLen})`);
205
215
  }
206
- const overhead = (0, supabaseClient_1.estimateUrlOverhead)(hostUrl, table, returnFields, filters, sort);
216
+ const overhead = (0, supabaseClient_1.estimateUrlOverhead)(hostUrl, table, selectWithJoins, filters, sort);
207
217
  const maxInChars = Math.max(500, supabaseClient_1.MAX_SAFE_URL_LENGTH - overhead);
208
- const maxItems = (0, supabaseClient_1.computeMaxIdsPerChunk)(returnFields);
218
+ const maxItems = (0, supabaseClient_1.computeMaxIdsPerChunk)(selectWithJoins);
209
219
  const filterChunks = (0, supabaseClient_1.expandChunkedFilters)(filters, maxInChars, maxItems);
210
220
  console.log(`[Supabase READ] item=${itemIndex} table=${table} returnAll=${returnAll} chunks=${filterChunks.length} maxItems=${maxItems} maxInChars=${maxInChars}`);
211
221
  const returnData = [];
@@ -224,7 +234,7 @@ async function handleRead(supabase, itemIndex, hostUrl) {
224
234
  if (hasIdColumn) {
225
235
  let lastId = null;
226
236
  while (hasMore) {
227
- let query = buildReadQuery(supabase, table, returnFields, chunkFilters, []);
237
+ let query = buildReadQuery(supabase, table, selectWithJoins, chunkFilters, []);
228
238
  if (lastId !== null) {
229
239
  query = query.gt('id', lastId);
230
240
  }
@@ -252,7 +262,7 @@ async function handleRead(supabase, itemIndex, hostUrl) {
252
262
  else {
253
263
  let batchOffset = 0;
254
264
  while (hasMore) {
255
- const query = buildReadQuery(supabase, table, returnFields, chunkFilters, sort);
265
+ const query = buildReadQuery(supabase, table, selectWithJoins, chunkFilters, sort);
256
266
  const { data, error } = await query.range(batchOffset, batchOffset + batchSize - 1);
257
267
  if (error) {
258
268
  console.log(`[Supabase READ] chunk ${ci + 1} batch ${batchCount + 1} FAILED after ${Date.now() - chunkStart}ms: ${(0, supabaseClient_1.formatSupabaseError)(error)}`);
@@ -301,7 +311,7 @@ async function handleRead(supabase, itemIndex, hostUrl) {
301
311
  const userOffset = this.getNodeParameter('offset', itemIndex, 0);
302
312
  const isMultiChunk = filterChunks.length > 1;
303
313
  for (const chunkFilters of filterChunks) {
304
- let query = buildReadQuery(supabase, table, returnFields, chunkFilters, sort);
314
+ let query = buildReadQuery(supabase, table, selectWithJoins, chunkFilters, sort);
305
315
  if (isMultiChunk) {
306
316
  query = query.limit(userOffset + limit);
307
317
  }
@@ -341,10 +351,13 @@ async function handleRead(supabase, itemIndex, hostUrl) {
341
351
  },
342
352
  });
343
353
  }
344
- const singleItem = this.getNodeParameter('singleItem', itemIndex, false);
345
354
  if (singleItem && returnData.length > 0) {
346
- const allRows = returnData.map(item => item.json);
347
- return [{ json: { data: allRows, count: allRows.length } }];
355
+ const count = returnData.length;
356
+ const allRows = new Array(count);
357
+ for (let i = 0; i < count; i++)
358
+ allRows[i] = returnData[i].json;
359
+ returnData.length = 0;
360
+ return [{ json: { data: allRows, count } }];
348
361
  }
349
362
  return returnData;
350
363
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fachkraftfreund/n8n-nodes-supabase",
3
- "version": "1.2.22",
3
+ "version": "1.2.23",
4
4
  "description": "Comprehensive n8n community node for Supabase with database and storage operations",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",