harden business rules
This commit is contained in:
98
core/racing/domain/value-objects/SessionDuration.ts
Normal file
98
core/racing/domain/value-objects/SessionDuration.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Domain Value Object: SessionDuration
|
||||
*
|
||||
* Represents the duration of a racing session in minutes.
|
||||
* Enforces reasonable limits for different session types.
|
||||
*/
|
||||
|
||||
import type { IValueObject } from '@core/shared/domain';
|
||||
import { RacingDomainValidationError } from '../errors/RacingDomainError';
|
||||
|
||||
export interface SessionDurationProps {
|
||||
value: number;
|
||||
}
|
||||
|
||||
export class SessionDuration implements IValueObject<SessionDurationProps> {
|
||||
readonly value: number;
|
||||
|
||||
private constructor(value: number) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
static create(value: number): SessionDuration {
|
||||
if (!Number.isInteger(value) || value <= 0) {
|
||||
throw new RacingDomainValidationError('Session duration must be a positive integer');
|
||||
}
|
||||
|
||||
// Enforce reasonable limits
|
||||
if (value < 15) {
|
||||
throw new RacingDomainValidationError('Session duration must be at least 15 minutes');
|
||||
}
|
||||
|
||||
if (value > 240) {
|
||||
throw new RacingDomainValidationError('Session duration cannot exceed 240 minutes (4 hours)');
|
||||
}
|
||||
|
||||
return new SessionDuration(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if duration is suitable for sprint racing
|
||||
*/
|
||||
isSprint(): boolean {
|
||||
return this.value >= 15 && this.value <= 45;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if duration is suitable for standard racing
|
||||
*/
|
||||
isStandard(): boolean {
|
||||
return this.value > 45 && this.value <= 90;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if duration is suitable for endurance racing
|
||||
*/
|
||||
isEndurance(): boolean {
|
||||
return this.value > 90;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duration classification
|
||||
*/
|
||||
getClassification(): 'sprint' | 'standard' | 'endurance' {
|
||||
if (this.isSprint()) return 'sprint';
|
||||
if (this.isStandard()) return 'standard';
|
||||
return 'endurance';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if duration is within specified range
|
||||
*/
|
||||
isWithinRange(min: number, max: number): boolean {
|
||||
return this.value >= min && this.value <= max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duration in hours
|
||||
*/
|
||||
inHours(): number {
|
||||
return this.value / 60;
|
||||
}
|
||||
|
||||
get props(): SessionDurationProps {
|
||||
return { value: this.value };
|
||||
}
|
||||
|
||||
equals(other: IValueObject<SessionDurationProps>): boolean {
|
||||
return this.value === other.props.value;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.value} minutes`;
|
||||
}
|
||||
|
||||
toNumber(): number {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user