@fachkraftfreund/n8n-nodes-supabase 1.3.3 → 1.3.5

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.
@@ -55,6 +55,18 @@ exports.executeDatabaseOperation = executeDatabaseOperation;
55
55
  const BULK_BATCH_SIZE = 500;
56
56
  const MAX_RETRIES = 3;
57
57
  const RETRY_BASE_DELAY_MS = 1000;
58
+ function deduplicateByConflictKeys(rows, conflictColumns) {
59
+ const keys = conflictColumns.split(',').map((k) => k.trim()).filter(Boolean);
60
+ if (keys.length === 0)
61
+ return rows;
62
+ const seen = new Map();
63
+ for (let i = 0; i < rows.length; i++) {
64
+ const row = rows[i];
65
+ const compositeKey = keys.map((k) => { var _a; return String((_a = row[k]) !== null && _a !== void 0 ? _a : ''); }).join('\0');
66
+ seen.set(compositeKey, i);
67
+ }
68
+ return Array.from(seen.values()).sort((a, b) => a - b).map((i) => rows[i]);
69
+ }
58
70
  function isRetryableError(msg) {
59
71
  const lower = msg.toLowerCase();
60
72
  return (lower.includes('lock timeout') ||
@@ -192,13 +204,20 @@ async function handleBulkUpsert(supabase, itemCount) {
192
204
  const table = this.getNodeParameter('table', 0);
193
205
  const onConflict = this.getNodeParameter('onConflict', 0, '');
194
206
  (0, supabaseClient_1.validateTableName)(table);
195
- const rows = collectRowData(this, itemCount);
207
+ let rows = collectRowData(this, itemCount);
196
208
  const options = {};
197
- if (onConflict)
209
+ if (onConflict) {
198
210
  options.onConflict = onConflict;
211
+ const before = rows.length;
212
+ rows = deduplicateByConflictKeys(rows, onConflict);
213
+ if (rows.length < before) {
214
+ console.log(`[Supabase UPSERT ${table}] deduplicated input: ${before} → ${rows.length} rows by conflict key "${onConflict}"`);
215
+ }
216
+ }
199
217
  const returnData = [];
200
218
  for (let offset = 0; offset < rows.length; offset += BULK_BATCH_SIZE) {
201
219
  const batch = rows.slice(offset, offset + BULK_BATCH_SIZE);
220
+ const batchLabel = `UPSERT ${table} batch ${Math.floor(offset / BULK_BATCH_SIZE) + 1}`;
202
221
  const data = await withRetry(async () => {
203
222
  const { data, error } = await supabase
204
223
  .from(table)
@@ -207,7 +226,7 @@ async function handleBulkUpsert(supabase, itemCount) {
207
226
  if (error)
208
227
  throw new Error((0, supabaseClient_1.formatSupabaseError)(error));
209
228
  return data;
210
- }, `UPSERT ${table} batch ${Math.floor(offset / BULK_BATCH_SIZE) + 1}`);
229
+ }, batchLabel);
211
230
  if (Array.isArray(data)) {
212
231
  for (const row of data)
213
232
  returnData.push({ json: row });
@@ -224,16 +243,22 @@ async function handleBulkUpdate(supabase, itemCount) {
224
243
  if (!matchColumn) {
225
244
  throw new Error('Match Column is required for update operations');
226
245
  }
227
- const rows = collectRowData(this, itemCount);
246
+ let rows = collectRowData(this, itemCount);
228
247
  for (let i = 0; i < rows.length; i++) {
229
248
  const row = rows[i];
230
249
  if (!row || row[matchColumn] === undefined) {
231
250
  throw new Error(`Item ${i} is missing the match column "${matchColumn}"`);
232
251
  }
233
252
  }
253
+ const before = rows.length;
254
+ rows = deduplicateByConflictKeys(rows, matchColumn);
255
+ if (rows.length < before) {
256
+ console.log(`[Supabase UPDATE ${table}] deduplicated input: ${before} → ${rows.length} rows by match column "${matchColumn}"`);
257
+ }
234
258
  const returnData = [];
235
259
  for (let offset = 0; offset < rows.length; offset += BULK_BATCH_SIZE) {
236
260
  const batch = rows.slice(offset, offset + BULK_BATCH_SIZE);
261
+ const batchLabel = `UPDATE ${table} batch ${Math.floor(offset / BULK_BATCH_SIZE) + 1}`;
237
262
  const data = await withRetry(async () => {
238
263
  const { data, error } = await supabase
239
264
  .from(table)
@@ -242,7 +267,7 @@ async function handleBulkUpdate(supabase, itemCount) {
242
267
  if (error)
243
268
  throw new Error((0, supabaseClient_1.formatSupabaseError)(error));
244
269
  return data;
245
- }, `UPDATE ${table} batch ${Math.floor(offset / BULK_BATCH_SIZE) + 1}`);
270
+ }, batchLabel);
246
271
  if (Array.isArray(data)) {
247
272
  for (const row of data)
248
273
  returnData.push({ json: row });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fachkraftfreund/n8n-nodes-supabase",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "Comprehensive n8n community node for Supabase with database and storage operations",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",