128 lines
3.1 KiB
TypeScript
128 lines
3.1 KiB
TypeScript
/**
|
|
* Domain Entity: Team
|
|
*
|
|
* Represents a racing team in the GridPilot platform.
|
|
* Implements the shared IEntity<string> contract and encapsulates
|
|
* basic invariants around identity and core properties.
|
|
*/
|
|
|
|
import type { IEntity } from '@gridpilot/shared/domain';
|
|
import { RacingDomainValidationError } from '../errors/RacingDomainError';
|
|
|
|
export class Team implements IEntity<string> {
|
|
readonly id: string;
|
|
readonly name: string;
|
|
readonly tag: string;
|
|
readonly description: string;
|
|
readonly ownerId: string;
|
|
readonly leagues: string[];
|
|
readonly createdAt: Date;
|
|
|
|
private constructor(props: {
|
|
id: string;
|
|
name: string;
|
|
tag: string;
|
|
description: string;
|
|
ownerId: string;
|
|
leagues: string[];
|
|
createdAt: Date;
|
|
}) {
|
|
this.id = props.id;
|
|
this.name = props.name;
|
|
this.tag = props.tag;
|
|
this.description = props.description;
|
|
this.ownerId = props.ownerId;
|
|
this.leagues = props.leagues;
|
|
this.createdAt = props.createdAt;
|
|
}
|
|
|
|
/**
|
|
* Factory method to create a new Team entity.
|
|
*/
|
|
static create(props: {
|
|
id: string;
|
|
name: string;
|
|
tag: string;
|
|
description: string;
|
|
ownerId: string;
|
|
leagues: string[];
|
|
createdAt?: Date;
|
|
}): Team {
|
|
this.validate(props);
|
|
|
|
return new Team({
|
|
id: props.id,
|
|
name: props.name,
|
|
tag: props.tag,
|
|
description: props.description,
|
|
ownerId: props.ownerId,
|
|
leagues: [...props.leagues],
|
|
createdAt: props.createdAt ?? new Date(),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create a copy with updated properties.
|
|
*/
|
|
update(props: Partial<{
|
|
name: string;
|
|
tag: string;
|
|
description: string;
|
|
ownerId: string;
|
|
leagues: string[];
|
|
}>): Team {
|
|
const next: Team = new Team({
|
|
id: this.id,
|
|
name: props.name ?? this.name,
|
|
tag: props.tag ?? this.tag,
|
|
description: props.description ?? this.description,
|
|
ownerId: props.ownerId ?? this.ownerId,
|
|
leagues: props.leagues ? [...props.leagues] : [...this.leagues],
|
|
createdAt: this.createdAt,
|
|
});
|
|
|
|
// Re-validate updated aggregate
|
|
Team.validate({
|
|
id: next.id,
|
|
name: next.name,
|
|
tag: next.tag,
|
|
description: next.description,
|
|
ownerId: next.ownerId,
|
|
leagues: next.leagues,
|
|
});
|
|
|
|
return next;
|
|
}
|
|
|
|
/**
|
|
* Domain validation logic for core invariants.
|
|
*/
|
|
private static validate(props: {
|
|
id: string;
|
|
name: string;
|
|
tag: string;
|
|
description: string;
|
|
ownerId: string;
|
|
leagues: string[];
|
|
}): void {
|
|
if (!props.id || props.id.trim().length === 0) {
|
|
throw new RacingDomainValidationError('Team ID is required');
|
|
}
|
|
|
|
if (!props.name || props.name.trim().length === 0) {
|
|
throw new RacingDomainValidationError('Team name is required');
|
|
}
|
|
|
|
if (!props.tag || props.tag.trim().length === 0) {
|
|
throw new RacingDomainValidationError('Team tag is required');
|
|
}
|
|
|
|
if (!props.ownerId || props.ownerId.trim().length === 0) {
|
|
throw new RacingDomainValidationError('Team owner ID is required');
|
|
}
|
|
|
|
if (!Array.isArray(props.leagues)) {
|
|
throw new RacingDomainValidationError('Team leagues must be an array');
|
|
}
|
|
}
|
|
} |