mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
240 lines
5.2 KiB
TypeScript
240 lines
5.2 KiB
TypeScript
/**
|
|
* Query Parameter Builder Utilities
|
|
* Provides type-safe query parameter construction and URL building
|
|
*/
|
|
|
|
import { z } from 'zod';
|
|
|
|
// Query parameter value types
|
|
type QueryValue = string | number | boolean | null | undefined;
|
|
|
|
// Query parameter schema for validation
|
|
export const QueryParamsSchema = z.record(
|
|
z.union([
|
|
z.string(),
|
|
z.number(),
|
|
z.boolean(),
|
|
z.null(),
|
|
z.undefined(),
|
|
])
|
|
).optional();
|
|
|
|
export type QueryParams = z.infer<typeof QueryParamsSchema>;
|
|
|
|
/**
|
|
* Builds URL query string from parameters
|
|
*/
|
|
export function buildQueryString(params: QueryParams): string {
|
|
if (!params || Object.keys(params).length === 0) {
|
|
return '';
|
|
}
|
|
|
|
const searchParams = new URLSearchParams();
|
|
|
|
for (const [key, value] of Object.entries(params)) {
|
|
if (value !== null && value !== undefined && value !== '') {
|
|
searchParams.append(key, String(value));
|
|
}
|
|
}
|
|
|
|
const queryString = searchParams.toString();
|
|
return queryString ? `?${queryString}` : '';
|
|
}
|
|
|
|
/**
|
|
* Builds a complete URL with query parameters
|
|
*/
|
|
export function buildUrl(basePath: string, params?: QueryParams): string {
|
|
const queryString = buildQueryString(params);
|
|
return `${basePath}${queryString}`;
|
|
}
|
|
|
|
/**
|
|
* Type-safe query parameter builder with fluent interface
|
|
*/
|
|
export class QueryBuilder {
|
|
private queryParams: Record<string, QueryValue> = {};
|
|
|
|
/**
|
|
* Add a query parameter
|
|
*/
|
|
param(key: string, value: QueryValue): this {
|
|
if (value !== null && value !== undefined && value !== '') {
|
|
this.queryParams[key] = value;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add multiple parameters at once
|
|
*/
|
|
params(params: QueryParams): this {
|
|
if (params) {
|
|
for (const [key, value] of Object.entries(params)) {
|
|
this.param(key, value);
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add parameters conditionally
|
|
*/
|
|
when(condition: boolean, callback: (builder: this) => this): this {
|
|
if (condition) {
|
|
return callback(this);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add parameter if value is truthy
|
|
*/
|
|
whenTruthy(key: string, value: QueryValue): this {
|
|
return this.when(!!value, builder => builder.param(key, value));
|
|
}
|
|
|
|
/**
|
|
* Add parameter if value is not null/undefined
|
|
*/
|
|
whenDefined(key: string, value: QueryValue): this {
|
|
return this.when(value != null, builder => builder.param(key, value));
|
|
}
|
|
|
|
/**
|
|
* Build query string
|
|
*/
|
|
toString(): string {
|
|
return buildQueryString(this.queryParams);
|
|
}
|
|
|
|
/**
|
|
* Build complete URL
|
|
*/
|
|
toUrl(basePath: string): string {
|
|
return buildUrl(basePath, this.queryParams);
|
|
}
|
|
|
|
/**
|
|
* Get raw parameters object
|
|
*/
|
|
toParams(): QueryParams {
|
|
return { ...this.queryParams };
|
|
}
|
|
|
|
/**
|
|
* Clear all parameters
|
|
*/
|
|
clear(): this {
|
|
this.queryParams = {};
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Create a new builder instance
|
|
*/
|
|
static create(): QueryBuilder {
|
|
return new QueryBuilder();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Common query parameter patterns
|
|
*/
|
|
export const QueryPatterns = {
|
|
/**
|
|
* Pagination parameters
|
|
*/
|
|
pagination: (page?: number, limit?: number) =>
|
|
QueryBuilder.create()
|
|
.whenDefined('page', page)
|
|
.whenDefined('limit', limit),
|
|
|
|
/**
|
|
* Sorting parameters
|
|
*/
|
|
sorting: (sortBy?: string, sortOrder?: 'asc' | 'desc') =>
|
|
QueryBuilder.create()
|
|
.whenDefined('sort', sortBy)
|
|
.whenDefined('order', sortOrder),
|
|
|
|
/**
|
|
* Filtering parameters
|
|
*/
|
|
filtering: (filters: Record<string, QueryValue>) =>
|
|
QueryBuilder.create().params(filters),
|
|
|
|
/**
|
|
* Search parameters
|
|
*/
|
|
search: (query?: string, fields?: string[]) =>
|
|
QueryBuilder.create()
|
|
.whenDefined('q', query)
|
|
.whenDefined('fields', fields?.join(',')),
|
|
|
|
/**
|
|
* Date range parameters
|
|
*/
|
|
dateRange: (startDate?: string, endDate?: string) =>
|
|
QueryBuilder.create()
|
|
.whenDefined('start_date', startDate)
|
|
.whenDefined('end_date', endDate),
|
|
|
|
/**
|
|
* Common list parameters (search, pagination, sorting, filtering)
|
|
*/
|
|
list: (options: {
|
|
query?: string;
|
|
page?: number;
|
|
limit?: number;
|
|
sortBy?: string;
|
|
sortOrder?: 'asc' | 'desc';
|
|
filters?: Record<string, QueryValue>;
|
|
} = {}) => {
|
|
const { query, page, limit, sortBy, sortOrder, filters } = options;
|
|
|
|
return QueryBuilder.create()
|
|
.whenDefined('q', query)
|
|
.whenDefined('page', page)
|
|
.whenDefined('limit', limit)
|
|
.whenDefined('sort', sortBy)
|
|
.whenDefined('order', sortOrder)
|
|
.params(filters);
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Type-safe query parameter schema builder
|
|
*/
|
|
export function createQuerySchema<T extends z.ZodRawShape>(
|
|
shape: T,
|
|
options?: { strict?: boolean }
|
|
) {
|
|
const baseSchema = z.object(shape);
|
|
|
|
if (options?.strict) {
|
|
return baseSchema.strict();
|
|
}
|
|
|
|
return baseSchema;
|
|
}
|
|
|
|
/**
|
|
* Validate and build query parameters
|
|
*/
|
|
export function validateAndBuildQuery(
|
|
schema: z.ZodSchema,
|
|
params: unknown,
|
|
basePath: string
|
|
): string {
|
|
try {
|
|
const validated = schema.parse(params);
|
|
return buildUrl(basePath, validated as QueryParams);
|
|
} catch (error) {
|
|
if (import.meta.env.DEV) {
|
|
console.error('[Query Builder] Query validation failed:', error);
|
|
}
|
|
throw new Error('Invalid query parameters');
|
|
}
|
|
}
|