mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 20:11:14 -05:00
Implement Test Data Generator
This commit is contained in:
266
src/lib/testDataGenerator.ts
Normal file
266
src/lib/testDataGenerator.ts
Normal file
@@ -0,0 +1,266 @@
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import type { ParkSubmissionData, RideSubmissionData, CompanySubmissionData, RideModelSubmissionData } from '@/types/submission-data';
|
||||
|
||||
// Preset configurations
|
||||
export const PRESETS = {
|
||||
small: { parks: 5, rides: 10, companies: 3, rideModels: 2, photos: 0 },
|
||||
medium: { parks: 20, rides: 50, companies: 20, rideModels: 10, photos: 0 },
|
||||
large: { parks: 100, rides: 250, companies: 100, rideModels: 50, photos: 0 },
|
||||
stress: { parks: 400, rides: 1000, companies: 400, rideModels: 200, photos: 0 }
|
||||
} as const;
|
||||
|
||||
// Word lists for realistic names
|
||||
const PARK_ADJECTIVES = ['Adventure', 'Fantasy', 'Wonder', 'Magic', 'Dream', 'Thrill', 'Fun', 'Happy', 'Paradise', 'Epic'];
|
||||
const PARK_NOUNS = ['World', 'Land', 'Park', 'Gardens', 'Kingdom', 'Realm', 'Island', 'Bay', 'Point', 'Valley'];
|
||||
const RIDE_PREFIXES = ['Super', 'Mega', 'Ultra', 'Extreme', 'Wild', 'Crazy', 'Thunder', 'Lightning', 'Dragon', 'Phoenix'];
|
||||
const RIDE_TYPES = ['Coaster', 'Drop', 'Spinner', 'Flyer', 'Racer', 'Twister', 'Loop', 'Screamer', 'Rush', 'Blast'];
|
||||
const COMPANY_PREFIXES = ['Ace', 'Premier', 'Advanced', 'Dynamic', 'Innovative', 'Global', 'United', 'International'];
|
||||
const COMPANY_SUFFIXES = ['Industries', 'Manufacturing', 'Enterprises', 'Solutions', 'Systems', 'Designs', 'Works', 'Creations'];
|
||||
|
||||
const CITIES = ['New York', 'Los Angeles', 'Chicago', 'London', 'Paris', 'Tokyo', 'Sydney', 'Toronto', 'Berlin', 'Madrid'];
|
||||
const COUNTRIES = ['USA', 'UK', 'France', 'Japan', 'Australia', 'Canada', 'Germany', 'Spain', 'Italy', 'Netherlands'];
|
||||
|
||||
// Helper functions
|
||||
function randomItem<T>(array: T[]): T {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
|
||||
function randomInt(min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function randomFloat(min: number, max: number, decimals = 2): number {
|
||||
return parseFloat((Math.random() * (max - min) + min).toFixed(decimals));
|
||||
}
|
||||
|
||||
function randomDate(startYear: number, endYear: number): string {
|
||||
const start = new Date(startYear, 0, 1);
|
||||
const end = new Date(endYear, 11, 31);
|
||||
const date = new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
|
||||
return date.toISOString().split('T')[0];
|
||||
}
|
||||
|
||||
function generateSlug(name: string, counter?: number): string {
|
||||
let slug = name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9\s-]/g, '')
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
|
||||
if (counter) {
|
||||
slug += `-${counter}`;
|
||||
}
|
||||
|
||||
return slug;
|
||||
}
|
||||
|
||||
// Test data context for tracking created entities
|
||||
export class TestDataContext {
|
||||
createdParks: Array<{ id: string; name: string }> = [];
|
||||
createdCompanies: Array<{ id: string; name: string; type: string }> = [];
|
||||
createdRideModels: Array<{ id: string; name: string; manufacturer_id: string }> = [];
|
||||
stats = {
|
||||
parks: 0,
|
||||
rides: 0,
|
||||
companies: 0,
|
||||
rideModels: 0,
|
||||
photos: 0,
|
||||
conflicts: 0,
|
||||
versionChains: 0
|
||||
};
|
||||
|
||||
addPark(id: string, name: string) {
|
||||
this.createdParks.push({ id, name });
|
||||
this.stats.parks++;
|
||||
}
|
||||
|
||||
addCompany(id: string, name: string, type: string) {
|
||||
this.createdCompanies.push({ id, name, type });
|
||||
this.stats.companies++;
|
||||
}
|
||||
|
||||
addRideModel(id: string, name: string, manufacturer_id: string) {
|
||||
this.createdRideModels.push({ id, name, manufacturer_id });
|
||||
this.stats.rideModels++;
|
||||
}
|
||||
|
||||
getRandomPark() {
|
||||
return this.createdParks.length > 0 ? randomItem(this.createdParks) : null;
|
||||
}
|
||||
|
||||
getRandomCompany(type?: string) {
|
||||
const filtered = type
|
||||
? this.createdCompanies.filter(c => c.type === type)
|
||||
: this.createdCompanies;
|
||||
return filtered.length > 0 ? randomItem(filtered) : null;
|
||||
}
|
||||
|
||||
getRandomRideModel() {
|
||||
return this.createdRideModels.length > 0 ? randomItem(this.createdRideModels) : null;
|
||||
}
|
||||
|
||||
getSummary() {
|
||||
return this.stats;
|
||||
}
|
||||
}
|
||||
|
||||
// Random data generators
|
||||
export function generateRandomPark(counter: number): ParkSubmissionData {
|
||||
const name = `${randomItem(PARK_ADJECTIVES)} ${randomItem(PARK_NOUNS)}`;
|
||||
const slug = generateSlug(name, counter);
|
||||
|
||||
return {
|
||||
name,
|
||||
slug,
|
||||
description: `A thrilling amusement park featuring world-class attractions and entertainment.`,
|
||||
park_type: randomItem(['theme_park', 'amusement_park', 'water_park', 'adventure_park']),
|
||||
status: randomItem(['operating', 'operating', 'operating', 'seasonal']), // More likely to be operating
|
||||
opening_date: randomDate(1950, 2024),
|
||||
closing_date: Math.random() > 0.9 ? randomDate(2000, 2024) : null,
|
||||
website_url: `https://${slug}.example.com`,
|
||||
phone: `+1-555-${randomInt(100, 999)}-${randomInt(1000, 9999)}`,
|
||||
email: `info@${slug}.example.com`,
|
||||
operator_id: null,
|
||||
property_owner_id: null,
|
||||
location_id: null,
|
||||
banner_image_url: null,
|
||||
banner_image_id: null,
|
||||
card_image_url: null,
|
||||
card_image_id: null
|
||||
};
|
||||
}
|
||||
|
||||
export function generateRandomRide(parkId: string, counter: number): RideSubmissionData {
|
||||
const name = `${randomItem(RIDE_PREFIXES)} ${randomItem(RIDE_TYPES)}`;
|
||||
const slug = generateSlug(name, counter);
|
||||
const category = randomItem(['roller_coaster', 'flat_ride', 'water_ride', 'dark_ride', 'family_ride']);
|
||||
|
||||
return {
|
||||
name,
|
||||
slug,
|
||||
description: `An exciting ${category.replace('_', ' ')} experience for all ages.`,
|
||||
category,
|
||||
ride_sub_type: null,
|
||||
status: randomItem(['operating', 'operating', 'operating', 'seasonal']),
|
||||
park_id: parkId,
|
||||
ride_model_id: null,
|
||||
manufacturer_id: null,
|
||||
designer_id: null,
|
||||
opening_date: randomDate(1980, 2024),
|
||||
closing_date: Math.random() > 0.95 ? randomDate(2010, 2024) : null,
|
||||
height_requirement: randomInt(90, 140),
|
||||
age_requirement: null,
|
||||
capacity_per_hour: randomInt(500, 2000),
|
||||
duration_seconds: randomInt(60, 300),
|
||||
max_speed_kmh: category === 'roller_coaster' ? randomFloat(40, 150, 1) : randomFloat(10, 60, 1),
|
||||
max_height_meters: category === 'roller_coaster' ? randomFloat(20, 100, 1) : randomFloat(5, 30, 1),
|
||||
length_meters: category === 'roller_coaster' ? randomFloat(500, 2500, 1) : null,
|
||||
drop_height_meters: category === 'roller_coaster' ? randomFloat(15, 80, 1) : null,
|
||||
inversions: category === 'roller_coaster' && Math.random() > 0.5 ? randomInt(1, 7) : 0,
|
||||
max_g_force: category === 'roller_coaster' ? randomFloat(2, 5, 1) : null,
|
||||
coaster_type: category === 'roller_coaster' ? randomItem(['steel', 'wooden', 'hybrid']) : null,
|
||||
seating_type: category === 'roller_coaster' ? randomItem(['sit_down', 'inverted', 'floorless', 'suspended']) : null,
|
||||
intensity_level: randomItem(['family', 'moderate', 'thrill', 'extreme']),
|
||||
banner_image_url: null,
|
||||
banner_image_id: null,
|
||||
card_image_url: null,
|
||||
card_image_id: null,
|
||||
image_url: null
|
||||
};
|
||||
}
|
||||
|
||||
export function generateRandomCompany(type: 'manufacturer' | 'operator' | 'designer' | 'property_owner', counter: number): CompanySubmissionData {
|
||||
const name = `${randomItem(COMPANY_PREFIXES)} ${randomItem(COMPANY_SUFFIXES)}`;
|
||||
const slug = generateSlug(name, counter);
|
||||
|
||||
return {
|
||||
name,
|
||||
slug,
|
||||
description: `A leading ${type.replace('_', ' ')} in the amusement industry.`,
|
||||
person_type: Math.random() > 0.9 ? 'individual' : 'company',
|
||||
founded_year: randomInt(1950, 2020),
|
||||
headquarters_location: `${randomItem(CITIES)}, ${randomItem(COUNTRIES)}`,
|
||||
website_url: `https://${slug}.example.com`,
|
||||
logo_url: null,
|
||||
banner_image_url: null,
|
||||
banner_image_id: null,
|
||||
card_image_url: null,
|
||||
card_image_id: null
|
||||
};
|
||||
}
|
||||
|
||||
export function generateRandomRideModel(manufacturerId: string, counter: number): RideModelSubmissionData {
|
||||
const name = `${randomItem(RIDE_PREFIXES)} Model ${randomInt(100, 999)}`;
|
||||
const slug = generateSlug(name, counter);
|
||||
const category = randomItem(['roller_coaster', 'flat_ride', 'water_ride', 'dark_ride']);
|
||||
|
||||
return {
|
||||
name,
|
||||
slug,
|
||||
manufacturer_id: manufacturerId,
|
||||
category,
|
||||
ride_type: randomItem(['spinning', 'launch', 'inverted', 'suspended', 'floorless']),
|
||||
description: `A state-of-the-art ${category.replace('_', ' ')} model.`,
|
||||
banner_image_url: null,
|
||||
banner_image_id: null,
|
||||
card_image_url: null,
|
||||
card_image_id: null
|
||||
};
|
||||
}
|
||||
|
||||
// Cleanup utilities
|
||||
export async function clearTestData(): Promise<{ deleted: number }> {
|
||||
try {
|
||||
// Find all test submissions
|
||||
const { data: testSubmissions, error: fetchError } = await supabase
|
||||
.from('content_submissions')
|
||||
.select('id')
|
||||
.eq('status', 'pending')
|
||||
.contains('content', { metadata: { is_test_data: true } });
|
||||
|
||||
if (fetchError) throw fetchError;
|
||||
if (!testSubmissions || testSubmissions.length === 0) {
|
||||
return { deleted: 0 };
|
||||
}
|
||||
|
||||
// Delete in batches of 100
|
||||
const batchSize = 100;
|
||||
let totalDeleted = 0;
|
||||
|
||||
for (let i = 0; i < testSubmissions.length; i += batchSize) {
|
||||
const batch = testSubmissions.slice(i, i + batchSize);
|
||||
const ids = batch.map(s => s.id);
|
||||
|
||||
const { error: deleteError } = await supabase
|
||||
.from('content_submissions')
|
||||
.delete()
|
||||
.in('id', ids);
|
||||
|
||||
if (deleteError) throw deleteError;
|
||||
totalDeleted += ids.length;
|
||||
}
|
||||
|
||||
return { deleted: totalDeleted };
|
||||
} catch (error) {
|
||||
console.error('Error clearing test data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTestDataStats(): Promise<{ total: number; pending: number; approved: number }> {
|
||||
const { data, error } = await supabase
|
||||
.from('content_submissions')
|
||||
.select('status')
|
||||
.contains('content', { metadata: { is_test_data: true } });
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
const stats = {
|
||||
total: data?.length || 0,
|
||||
pending: data?.filter(s => s.status === 'pending').length || 0,
|
||||
approved: data?.filter(s => s.status === 'approved').length || 0
|
||||
};
|
||||
|
||||
return stats;
|
||||
}
|
||||
Reference in New Issue
Block a user