@fachkraftfreund/n8n-nodes-supabase 1.3.4 → 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,7 +55,6 @@ 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
|
-
const DUPLICATE_ROW_ERROR = 'cannot affect row a second time';
|
|
59
58
|
function deduplicateByConflictKeys(rows, conflictColumns) {
|
|
60
59
|
const keys = conflictColumns.split(',').map((k) => k.trim()).filter(Boolean);
|
|
61
60
|
if (keys.length === 0)
|
|
@@ -205,32 +204,27 @@ async function handleBulkUpsert(supabase, itemCount) {
|
|
|
205
204
|
const table = this.getNodeParameter('table', 0);
|
|
206
205
|
const onConflict = this.getNodeParameter('onConflict', 0, '');
|
|
207
206
|
(0, supabaseClient_1.validateTableName)(table);
|
|
208
|
-
|
|
207
|
+
let rows = collectRowData(this, itemCount);
|
|
209
208
|
const options = {};
|
|
210
|
-
if (onConflict)
|
|
209
|
+
if (onConflict) {
|
|
211
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
|
+
}
|
|
212
217
|
const returnData = [];
|
|
213
218
|
for (let offset = 0; offset < rows.length; offset += BULK_BATCH_SIZE) {
|
|
214
|
-
|
|
219
|
+
const batch = rows.slice(offset, offset + BULK_BATCH_SIZE);
|
|
215
220
|
const batchLabel = `UPSERT ${table} batch ${Math.floor(offset / BULK_BATCH_SIZE) + 1}`;
|
|
216
221
|
const data = await withRetry(async () => {
|
|
217
222
|
const { data, error } = await supabase
|
|
218
223
|
.from(table)
|
|
219
224
|
.upsert(batch, options)
|
|
220
225
|
.select();
|
|
221
|
-
if (error)
|
|
222
|
-
|
|
223
|
-
if (msg.toLowerCase().includes(DUPLICATE_ROW_ERROR) && onConflict) {
|
|
224
|
-
const before = batch.length;
|
|
225
|
-
batch = deduplicateByConflictKeys(batch, onConflict);
|
|
226
|
-
console.log(`[Supabase ${batchLabel}] removed ${before - batch.length} duplicate(s) by conflict key "${onConflict}", retrying ${batch.length} rows`);
|
|
227
|
-
const retry = await supabase.from(table).upsert(batch, options).select();
|
|
228
|
-
if (retry.error)
|
|
229
|
-
throw new Error((0, supabaseClient_1.formatSupabaseError)(retry.error));
|
|
230
|
-
return retry.data;
|
|
231
|
-
}
|
|
232
|
-
throw new Error(msg);
|
|
233
|
-
}
|
|
226
|
+
if (error)
|
|
227
|
+
throw new Error((0, supabaseClient_1.formatSupabaseError)(error));
|
|
234
228
|
return data;
|
|
235
229
|
}, batchLabel);
|
|
236
230
|
if (Array.isArray(data)) {
|
|
@@ -249,35 +243,29 @@ async function handleBulkUpdate(supabase, itemCount) {
|
|
|
249
243
|
if (!matchColumn) {
|
|
250
244
|
throw new Error('Match Column is required for update operations');
|
|
251
245
|
}
|
|
252
|
-
|
|
246
|
+
let rows = collectRowData(this, itemCount);
|
|
253
247
|
for (let i = 0; i < rows.length; i++) {
|
|
254
248
|
const row = rows[i];
|
|
255
249
|
if (!row || row[matchColumn] === undefined) {
|
|
256
250
|
throw new Error(`Item ${i} is missing the match column "${matchColumn}"`);
|
|
257
251
|
}
|
|
258
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
|
+
}
|
|
259
258
|
const returnData = [];
|
|
260
259
|
for (let offset = 0; offset < rows.length; offset += BULK_BATCH_SIZE) {
|
|
261
|
-
|
|
260
|
+
const batch = rows.slice(offset, offset + BULK_BATCH_SIZE);
|
|
262
261
|
const batchLabel = `UPDATE ${table} batch ${Math.floor(offset / BULK_BATCH_SIZE) + 1}`;
|
|
263
262
|
const data = await withRetry(async () => {
|
|
264
263
|
const { data, error } = await supabase
|
|
265
264
|
.from(table)
|
|
266
265
|
.upsert(batch, { onConflict: matchColumn })
|
|
267
266
|
.select();
|
|
268
|
-
if (error)
|
|
269
|
-
|
|
270
|
-
if (msg.toLowerCase().includes(DUPLICATE_ROW_ERROR)) {
|
|
271
|
-
const before = batch.length;
|
|
272
|
-
batch = deduplicateByConflictKeys(batch, matchColumn);
|
|
273
|
-
console.log(`[Supabase ${batchLabel}] removed ${before - batch.length} duplicate(s) by match column "${matchColumn}", retrying ${batch.length} rows`);
|
|
274
|
-
const retry = await supabase.from(table).upsert(batch, { onConflict: matchColumn }).select();
|
|
275
|
-
if (retry.error)
|
|
276
|
-
throw new Error((0, supabaseClient_1.formatSupabaseError)(retry.error));
|
|
277
|
-
return retry.data;
|
|
278
|
-
}
|
|
279
|
-
throw new Error(msg);
|
|
280
|
-
}
|
|
267
|
+
if (error)
|
|
268
|
+
throw new Error((0, supabaseClient_1.formatSupabaseError)(error));
|
|
281
269
|
return data;
|
|
282
270
|
}, batchLabel);
|
|
283
271
|
if (Array.isArray(data)) {
|
package/package.json
CHANGED