Files
gridpilot.gg/apps/website/lib/page/PageDataFetcher.ts
2026-01-14 02:02:24 +01:00

64 lines
1.9 KiB
TypeScript

export interface FetchResult<T> {
data: T | null;
errors: Record<string, Error>;
hasErrors: boolean;
}
export class PageDataFetcher {
/**
* Fetch using manual service instantiation
* Use for: Multiple dependencies, request-scoped services, or auth context
* RECOMMENDED for SSR
*/
static async fetchManual<TData>(
serviceFactory: () => Promise<TData> | TData
): Promise<TData | null> {
try {
const result = await serviceFactory();
return result;
} catch (error) {
console.error('Failed to fetch manual:', error);
return null;
}
}
/**
* Fetch multiple datasets in parallel with error aggregation
* Use for: Pages needing multiple service calls
* UPDATED: Returns both data and errors for proper handling
*/
static async fetchMultiple<T extends Record<string, any>>(
queries: T
): Promise<FetchResult<{ [K in keyof T]: T[K] }>> {
const results = {} as { [K in keyof T]: T[K] };
const errors = {} as Record<string, Error>;
const entries = await Promise.all(
Object.entries(queries).map(async ([key, query]) => {
try {
const result = await query();
return [key, { success: true, data: result }] as const;
} catch (error) {
console.error(`Failed to fetch ${key}:`, error);
return [key, { success: false, error: error instanceof Error ? error : new Error(String(error)) }] as const;
}
})
);
entries.forEach(([key, result]) => {
if (typeof result === 'object' && result !== null && 'success' in result) {
if (result.success) {
results[key as keyof T] = (result as { data: T[keyof T] }).data;
} else {
errors[key] = (result as { error: Error }).error;
}
}
});
return {
data: results,
errors,
hasErrors: Object.keys(errors).length > 0
};
}
}