115 lines
2.7 KiB
TypeScript
115 lines
2.7 KiB
TypeScript
/**
|
|
* Domain Entity: League
|
|
*
|
|
* Represents a league in the GridPilot platform.
|
|
* Immutable entity with factory methods and domain validation.
|
|
*/
|
|
|
|
export interface LeagueSettings {
|
|
pointsSystem: 'f1-2024' | 'indycar' | 'custom';
|
|
sessionDuration?: number;
|
|
qualifyingFormat?: 'single-lap' | 'open';
|
|
customPoints?: Record<number, number>;
|
|
}
|
|
|
|
export class League {
|
|
readonly id: string;
|
|
readonly name: string;
|
|
readonly description: string;
|
|
readonly ownerId: string;
|
|
readonly settings: LeagueSettings;
|
|
readonly createdAt: Date;
|
|
|
|
private constructor(props: {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
ownerId: string;
|
|
settings: LeagueSettings;
|
|
createdAt: Date;
|
|
}) {
|
|
this.id = props.id;
|
|
this.name = props.name;
|
|
this.description = props.description;
|
|
this.ownerId = props.ownerId;
|
|
this.settings = props.settings;
|
|
this.createdAt = props.createdAt;
|
|
}
|
|
|
|
/**
|
|
* Factory method to create a new League entity
|
|
*/
|
|
static create(props: {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
ownerId: string;
|
|
settings?: Partial<LeagueSettings>;
|
|
createdAt?: Date;
|
|
}): League {
|
|
this.validate(props);
|
|
|
|
const defaultSettings: LeagueSettings = {
|
|
pointsSystem: 'f1-2024',
|
|
sessionDuration: 60,
|
|
qualifyingFormat: 'open',
|
|
};
|
|
|
|
return new League({
|
|
id: props.id,
|
|
name: props.name,
|
|
description: props.description,
|
|
ownerId: props.ownerId,
|
|
settings: { ...defaultSettings, ...props.settings },
|
|
createdAt: props.createdAt ?? new Date(),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Domain validation logic
|
|
*/
|
|
private static validate(props: {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
ownerId: string;
|
|
}): void {
|
|
if (!props.id || props.id.trim().length === 0) {
|
|
throw new Error('League ID is required');
|
|
}
|
|
|
|
if (!props.name || props.name.trim().length === 0) {
|
|
throw new Error('League name is required');
|
|
}
|
|
|
|
if (props.name.length > 100) {
|
|
throw new Error('League name must be 100 characters or less');
|
|
}
|
|
|
|
if (!props.description || props.description.trim().length === 0) {
|
|
throw new Error('League description is required');
|
|
}
|
|
|
|
if (!props.ownerId || props.ownerId.trim().length === 0) {
|
|
throw new Error('League owner ID is required');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a copy with updated properties
|
|
*/
|
|
update(props: Partial<{
|
|
name: string;
|
|
description: string;
|
|
settings: LeagueSettings;
|
|
}>): League {
|
|
return new League({
|
|
id: this.id,
|
|
name: props.name ?? this.name,
|
|
description: props.description ?? this.description,
|
|
ownerId: this.ownerId,
|
|
settings: props.settings ?? this.settings,
|
|
createdAt: this.createdAt,
|
|
});
|
|
}
|
|
} |