Builder Pattern with Fluent API
Type-safe builder pattern for complex object creation
Code
// Base Builder interface
type Builder<T> = {
[K in keyof T]-?: (value: T[K]) => Builder<T>;
} & {
build(): T;
};
// Generic builder creator
function createBuilder<T>(): Builder<T> {
const built: Partial<T> = {};
const handler: ProxyHandler<object> = {
get(target, prop: string) {
__TOKEN_52__ (prop === 'build') {
__TOKEN_53__ () => {
// Validate required fields here if needed
return built as T;
};
}
__TOKEN_55__ (value: any) => {
built[prop as keyof T] = value;
return proxy;
};
}
};
const proxy = new Proxy({}, handler);
return proxy as Builder<T>;
}
// Example: User builder
interface User {
id: number;
name: string;
email: string;
age?: number;
roles: string[];
metadata: Record<string, any>;
}
// Specific builder with validation
class UserBuilder {
private user: Partial<User> = {
roles: [],
metadata: {},
};
withId(id: number): this {
this.user.id = id;
return this;
}
withName(name: string): this {
__TOKEN_68__ (name.length < 2) {
throw new Error('Name must be at least 2 characters');
}
this.user.name = name;
return this;
}
withEmail(email: string): this {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
__TOKEN_76__ (!emailRegex.test(email)) {
throw new Error('Invalid email address');
}
this.user.email = email;
return this;
}
withAge(age: number): this {
__TOKEN_83__ (age < 0 || age > 150) {
throw new Error('Age must be between 0 and 150');
}
this.user.age = age;
return this;
}
addRole(role: string): this {
this.user.roles!.push(role);
return this;
}
withMetadata(key: string, value: any): this {
this.user.metadata![key] = value;
return this;
}
build(): User {
// Validate required fields
__TOKEN_97__ (!this.user.id || !this.user.name || !this.user.email) {
throw new Error('Missing required fields');
}
return this.user as User;
}
}
// Advanced: Step builder pattern
interface QueryBuilder {
select(...columns: string[]): QueryBuilder;
__TOKEN_106__(table: string): QueryBuilder;
where(condition: string): QueryBuilder;
orderBy(column: string, direction?: 'ASC' | 'DESC'): QueryBuilder;
limit(count: number): QueryBuilder;
build(): string;
}
class SQLQueryBuilder implements QueryBuilder {
private query = {
select: [] as string[],
from: '',
where: [] as string[],
orderBy: [] as string[],
limit: null as number | null,
};
select(...columns: string[]): this {
this.query.select = columns;
return this;
}
__TOKEN_115__(table: string): this {
this.query.from = table;
return this;
}
where(condition: string): this {
this.query.where.push(condition);
return this;
}
andWhere(condition: string): this {
this.query.where.push(`AND ${condition}`);
return this;
}
orWhere(condition: string): this {
this.query.where.push(`OR ${condition}`);
return this;
}
orderBy(column: string, direction: 'ASC' | 'DESC' = 'ASC'): this {
this.query.orderBy.push(`${column} ${direction}`);
return this;
}
limit(count: number): this {
this.query.limit = count;
return this;
}
build(): string {
__TOKEN_141__ (!this.query.select.length || !this.query.from) {
throw new Error('SELECT and FROM clauses are required');
}
const parts = [
`SELECT ${this.query.select.join(', ')}`,
`FROM ${this.query.from}`,
];
__TOKEN_148__ (this.query.where.length) {
parts.push(`WHERE ${this.query.where.join(' ')}`);
}
__TOKEN_150__ (this.query.orderBy.length) {
parts.push(`ORDER BY ${this.query.orderBy.join(', ')}`);
}
__TOKEN_152__ (this.query.limit !== null) {
parts.push(`LIMIT ${this.query.limit}`);
}
return parts.join('\n');
}
}
// Usage examples
// Generic builder
const user = createBuilder<User>()
.id(1)
.name('John Doe')
.email('[email protected]')
.age(30)
.build();
// Specific builder with validation
const user2 = new UserBuilder()
.withId(1)
.withName('Jane Smith')
.withEmail('[email protected]')
.addRole('admin')
.addRole('user')
.withMetadata('createdAt', new Date())
.build();
// Query builder
const query = new SQLQueryBuilder()
.select('id', 'name', 'email')
.__TOKEN_161__('users')
.where('age > 18')
.andWhere('status = "active"')
.orderBy('name', 'ASC')
.limit(10)
.build();