@fachkraftfreund/n8n-nodes-supabase 1.4.0 → 1.4.1
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.
|
@@ -729,6 +729,37 @@ class Supabase {
|
|
|
729
729
|
},
|
|
730
730
|
},
|
|
731
731
|
},
|
|
732
|
+
{
|
|
733
|
+
displayName: 'Batch Counts',
|
|
734
|
+
name: 'batchCounts',
|
|
735
|
+
type: 'boolean',
|
|
736
|
+
default: false,
|
|
737
|
+
description: 'Whether to combine all input items into a single GROUP BY query instead of one count per item. Requires the exec_sql_select RPC function.',
|
|
738
|
+
displayOptions: {
|
|
739
|
+
show: {
|
|
740
|
+
resource: ['database'],
|
|
741
|
+
operation: ['count'],
|
|
742
|
+
},
|
|
743
|
+
},
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
displayName: 'Group By Column',
|
|
747
|
+
name: 'groupByColumn',
|
|
748
|
+
type: 'options',
|
|
749
|
+
typeOptions: {
|
|
750
|
+
loadOptionsMethod: 'getColumns',
|
|
751
|
+
},
|
|
752
|
+
required: true,
|
|
753
|
+
default: '',
|
|
754
|
+
description: 'Column to group counts by (e.g. sector). Each unique value produces one output item with its count.',
|
|
755
|
+
displayOptions: {
|
|
756
|
+
show: {
|
|
757
|
+
resource: ['database'],
|
|
758
|
+
operation: ['count'],
|
|
759
|
+
batchCounts: [true],
|
|
760
|
+
},
|
|
761
|
+
},
|
|
762
|
+
},
|
|
732
763
|
{
|
|
733
764
|
displayName: 'Bucket',
|
|
734
765
|
name: 'bucket',
|
|
@@ -1023,7 +1054,23 @@ class Supabase {
|
|
|
1023
1054
|
const supabase = (0, supabaseClient_1.createSupabaseClient)(credentials);
|
|
1024
1055
|
const resource = this.getNodeParameter('resource', 0);
|
|
1025
1056
|
const operation = this.getNodeParameter('operation', 0);
|
|
1026
|
-
if (resource === 'database' &&
|
|
1057
|
+
if (resource === 'database' && operation === 'count' && this.getNodeParameter('batchCounts', 0, false)) {
|
|
1058
|
+
try {
|
|
1059
|
+
const results = await database_1.executeBulkDatabaseOperation.call(this, supabase, operation, items.length);
|
|
1060
|
+
for (const r of results)
|
|
1061
|
+
returnData.push(r);
|
|
1062
|
+
}
|
|
1063
|
+
catch (error) {
|
|
1064
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
1065
|
+
if (this.continueOnFail()) {
|
|
1066
|
+
returnData.push({ json: { error: errorMessage } });
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), errorMessage);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
else if (resource === 'database' && ['create', 'upsert', 'update'].includes(operation)) {
|
|
1027
1074
|
const firstItem = items[0];
|
|
1028
1075
|
if (items.length === 1 &&
|
|
1029
1076
|
(firstItem === null || firstItem === void 0 ? void 0 : firstItem.json) &&
|
|
@@ -1045,7 +1092,7 @@ class Supabase {
|
|
|
1045
1092
|
}
|
|
1046
1093
|
}
|
|
1047
1094
|
}
|
|
1048
|
-
else if (resource === 'database' &&
|
|
1095
|
+
else if (resource === 'database' && operation === 'read') {
|
|
1049
1096
|
try {
|
|
1050
1097
|
const operationResults = await database_1.executeDatabaseOperation.call(this, supabase, operation, 0, credentials.host);
|
|
1051
1098
|
for (const r of operationResults)
|
|
@@ -178,6 +178,8 @@ async function executeBulkDatabaseOperation(supabase, operation, itemCount) {
|
|
|
178
178
|
return await handleBulkUpsert.call(this, supabase, itemCount);
|
|
179
179
|
case 'update':
|
|
180
180
|
return await handleBulkUpdate.call(this, supabase, itemCount);
|
|
181
|
+
case 'count':
|
|
182
|
+
return await handleBatchCount.call(this, supabase, itemCount);
|
|
181
183
|
default:
|
|
182
184
|
throw new Error(`Operation ${operation} does not support bulk mode`);
|
|
183
185
|
}
|
|
@@ -813,3 +815,90 @@ async function handleCount(supabase, itemIndex, hostUrl) {
|
|
|
813
815
|
}
|
|
814
816
|
return [{ json: { count: totalCount, table } }];
|
|
815
817
|
}
|
|
818
|
+
async function handleBatchCount(supabase, itemCount) {
|
|
819
|
+
const table = this.getNodeParameter('table', 0);
|
|
820
|
+
const groupByColumn = this.getNodeParameter('groupByColumn', 0);
|
|
821
|
+
(0, supabaseClient_1.validateTableName)(table);
|
|
822
|
+
(0, supabaseClient_1.validateColumnName)(groupByColumn);
|
|
823
|
+
const baseFilters = getFilters(this, 0);
|
|
824
|
+
const groupValues = new Set();
|
|
825
|
+
for (let i = 0; i < itemCount; i++) {
|
|
826
|
+
const itemFilters = getFilters(this, i);
|
|
827
|
+
for (const f of itemFilters) {
|
|
828
|
+
if (f.column === groupByColumn) {
|
|
829
|
+
groupValues.add(String(f.value));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
const whereClauses = [];
|
|
834
|
+
const staticFilters = baseFilters.filter(f => f.column !== groupByColumn);
|
|
835
|
+
for (const f of staticFilters) {
|
|
836
|
+
const col = `"${f.column}"`;
|
|
837
|
+
switch (f.operator) {
|
|
838
|
+
case 'eq':
|
|
839
|
+
whereClauses.push(`${col} = '${String(f.value).replace(/'/g, "''")}'`);
|
|
840
|
+
break;
|
|
841
|
+
case 'neq':
|
|
842
|
+
whereClauses.push(`${col} != '${String(f.value).replace(/'/g, "''")}'`);
|
|
843
|
+
break;
|
|
844
|
+
case 'gt':
|
|
845
|
+
whereClauses.push(`${col} > '${String(f.value).replace(/'/g, "''")}'`);
|
|
846
|
+
break;
|
|
847
|
+
case 'gte':
|
|
848
|
+
whereClauses.push(`${col} >= '${String(f.value).replace(/'/g, "''")}'`);
|
|
849
|
+
break;
|
|
850
|
+
case 'lt':
|
|
851
|
+
whereClauses.push(`${col} < '${String(f.value).replace(/'/g, "''")}'`);
|
|
852
|
+
break;
|
|
853
|
+
case 'lte':
|
|
854
|
+
whereClauses.push(`${col} <= '${String(f.value).replace(/'/g, "''")}'`);
|
|
855
|
+
break;
|
|
856
|
+
case 'is':
|
|
857
|
+
whereClauses.push(`${col} IS ${f.value}`);
|
|
858
|
+
break;
|
|
859
|
+
case 'like':
|
|
860
|
+
whereClauses.push(`${col} LIKE '${String(f.value).replace(/'/g, "''")}'`);
|
|
861
|
+
break;
|
|
862
|
+
case 'ilike':
|
|
863
|
+
whereClauses.push(`${col} ILIKE '${String(f.value).replace(/'/g, "''")}'`);
|
|
864
|
+
break;
|
|
865
|
+
case 'in': {
|
|
866
|
+
const vals = Array.isArray(f.value) ? f.value : String(f.value).split(',');
|
|
867
|
+
const escaped = vals.map(v => `'${String(v).trim().replace(/'/g, "''")}'`).join(',');
|
|
868
|
+
whereClauses.push(`${col} IN (${escaped})`);
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
default: whereClauses.push(`${col} = '${String(f.value).replace(/'/g, "''")}'`);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (groupValues.size > 0) {
|
|
875
|
+
const escaped = Array.from(groupValues).map(v => `'${v.replace(/'/g, "''")}'`).join(',');
|
|
876
|
+
whereClauses.push(`"${groupByColumn}" IN (${escaped})`);
|
|
877
|
+
}
|
|
878
|
+
const joins = this.getNodeParameter('joins.join', 0, []);
|
|
879
|
+
const joinClauses = [];
|
|
880
|
+
for (const j of joins) {
|
|
881
|
+
if (!j.table)
|
|
882
|
+
continue;
|
|
883
|
+
(0, supabaseClient_1.validateTableName)(j.table);
|
|
884
|
+
const joinType = j.joinType === 'inner' ? 'INNER JOIN' : 'LEFT JOIN';
|
|
885
|
+
joinClauses.push(`${joinType} "${j.table}" ON "${j.table}"."${table.replace(/s$/, '')}_id" = "${table}"."id"`);
|
|
886
|
+
}
|
|
887
|
+
const whereStr = whereClauses.length > 0 ? ` WHERE ${whereClauses.join(' AND ')}` : '';
|
|
888
|
+
const joinStr = joinClauses.length > 0 ? ` ${joinClauses.join(' ')}` : '';
|
|
889
|
+
const sql = `SELECT "${groupByColumn}", COUNT(*) as count FROM "${table}"${joinStr}${whereStr} GROUP BY "${groupByColumn}" ORDER BY count DESC`;
|
|
890
|
+
console.log(`[Supabase BATCH COUNT] sql: ${sql}`);
|
|
891
|
+
const { data, error } = await supabase.rpc('exec_sql_select', { sql });
|
|
892
|
+
if (error)
|
|
893
|
+
throw new Error((0, supabaseClient_1.formatSupabaseError)(error));
|
|
894
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
895
|
+
return [{ json: { table, groupByColumn, counts: [], message: 'No rows matched' } }];
|
|
896
|
+
}
|
|
897
|
+
return data.map((row) => ({
|
|
898
|
+
json: {
|
|
899
|
+
[groupByColumn]: row[groupByColumn],
|
|
900
|
+
count: Number(row.count),
|
|
901
|
+
table,
|
|
902
|
+
},
|
|
903
|
+
}));
|
|
904
|
+
}
|
package/package.json
CHANGED