75 lines
1.7 KiB
TypeScript
75 lines
1.7 KiB
TypeScript
import { TaggedError, type UUID } from "@fabric/core";
|
|
import {
|
|
type Command,
|
|
type DomainEvent,
|
|
Field,
|
|
Model,
|
|
type ModelToType,
|
|
type UUIDGenerator,
|
|
} from "@fabric/domain";
|
|
import type { ReadStateStore } from "../../services/state-store.ts";
|
|
|
|
export interface CreateProjectDependencies {
|
|
state: ReadStateStore;
|
|
uuid: UUIDGenerator;
|
|
currentUserId: UUID;
|
|
}
|
|
|
|
export const CreateProjectRequestModel = Model.from(
|
|
"CreateProjectRequestModel",
|
|
{
|
|
name: Field.string(),
|
|
description: Field.string(),
|
|
},
|
|
);
|
|
export type CreateProjectRequestModel = ModelToType<
|
|
typeof CreateProjectRequestModel
|
|
>;
|
|
|
|
export type ProjectCreatedEvent = DomainEvent<"ProjectCreated", {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
userId: string;
|
|
}>;
|
|
|
|
export type CreateProjectErrors = ProjectNameInUseError;
|
|
|
|
export default {
|
|
name: "createProject",
|
|
isAuthRequired: true,
|
|
useCase: ({ state, uuid, currentUserId }, { name, description }) =>
|
|
state.from("projects")
|
|
.where({ name })
|
|
.assertNone()
|
|
.errorMap(() => new ProjectNameInUseError())
|
|
.map(() => {
|
|
const newEventId = uuid.generate();
|
|
const newProjectId = uuid.generate();
|
|
|
|
return {
|
|
_tag: "ProjectCreated",
|
|
id: newEventId,
|
|
streamId: newProjectId,
|
|
payload: {
|
|
id: newProjectId,
|
|
name,
|
|
description,
|
|
userId: currentUserId,
|
|
},
|
|
};
|
|
}),
|
|
} as const satisfies Command<
|
|
CreateProjectDependencies,
|
|
CreateProjectRequestModel,
|
|
ProjectCreatedEvent,
|
|
CreateProjectErrors
|
|
>;
|
|
|
|
export class ProjectNameInUseError
|
|
extends TaggedError<"ProjectNameInUseError"> {
|
|
constructor() {
|
|
super("ProjectNameInUseError");
|
|
}
|
|
}
|