Files
gridpilot.gg/apps/website/lib/routing/search-params/SearchParamBuilder.ts
2026-01-16 01:00:03 +01:00

206 lines
5.3 KiB
TypeScript

/**
* @file SearchParamBuilder.ts
* Type-safe builder for constructing search parameter strings
* Pure function, no side effects
*/
import { SearchParamValidators } from './SearchParamValidators';
export class SearchParamBuilder {
private params: URLSearchParams;
constructor() {
this.params = new URLSearchParams();
}
// Auth params
returnTo(value: string | null): this {
if (value !== null) {
const validation = SearchParamValidators.validateReturnTo(value);
if (!validation.isValid) {
throw new Error(`Invalid returnTo: ${validation.errors.join(', ')}`);
}
this.params.set('returnTo', value);
}
return this;
}
token(value: string | null): this {
if (value !== null) {
const validation = SearchParamValidators.validateToken(value);
if (!validation.isValid) {
throw new Error(`Invalid token: ${validation.errors.join(', ')}`);
}
this.params.set('token', value);
}
return this;
}
email(value: string | null): this {
if (value !== null) {
const validation = SearchParamValidators.validateEmail(value);
if (!validation.isValid) {
throw new Error(`Invalid email: ${validation.errors.join(', ')}`);
}
this.params.set('email', value);
}
return this;
}
error(value: string | null): this {
if (value !== null) {
this.params.set('error', value);
}
return this;
}
message(value: string | null): this {
if (value !== null) {
this.params.set('message', value);
}
return this;
}
// Sponsor params
campaignType(value: string | null): this {
if (value !== null) {
const validation = SearchParamValidators.validateCampaignType(value);
if (!validation.isValid) {
throw new Error(`Invalid campaign type: ${validation.errors.join(', ')}`);
}
this.params.set('type', value);
}
return this;
}
campaignId(value: string | null): this {
if (value !== null) {
this.params.set('campaignId', value);
}
return this;
}
// Pagination params
page(value: number | null): this {
if (value !== null) {
const validation = SearchParamValidators.validatePage(value.toString());
if (!validation.isValid) {
throw new Error(`Invalid page: ${validation.errors.join(', ')}`);
}
this.params.set('page', value.toString());
}
return this;
}
limit(value: number | null): this {
if (value !== null) {
const validation = SearchParamValidators.validateLimit(value.toString());
if (!validation.isValid) {
throw new Error(`Invalid limit: ${validation.errors.join(', ')}`);
}
this.params.set('limit', value.toString());
}
return this;
}
offset(value: number | null): this {
if (value !== null) {
this.params.set('offset', value.toString());
}
return this;
}
// Sorting params
sortBy(value: string | null): this {
if (value !== null) {
this.params.set('sortBy', value);
}
return this;
}
order(value: string | null): this {
if (value !== null) {
const validation = SearchParamValidators.validateOrder(value);
if (!validation.isValid) {
throw new Error(`Invalid order: ${validation.errors.join(', ')}`);
}
this.params.set('order', value);
}
return this;
}
// Filtering params
status(value: string | null): this {
if (value !== null) {
this.params.set('status', value);
}
return this;
}
role(value: string | null): this {
if (value !== null) {
this.params.set('role', value);
}
return this;
}
tier(value: string | null): this {
if (value !== null) {
this.params.set('tier', value);
}
return this;
}
// Wizard params
step(value: string | null): this {
if (value !== null) {
this.params.set('step', value);
}
return this;
}
// Generic setter
set(key: string, value: string | null): this {
if (value !== null) {
this.params.set(key, value);
}
return this;
}
// Build the query string
build(): string {
const queryString = this.params.toString();
return queryString ? `?${queryString}` : '';
}
// Static factory methods for common scenarios
static auth(returnTo?: string | null, token?: string | null, email?: string | null): string {
const builder = new SearchParamBuilder();
if (returnTo !== undefined) builder.returnTo(returnTo);
if (token !== undefined) builder.token(token);
if (email !== undefined) builder.email(email);
return builder.build();
}
static pagination(page?: number | null, limit?: number | null): string {
const builder = new SearchParamBuilder();
if (page !== undefined) builder.page(page);
if (limit !== undefined) builder.limit(limit);
return builder.build();
}
static sorting(sortBy?: string | null, order?: string | null): string {
const builder = new SearchParamBuilder();
if (sortBy !== undefined) builder.sortBy(sortBy);
if (order !== undefined) builder.order(order);
return builder.build();
}
static sponsorCampaign(type?: string | null, campaignId?: string | null): string {
const builder = new SearchParamBuilder();
if (type !== undefined) builder.campaignType(type);
if (campaignId !== undefined) builder.campaignId(campaignId);
return builder.build();
}
}