-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: enforce value object creation within entity boundaries (invaria…
…nt ssot)
- Loading branch information
Showing
9 changed files
with
89 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,52 @@ | ||
import { Entity, Guard, success } from "@clean-architecture/shared-kernel"; | ||
import type { IdValueObject } from "@clean-architecture/shared-kernel"; | ||
import { | ||
Entity, | ||
Guard, | ||
IdValueObject, | ||
success, | ||
} from "@clean-architecture/shared-kernel"; | ||
import type { GetValueFromValueObject } from "@clean-architecture/shared-kernel"; | ||
|
||
import { CreatedAtValueObject } from "./CreatedAtValueObject"; | ||
import type { AuthorValueObject } from "./AuthorValueObject"; | ||
|
||
export class QuoteEntity extends Entity { | ||
public createdAt: CreatedAtValueObject; | ||
|
||
private constructor( | ||
public override id: IdValueObject, | ||
public author: AuthorValueObject, | ||
public content: string, | ||
) { | ||
super(id); | ||
this.createdAt = CreatedAtValueObject.create(); | ||
import { AuthorValueObject } from "./AuthorValueObject"; | ||
|
||
type QuoteEntityAttributes = { | ||
id: IdValueObject; | ||
author: AuthorValueObject; | ||
content: string; | ||
createdAt: CreatedAtValueObject; | ||
}; | ||
|
||
type QuoteEntityCreateInput = GetValueFromValueObject<AuthorValueObject> & | ||
Pick<QuoteEntityAttributes, "content"> & { | ||
id: string; | ||
}; | ||
|
||
export class QuoteEntity extends Entity<QuoteEntityAttributes> { | ||
private constructor(public override attributes: QuoteEntityAttributes) { | ||
super(attributes); | ||
} | ||
|
||
public static override create( | ||
id: IdValueObject, | ||
author: AuthorValueObject, | ||
content: string, | ||
) { | ||
const guardResult = Guard.mustBeLessThanCharacters(content, 280); | ||
public static override create({ | ||
id, | ||
content, | ||
firstName, | ||
lastName, | ||
}: QuoteEntityCreateInput) { | ||
const guardContentResult = Guard.mustBeLessThanCharacters(content, 280); | ||
|
||
if (guardContentResult.type === "failure") return guardContentResult; | ||
|
||
const author = AuthorValueObject.create({ firstName, lastName }); | ||
|
||
if (guardResult.type === "failure") return guardResult; | ||
if (author.type === "failure") return author; | ||
|
||
return success(new QuoteEntity(id, author, content)); | ||
return success( | ||
new QuoteEntity({ | ||
id: IdValueObject.create(id), | ||
author: author.payload, | ||
content, | ||
createdAt: CreatedAtValueObject.create(), | ||
}), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,37 @@ | ||
import type { Result } from "@open-vanilla/result"; | ||
|
||
import { IdValueObject } from "./IdValueObject"; | ||
import type { GetValueFromValueObject } from "./ValueObject"; | ||
import type { IdValueObject } from "./IdValueObject"; | ||
import { Guard } from "./Guard"; | ||
import type { DomainObject } from "./DomainObject"; | ||
|
||
export abstract class Entity implements DomainObject { | ||
protected constructor( | ||
public id: IdValueObject = IdValueObject.create(crypto.randomUUID()), | ||
) {} | ||
type EntityAttributes = { id: IdValueObject }; | ||
|
||
public static create(..._: unknown[]): Entity | Result<Entity> { | ||
export abstract class Entity< | ||
Attributes extends EntityAttributes = EntityAttributes, | ||
> implements DomainObject | ||
{ | ||
protected constructor(public attributes: Attributes) {} | ||
|
||
public static create(_input: { | ||
id: GetValueFromValueObject<EntityAttributes["id"]>; | ||
}): Entity | Result<Entity> { | ||
throw new Error("NotImplementedException"); | ||
} | ||
|
||
public static isInstanceOf(input: unknown): input is Entity { | ||
return input instanceof Entity; | ||
} | ||
|
||
public equals(input: unknown) { | ||
if (this === input) return true; | ||
|
||
if ( | ||
!(input instanceof Entity) || | ||
!Entity.isInstanceOf(input) || | ||
Guard.mustBeDefinedAndNonNull(input).type === "failure" | ||
) | ||
return false; | ||
|
||
return this.id.equals(input.id); | ||
return this.attributes.id.equals(input.attributes.id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,15 @@ | ||
import type { Result } from "@open-vanilla/result"; | ||
|
||
import type { AnyRecord } from "./types"; | ||
import type { GetValueFromValueObject } from "./ValueObject"; | ||
import type { Entity } from "./Entity"; | ||
|
||
export type EntityGateway< | ||
E extends Entity = Entity, | ||
Methods = AnyRecord, | ||
> = Methods & { | ||
getMany: () => Promise<Result<E[]>>; | ||
getOne: (id: E["id"]) => Promise<Result<E>>; | ||
getOne: ( | ||
id: GetValueFromValueObject<E["attributes"]["id"]>, | ||
) => Promise<Result<E>>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters