From 0688c23093a883fb92215a916abc7efba41ac23a Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 12 Aug 2025 13:15:06 +0200 Subject: [PATCH] fix(events): Convert NocoDB query syntax from SQL-like to v2 API format - Updated all where clauses to use NocoDB v2 syntax: (field,operator,value) - Changed SQL-like syntax (field >= 'value' AND field = 'value') to v2 format - Fixed date range queries: (start_datetime,gte,date) and (start_datetime,lte,date) - Fixed equality queries: (status,eq,active) instead of (status = 'active') - Fixed AND/OR logic: ~and() and ~or() syntax for complex conditions - Updated findEventRSVPs, findUserRSVP, and findUserEvents methods - Fixed RSVP queries to use proper v2 format for member and event matching This should resolve the 422 Unprocessable Entity errors that were caused by using deprecated SQL-like syntax with the v2 API endpoints. --- server/utils/nocodb-events.ts | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/server/utils/nocodb-events.ts b/server/utils/nocodb-events.ts index b1dc3d5..20be8b6 100644 --- a/server/utils/nocodb-events.ts +++ b/server/utils/nocodb-events.ts @@ -62,42 +62,47 @@ export function createNocoDBEventsClient() { if (filters?.limit) queryParams.set('limit', filters.limit.toString()); if (filters?.offset) queryParams.set('offset', filters.offset.toString()); - // Build where clause for filtering + // Build where clause for filtering using NocoDB v2 syntax const whereConditions: string[] = []; if (filters?.start_date && filters?.end_date) { - whereConditions.push(`(start_datetime >= '${filters.start_date}' AND start_datetime <= '${filters.end_date}')`); + whereConditions.push(`(start_datetime,gte,${filters.start_date})`); + whereConditions.push(`(start_datetime,lte,${filters.end_date})`); } if (filters?.event_type) { - whereConditions.push(`(event_type = '${filters.event_type}')`); + whereConditions.push(`(event_type,eq,${filters.event_type})`); } if (filters?.visibility) { - whereConditions.push(`(visibility = '${filters.visibility}')`); + whereConditions.push(`(visibility,eq,${filters.visibility})`); } else if (filters?.user_role) { // Role-based visibility filtering if (filters.user_role === 'user') { - whereConditions.push(`(visibility = 'public')`); + whereConditions.push(`(visibility,eq,public)`); } else if (filters.user_role === 'board') { - whereConditions.push(`(visibility = 'public' OR visibility = 'board-only')`); + // For multiple OR conditions, we'll need to handle this differently + whereConditions.push(`~or(visibility,eq,public)~or(visibility,eq,board-only)`); } // Admin sees all events (no filter) } if (filters?.status) { - whereConditions.push(`(status = '${filters.status}')`); + whereConditions.push(`(status,eq,${filters.status})`); } else { // Default to active events only - whereConditions.push(`(status = 'active')`); + whereConditions.push(`(status,eq,active)`); } if (filters?.search) { - whereConditions.push(`(title LIKE '%${filters.search}%' OR description LIKE '%${filters.search}%')`); + whereConditions.push(`~or(title,like,%${filters.search}%)~or(description,like,%${filters.search}%)`); } if (whereConditions.length > 0) { - queryParams.set('where', whereConditions.join(' AND ')); + const whereClause = whereConditions.length === 1 + ? whereConditions[0] + : `~and(${whereConditions.join(',')})`; + queryParams.set('where', whereClause); } // Sort by start date @@ -202,7 +207,7 @@ export function createNocoDBEventsClient() { */ async findEventRSVPs(eventId: string) { const queryParams = new URLSearchParams(); - queryParams.set('where', `(event_id = '${eventId}')`); + queryParams.set('where', `(event_id,eq,${eventId})`); queryParams.set('sort', 'created_time'); const url = `${baseUrl}/api/v2/tables/${rsvpTableId}/records?${queryParams.toString()}`; @@ -218,7 +223,7 @@ export function createNocoDBEventsClient() { */ async findUserRSVP(eventId: string, memberId: string) { const queryParams = new URLSearchParams(); - queryParams.set('where', `(event_id = '${eventId}' AND member_id = '${memberId}')`); + queryParams.set('where', `~and((event_id,eq,${eventId}),(member_id,eq,${memberId}))`); queryParams.set('limit', '1'); const url = `${baseUrl}/api/v2/tables/${rsvpTableId}/records?${queryParams.toString()}`; @@ -281,7 +286,8 @@ export function createNocoDBEventsClient() { // Get user's RSVPs for these events const eventIds = events.list.map((e: Event) => e.id); const rsvpQueryParams = new URLSearchParams(); - rsvpQueryParams.set('where', `(member_id = '${memberId}' AND event_id IN (${eventIds.map((id: string) => `'${id}'`).join(',')}))`); + const eventIdConditions = eventIds.map(id => `(event_id,eq,${id})`).join(','); + rsvpQueryParams.set('where', `~and((member_id,eq,${memberId}),~or(${eventIdConditions}))`); const rsvpUrl = `${baseUrl}/api/v2/tables/${rsvpTableId}/records?${rsvpQueryParams.toString()}`;