diff --git a/src/models/src/machine.ts b/src/models/src/machine.ts new file mode 100644 index 0000000..bd1d59e --- /dev/null +++ b/src/models/src/machine.ts @@ -0,0 +1,113 @@ +import { ToJson } from '@/types.ts' +import { Group } from '@models/group.ts' +import { Ressource } from '@models/ressource.ts' +import { Ref } from '@/src/models/utils/ref.ts' + +export class Machine extends Ressource { + static fromJSON( + json: ToJson, + ): Machine { + const url = new URL(json.url) + const avatar = new URL(json.avatar) + const groups = json.groups.map((group) => Ref.fromString(group)) + + return new Machine({ ...json, url, avatar, groups }) + } + + static create( + { tags, url, status, avatar, groups, ...props }: + & Pick + & Pick, + ): Machine { + return new Machine({ ...props, tags, url, status, avatar, groups }) + } + + #tags: readonly string[] + #url: URL + #status: + | 'ready' + | 'busy' + | 'unavailable' + | 'discontinued' + | 'error' + | 'unknown' + #avatar: URL + #groups: readonly Ref[] + + private constructor( + { tags, url, status, avatar, groups, ...props }: + & Pick + & Pick, + ) { + super(props) + + this.#tags = Object.freeze(tags) + this.#url = new URL(url) + if (!['working', 'pending', 'ready', 'unavailable'].includes(status)) { + throw new TypeError( + `status is "${status}" but ('ready' | 'busy' | 'unavailable' | 'discontinued' | 'error' | 'unknown') is required`, + ) + } + this.#status = status + this.#avatar = new URL(avatar) + this.#groups = Object.freeze(groups) + } + + get type(): 'machine' { + return 'machine' + } + get tags() { + return this.#tags.slice() + } + get url() { + return new URL(this.#url) + } + get status() { + return this.#status + } + get avatar() { + return new URL(this.#avatar) + } + get groups() { + return this.#groups + } + + update( + props: Partial>, + ): Machine { + const { updatedAt } = super.update(props) + const machine = new Machine({ ...this, ...props, updatedAt }) + return machine + } + + toJSON() { + return { + ...super.toJSON(), + type: this.type, + tags: this.tags.slice(), + url: this.url.toJSON(), + status: this.status, + avatar: this.avatar.toJSON(), + groups: Object.freeze(this.groups.map((group) => group.toJSON())), + } as const + } + + toString(): string { + return `Machine (${JSON.stringify(this)})` + } +} + +export interface Machine extends Ressource { + type: 'machine' + tags: string[] + url: URL + status: + | 'ready' + | 'busy' + | 'unavailable' + | 'discontinued' + | 'error' + | 'unknown' + avatar: URL + groups: readonly Ref[] +}