mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 07:51:13 -05:00
221 lines
6.4 KiB
TypeScript
221 lines
6.4 KiB
TypeScript
/**
|
|
* Modern versioning utilities for relational version tables
|
|
*
|
|
* These functions work with the new trigger-based versioning system.
|
|
* All version creation is automatic via database triggers - no manual calls needed.
|
|
*
|
|
* @see docs/versioning/ARCHITECTURE.md for system design
|
|
* @see docs/versioning/API.md for complete API reference
|
|
*/
|
|
|
|
import { supabase } from '@/lib/supabaseClient';
|
|
import type { EntityType } from '@/types/versioning';
|
|
import { createTableQuery } from './supabaseHelpers';
|
|
import { handleNonCriticalError } from './errorHandler';
|
|
|
|
/**
|
|
* Manually trigger cleanup of old versions for a specific entity type
|
|
*
|
|
* Note: This should normally run automatically via pg_cron, but can be called manually.
|
|
*
|
|
* @param entityType - The entity type to clean up ('park', 'ride', 'company', 'ride_model')
|
|
* @param keepCount - Number of most recent versions to keep per entity (default: 50)
|
|
* @returns Number of versions deleted
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const deleted = await cleanupVersions('park', 50);
|
|
* console.log(`Deleted ${deleted} old park versions`);
|
|
* ```
|
|
*/
|
|
export async function cleanupVersions(
|
|
entityType: EntityType,
|
|
keepCount: number = 50
|
|
): Promise<number> {
|
|
const { data, error } = await supabase.rpc('cleanup_old_versions', {
|
|
entity_type: entityType,
|
|
keep_versions: keepCount
|
|
});
|
|
|
|
if (error) {
|
|
handleNonCriticalError(error, {
|
|
action: 'Version cleanup',
|
|
metadata: { entityType, keepCount }
|
|
});
|
|
return 0;
|
|
}
|
|
|
|
return data as number;
|
|
}
|
|
|
|
/**
|
|
* Get statistics about versions for a specific entity
|
|
*
|
|
* @param entityType - The entity type ('park', 'ride', 'company', 'ride_model')
|
|
* @param entityId - The UUID of the entity
|
|
* @returns Version statistics including total count, date range, and change type distribution
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const stats = await getVersionStats('park', 'uuid-here');
|
|
* console.log(`Total versions: ${stats.totalVersions}`);
|
|
* console.log(`Change types:`, stats.changeTypes);
|
|
* ```
|
|
*/
|
|
export async function getVersionStats(
|
|
entityType: EntityType,
|
|
entityId: string
|
|
) {
|
|
const entityIdCol = `${entityType}_id`;
|
|
|
|
// Directly query the version table based on entity type
|
|
// Use simpler type inference to avoid TypeScript deep instantiation issues
|
|
let result;
|
|
|
|
if (entityType === 'park') {
|
|
result = await supabase
|
|
.from('park_versions')
|
|
.select('version_number, created_at, change_type', { count: 'exact' })
|
|
.eq('park_id', entityId)
|
|
.order('version_number', { ascending: true });
|
|
} else if (entityType === 'ride') {
|
|
result = await supabase
|
|
.from('ride_versions')
|
|
.select('version_number, created_at, change_type', { count: 'exact' })
|
|
.eq('ride_id', entityId)
|
|
.order('version_number', { ascending: true });
|
|
} else if (entityType === 'company') {
|
|
result = await supabase
|
|
.from('company_versions')
|
|
.select('version_number, created_at, change_type', { count: 'exact' })
|
|
.eq('company_id', entityId)
|
|
.order('version_number', { ascending: true });
|
|
} else {
|
|
result = await supabase
|
|
.from('ride_model_versions')
|
|
.select('version_number, created_at, change_type', { count: 'exact' })
|
|
.eq('ride_model_id', entityId)
|
|
.order('version_number', { ascending: true });
|
|
}
|
|
|
|
const { data, error } = result;
|
|
|
|
if (error || !data) {
|
|
handleNonCriticalError(error || new Error('No data returned'), {
|
|
action: 'Fetch version stats',
|
|
metadata: { entityType, entityId }
|
|
});
|
|
return null;
|
|
}
|
|
|
|
if (data.length === 0) {
|
|
return {
|
|
totalVersions: 0,
|
|
oldestVersion: null,
|
|
newestVersion: null,
|
|
changeTypes: {}
|
|
};
|
|
}
|
|
|
|
// Type-safe access to version data
|
|
const versions = data as unknown as Array<{
|
|
version_number: number;
|
|
created_at: string;
|
|
change_type: string;
|
|
}>;
|
|
|
|
return {
|
|
totalVersions: versions.length,
|
|
oldestVersion: versions[0]?.created_at || null,
|
|
newestVersion: versions[versions.length - 1]?.created_at || null,
|
|
changeTypes: versions.reduce((acc, v) => {
|
|
acc[v.change_type] = (acc[v.change_type] || 0) + 1;
|
|
return acc;
|
|
}, {} as Record<string, number>)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get total version counts across all entity types
|
|
*
|
|
* Useful for monitoring storage usage and cleanup effectiveness.
|
|
*
|
|
* @returns Total version counts for each entity type
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const counts = await getAllVersionCounts();
|
|
* console.log('Park versions:', counts.park);
|
|
* console.log('Ride versions:', counts.ride);
|
|
* ```
|
|
*/
|
|
export async function getAllVersionCounts() {
|
|
const counts = {
|
|
park: 0,
|
|
ride: 0,
|
|
company: 0,
|
|
ride_model: 0,
|
|
};
|
|
|
|
const parkCount = await supabase
|
|
.from('park_versions')
|
|
.select('*', { count: 'exact', head: true });
|
|
counts.park = parkCount.count || 0;
|
|
|
|
const rideCount = await supabase
|
|
.from('ride_versions')
|
|
.select('*', { count: 'exact', head: true });
|
|
counts.ride = rideCount.count || 0;
|
|
|
|
const companyCount = await supabase
|
|
.from('company_versions')
|
|
.select('*', { count: 'exact', head: true });
|
|
counts.company = companyCount.count || 0;
|
|
|
|
const modelCount = await supabase
|
|
.from('ride_model_versions')
|
|
.select('*', { count: 'exact', head: true });
|
|
counts.ride_model = modelCount.count || 0;
|
|
|
|
return counts;
|
|
}
|
|
|
|
/**
|
|
* Check if an entity has any versions
|
|
*
|
|
* @param entityType - The entity type
|
|
* @param entityId - The UUID of the entity
|
|
* @returns True if entity has at least one version
|
|
*/
|
|
export async function hasVersions(
|
|
entityType: EntityType,
|
|
entityId: string
|
|
): Promise<boolean> {
|
|
// Directly query the version table based on entity type with explicit column names
|
|
let result;
|
|
|
|
if (entityType === 'park') {
|
|
result = await supabase
|
|
.from('park_versions')
|
|
.select('*', { count: 'exact', head: true })
|
|
.eq('park_id', entityId);
|
|
} else if (entityType === 'ride') {
|
|
result = await supabase
|
|
.from('ride_versions')
|
|
.select('*', { count: 'exact', head: true })
|
|
.eq('ride_id', entityId);
|
|
} else if (entityType === 'company') {
|
|
result = await supabase
|
|
.from('company_versions')
|
|
.select('*', { count: 'exact', head: true })
|
|
.eq('company_id', entityId);
|
|
} else {
|
|
result = await supabase
|
|
.from('ride_model_versions')
|
|
.select('*', { count: 'exact', head: true })
|
|
.eq('ride_model_id', entityId);
|
|
}
|
|
|
|
return (result.count || 0) > 0;
|
|
}
|