mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 06:11:11 -05:00
Fix submission_items foreign keys
This commit is contained in:
@@ -90,9 +90,9 @@ export const EntityEditPreview = ({ submissionId, entityType, entityName }: Enti
|
|||||||
.from('submission_items')
|
.from('submission_items')
|
||||||
.select(`
|
.select(`
|
||||||
*,
|
*,
|
||||||
park_submission:park_submissions!item_data_id(*),
|
park_submission:park_submissions!park_submission_id(*),
|
||||||
ride_submission:ride_submissions!item_data_id(*),
|
ride_submission:ride_submissions!ride_submission_id(*),
|
||||||
photo_submission:photo_submissions!item_data_id(
|
photo_submission:photo_submissions!photo_submission_id(
|
||||||
*,
|
*,
|
||||||
photo_items:photo_submission_items(*)
|
photo_items:photo_submission_items(*)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -59,10 +59,39 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
|||||||
|
|
||||||
if (itemsError) throw itemsError;
|
if (itemsError) throw itemsError;
|
||||||
|
|
||||||
// Fetch entity data for each item based on item_type
|
// Fetch entity data for each item based on item_type and typed FK columns
|
||||||
const transformedItems = await Promise.all(
|
const transformedItems = await Promise.all(
|
||||||
(itemsData || []).map(async (item) => {
|
(itemsData || []).map(async (item) => {
|
||||||
if (!item.item_data_id) {
|
// Determine which FK column to use based on item_type
|
||||||
|
let itemDataId: string | null = null;
|
||||||
|
switch (item.item_type) {
|
||||||
|
case 'park':
|
||||||
|
itemDataId = item.park_submission_id;
|
||||||
|
break;
|
||||||
|
case 'ride':
|
||||||
|
itemDataId = item.ride_submission_id;
|
||||||
|
break;
|
||||||
|
case 'photo':
|
||||||
|
case 'photo_edit':
|
||||||
|
case 'photo_delete':
|
||||||
|
itemDataId = item.photo_submission_id;
|
||||||
|
break;
|
||||||
|
case 'manufacturer':
|
||||||
|
case 'operator':
|
||||||
|
case 'designer':
|
||||||
|
case 'property_owner':
|
||||||
|
itemDataId = item.company_submission_id;
|
||||||
|
break;
|
||||||
|
case 'ride_model':
|
||||||
|
itemDataId = item.ride_model_submission_id;
|
||||||
|
break;
|
||||||
|
case 'milestone':
|
||||||
|
case 'timeline_event':
|
||||||
|
itemDataId = item.timeline_event_submission_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!itemDataId) {
|
||||||
return { ...item, item_data: {}, entity_data: null };
|
return { ...item, item_data: {}, entity_data: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +104,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
|||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
.from('park_submissions')
|
.from('park_submissions')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('id', item.item_data_id)
|
.eq('id', itemDataId)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
entityData = data as any;
|
entityData = data as any;
|
||||||
break;
|
break;
|
||||||
@@ -84,7 +113,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
|||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
.from('ride_submissions')
|
.from('ride_submissions')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('id', item.item_data_id)
|
.eq('id', itemDataId)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
entityData = data as any;
|
entityData = data as any;
|
||||||
break;
|
break;
|
||||||
@@ -96,7 +125,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
|||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
.from('company_submissions')
|
.from('company_submissions')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('id', item.item_data_id)
|
.eq('id', itemDataId)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
entityData = data as any;
|
entityData = data as any;
|
||||||
break;
|
break;
|
||||||
@@ -105,7 +134,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
|||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
.from('photo_submissions')
|
.from('photo_submissions')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('id', item.item_data_id)
|
.eq('id', itemDataId)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
entityData = data as any;
|
entityData = data as any;
|
||||||
break;
|
break;
|
||||||
@@ -114,7 +143,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
|||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
.from('ride_model_submissions')
|
.from('ride_model_submissions')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('id', item.item_data_id)
|
.eq('id', itemDataId)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
entityData = data as any;
|
entityData = data as any;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
|||||||
.select(`
|
.select(`
|
||||||
id,
|
id,
|
||||||
item_type,
|
item_type,
|
||||||
park_submission:park_submissions!item_data_id(*),
|
park_submission:park_submissions!park_submission_id(*),
|
||||||
ride_submission:ride_submissions!item_data_id(*)
|
ride_submission:ride_submissions!ride_submission_id(*)
|
||||||
`)
|
`)
|
||||||
.eq('submission_id', item.id)
|
.eq('submission_id', item.id)
|
||||||
.in('status', ['pending', 'rejected']);
|
.in('status', ['pending', 'rejected']);
|
||||||
|
|||||||
@@ -765,6 +765,27 @@ export type Database = {
|
|||||||
referencedRelation: "filtered_profiles"
|
referencedRelation: "filtered_profiles"
|
||||||
referencedColumns: ["id"]
|
referencedColumns: ["id"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "contact_submissions_submitter_profile_id_fkey"
|
||||||
|
columns: ["submitter_profile_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "moderation_queue_with_entities"
|
||||||
|
referencedColumns: ["assignee_profile_id"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "contact_submissions_submitter_profile_id_fkey"
|
||||||
|
columns: ["submitter_profile_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "moderation_queue_with_entities"
|
||||||
|
referencedColumns: ["reviewer_profile_id"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "contact_submissions_submitter_profile_id_fkey"
|
||||||
|
columns: ["submitter_profile_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "moderation_queue_with_entities"
|
||||||
|
referencedColumns: ["submitter_profile_id"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
foreignKeyName: "contact_submissions_submitter_profile_id_fkey"
|
foreignKeyName: "contact_submissions_submitter_profile_id_fkey"
|
||||||
columns: ["submitter_profile_id"]
|
columns: ["submitter_profile_id"]
|
||||||
@@ -4660,49 +4681,71 @@ export type Database = {
|
|||||||
Row: {
|
Row: {
|
||||||
action_type: string | null
|
action_type: string | null
|
||||||
approved_entity_id: string | null
|
approved_entity_id: string | null
|
||||||
|
company_submission_id: string | null
|
||||||
created_at: string
|
created_at: string
|
||||||
depends_on: string | null
|
depends_on: string | null
|
||||||
id: string
|
id: string
|
||||||
is_test_data: boolean | null
|
is_test_data: boolean | null
|
||||||
item_data_id: string | null
|
|
||||||
item_type: string
|
item_type: string
|
||||||
order_index: number | null
|
order_index: number | null
|
||||||
|
park_submission_id: string | null
|
||||||
|
photo_submission_id: string | null
|
||||||
rejection_reason: string | null
|
rejection_reason: string | null
|
||||||
|
ride_model_submission_id: string | null
|
||||||
|
ride_submission_id: string | null
|
||||||
status: string
|
status: string
|
||||||
submission_id: string
|
submission_id: string
|
||||||
|
timeline_event_submission_id: string | null
|
||||||
updated_at: string
|
updated_at: string
|
||||||
}
|
}
|
||||||
Insert: {
|
Insert: {
|
||||||
action_type?: string | null
|
action_type?: string | null
|
||||||
approved_entity_id?: string | null
|
approved_entity_id?: string | null
|
||||||
|
company_submission_id?: string | null
|
||||||
created_at?: string
|
created_at?: string
|
||||||
depends_on?: string | null
|
depends_on?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
is_test_data?: boolean | null
|
is_test_data?: boolean | null
|
||||||
item_data_id?: string | null
|
|
||||||
item_type: string
|
item_type: string
|
||||||
order_index?: number | null
|
order_index?: number | null
|
||||||
|
park_submission_id?: string | null
|
||||||
|
photo_submission_id?: string | null
|
||||||
rejection_reason?: string | null
|
rejection_reason?: string | null
|
||||||
|
ride_model_submission_id?: string | null
|
||||||
|
ride_submission_id?: string | null
|
||||||
status?: string
|
status?: string
|
||||||
submission_id: string
|
submission_id: string
|
||||||
|
timeline_event_submission_id?: string | null
|
||||||
updated_at?: string
|
updated_at?: string
|
||||||
}
|
}
|
||||||
Update: {
|
Update: {
|
||||||
action_type?: string | null
|
action_type?: string | null
|
||||||
approved_entity_id?: string | null
|
approved_entity_id?: string | null
|
||||||
|
company_submission_id?: string | null
|
||||||
created_at?: string
|
created_at?: string
|
||||||
depends_on?: string | null
|
depends_on?: string | null
|
||||||
id?: string
|
id?: string
|
||||||
is_test_data?: boolean | null
|
is_test_data?: boolean | null
|
||||||
item_data_id?: string | null
|
|
||||||
item_type?: string
|
item_type?: string
|
||||||
order_index?: number | null
|
order_index?: number | null
|
||||||
|
park_submission_id?: string | null
|
||||||
|
photo_submission_id?: string | null
|
||||||
rejection_reason?: string | null
|
rejection_reason?: string | null
|
||||||
|
ride_model_submission_id?: string | null
|
||||||
|
ride_submission_id?: string | null
|
||||||
status?: string
|
status?: string
|
||||||
submission_id?: string
|
submission_id?: string
|
||||||
|
timeline_event_submission_id?: string | null
|
||||||
updated_at?: string
|
updated_at?: string
|
||||||
}
|
}
|
||||||
Relationships: [
|
Relationships: [
|
||||||
|
{
|
||||||
|
foreignKeyName: "submission_items_company_submission_id_fkey"
|
||||||
|
columns: ["company_submission_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "company_submissions"
|
||||||
|
referencedColumns: ["id"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
foreignKeyName: "submission_items_depends_on_fkey"
|
foreignKeyName: "submission_items_depends_on_fkey"
|
||||||
columns: ["depends_on"]
|
columns: ["depends_on"]
|
||||||
@@ -4710,6 +4753,34 @@ export type Database = {
|
|||||||
referencedRelation: "submission_items"
|
referencedRelation: "submission_items"
|
||||||
referencedColumns: ["id"]
|
referencedColumns: ["id"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "submission_items_park_submission_id_fkey"
|
||||||
|
columns: ["park_submission_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "park_submissions"
|
||||||
|
referencedColumns: ["id"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "submission_items_photo_submission_id_fkey"
|
||||||
|
columns: ["photo_submission_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "photo_submissions"
|
||||||
|
referencedColumns: ["id"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "submission_items_ride_model_submission_id_fkey"
|
||||||
|
columns: ["ride_model_submission_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "ride_model_submissions"
|
||||||
|
referencedColumns: ["id"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "submission_items_ride_submission_id_fkey"
|
||||||
|
columns: ["ride_submission_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "ride_submissions"
|
||||||
|
referencedColumns: ["id"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
foreignKeyName: "submission_items_submission_id_fkey"
|
foreignKeyName: "submission_items_submission_id_fkey"
|
||||||
columns: ["submission_id"]
|
columns: ["submission_id"]
|
||||||
@@ -4724,6 +4795,13 @@ export type Database = {
|
|||||||
referencedRelation: "moderation_queue_with_entities"
|
referencedRelation: "moderation_queue_with_entities"
|
||||||
referencedColumns: ["id"]
|
referencedColumns: ["id"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "submission_items_timeline_event_submission_id_fkey"
|
||||||
|
columns: ["timeline_event_submission_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "timeline_event_submissions"
|
||||||
|
referencedColumns: ["id"]
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
submission_metadata: {
|
submission_metadata: {
|
||||||
@@ -5264,26 +5342,43 @@ export type Database = {
|
|||||||
}
|
}
|
||||||
moderation_queue_with_entities: {
|
moderation_queue_with_entities: {
|
||||||
Row: {
|
Row: {
|
||||||
|
approval_mode: string | null
|
||||||
assigned_at: string | null
|
assigned_at: string | null
|
||||||
assigned_profile: Json | null
|
|
||||||
assigned_to: string | null
|
assigned_to: string | null
|
||||||
|
assignee_avatar_url: string | null
|
||||||
|
assignee_display_name: string | null
|
||||||
|
assignee_profile_id: string | null
|
||||||
|
assignee_username: string | null
|
||||||
created_at: string | null
|
created_at: string | null
|
||||||
escalated: boolean | null
|
escalated: boolean | null
|
||||||
escalated_at: string | null
|
escalated_at: string | null
|
||||||
|
escalated_by: string | null
|
||||||
escalation_reason: string | null
|
escalation_reason: string | null
|
||||||
|
first_reviewed_at: string | null
|
||||||
id: string | null
|
id: string | null
|
||||||
is_test_data: boolean | null
|
is_test_data: boolean | null
|
||||||
|
last_modified_at: string | null
|
||||||
|
last_modified_by: string | null
|
||||||
locked_until: string | null
|
locked_until: string | null
|
||||||
|
resolved_at: string | null
|
||||||
|
review_count: number | null
|
||||||
|
review_notes: string | null
|
||||||
reviewed_at: string | null
|
reviewed_at: string | null
|
||||||
reviewed_by: string | null
|
reviewed_by: string | null
|
||||||
reviewer_notes: string | null
|
reviewer_avatar_url: string | null
|
||||||
reviewer_profile: Json | null
|
reviewer_display_name: string | null
|
||||||
|
reviewer_profile_id: string | null
|
||||||
|
reviewer_username: string | null
|
||||||
status: string | null
|
status: string | null
|
||||||
submission_items: Json | null
|
submission_items: Json | null
|
||||||
submission_type: string | null
|
submission_type: string | null
|
||||||
submitted_at: string | null
|
submitted_at: string | null
|
||||||
submitter_id: string | null
|
submitted_by: string | null
|
||||||
submitter_profile: Json | null
|
submitter_avatar_url: string | null
|
||||||
|
submitter_display_name: string | null
|
||||||
|
submitter_profile_id: string | null
|
||||||
|
submitter_reputation: number | null
|
||||||
|
submitter_username: string | null
|
||||||
}
|
}
|
||||||
Relationships: [
|
Relationships: [
|
||||||
{
|
{
|
||||||
@@ -5300,6 +5395,20 @@ export type Database = {
|
|||||||
referencedRelation: "profiles"
|
referencedRelation: "profiles"
|
||||||
referencedColumns: ["user_id"]
|
referencedColumns: ["user_id"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "content_submissions_escalated_by_fkey"
|
||||||
|
columns: ["escalated_by"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "filtered_profiles"
|
||||||
|
referencedColumns: ["user_id"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
foreignKeyName: "content_submissions_escalated_by_fkey"
|
||||||
|
columns: ["escalated_by"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "profiles"
|
||||||
|
referencedColumns: ["user_id"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
foreignKeyName: "content_submissions_reviewer_id_fkey"
|
foreignKeyName: "content_submissions_reviewer_id_fkey"
|
||||||
columns: ["reviewed_by"]
|
columns: ["reviewed_by"]
|
||||||
@@ -5316,14 +5425,14 @@ export type Database = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
foreignKeyName: "content_submissions_user_id_fkey"
|
foreignKeyName: "content_submissions_user_id_fkey"
|
||||||
columns: ["submitter_id"]
|
columns: ["submitted_by"]
|
||||||
isOneToOne: false
|
isOneToOne: false
|
||||||
referencedRelation: "filtered_profiles"
|
referencedRelation: "filtered_profiles"
|
||||||
referencedColumns: ["user_id"]
|
referencedColumns: ["user_id"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
foreignKeyName: "content_submissions_user_id_fkey"
|
foreignKeyName: "content_submissions_user_id_fkey"
|
||||||
columns: ["submitter_id"]
|
columns: ["submitted_by"]
|
||||||
isOneToOne: false
|
isOneToOne: false
|
||||||
referencedRelation: "profiles"
|
referencedRelation: "profiles"
|
||||||
referencedColumns: ["user_id"]
|
referencedColumns: ["user_id"]
|
||||||
|
|||||||
@@ -503,7 +503,7 @@ export async function submitParkCreation(
|
|||||||
submission_id: submissionData.id,
|
submission_id: submissionData.id,
|
||||||
item_type: 'park',
|
item_type: 'park',
|
||||||
action_type: 'create',
|
action_type: 'create',
|
||||||
item_data_id: (parkSubmission as any).id,
|
park_submission_id: (parkSubmission as any).id,
|
||||||
status: 'pending' as const,
|
status: 'pending' as const,
|
||||||
order_index: 0
|
order_index: 0
|
||||||
} as any);
|
} as any);
|
||||||
@@ -827,7 +827,7 @@ export async function submitRideCreation(
|
|||||||
submission_id: submissionData.id,
|
submission_id: submissionData.id,
|
||||||
item_type: 'ride',
|
item_type: 'ride',
|
||||||
action_type: 'create',
|
action_type: 'create',
|
||||||
item_data_id: (rideSubmission as any).id,
|
ride_submission_id: (rideSubmission as any).id,
|
||||||
status: 'pending' as const,
|
status: 'pending' as const,
|
||||||
order_index: 0
|
order_index: 0
|
||||||
} as any);
|
} as any);
|
||||||
|
|||||||
@@ -29,7 +29,13 @@ const SubmissionItemSchema = z.object({
|
|||||||
status: z.string(),
|
status: z.string(),
|
||||||
item_type: z.string().optional(),
|
item_type: z.string().optional(),
|
||||||
item_data: z.record(z.string(), z.any()).optional().nullable(),
|
item_data: z.record(z.string(), z.any()).optional().nullable(),
|
||||||
item_data_id: z.string().uuid().optional().nullable(),
|
// Typed FK columns (optional, only one will be populated)
|
||||||
|
park_submission_id: z.string().uuid().optional().nullable(),
|
||||||
|
ride_submission_id: z.string().uuid().optional().nullable(),
|
||||||
|
photo_submission_id: z.string().uuid().optional().nullable(),
|
||||||
|
company_submission_id: z.string().uuid().optional().nullable(),
|
||||||
|
ride_model_submission_id: z.string().uuid().optional().nullable(),
|
||||||
|
timeline_event_submission_id: z.string().uuid().optional().nullable(),
|
||||||
action_type: z.enum(['create', 'edit', 'delete']).optional(),
|
action_type: z.enum(['create', 'edit', 'delete']).optional(),
|
||||||
original_data: z.record(z.string(), z.any()).optional().nullable(),
|
original_data: z.record(z.string(), z.any()).optional().nullable(),
|
||||||
error_message: z.string().optional().nullable(),
|
error_message: z.string().optional().nullable(),
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ export async function fetchSubmissionItems(submissionId: string): Promise<Submis
|
|||||||
.from('submission_items')
|
.from('submission_items')
|
||||||
.select(`
|
.select(`
|
||||||
*,
|
*,
|
||||||
park_submission:park_submissions!item_data_id(*),
|
park_submission:park_submissions!park_submission_id(*),
|
||||||
ride_submission:ride_submissions!item_data_id(*),
|
ride_submission:ride_submissions!ride_submission_id(*),
|
||||||
photo_submission:photo_submissions!item_data_id(
|
photo_submission:photo_submissions!photo_submission_id(
|
||||||
*,
|
*,
|
||||||
photo_items:photo_submission_items(*)
|
photo_items:photo_submission_items(*)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ export async function fetchSystemActivities(
|
|||||||
.select(`
|
.select(`
|
||||||
submission_id,
|
submission_id,
|
||||||
item_type,
|
item_type,
|
||||||
photo_submission:photo_submissions!item_data_id(
|
photo_submission:photo_submissions!photo_submission_id(
|
||||||
*,
|
*,
|
||||||
photo_items:photo_submission_items(*)
|
photo_items:photo_submission_items(*)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ export type SubmissionItemData =
|
|||||||
export interface SubmissionItem {
|
export interface SubmissionItem {
|
||||||
id: string;
|
id: string;
|
||||||
item_type: string;
|
item_type: string;
|
||||||
item_data_id: string | null;
|
|
||||||
action_type: 'create' | 'edit' | 'delete';
|
action_type: 'create' | 'edit' | 'delete';
|
||||||
status: string;
|
status: string;
|
||||||
order_index: number;
|
order_index: number;
|
||||||
@@ -132,6 +131,14 @@ export interface SubmissionItem {
|
|||||||
approved_entity_id: string | null;
|
approved_entity_id: string | null;
|
||||||
rejection_reason: string | null;
|
rejection_reason: string | null;
|
||||||
|
|
||||||
|
// Typed foreign key columns (one will be populated based on item_type)
|
||||||
|
park_submission_id?: string | null;
|
||||||
|
ride_submission_id?: string | null;
|
||||||
|
photo_submission_id?: string | null;
|
||||||
|
company_submission_id?: string | null;
|
||||||
|
ride_model_submission_id?: string | null;
|
||||||
|
timeline_event_submission_id?: string | null;
|
||||||
|
|
||||||
// Entity data from dynamic join (pre-loaded from view)
|
// Entity data from dynamic join (pre-loaded from view)
|
||||||
entity_data?: {
|
entity_data?: {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
-- Add typed foreign key columns to submission_items for proper relational integrity
|
||||||
|
-- This replaces the generic item_data_id with specific FK columns
|
||||||
|
|
||||||
|
-- Step 0: Drop dependent view
|
||||||
|
DROP VIEW IF EXISTS moderation_queue_with_entities CASCADE;
|
||||||
|
|
||||||
|
-- Step 1: Add typed foreign key columns
|
||||||
|
ALTER TABLE public.submission_items
|
||||||
|
ADD COLUMN park_submission_id UUID REFERENCES public.park_submissions(id) ON DELETE CASCADE,
|
||||||
|
ADD COLUMN ride_submission_id UUID REFERENCES public.ride_submissions(id) ON DELETE CASCADE,
|
||||||
|
ADD COLUMN photo_submission_id UUID REFERENCES public.photo_submissions(id) ON DELETE CASCADE,
|
||||||
|
ADD COLUMN company_submission_id UUID REFERENCES public.company_submissions(id) ON DELETE CASCADE,
|
||||||
|
ADD COLUMN ride_model_submission_id UUID REFERENCES public.ride_model_submissions(id) ON DELETE CASCADE,
|
||||||
|
ADD COLUMN timeline_event_submission_id UUID REFERENCES public.timeline_event_submissions(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- Step 2: Migrate existing data from item_data_id to typed columns based on item_type
|
||||||
|
UPDATE public.submission_items
|
||||||
|
SET park_submission_id = item_data_id
|
||||||
|
WHERE item_type = 'park' AND item_data_id IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE public.submission_items
|
||||||
|
SET ride_submission_id = item_data_id
|
||||||
|
WHERE item_type = 'ride' AND item_data_id IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE public.submission_items
|
||||||
|
SET photo_submission_id = item_data_id
|
||||||
|
WHERE item_type = 'photo' AND item_data_id IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE public.submission_items
|
||||||
|
SET company_submission_id = item_data_id
|
||||||
|
WHERE item_type IN ('manufacturer', 'operator', 'designer', 'property_owner') AND item_data_id IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE public.submission_items
|
||||||
|
SET ride_model_submission_id = item_data_id
|
||||||
|
WHERE item_type = 'ride_model' AND item_data_id IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE public.submission_items
|
||||||
|
SET timeline_event_submission_id = item_data_id
|
||||||
|
WHERE item_type IN ('milestone', 'timeline_event') AND item_data_id IS NOT NULL;
|
||||||
|
|
||||||
|
-- Step 3: Add check constraint to ensure only one FK is populated per row
|
||||||
|
ALTER TABLE public.submission_items
|
||||||
|
ADD CONSTRAINT submission_items_single_fk_check
|
||||||
|
CHECK (
|
||||||
|
(CASE WHEN park_submission_id IS NOT NULL THEN 1 ELSE 0 END +
|
||||||
|
CASE WHEN ride_submission_id IS NOT NULL THEN 1 ELSE 0 END +
|
||||||
|
CASE WHEN photo_submission_id IS NOT NULL THEN 1 ELSE 0 END +
|
||||||
|
CASE WHEN company_submission_id IS NOT NULL THEN 1 ELSE 0 END +
|
||||||
|
CASE WHEN ride_model_submission_id IS NOT NULL THEN 1 ELSE 0 END +
|
||||||
|
CASE WHEN timeline_event_submission_id IS NOT NULL THEN 1 ELSE 0 END) <= 1
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Step 4: Drop the old generic item_data_id column
|
||||||
|
ALTER TABLE public.submission_items DROP COLUMN item_data_id;
|
||||||
|
|
||||||
|
-- Step 5: Recreate moderation_queue_with_entities view
|
||||||
|
CREATE VIEW moderation_queue_with_entities AS
|
||||||
|
SELECT
|
||||||
|
cs.id,
|
||||||
|
cs.submission_type,
|
||||||
|
cs.status,
|
||||||
|
|
||||||
|
-- Temporal fields (with backward compatibility alias)
|
||||||
|
cs.submitted_at AS created_at,
|
||||||
|
cs.submitted_at,
|
||||||
|
cs.reviewed_at,
|
||||||
|
cs.resolved_at,
|
||||||
|
cs.assigned_at,
|
||||||
|
cs.escalated_at,
|
||||||
|
cs.last_modified_at,
|
||||||
|
cs.first_reviewed_at,
|
||||||
|
|
||||||
|
-- User IDs
|
||||||
|
cs.user_id AS submitted_by,
|
||||||
|
cs.reviewer_id AS reviewed_by,
|
||||||
|
cs.assigned_to,
|
||||||
|
cs.escalated_by,
|
||||||
|
cs.last_modified_by,
|
||||||
|
|
||||||
|
-- State flags
|
||||||
|
cs.escalated,
|
||||||
|
cs.escalation_reason,
|
||||||
|
cs.reviewer_notes AS review_notes,
|
||||||
|
cs.approval_mode,
|
||||||
|
cs.review_count,
|
||||||
|
cs.locked_until,
|
||||||
|
cs.is_test_data,
|
||||||
|
|
||||||
|
-- Submitter profile (aliased for backward compatibility)
|
||||||
|
sp.id AS submitter_profile_id,
|
||||||
|
sp.username AS submitter_username,
|
||||||
|
sp.display_name AS submitter_display_name,
|
||||||
|
sp.avatar_url AS submitter_avatar_url,
|
||||||
|
sp.reputation_score AS submitter_reputation,
|
||||||
|
|
||||||
|
-- Reviewer profile
|
||||||
|
rp.id AS reviewer_profile_id,
|
||||||
|
rp.username AS reviewer_username,
|
||||||
|
rp.display_name AS reviewer_display_name,
|
||||||
|
rp.avatar_url AS reviewer_avatar_url,
|
||||||
|
|
||||||
|
-- Assignee profile
|
||||||
|
ap.id AS assignee_profile_id,
|
||||||
|
ap.username AS assignee_username,
|
||||||
|
ap.display_name AS assignee_display_name,
|
||||||
|
ap.avatar_url AS assignee_avatar_url,
|
||||||
|
|
||||||
|
-- Submission items (aggregated with new typed FK columns)
|
||||||
|
(
|
||||||
|
SELECT json_agg(si.*)
|
||||||
|
FROM submission_items si
|
||||||
|
WHERE si.submission_id = cs.id
|
||||||
|
) as submission_items
|
||||||
|
|
||||||
|
FROM content_submissions cs
|
||||||
|
LEFT JOIN profiles sp ON sp.user_id = cs.user_id
|
||||||
|
LEFT JOIN profiles rp ON rp.user_id = cs.reviewer_id
|
||||||
|
LEFT JOIN profiles ap ON ap.user_id = cs.assigned_to;
|
||||||
|
|
||||||
|
COMMENT ON VIEW moderation_queue_with_entities IS
|
||||||
|
'Optimized view for moderation queue with pre-joined profiles and entity data. Uses typed FK columns for submission_items.';
|
||||||
|
|
||||||
|
-- Add helpful comments
|
||||||
|
COMMENT ON COLUMN public.submission_items.park_submission_id IS 'Foreign key to park_submissions for park-type items';
|
||||||
|
COMMENT ON COLUMN public.submission_items.ride_submission_id IS 'Foreign key to ride_submissions for ride-type items';
|
||||||
|
COMMENT ON COLUMN public.submission_items.photo_submission_id IS 'Foreign key to photo_submissions for photo-type items';
|
||||||
|
COMMENT ON COLUMN public.submission_items.company_submission_id IS 'Foreign key to company_submissions for company-type items (manufacturer, operator, designer, property_owner)';
|
||||||
|
COMMENT ON COLUMN public.submission_items.ride_model_submission_id IS 'Foreign key to ride_model_submissions for ride_model-type items';
|
||||||
|
COMMENT ON COLUMN public.submission_items.timeline_event_submission_id IS 'Foreign key to timeline_event_submissions for timeline/milestone items';
|
||||||
|
COMMENT ON CONSTRAINT submission_items_single_fk_check ON public.submission_items IS 'Ensures only one typed foreign key is populated per row';
|
||||||
Reference in New Issue
Block a user