mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 15:51:13 -05:00
feat: Implement is_test_data flag system
This commit is contained in:
@@ -194,6 +194,7 @@ export type Database = {
|
|||||||
founded_year: number | null
|
founded_year: number | null
|
||||||
headquarters_location: string | null
|
headquarters_location: string | null
|
||||||
id: string
|
id: string
|
||||||
|
is_test_data: boolean | null
|
||||||
logo_url: string | null
|
logo_url: string | null
|
||||||
name: string
|
name: string
|
||||||
person_type: string | null
|
person_type: string | null
|
||||||
@@ -219,6 +220,7 @@ export type Database = {
|
|||||||
founded_year?: number | null
|
founded_year?: number | null
|
||||||
headquarters_location?: string | null
|
headquarters_location?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
logo_url?: string | null
|
logo_url?: string | null
|
||||||
name: string
|
name: string
|
||||||
person_type?: string | null
|
person_type?: string | null
|
||||||
@@ -244,6 +246,7 @@ export type Database = {
|
|||||||
founded_year?: number | null
|
founded_year?: number | null
|
||||||
headquarters_location?: string | null
|
headquarters_location?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
logo_url?: string | null
|
logo_url?: string | null
|
||||||
name?: string
|
name?: string
|
||||||
person_type?: string | null
|
person_type?: string | null
|
||||||
@@ -349,6 +352,7 @@ export type Database = {
|
|||||||
founded_year: number | null
|
founded_year: number | null
|
||||||
headquarters_location: string | null
|
headquarters_location: string | null
|
||||||
is_current: boolean
|
is_current: boolean
|
||||||
|
is_test_data: boolean | null
|
||||||
logo_url: string | null
|
logo_url: string | null
|
||||||
name: string
|
name: string
|
||||||
person_type: string | null
|
person_type: string | null
|
||||||
@@ -375,6 +379,7 @@ export type Database = {
|
|||||||
founded_year?: number | null
|
founded_year?: number | null
|
||||||
headquarters_location?: string | null
|
headquarters_location?: string | null
|
||||||
is_current?: boolean
|
is_current?: boolean
|
||||||
|
is_test_data?: boolean | null
|
||||||
logo_url?: string | null
|
logo_url?: string | null
|
||||||
name: string
|
name: string
|
||||||
person_type?: string | null
|
person_type?: string | null
|
||||||
@@ -401,6 +406,7 @@ export type Database = {
|
|||||||
founded_year?: number | null
|
founded_year?: number | null
|
||||||
headquarters_location?: string | null
|
headquarters_location?: string | null
|
||||||
is_current?: boolean
|
is_current?: boolean
|
||||||
|
is_test_data?: boolean | null
|
||||||
logo_url?: string | null
|
logo_url?: string | null
|
||||||
name?: string
|
name?: string
|
||||||
person_type?: string | null
|
person_type?: string | null
|
||||||
@@ -628,6 +634,7 @@ export type Database = {
|
|||||||
escalation_reason: string | null
|
escalation_reason: string | null
|
||||||
first_reviewed_at: string | null
|
first_reviewed_at: string | null
|
||||||
id: string
|
id: string
|
||||||
|
is_test_data: boolean | null
|
||||||
locked_until: string | null
|
locked_until: string | null
|
||||||
original_submission_id: string | null
|
original_submission_id: string | null
|
||||||
resolved_at: string | null
|
resolved_at: string | null
|
||||||
@@ -653,6 +660,7 @@ export type Database = {
|
|||||||
escalation_reason?: string | null
|
escalation_reason?: string | null
|
||||||
first_reviewed_at?: string | null
|
first_reviewed_at?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
locked_until?: string | null
|
locked_until?: string | null
|
||||||
original_submission_id?: string | null
|
original_submission_id?: string | null
|
||||||
resolved_at?: string | null
|
resolved_at?: string | null
|
||||||
@@ -678,6 +686,7 @@ export type Database = {
|
|||||||
escalation_reason?: string | null
|
escalation_reason?: string | null
|
||||||
first_reviewed_at?: string | null
|
first_reviewed_at?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
locked_until?: string | null
|
locked_until?: string | null
|
||||||
original_submission_id?: string | null
|
original_submission_id?: string | null
|
||||||
resolved_at?: string | null
|
resolved_at?: string | null
|
||||||
@@ -1509,6 +1518,7 @@ export type Database = {
|
|||||||
description: string | null
|
description: string | null
|
||||||
email: string | null
|
email: string | null
|
||||||
is_current: boolean
|
is_current: boolean
|
||||||
|
is_test_data: boolean | null
|
||||||
location_id: string | null
|
location_id: string | null
|
||||||
name: string
|
name: string
|
||||||
opening_date: string | null
|
opening_date: string | null
|
||||||
@@ -1539,6 +1549,7 @@ export type Database = {
|
|||||||
description?: string | null
|
description?: string | null
|
||||||
email?: string | null
|
email?: string | null
|
||||||
is_current?: boolean
|
is_current?: boolean
|
||||||
|
is_test_data?: boolean | null
|
||||||
location_id?: string | null
|
location_id?: string | null
|
||||||
name: string
|
name: string
|
||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
@@ -1569,6 +1580,7 @@ export type Database = {
|
|||||||
description?: string | null
|
description?: string | null
|
||||||
email?: string | null
|
email?: string | null
|
||||||
is_current?: boolean
|
is_current?: boolean
|
||||||
|
is_test_data?: boolean | null
|
||||||
location_id?: string | null
|
location_id?: string | null
|
||||||
name?: string
|
name?: string
|
||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
@@ -1651,6 +1663,7 @@ export type Database = {
|
|||||||
description: string | null
|
description: string | null
|
||||||
email: string | null
|
email: string | null
|
||||||
id: string
|
id: string
|
||||||
|
is_test_data: boolean | null
|
||||||
location_id: string | null
|
location_id: string | null
|
||||||
name: string
|
name: string
|
||||||
opening_date: string | null
|
opening_date: string | null
|
||||||
@@ -1682,6 +1695,7 @@ export type Database = {
|
|||||||
description?: string | null
|
description?: string | null
|
||||||
email?: string | null
|
email?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
location_id?: string | null
|
location_id?: string | null
|
||||||
name: string
|
name: string
|
||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
@@ -1713,6 +1727,7 @@ export type Database = {
|
|||||||
description?: string | null
|
description?: string | null
|
||||||
email?: string | null
|
email?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
location_id?: string | null
|
location_id?: string | null
|
||||||
name?: string
|
name?: string
|
||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
@@ -1866,6 +1881,7 @@ export type Database = {
|
|||||||
entity_type: string
|
entity_type: string
|
||||||
id: string
|
id: string
|
||||||
is_featured: boolean | null
|
is_featured: boolean | null
|
||||||
|
is_test_data: boolean | null
|
||||||
order_index: number | null
|
order_index: number | null
|
||||||
photographer_credit: string | null
|
photographer_credit: string | null
|
||||||
submission_id: string | null
|
submission_id: string | null
|
||||||
@@ -1886,6 +1902,7 @@ export type Database = {
|
|||||||
entity_type: string
|
entity_type: string
|
||||||
id?: string
|
id?: string
|
||||||
is_featured?: boolean | null
|
is_featured?: boolean | null
|
||||||
|
is_test_data?: boolean | null
|
||||||
order_index?: number | null
|
order_index?: number | null
|
||||||
photographer_credit?: string | null
|
photographer_credit?: string | null
|
||||||
submission_id?: string | null
|
submission_id?: string | null
|
||||||
@@ -1906,6 +1923,7 @@ export type Database = {
|
|||||||
entity_type?: string
|
entity_type?: string
|
||||||
id?: string
|
id?: string
|
||||||
is_featured?: boolean | null
|
is_featured?: boolean | null
|
||||||
|
is_test_data?: boolean | null
|
||||||
order_index?: number | null
|
order_index?: number | null
|
||||||
photographer_credit?: string | null
|
photographer_credit?: string | null
|
||||||
submission_id?: string | null
|
submission_id?: string | null
|
||||||
@@ -2301,6 +2319,7 @@ export type Database = {
|
|||||||
created_at: string
|
created_at: string
|
||||||
helpful_votes: number | null
|
helpful_votes: number | null
|
||||||
id: string
|
id: string
|
||||||
|
is_test_data: boolean | null
|
||||||
moderated_at: string | null
|
moderated_at: string | null
|
||||||
moderated_by: string | null
|
moderated_by: string | null
|
||||||
moderation_status: string
|
moderation_status: string
|
||||||
@@ -2321,6 +2340,7 @@ export type Database = {
|
|||||||
created_at?: string
|
created_at?: string
|
||||||
helpful_votes?: number | null
|
helpful_votes?: number | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
moderated_at?: string | null
|
moderated_at?: string | null
|
||||||
moderated_by?: string | null
|
moderated_by?: string | null
|
||||||
moderation_status?: string
|
moderation_status?: string
|
||||||
@@ -2341,6 +2361,7 @@ export type Database = {
|
|||||||
created_at?: string
|
created_at?: string
|
||||||
helpful_votes?: number | null
|
helpful_votes?: number | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
moderated_at?: string | null
|
moderated_at?: string | null
|
||||||
moderated_by?: string | null
|
moderated_by?: string | null
|
||||||
moderation_status?: string
|
moderation_status?: string
|
||||||
@@ -2788,6 +2809,7 @@ export type Database = {
|
|||||||
created_by: string | null
|
created_by: string | null
|
||||||
description: string | null
|
description: string | null
|
||||||
is_current: boolean
|
is_current: boolean
|
||||||
|
is_test_data: boolean | null
|
||||||
manufacturer_id: string | null
|
manufacturer_id: string | null
|
||||||
name: string
|
name: string
|
||||||
ride_model_id: string
|
ride_model_id: string
|
||||||
@@ -2809,6 +2831,7 @@ export type Database = {
|
|||||||
created_by?: string | null
|
created_by?: string | null
|
||||||
description?: string | null
|
description?: string | null
|
||||||
is_current?: boolean
|
is_current?: boolean
|
||||||
|
is_test_data?: boolean | null
|
||||||
manufacturer_id?: string | null
|
manufacturer_id?: string | null
|
||||||
name: string
|
name: string
|
||||||
ride_model_id: string
|
ride_model_id: string
|
||||||
@@ -2830,6 +2853,7 @@ export type Database = {
|
|||||||
created_by?: string | null
|
created_by?: string | null
|
||||||
description?: string | null
|
description?: string | null
|
||||||
is_current?: boolean
|
is_current?: boolean
|
||||||
|
is_test_data?: boolean | null
|
||||||
manufacturer_id?: string | null
|
manufacturer_id?: string | null
|
||||||
name?: string
|
name?: string
|
||||||
ride_model_id?: string
|
ride_model_id?: string
|
||||||
@@ -2887,6 +2911,7 @@ export type Database = {
|
|||||||
created_at: string
|
created_at: string
|
||||||
description: string | null
|
description: string | null
|
||||||
id: string
|
id: string
|
||||||
|
is_test_data: boolean | null
|
||||||
manufacturer_id: string
|
manufacturer_id: string
|
||||||
name: string
|
name: string
|
||||||
ride_type: string
|
ride_type: string
|
||||||
@@ -2902,6 +2927,7 @@ export type Database = {
|
|||||||
created_at?: string
|
created_at?: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
manufacturer_id: string
|
manufacturer_id: string
|
||||||
name: string
|
name: string
|
||||||
ride_type: string
|
ride_type: string
|
||||||
@@ -2917,6 +2943,7 @@ export type Database = {
|
|||||||
created_at?: string
|
created_at?: string
|
||||||
description?: string | null
|
description?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
manufacturer_id?: string
|
manufacturer_id?: string
|
||||||
name?: string
|
name?: string
|
||||||
ride_type?: string
|
ride_type?: string
|
||||||
@@ -3364,6 +3391,7 @@ export type Database = {
|
|||||||
intensity_level: string | null
|
intensity_level: string | null
|
||||||
inversions_count: number | null
|
inversions_count: number | null
|
||||||
is_current: boolean
|
is_current: boolean
|
||||||
|
is_test_data: boolean | null
|
||||||
length_meters: number | null
|
length_meters: number | null
|
||||||
manufacturer_id: string | null
|
manufacturer_id: string | null
|
||||||
max_age: number | null
|
max_age: number | null
|
||||||
@@ -3439,6 +3467,7 @@ export type Database = {
|
|||||||
intensity_level?: string | null
|
intensity_level?: string | null
|
||||||
inversions_count?: number | null
|
inversions_count?: number | null
|
||||||
is_current?: boolean
|
is_current?: boolean
|
||||||
|
is_test_data?: boolean | null
|
||||||
length_meters?: number | null
|
length_meters?: number | null
|
||||||
manufacturer_id?: string | null
|
manufacturer_id?: string | null
|
||||||
max_age?: number | null
|
max_age?: number | null
|
||||||
@@ -3514,6 +3543,7 @@ export type Database = {
|
|||||||
intensity_level?: string | null
|
intensity_level?: string | null
|
||||||
inversions_count?: number | null
|
inversions_count?: number | null
|
||||||
is_current?: boolean
|
is_current?: boolean
|
||||||
|
is_test_data?: boolean | null
|
||||||
length_meters?: number | null
|
length_meters?: number | null
|
||||||
manufacturer_id?: string | null
|
manufacturer_id?: string | null
|
||||||
max_age?: number | null
|
max_age?: number | null
|
||||||
@@ -3688,6 +3718,7 @@ export type Database = {
|
|||||||
image_url: string | null
|
image_url: string | null
|
||||||
intensity_level: string | null
|
intensity_level: string | null
|
||||||
inversions: number | null
|
inversions: number | null
|
||||||
|
is_test_data: boolean | null
|
||||||
length_meters: number | null
|
length_meters: number | null
|
||||||
manufacturer_id: string | null
|
manufacturer_id: string | null
|
||||||
max_age: number | null
|
max_age: number | null
|
||||||
@@ -3762,6 +3793,7 @@ export type Database = {
|
|||||||
image_url?: string | null
|
image_url?: string | null
|
||||||
intensity_level?: string | null
|
intensity_level?: string | null
|
||||||
inversions?: number | null
|
inversions?: number | null
|
||||||
|
is_test_data?: boolean | null
|
||||||
length_meters?: number | null
|
length_meters?: number | null
|
||||||
manufacturer_id?: string | null
|
manufacturer_id?: string | null
|
||||||
max_age?: number | null
|
max_age?: number | null
|
||||||
@@ -3836,6 +3868,7 @@ export type Database = {
|
|||||||
image_url?: string | null
|
image_url?: string | null
|
||||||
intensity_level?: string | null
|
intensity_level?: string | null
|
||||||
inversions?: number | null
|
inversions?: number | null
|
||||||
|
is_test_data?: boolean | null
|
||||||
length_meters?: number | null
|
length_meters?: number | null
|
||||||
manufacturer_id?: string | null
|
manufacturer_id?: string | null
|
||||||
max_age?: number | null
|
max_age?: number | null
|
||||||
@@ -3950,6 +3983,7 @@ export type Database = {
|
|||||||
created_at: string
|
created_at: string
|
||||||
depends_on: string | null
|
depends_on: string | null
|
||||||
id: string
|
id: string
|
||||||
|
is_test_data: boolean | null
|
||||||
item_data: Json
|
item_data: Json
|
||||||
item_type: string
|
item_type: string
|
||||||
order_index: number | null
|
order_index: number | null
|
||||||
@@ -3965,6 +3999,7 @@ export type Database = {
|
|||||||
created_at?: string
|
created_at?: string
|
||||||
depends_on?: string | null
|
depends_on?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
item_data: Json
|
item_data: Json
|
||||||
item_type: string
|
item_type: string
|
||||||
order_index?: number | null
|
order_index?: number | null
|
||||||
@@ -3980,6 +4015,7 @@ export type Database = {
|
|||||||
created_at?: string
|
created_at?: string
|
||||||
depends_on?: string | null
|
depends_on?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
item_data?: Json
|
item_data?: Json
|
||||||
item_type?: string
|
item_type?: string
|
||||||
order_index?: number | null
|
order_index?: number | null
|
||||||
@@ -4013,6 +4049,7 @@ export type Database = {
|
|||||||
entity_slug: string
|
entity_slug: string
|
||||||
entity_type: string
|
entity_type: string
|
||||||
id: string
|
id: string
|
||||||
|
is_test_data: boolean | null
|
||||||
metadata: Json | null
|
metadata: Json | null
|
||||||
submission_item_id: string | null
|
submission_item_id: string | null
|
||||||
test_session_id: string | null
|
test_session_id: string | null
|
||||||
@@ -4023,6 +4060,7 @@ export type Database = {
|
|||||||
entity_slug: string
|
entity_slug: string
|
||||||
entity_type: string
|
entity_type: string
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
metadata?: Json | null
|
metadata?: Json | null
|
||||||
submission_item_id?: string | null
|
submission_item_id?: string | null
|
||||||
test_session_id?: string | null
|
test_session_id?: string | null
|
||||||
@@ -4033,6 +4071,7 @@ export type Database = {
|
|||||||
entity_slug?: string
|
entity_slug?: string
|
||||||
entity_type?: string
|
entity_type?: string
|
||||||
id?: string
|
id?: string
|
||||||
|
is_test_data?: boolean | null
|
||||||
metadata?: Json | null
|
metadata?: Json | null
|
||||||
submission_item_id?: string | null
|
submission_item_id?: string | null
|
||||||
test_session_id?: string | null
|
test_session_id?: string | null
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export function transformParkData(submissionData: ParkSubmissionData): ParkInser
|
|||||||
review_count: 0,
|
review_count: 0,
|
||||||
ride_count: 0,
|
ride_count: 0,
|
||||||
coaster_count: 0,
|
coaster_count: 0,
|
||||||
|
is_test_data: submissionData.is_test_data || false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +121,7 @@ export function transformRideData(submissionData: RideSubmissionData): RideInser
|
|||||||
image_url: submissionData.image_url || null,
|
image_url: submissionData.image_url || null,
|
||||||
average_rating: 0,
|
average_rating: 0,
|
||||||
review_count: 0,
|
review_count: 0,
|
||||||
|
is_test_data: submissionData.is_test_data || false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +147,7 @@ export function transformCompanyData(
|
|||||||
logo_url: submissionData.logo_url || null,
|
logo_url: submissionData.logo_url || null,
|
||||||
average_rating: 0,
|
average_rating: 0,
|
||||||
review_count: 0,
|
review_count: 0,
|
||||||
|
is_test_data: submissionData.is_test_data || false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +170,7 @@ export function transformRideModelData(submissionData: RideModelSubmissionData):
|
|||||||
banner_image_id: submissionData.banner_image_id || null,
|
banner_image_id: submissionData.banner_image_id || null,
|
||||||
card_image_url: submissionData.card_image_url || null,
|
card_image_url: submissionData.card_image_url || null,
|
||||||
card_image_id: submissionData.card_image_id || null,
|
card_image_id: submissionData.card_image_id || null,
|
||||||
|
is_test_data: submissionData.is_test_data || false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
181
src/lib/integrationTests/TestDataTracker.ts
Normal file
181
src/lib/integrationTests/TestDataTracker.ts
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
|
import type { Database } from '@/integrations/supabase/types';
|
||||||
|
|
||||||
|
type TableName = keyof Database['public']['Tables'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TestDataTracker - Manages test data lifecycle for integration tests
|
||||||
|
*
|
||||||
|
* Tracks all created test entities and ensures proper cleanup in dependency order.
|
||||||
|
* All tracked entities are marked with is_test_data=true for easy identification.
|
||||||
|
*/
|
||||||
|
export class TestDataTracker {
|
||||||
|
private entities = new Map<string, Set<string>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track an entity for cleanup
|
||||||
|
* @param table - Database table name
|
||||||
|
* @param id - Entity ID
|
||||||
|
*/
|
||||||
|
track(table: string, id: string): void {
|
||||||
|
if (!this.entities.has(table)) {
|
||||||
|
this.entities.set(table, new Set());
|
||||||
|
}
|
||||||
|
this.entities.get(table)!.add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track multiple entities at once
|
||||||
|
* @param table - Database table name
|
||||||
|
* @param ids - Array of entity IDs
|
||||||
|
*/
|
||||||
|
trackMany(table: string, ids: string[]): void {
|
||||||
|
ids.forEach(id => this.track(table, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all tracked entity IDs for a specific table
|
||||||
|
* @param table - Database table name
|
||||||
|
* @returns Array of tracked IDs
|
||||||
|
*/
|
||||||
|
getTracked(table: string): string[] {
|
||||||
|
return Array.from(this.entities.get(table) || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup all tracked test data in proper dependency order
|
||||||
|
* Deletes children first, then parents to avoid foreign key violations
|
||||||
|
*/
|
||||||
|
async cleanup(): Promise<void> {
|
||||||
|
// Define deletion order (children first, parents last)
|
||||||
|
const deletionOrder: TableName[] = [
|
||||||
|
'reviews',
|
||||||
|
'photos',
|
||||||
|
'submission_items',
|
||||||
|
'content_submissions',
|
||||||
|
'ride_versions',
|
||||||
|
'park_versions',
|
||||||
|
'company_versions',
|
||||||
|
'ride_model_versions',
|
||||||
|
'rides',
|
||||||
|
'parks',
|
||||||
|
'ride_models',
|
||||||
|
'companies',
|
||||||
|
'test_data_registry'
|
||||||
|
];
|
||||||
|
|
||||||
|
const errors: Array<{ table: string; error: any }> = [];
|
||||||
|
|
||||||
|
for (const table of deletionOrder) {
|
||||||
|
const ids = this.getTracked(table);
|
||||||
|
if (ids.length === 0) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { error } = await supabase
|
||||||
|
.from(table as any)
|
||||||
|
.delete()
|
||||||
|
.in('id', ids);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
errors.push({ table, error });
|
||||||
|
console.warn(`Failed to cleanup ${table}:`, error);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
errors.push({ table, error: err });
|
||||||
|
console.warn(`Exception cleaning up ${table}:`, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear tracking after cleanup attempt
|
||||||
|
this.entities.clear();
|
||||||
|
|
||||||
|
if (errors.length > 0) {
|
||||||
|
console.warn(`Cleanup completed with ${errors.length} errors:`, errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that all tracked test data has been cleaned up
|
||||||
|
* @returns Array of remaining test data items
|
||||||
|
*/
|
||||||
|
async verifyCleanup(): Promise<Array<{ table: string; count: number }>> {
|
||||||
|
const tables: TableName[] = [
|
||||||
|
'parks', 'rides', 'companies', 'ride_models',
|
||||||
|
'content_submissions', 'submission_items',
|
||||||
|
'park_versions', 'ride_versions', 'company_versions', 'ride_model_versions',
|
||||||
|
'photos', 'reviews', 'test_data_registry'
|
||||||
|
];
|
||||||
|
|
||||||
|
const remaining: Array<{ table: string; count: number }> = [];
|
||||||
|
|
||||||
|
for (const table of tables) {
|
||||||
|
try {
|
||||||
|
const { count, error } = await supabase
|
||||||
|
.from(table as any)
|
||||||
|
.select('*', { count: 'exact', head: true })
|
||||||
|
.eq('is_test_data', true);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.warn(`Failed to check ${table}:`, error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count && count > 0) {
|
||||||
|
remaining.push({ table, count });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`Exception checking ${table}:`, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk delete all test data from the database (emergency cleanup)
|
||||||
|
* WARNING: This deletes ALL data marked with is_test_data=true
|
||||||
|
*/
|
||||||
|
static async bulkCleanupAllTestData(): Promise<{ deleted: number; errors: number }> {
|
||||||
|
const tables: TableName[] = [
|
||||||
|
'reviews', 'photos', 'submission_items', 'content_submissions',
|
||||||
|
'ride_versions', 'park_versions', 'company_versions', 'ride_model_versions',
|
||||||
|
'rides', 'parks', 'ride_models', 'companies', 'test_data_registry'
|
||||||
|
];
|
||||||
|
|
||||||
|
let totalDeleted = 0;
|
||||||
|
let totalErrors = 0;
|
||||||
|
|
||||||
|
for (const table of tables) {
|
||||||
|
try {
|
||||||
|
const { error, data } = await supabase
|
||||||
|
.from(table as any)
|
||||||
|
.delete()
|
||||||
|
.eq('is_test_data', true)
|
||||||
|
.select('id');
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.warn(`Failed to bulk delete from ${table}:`, error);
|
||||||
|
totalErrors++;
|
||||||
|
} else if (data) {
|
||||||
|
totalDeleted += data.length;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`Exception bulk deleting from ${table}:`, err);
|
||||||
|
totalErrors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { deleted: totalDeleted, errors: totalErrors };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get summary of tracked entities
|
||||||
|
*/
|
||||||
|
getSummary(): Record<string, number> {
|
||||||
|
const summary: Record<string, number> = {};
|
||||||
|
this.entities.forEach((ids, table) => {
|
||||||
|
summary[table] = ids.size;
|
||||||
|
});
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -127,7 +127,8 @@ export function generateRandomPark(counter: number): ParkSubmissionData {
|
|||||||
banner_image_url: null,
|
banner_image_url: null,
|
||||||
banner_image_id: null,
|
banner_image_id: null,
|
||||||
card_image_url: null,
|
card_image_url: null,
|
||||||
card_image_id: null
|
card_image_id: null,
|
||||||
|
is_test_data: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +167,8 @@ export function generateRandomRide(parkId: string, counter: number): RideSubmiss
|
|||||||
banner_image_id: null,
|
banner_image_id: null,
|
||||||
card_image_url: null,
|
card_image_url: null,
|
||||||
card_image_id: null,
|
card_image_id: null,
|
||||||
image_url: null
|
image_url: null,
|
||||||
|
is_test_data: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +189,8 @@ export function generateRandomCompany(type: 'manufacturer' | 'operator' | 'desig
|
|||||||
banner_image_url: null,
|
banner_image_url: null,
|
||||||
banner_image_id: null,
|
banner_image_id: null,
|
||||||
card_image_url: null,
|
card_image_url: null,
|
||||||
card_image_id: null
|
card_image_id: null,
|
||||||
|
is_test_data: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +209,8 @@ export function generateRandomRideModel(manufacturerId: string, counter: number)
|
|||||||
banner_image_url: null,
|
banner_image_url: null,
|
||||||
banner_image_id: null,
|
banner_image_id: null,
|
||||||
card_image_url: null,
|
card_image_url: null,
|
||||||
card_image_id: null
|
card_image_id: null,
|
||||||
|
is_test_data: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface ParkSubmissionData {
|
|||||||
card_image_id?: string | null;
|
card_image_id?: string | null;
|
||||||
source_url?: string;
|
source_url?: string;
|
||||||
submission_notes?: string;
|
submission_notes?: string;
|
||||||
|
is_test_data?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RideSubmissionData {
|
export interface RideSubmissionData {
|
||||||
@@ -100,6 +101,7 @@ export interface RideSubmissionData {
|
|||||||
image_url?: string | null;
|
image_url?: string | null;
|
||||||
source_url?: string;
|
source_url?: string;
|
||||||
submission_notes?: string;
|
submission_notes?: string;
|
||||||
|
is_test_data?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CompanySubmissionData {
|
export interface CompanySubmissionData {
|
||||||
@@ -120,6 +122,7 @@ export interface CompanySubmissionData {
|
|||||||
card_image_id?: string | null;
|
card_image_id?: string | null;
|
||||||
source_url?: string;
|
source_url?: string;
|
||||||
submission_notes?: string;
|
submission_notes?: string;
|
||||||
|
is_test_data?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RideModelSubmissionData {
|
export interface RideModelSubmissionData {
|
||||||
@@ -135,6 +138,7 @@ export interface RideModelSubmissionData {
|
|||||||
card_image_id?: string | null;
|
card_image_id?: string | null;
|
||||||
source_url?: string;
|
source_url?: string;
|
||||||
submission_notes?: string;
|
submission_notes?: string;
|
||||||
|
is_test_data?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TimelineEventItemData {
|
export interface TimelineEventItemData {
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
-- Add is_test_data flag to all entity tables for test data identification
|
||||||
|
-- This allows safe cleanup and filtering of test data from production queries
|
||||||
|
|
||||||
|
-- Add is_test_data column to parks
|
||||||
|
ALTER TABLE public.parks
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_parks_is_test_data ON public.parks(is_test_data) WHERE is_test_data = true;
|
||||||
|
|
||||||
|
-- Add is_test_data column to rides
|
||||||
|
ALTER TABLE public.rides
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_rides_is_test_data ON public.rides(is_test_data) WHERE is_test_data = true;
|
||||||
|
|
||||||
|
-- Add is_test_data column to companies
|
||||||
|
ALTER TABLE public.companies
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_companies_is_test_data ON public.companies(is_test_data) WHERE is_test_data = true;
|
||||||
|
|
||||||
|
-- Add is_test_data column to ride_models
|
||||||
|
ALTER TABLE public.ride_models
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ride_models_is_test_data ON public.ride_models(is_test_data) WHERE is_test_data = true;
|
||||||
|
|
||||||
|
-- Add is_test_data column to content_submissions
|
||||||
|
ALTER TABLE public.content_submissions
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_content_submissions_is_test_data ON public.content_submissions(is_test_data) WHERE is_test_data = true;
|
||||||
|
|
||||||
|
-- Add is_test_data column to submission_items
|
||||||
|
ALTER TABLE public.submission_items
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_submission_items_is_test_data ON public.submission_items(is_test_data) WHERE is_test_data = true;
|
||||||
|
|
||||||
|
-- Add is_test_data column to version tables
|
||||||
|
ALTER TABLE public.park_versions
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
ALTER TABLE public.ride_versions
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
ALTER TABLE public.company_versions
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
ALTER TABLE public.ride_model_versions
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
-- Add is_test_data column to photos
|
||||||
|
ALTER TABLE public.photos
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_photos_is_test_data ON public.photos(is_test_data) WHERE is_test_data = true;
|
||||||
|
|
||||||
|
-- Add is_test_data column to reviews
|
||||||
|
ALTER TABLE public.reviews
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT false;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_reviews_is_test_data ON public.reviews(is_test_data) WHERE is_test_data = true;
|
||||||
|
|
||||||
|
-- Add is_test_data column to test_data_registry
|
||||||
|
ALTER TABLE public.test_data_registry
|
||||||
|
ADD COLUMN IF NOT EXISTS is_test_data BOOLEAN DEFAULT true;
|
||||||
|
|
||||||
|
COMMENT ON COLUMN public.parks.is_test_data IS 'Flag to identify test data for safe cleanup and filtering';
|
||||||
|
COMMENT ON COLUMN public.rides.is_test_data IS 'Flag to identify test data for safe cleanup and filtering';
|
||||||
|
COMMENT ON COLUMN public.companies.is_test_data IS 'Flag to identify test data for safe cleanup and filtering';
|
||||||
|
COMMENT ON COLUMN public.ride_models.is_test_data IS 'Flag to identify test data for safe cleanup and filtering';
|
||||||
|
COMMENT ON COLUMN public.content_submissions.is_test_data IS 'Flag to identify test data for safe cleanup and filtering';
|
||||||
|
COMMENT ON COLUMN public.submission_items.is_test_data IS 'Flag to identify test data for safe cleanup and filtering';
|
||||||
Reference in New Issue
Block a user