90 lines
2.5 KiB
TypeScript
90 lines
2.5 KiB
TypeScript
import DataLoader from "dataloader";
|
|
import type { Product, Page } from "../types/index.js";
|
|
import type { User } from "../types/user.js";
|
|
import { dataService } from "../dataService.js";
|
|
import { userService } from "../auth/userService.js";
|
|
|
|
/**
|
|
* Dataloader für Batch-Loading von Produkten
|
|
* Verhindert N+1 Queries, wenn mehrere Produkte in einer Query abgefragt werden
|
|
*/
|
|
export const createProductLoader = () => {
|
|
return new DataLoader<string, Product | null>(
|
|
async (ids: readonly string[]) => {
|
|
// Batch-Loading: Lade alle Produkte in einem Batch
|
|
const products = await Promise.all(
|
|
ids.map((id) => dataService.getProduct(id))
|
|
);
|
|
|
|
// Stelle sicher, dass die Reihenfolge mit den IDs übereinstimmt
|
|
return products;
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Dataloader für Batch-Loading von Seiten
|
|
* Unterstützt Locale im Key-Format: "slug:locale" oder "slug"
|
|
*/
|
|
export const createPageLoader = () => {
|
|
return new DataLoader<string, Page | null>(
|
|
async (keys: readonly string[]) => {
|
|
const pages = await Promise.all(
|
|
keys.map((key) => {
|
|
// Parse Key: Format kann "slug:locale" oder "slug" sein
|
|
const parts = key.split(":");
|
|
const slug = parts[0] ?? "";
|
|
const locale = parts.length > 1 ? parts[1] : undefined;
|
|
return dataService.getPage(slug, locale);
|
|
})
|
|
);
|
|
return pages;
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Dataloader für Batch-Loading von Usern
|
|
*/
|
|
export const createUserLoader = () => {
|
|
return new DataLoader<string, User | null>(
|
|
async (userIds: readonly string[]) => {
|
|
const users = await Promise.all(
|
|
userIds.map((id) => userService.getUserById(id))
|
|
);
|
|
return users;
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Context für GraphQL Resolver
|
|
* Enthält Dataloader-Instanzen und User-Informationen
|
|
*
|
|
* Der Context wird für jeden GraphQL Request erstellt und enthält:
|
|
* - `user`: Aktueller authentifizierter User (oder null)
|
|
* - `loaders`: Dataloader-Instanzen für Batch-Loading (verhindert N+1 Queries)
|
|
*/
|
|
export interface GraphQLContext {
|
|
user: User | null;
|
|
loaders: {
|
|
product: DataLoader<string, Product | null>;
|
|
page: DataLoader<string, Page | null>;
|
|
user: DataLoader<string, User | null>;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Erstellt einen neuen Context mit Dataloadern und User
|
|
*/
|
|
export const createContext = (user: User | null = null): GraphQLContext => {
|
|
return {
|
|
user,
|
|
loaders: {
|
|
product: createProductLoader(),
|
|
page: createPageLoader(),
|
|
user: createUserLoader(),
|
|
},
|
|
};
|
|
};
|