Skip to content

Commit

Permalink
refactor: improve value objects definition
Browse files Browse the repository at this point in the history
  • Loading branch information
borjapazr committed Jul 28, 2023
1 parent ff661f7 commit ee7dd93
Show file tree
Hide file tree
Showing 12 changed files with 47 additions and 47 deletions.
4 changes: 2 additions & 2 deletions src/domain/sessions/session-user-data.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ValueObject } from '@domain/shared/value-object';
import { CompositeValueObject } from '@domain/shared/value-object';

class SessionUserData extends ValueObject {
class SessionUserData extends CompositeValueObject {
readonly username: string;

readonly email: string;
Expand Down
6 changes: 1 addition & 5 deletions src/domain/shared/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
type Nullable<T> = T | null | undefined;

type Primitive = bigint | boolean | null | number | string | symbol | undefined;

type PlainObject = Record<string, Primitive>;

export { Nullable, PlainObject, Primitive };
export { Nullable };
13 changes: 13 additions & 0 deletions src/domain/shared/value-object/composite-value-object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { deepEqual } from 'fast-equals';

abstract class CompositeValueObject {
public equalsTo(other: CompositeValueObject): boolean {
return other.constructor.name === this.constructor.name && deepEqual(this, other);
}

public toString(): string {
return JSON.stringify(this);
}
}

export { CompositeValueObject };
9 changes: 1 addition & 8 deletions src/domain/shared/value-object/date-value-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@ import { DateTime } from 'luxon';

import { ValueObject } from './value-object';

abstract class DateValueObject extends ValueObject {
readonly value: Date;

constructor(value: Date) {
super();
this.value = value;
}

abstract class DateValueObject extends ValueObject<Date> {
public static fromISOString<T extends DateValueObject>(this: new (value: Date) => T, dateISOString: string): T {
const dateObject = DateTime.fromISO(dateISOString).toJSDate();
return new this(dateObject);
Expand Down
7 changes: 2 additions & 5 deletions src/domain/shared/value-object/enum-value-object.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { ValueObject } from './value-object';

abstract class EnumValueObject<T> extends ValueObject {
abstract class EnumValueObject<T> {
readonly value: T;

constructor(
value: T,
public readonly validValues: T[]
) {
super();
this.checkIfValueIsValid(value);
this.value = value;
this.checkIfValueIsValid(value);
}

public checkIfValueIsValid(value: T): void {
Expand Down
1 change: 1 addition & 0 deletions src/domain/shared/value-object/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './composite-value-object';
export * from './date-value-object';
export * from './enum-value-object';
export * from './number-value-object';
Expand Down
3 changes: 0 additions & 3 deletions src/domain/shared/value-object/invalid-argument-error.ts

This file was deleted.

9 changes: 1 addition & 8 deletions src/domain/shared/value-object/number-value-object.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { ValueObject } from './value-object';

abstract class NumberValueObject extends ValueObject {
readonly value: number;

constructor(value: number) {
super();
this.value = value;
}

abstract class NumberValueObject extends ValueObject<number> {
public isBiggerThan(other: NumberValueObject): boolean {
return this.value > other.value;
}
Expand Down
9 changes: 1 addition & 8 deletions src/domain/shared/value-object/string-value-object.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { ValueObject } from './value-object';

abstract class StringValueObject extends ValueObject {
readonly value: string;

constructor(value: string) {
super();
this.value = value;
}

abstract class StringValueObject extends ValueObject<string> {
public toString(): string {
return this.value;
}
Expand Down
4 changes: 2 additions & 2 deletions src/domain/shared/value-object/uuid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { StringValueObject } from './string-value-object';
class Uuid extends StringValueObject {
constructor(value: string) {
super(value);
this.checkIfValueIsValid(value);
this.ensureValueIsValid(value);
}

public static random(): Uuid {
return new Uuid(v4());
}

private checkIfValueIsValid(value: string): void {
private ensureValueIsValid(value: string): void {
if (!validate(value)) {
throw new InvalidParameterException(`<${this.constructor.name}> does not allow the value <${value}>`);
}
Expand Down
25 changes: 21 additions & 4 deletions src/domain/shared/value-object/value-object.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
import { deepEqual } from 'fast-equals';

abstract class ValueObject {
public equalsTo(other: ValueObject): boolean {
return deepEqual(this, other);
import { InvalidParameterException } from '@domain/shared/exceptions';

type Primitive = bigint | number | boolean | string | Date | symbol;

abstract class ValueObject<T extends Primitive> {
readonly value: T;

constructor(value: T) {
this.value = value;
this.ensureValueIsDefined(value);
}

public equalsTo(other: ValueObject<T>): boolean {
return other.constructor.name === this.constructor.name && other.value === this.value && deepEqual(this, other);
}

public toString(): string {
return JSON.stringify(this);
return this.value.toString();
}

private ensureValueIsDefined(value: T): void {
if (value === null || value === undefined) {
throw new InvalidParameterException('Value must be provided');
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/domain/users/user-name.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ValueObject } from '@domain/shared/value-object';
import { CompositeValueObject } from '@domain/shared/value-object';

class UserName extends ValueObject {
class UserName extends CompositeValueObject {
readonly firstName: string;

readonly lastName: string;
Expand Down

0 comments on commit ee7dd93

Please sign in to comment.