fix(events): Convert NocoDB query syntax from SQL-like to v2 API format
Build And Push Image / docker (push) Successful in 3m20s Details

- 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.
This commit is contained in:
Matt 2025-08-12 13:15:06 +02:00
parent 122d6fdd26
commit 0688c23093
1 changed files with 19 additions and 13 deletions

View File

@ -62,42 +62,47 @@ export function createNocoDBEventsClient() {
if (filters?.limit) queryParams.set('limit', filters.limit.toString()); if (filters?.limit) queryParams.set('limit', filters.limit.toString());
if (filters?.offset) queryParams.set('offset', filters.offset.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[] = []; const whereConditions: string[] = [];
if (filters?.start_date && filters?.end_date) { 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) { if (filters?.event_type) {
whereConditions.push(`(event_type = '${filters.event_type}')`); whereConditions.push(`(event_type,eq,${filters.event_type})`);
} }
if (filters?.visibility) { if (filters?.visibility) {
whereConditions.push(`(visibility = '${filters.visibility}')`); whereConditions.push(`(visibility,eq,${filters.visibility})`);
} else if (filters?.user_role) { } else if (filters?.user_role) {
// Role-based visibility filtering // Role-based visibility filtering
if (filters.user_role === 'user') { if (filters.user_role === 'user') {
whereConditions.push(`(visibility = 'public')`); whereConditions.push(`(visibility,eq,public)`);
} else if (filters.user_role === 'board') { } 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) // Admin sees all events (no filter)
} }
if (filters?.status) { if (filters?.status) {
whereConditions.push(`(status = '${filters.status}')`); whereConditions.push(`(status,eq,${filters.status})`);
} else { } else {
// Default to active events only // Default to active events only
whereConditions.push(`(status = 'active')`); whereConditions.push(`(status,eq,active)`);
} }
if (filters?.search) { 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) { 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 // Sort by start date
@ -202,7 +207,7 @@ export function createNocoDBEventsClient() {
*/ */
async findEventRSVPs(eventId: string) { async findEventRSVPs(eventId: string) {
const queryParams = new URLSearchParams(); const queryParams = new URLSearchParams();
queryParams.set('where', `(event_id = '${eventId}')`); queryParams.set('where', `(event_id,eq,${eventId})`);
queryParams.set('sort', 'created_time'); queryParams.set('sort', 'created_time');
const url = `${baseUrl}/api/v2/tables/${rsvpTableId}/records?${queryParams.toString()}`; const url = `${baseUrl}/api/v2/tables/${rsvpTableId}/records?${queryParams.toString()}`;
@ -218,7 +223,7 @@ export function createNocoDBEventsClient() {
*/ */
async findUserRSVP(eventId: string, memberId: string) { async findUserRSVP(eventId: string, memberId: string) {
const queryParams = new URLSearchParams(); 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'); queryParams.set('limit', '1');
const url = `${baseUrl}/api/v2/tables/${rsvpTableId}/records?${queryParams.toString()}`; const url = `${baseUrl}/api/v2/tables/${rsvpTableId}/records?${queryParams.toString()}`;
@ -281,7 +286,8 @@ export function createNocoDBEventsClient() {
// Get user's RSVPs for these events // Get user's RSVPs for these events
const eventIds = events.list.map((e: Event) => e.id); const eventIds = events.list.map((e: Event) => e.id);
const rsvpQueryParams = new URLSearchParams(); 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()}`; const rsvpUrl = `${baseUrl}/api/v2/tables/${rsvpTableId}/records?${rsvpQueryParams.toString()}`;