mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 09:11:12 -05:00
feat: Implement entity creation functions
This commit is contained in:
214
src/lib/entityTransformers.ts
Normal file
214
src/lib/entityTransformers.ts
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
import { Database } from '@/integrations/supabase/types';
|
||||||
|
|
||||||
|
type ParkInsert = Database['public']['Tables']['parks']['Insert'];
|
||||||
|
type RideInsert = Database['public']['Tables']['rides']['Insert'];
|
||||||
|
type CompanyInsert = Database['public']['Tables']['companies']['Insert'];
|
||||||
|
type RideModelInsert = Database['public']['Tables']['ride_models']['Insert'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform park submission data to database insert format
|
||||||
|
*/
|
||||||
|
export function transformParkData(submissionData: any): ParkInsert {
|
||||||
|
return {
|
||||||
|
name: submissionData.name,
|
||||||
|
slug: submissionData.slug,
|
||||||
|
description: submissionData.description || null,
|
||||||
|
park_type: submissionData.park_type,
|
||||||
|
status: normalizeStatus(submissionData.status),
|
||||||
|
opening_date: submissionData.opening_date || null,
|
||||||
|
closing_date: submissionData.closing_date || null,
|
||||||
|
website_url: submissionData.website_url || null,
|
||||||
|
phone: submissionData.phone || null,
|
||||||
|
email: submissionData.email || null,
|
||||||
|
operator_id: submissionData.operator_id || null,
|
||||||
|
property_owner_id: submissionData.property_owner_id || null,
|
||||||
|
location_id: submissionData.location_id || null,
|
||||||
|
banner_image_url: submissionData.banner_image_url || null,
|
||||||
|
banner_image_id: submissionData.banner_image_id || null,
|
||||||
|
card_image_url: submissionData.card_image_url || null,
|
||||||
|
card_image_id: submissionData.card_image_id || null,
|
||||||
|
average_rating: 0,
|
||||||
|
review_count: 0,
|
||||||
|
ride_count: 0,
|
||||||
|
coaster_count: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform ride submission data to database insert format
|
||||||
|
*/
|
||||||
|
export function transformRideData(submissionData: any): RideInsert {
|
||||||
|
// Parse JSON fields if they're strings
|
||||||
|
let coasterStats = null;
|
||||||
|
let technicalSpecs = null;
|
||||||
|
let formerNames = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (submissionData.coaster_stats) {
|
||||||
|
coasterStats = typeof submissionData.coaster_stats === 'string'
|
||||||
|
? JSON.parse(submissionData.coaster_stats)
|
||||||
|
: submissionData.coaster_stats;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to parse coaster_stats:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (submissionData.technical_specs) {
|
||||||
|
technicalSpecs = typeof submissionData.technical_specs === 'string'
|
||||||
|
? JSON.parse(submissionData.technical_specs)
|
||||||
|
: submissionData.technical_specs;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to parse technical_specs:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (submissionData.former_names) {
|
||||||
|
formerNames = typeof submissionData.former_names === 'string'
|
||||||
|
? JSON.parse(submissionData.former_names)
|
||||||
|
: submissionData.former_names;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to parse former_names:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: submissionData.name,
|
||||||
|
slug: submissionData.slug,
|
||||||
|
description: submissionData.description || null,
|
||||||
|
category: submissionData.category,
|
||||||
|
ride_sub_type: submissionData.ride_sub_type || null,
|
||||||
|
status: normalizeStatus(submissionData.status),
|
||||||
|
park_id: submissionData.park_id,
|
||||||
|
ride_model_id: submissionData.ride_model_id || null,
|
||||||
|
manufacturer_id: submissionData.manufacturer_id || null,
|
||||||
|
designer_id: submissionData.designer_id || null,
|
||||||
|
opening_date: submissionData.opening_date || null,
|
||||||
|
closing_date: submissionData.closing_date || null,
|
||||||
|
height_requirement: submissionData.height_requirement || null,
|
||||||
|
age_requirement: submissionData.age_requirement || null,
|
||||||
|
capacity_per_hour: submissionData.capacity_per_hour || null,
|
||||||
|
duration_seconds: submissionData.duration_seconds || null,
|
||||||
|
max_speed_kmh: submissionData.max_speed_kmh || null,
|
||||||
|
max_height_meters: submissionData.max_height_meters || null,
|
||||||
|
length_meters: submissionData.length_meters || null,
|
||||||
|
drop_height_meters: submissionData.drop_height_meters || null,
|
||||||
|
inversions: submissionData.inversions || null,
|
||||||
|
max_g_force: submissionData.max_g_force || null,
|
||||||
|
coaster_type: submissionData.coaster_type || null,
|
||||||
|
seating_type: submissionData.seating_type || null,
|
||||||
|
intensity_level: submissionData.intensity_level || null,
|
||||||
|
coaster_stats: coasterStats,
|
||||||
|
technical_specs: technicalSpecs,
|
||||||
|
former_names: formerNames || [],
|
||||||
|
banner_image_url: submissionData.banner_image_url || null,
|
||||||
|
banner_image_id: submissionData.banner_image_id || null,
|
||||||
|
card_image_url: submissionData.card_image_url || null,
|
||||||
|
card_image_id: submissionData.card_image_id || null,
|
||||||
|
image_url: submissionData.image_url || null,
|
||||||
|
average_rating: 0,
|
||||||
|
review_count: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform company submission data to database insert format
|
||||||
|
*/
|
||||||
|
export function transformCompanyData(
|
||||||
|
submissionData: any,
|
||||||
|
companyType: 'manufacturer' | 'operator' | 'property_owner' | 'designer'
|
||||||
|
): CompanyInsert {
|
||||||
|
return {
|
||||||
|
name: submissionData.name,
|
||||||
|
slug: submissionData.slug,
|
||||||
|
description: submissionData.description || null,
|
||||||
|
company_type: companyType,
|
||||||
|
person_type: submissionData.person_type || 'company',
|
||||||
|
founded_year: submissionData.founded_year || null,
|
||||||
|
headquarters_location: submissionData.headquarters_location || null,
|
||||||
|
website_url: submissionData.website_url || null,
|
||||||
|
logo_url: submissionData.logo_url || null,
|
||||||
|
average_rating: 0,
|
||||||
|
review_count: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform ride model submission data to database insert format
|
||||||
|
*/
|
||||||
|
export function transformRideModelData(submissionData: any): RideModelInsert {
|
||||||
|
let technicalSpecs = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (submissionData.technical_specs) {
|
||||||
|
technicalSpecs = typeof submissionData.technical_specs === 'string'
|
||||||
|
? JSON.parse(submissionData.technical_specs)
|
||||||
|
: submissionData.technical_specs;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to parse technical_specs:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: submissionData.name,
|
||||||
|
slug: submissionData.slug,
|
||||||
|
manufacturer_id: submissionData.manufacturer_id,
|
||||||
|
category: submissionData.category,
|
||||||
|
ride_type: submissionData.ride_type || null,
|
||||||
|
description: submissionData.description || null,
|
||||||
|
technical_specs: technicalSpecs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize status values to match database enums
|
||||||
|
*/
|
||||||
|
function normalizeStatus(status: string): string {
|
||||||
|
if (!status) return 'operating';
|
||||||
|
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
'Operating': 'operating',
|
||||||
|
'operating': 'operating',
|
||||||
|
'Seasonal': 'seasonal',
|
||||||
|
'seasonal': 'seasonal',
|
||||||
|
'Closed Temporarily': 'closed_temporarily',
|
||||||
|
'closed_temporarily': 'closed_temporarily',
|
||||||
|
'Closed Permanently': 'closed_permanently',
|
||||||
|
'closed_permanently': 'closed_permanently',
|
||||||
|
'Under Construction': 'under_construction',
|
||||||
|
'under_construction': 'under_construction',
|
||||||
|
'Planned': 'planned',
|
||||||
|
'planned': 'planned',
|
||||||
|
'SBNO': 'sbno',
|
||||||
|
'sbno': 'sbno',
|
||||||
|
};
|
||||||
|
|
||||||
|
return statusMap[status] || 'operating';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract Cloudflare image ID from URL
|
||||||
|
*/
|
||||||
|
export function extractImageId(url: string): string {
|
||||||
|
const match = url.match(/\/([a-f0-9-]{36})\//);
|
||||||
|
return match ? match[1] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and sanitize submission data before transformation
|
||||||
|
*/
|
||||||
|
export function validateSubmissionData(data: any, itemType: string): void {
|
||||||
|
if (!data.name || typeof data.name !== 'string' || data.name.trim() === '') {
|
||||||
|
throw new Error(`${itemType} name is required`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.slug || typeof data.slug !== 'string' || data.slug.trim() === '') {
|
||||||
|
throw new Error(`${itemType} slug is required`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate slug format
|
||||||
|
if (!/^[a-z0-9-]+$/.test(data.slug)) {
|
||||||
|
throw new Error(`${itemType} slug must contain only lowercase letters, numbers, and hyphens`);
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/lib/slugUtils.ts
Normal file
66
src/lib/slugUtils.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a URL-safe slug from a name
|
||||||
|
*/
|
||||||
|
export function generateSlugFromName(name: string): string {
|
||||||
|
return name
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9\s-]/g, '')
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.replace(/-+/g, '-')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure slug is unique by checking database and appending number if needed
|
||||||
|
*/
|
||||||
|
export async function ensureUniqueSlug(
|
||||||
|
baseSlug: string,
|
||||||
|
tableName: 'parks' | 'rides' | 'companies' | 'ride_models',
|
||||||
|
excludeId?: string
|
||||||
|
): Promise<string> {
|
||||||
|
let slug = baseSlug;
|
||||||
|
let counter = 1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Check if slug exists
|
||||||
|
let query = supabase
|
||||||
|
.from(tableName)
|
||||||
|
.select('id')
|
||||||
|
.eq('slug', slug);
|
||||||
|
|
||||||
|
// Exclude current record when editing
|
||||||
|
if (excludeId) {
|
||||||
|
query = query.neq('id', excludeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data, error } = await query.limit(1);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error(`Error checking slug uniqueness in ${tableName}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no match found, slug is unique
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
return slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append counter and try again
|
||||||
|
counter++;
|
||||||
|
slug = `${baseSlug}-${counter}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and ensure unique slug in one operation
|
||||||
|
*/
|
||||||
|
export async function generateUniqueSlug(
|
||||||
|
name: string,
|
||||||
|
tableName: 'parks' | 'rides' | 'companies' | 'ride_models',
|
||||||
|
excludeId?: string
|
||||||
|
): Promise<string> {
|
||||||
|
const baseSlug = generateSlugFromName(name);
|
||||||
|
return ensureUniqueSlug(baseSlug, tableName, excludeId);
|
||||||
|
}
|
||||||
@@ -161,36 +161,59 @@ export async function approveSubmissionItems(
|
|||||||
// Sort by dependency order (parents first)
|
// Sort by dependency order (parents first)
|
||||||
const sortedItems = topologicalSort(items);
|
const sortedItems = topologicalSort(items);
|
||||||
|
|
||||||
|
// Build dependency resolution map
|
||||||
|
const dependencyMap = new Map<string, string>();
|
||||||
|
|
||||||
for (const item of sortedItems) {
|
for (const item of sortedItems) {
|
||||||
let entityId: string | null = null;
|
let entityId: string | null = null;
|
||||||
|
|
||||||
// Create the entity based on type
|
try {
|
||||||
|
// Create the entity based on type with dependency resolution
|
||||||
switch (item.item_type) {
|
switch (item.item_type) {
|
||||||
case 'park':
|
case 'park':
|
||||||
entityId = await createPark(item.item_data);
|
entityId = await createPark(item.item_data, dependencyMap);
|
||||||
break;
|
break;
|
||||||
case 'ride':
|
case 'ride':
|
||||||
entityId = await createRide(item.item_data);
|
entityId = await createRide(item.item_data, dependencyMap);
|
||||||
break;
|
break;
|
||||||
case 'manufacturer':
|
case 'manufacturer':
|
||||||
case 'operator':
|
case 'operator':
|
||||||
case 'property_owner':
|
case 'property_owner':
|
||||||
case 'designer':
|
case 'designer':
|
||||||
entityId = await createCompany(item.item_data, item.item_type);
|
entityId = await createCompany(item.item_data, item.item_type, dependencyMap);
|
||||||
break;
|
break;
|
||||||
case 'ride_model':
|
case 'ride_model':
|
||||||
entityId = await createRideModel(item.item_data);
|
entityId = await createRideModel(item.item_data, dependencyMap);
|
||||||
break;
|
break;
|
||||||
case 'photo':
|
case 'photo':
|
||||||
entityId = await approvePhotos(item.item_data);
|
entityId = await approvePhotos(item.item_data, dependencyMap);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!entityId) {
|
||||||
|
throw new Error(`Failed to create ${item.item_type}: no entity ID returned`);
|
||||||
|
}
|
||||||
|
|
||||||
// Update item status
|
// Update item status
|
||||||
await updateSubmissionItem(item.id, {
|
await updateSubmissionItem(item.id, {
|
||||||
status: 'approved',
|
status: 'approved',
|
||||||
approved_entity_id: entityId,
|
approved_entity_id: entityId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add to dependency map for child items
|
||||||
|
dependencyMap.set(item.id, entityId);
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`Error approving ${item.item_type} item ${item.id}:`, error);
|
||||||
|
|
||||||
|
// Update item with error status
|
||||||
|
await updateSubmissionItem(item.id, {
|
||||||
|
status: 'rejected',
|
||||||
|
rejection_reason: `Failed to create entity: ${error.message}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
throw new Error(`Failed to approve ${item.item_type}: ${error.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,56 +252,190 @@ function topologicalSort(items: SubmissionItemWithDeps[]): SubmissionItemWithDep
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper functions to create entities
|
* Helper functions to create entities with dependency resolution
|
||||||
*/
|
*/
|
||||||
async function createPark(data: any): Promise<string> {
|
async function createPark(data: any, dependencyMap: Map<string, string>): Promise<string> {
|
||||||
|
const { transformParkData, validateSubmissionData } = await import('./entityTransformers');
|
||||||
|
const { ensureUniqueSlug } = await import('./slugUtils');
|
||||||
|
|
||||||
|
// Validate input data
|
||||||
|
validateSubmissionData(data, 'Park');
|
||||||
|
|
||||||
|
// Resolve dependencies
|
||||||
|
const resolvedData = resolveDependencies(data, dependencyMap);
|
||||||
|
|
||||||
|
// Ensure unique slug
|
||||||
|
const uniqueSlug = await ensureUniqueSlug(resolvedData.slug, 'parks');
|
||||||
|
resolvedData.slug = uniqueSlug;
|
||||||
|
|
||||||
|
// Transform to database format
|
||||||
|
const parkData = transformParkData(resolvedData);
|
||||||
|
|
||||||
|
// Insert into database
|
||||||
const { data: park, error } = await supabase
|
const { data: park, error } = await supabase
|
||||||
.from('parks')
|
.from('parks')
|
||||||
.insert(data)
|
.insert(parkData)
|
||||||
.select('id')
|
.select('id')
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
if (error) throw error;
|
if (error) {
|
||||||
|
console.error('Error creating park:', error);
|
||||||
|
throw new Error(`Database error: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
return park.id;
|
return park.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createRide(data: any): Promise<string> {
|
async function createRide(data: any, dependencyMap: Map<string, string>): Promise<string> {
|
||||||
|
const { transformRideData, validateSubmissionData } = await import('./entityTransformers');
|
||||||
|
const { ensureUniqueSlug } = await import('./slugUtils');
|
||||||
|
|
||||||
|
// Validate input data
|
||||||
|
validateSubmissionData(data, 'Ride');
|
||||||
|
|
||||||
|
// Resolve dependencies
|
||||||
|
const resolvedData = resolveDependencies(data, dependencyMap);
|
||||||
|
|
||||||
|
// Validate park_id is present (required for rides)
|
||||||
|
if (!resolvedData.park_id) {
|
||||||
|
throw new Error('Ride must be associated with a park');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure unique slug
|
||||||
|
const uniqueSlug = await ensureUniqueSlug(resolvedData.slug, 'rides');
|
||||||
|
resolvedData.slug = uniqueSlug;
|
||||||
|
|
||||||
|
// Transform to database format
|
||||||
|
const rideData = transformRideData(resolvedData);
|
||||||
|
|
||||||
|
// Insert into database
|
||||||
const { data: ride, error } = await supabase
|
const { data: ride, error } = await supabase
|
||||||
.from('rides')
|
.from('rides')
|
||||||
.insert(data)
|
.insert(rideData)
|
||||||
.select('id')
|
.select('id')
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
if (error) throw error;
|
if (error) {
|
||||||
|
console.error('Error creating ride:', error);
|
||||||
|
throw new Error(`Database error: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
return ride.id;
|
return ride.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createCompany(data: any, companyType: string): Promise<string> {
|
async function createCompany(
|
||||||
|
data: any,
|
||||||
|
companyType: string,
|
||||||
|
dependencyMap: Map<string, string>
|
||||||
|
): Promise<string> {
|
||||||
|
const { transformCompanyData, validateSubmissionData } = await import('./entityTransformers');
|
||||||
|
const { ensureUniqueSlug } = await import('./slugUtils');
|
||||||
|
|
||||||
|
// Validate input data
|
||||||
|
validateSubmissionData(data, 'Company');
|
||||||
|
|
||||||
|
// Resolve dependencies
|
||||||
|
const resolvedData = resolveDependencies(data, dependencyMap);
|
||||||
|
|
||||||
|
// Ensure unique slug
|
||||||
|
const uniqueSlug = await ensureUniqueSlug(resolvedData.slug, 'companies');
|
||||||
|
resolvedData.slug = uniqueSlug;
|
||||||
|
|
||||||
|
// Transform to database format
|
||||||
|
const companyData = transformCompanyData(resolvedData, companyType as any);
|
||||||
|
|
||||||
|
// Insert into database
|
||||||
const { data: company, error } = await supabase
|
const { data: company, error } = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.insert({ ...data, company_type: companyType })
|
.insert(companyData)
|
||||||
.select('id')
|
.select('id')
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
if (error) throw error;
|
if (error) {
|
||||||
|
console.error('Error creating company:', error);
|
||||||
|
throw new Error(`Database error: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
return company.id;
|
return company.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createRideModel(data: any): Promise<string> {
|
async function createRideModel(data: any, dependencyMap: Map<string, string>): Promise<string> {
|
||||||
|
const { transformRideModelData, validateSubmissionData } = await import('./entityTransformers');
|
||||||
|
const { ensureUniqueSlug } = await import('./slugUtils');
|
||||||
|
|
||||||
|
// Validate input data
|
||||||
|
validateSubmissionData(data, 'Ride Model');
|
||||||
|
|
||||||
|
// Resolve dependencies
|
||||||
|
const resolvedData = resolveDependencies(data, dependencyMap);
|
||||||
|
|
||||||
|
// Validate manufacturer_id is present (required for ride models)
|
||||||
|
if (!resolvedData.manufacturer_id) {
|
||||||
|
throw new Error('Ride model must be associated with a manufacturer');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure unique slug
|
||||||
|
const uniqueSlug = await ensureUniqueSlug(resolvedData.slug, 'ride_models');
|
||||||
|
resolvedData.slug = uniqueSlug;
|
||||||
|
|
||||||
|
// Transform to database format
|
||||||
|
const modelData = transformRideModelData(resolvedData);
|
||||||
|
|
||||||
|
// Insert into database
|
||||||
const { data: model, error } = await supabase
|
const { data: model, error } = await supabase
|
||||||
.from('ride_models')
|
.from('ride_models')
|
||||||
.insert(data)
|
.insert(modelData)
|
||||||
.select('id')
|
.select('id')
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
if (error) throw error;
|
if (error) {
|
||||||
|
console.error('Error creating ride model:', error);
|
||||||
|
throw new Error(`Database error: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
return model.id;
|
return model.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function approvePhotos(data: any): Promise<string> {
|
async function approvePhotos(data: any, dependencyMap: Map<string, string>): Promise<string> {
|
||||||
// Photos are already uploaded to Cloudflare
|
// Photos are already uploaded to Cloudflare
|
||||||
// Just need to associate them with the entity
|
// Resolve dependencies for entity associations
|
||||||
return data.photos?.[0]?.url || '';
|
const resolvedData = resolveDependencies(data, dependencyMap);
|
||||||
|
|
||||||
|
// For now, return the first photo URL
|
||||||
|
// In the future, this could create photo records in a dedicated table
|
||||||
|
if (resolvedData.photos && Array.isArray(resolvedData.photos) && resolvedData.photos.length > 0) {
|
||||||
|
return resolvedData.photos[0].url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve dependency references in submission data
|
||||||
|
* Replaces submission item IDs with actual database entity IDs
|
||||||
|
*/
|
||||||
|
function resolveDependencies(data: any, dependencyMap: Map<string, string>): any {
|
||||||
|
const resolved = { ...data };
|
||||||
|
|
||||||
|
// List of foreign key fields that may need resolution
|
||||||
|
const foreignKeys = [
|
||||||
|
'park_id',
|
||||||
|
'manufacturer_id',
|
||||||
|
'designer_id',
|
||||||
|
'operator_id',
|
||||||
|
'property_owner_id',
|
||||||
|
'ride_model_id',
|
||||||
|
'location_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Resolve each foreign key if it's a submission item ID
|
||||||
|
for (const key of foreignKeys) {
|
||||||
|
if (resolved[key] && dependencyMap.has(resolved[key])) {
|
||||||
|
resolved[key] = dependencyMap.get(resolved[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user