diff --git a/CHANGELOG.md b/CHANGELOG.md index 58128ab..688cd9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,62 +10,28 @@ All notable changes to this project will be documented in this file. --- -### [1.26.0] - 2025-01-27 +### [2.0.0] - 2025-10-20 -#### **Feat** +#### **BREAKING CHANGE** -- **Nodejs Version**: - - Added support for nodejs v23 +- **Replaced `Result` with `Promise`**: + - The `Result` class has been completely removed from the library. + - All methods that previously returned a `Result` now return a `Promise`. + - `Ok(data)` is replaced with `Promise.resolve(data)`. + - `Fail(error)` is replaced with `Promise.resolve(null)`. + - This change simplifies the API and aligns it with modern asynchronous JavaScript patterns. + - All `create` methods on `ValueObject`, `Entity`, and `Aggregate` are now `async` and return a `Promise`. + - The `toObject` method on `ValueObject` and `Entity` is now `async` and returns a `Promise`. + - The `createMany` method on `ValueObject`, `Entity`, and `Aggregate` now returns a `CreateManyResult` where `result` is a `Promise`. --- -### [1.25.1] - 2024-12-20 +### [1.26.0] - 2025-01-27 #### **Feat** -- **Dynamic Typing in `Result` Made Optional**: - - Developers can now choose between `Result` (non-nullable) and `Result` (nullable), based on their specific use case. - - This update allows greater flexibility for explicit `null` handling without forcing unnecessary complexity in scenarios where nullability is not required. - -#### **Examples** - -1. **Explicit Null Handling**: - Use `Result` to manage nullable states explicitly: - ```typescript - class SampleNullish { - public static create(props: Props): Result { - if (!props.name || props.name.trim() === '') { - return Fail('name is required'); - } - return Ok(new SampleNullish(props)); - } - } - ``` - -2. **Non-Nullable Values**: - Use `Result` for cases where null handling is unnecessary: - ```typescript - class Sample { - public static create(props: Props): Result { - if (!props.name || props.name.trim() === '') { - return Fail('name is required'); - } - return Ok(new Sample(props)); - } - } - ``` - -#### **Fix** - -- Enhanced backward compatibility by making nullable typing optional, ensuring existing integrations using `Result` remain unaffected. - -#### **Impact** - -- **Improved Flexibility**: - Developers can adapt the `Result` type to suit their needs, supporting nullable and non-nullable use cases seamlessly. - -- **Enhanced Clarity**: - Provides explicit type inference, ensuring safer and more intuitive code handling for nullable scenarios. +- **Nodejs Version**: + - Added support for nodejs v23 --- @@ -78,7 +44,6 @@ All notable changes to this project will be documented in this file. - Enhance class method comments for better documentation. - Rename several interfaces for consistency: - `IUseCase` renamed to `UseCase` - - `IResult` renamed to `Result` or `_Result` - `IAdapter` renamed to `Adapter` or `_Adapter` - `ICommand` renamed to `Command` @@ -94,25 +59,6 @@ All notable changes to this project will be documented in this file. --- -### [1.24.0] - 2024-11-28 - -#### Fix - -- **Explicit Typing for Failures**: `Result.fail` now explicitly returns `Result`, ensuring that values are always `null` in failure states. -- **New `isNull` Method**: Added to simplify validation of `null` values or failure states, improving readability and type safety. -- **Adjusted Creation Methods**: Methods like `create` and adapters now return `Result` where applicable for better consistency and error handling. - -### **Impact** -These changes improve type safety, make failure handling more explicit, and encourage clearer checks in code. The updates may require minor adjustments in existing codebases to accommodate the explicit `null` typing in failures. This release is marked as beta for testing purposes. - -Feedback is welcome! 🚀 - -[issue](https://github.com/4lessandrodev/rich-domain/issues/194) - -### Updates - ---- - ### [1.23.4] - 2024-09-22 #### Fix @@ -227,7 +173,7 @@ Another alternative is to use an adapter. ```ts class Adapter implements IAdapter { - adapt(domain: Domain): Result { + adapt(domain: Domain): Promise { //... } } @@ -327,6 +273,7 @@ context.dispatchEvent('Context-B:*'); console.log(model); console.log(event); + console.log(event.eventName); console.log(event.options); // custom params provided on call dispatchEvent @@ -357,8 +304,8 @@ context.dispatchEvent('Context-B:*'); return user; } - public static create(props: Props): Result { - return Ok(new User(props)); + public static create(props: Props): Promise { + return Promise.resolve(new User(props)); } } @@ -369,9 +316,10 @@ context.dispatchEvent('Context-B:*'); super({ eventName: 'SIGNUP' }) } - dispatch(user: User): void { + async dispatch(user: User): Promise { // dispatch to global context event manager - user.context().dispatchEvent("ACCOUNT:USER_REGISTERED", user.toObject()); + const model = await user.toObject(); + user.context().dispatchEvent("ACCOUNT:USER_REGISTERED", model); }; } @@ -415,7 +363,7 @@ This version introduces significant changes to the event handling system, enhanc ```ts - import { Aggregate, Ok, Result, Context, EventHandler } from 'rich-domain'; + import { Aggregate, Context, EventHandler } from 'rich-domain'; // ------------------ // Some Context X @@ -445,8 +393,8 @@ This version introduces significant changes to the event handling system, enhanc return user; } - public static create(props: Props): Result { - return Ok(new User(props)); + public static create(props: Props): Promise { + return Promise.resolve(new User(props)); } } @@ -457,9 +405,10 @@ This version introduces significant changes to the event handling system, enhanc super({ eventName: 'SIGNUP' }) } - dispatch(user: User): void { + async dispatch(user: User): Promise { // dispatch to global context event manager - user.context().dispatchEvent("USER_REGISTERED", user.toObject()); + const model = await user.toObject(); + user.context().dispatchEvent("USER_REGISTERED", model); }; } @@ -711,7 +660,6 @@ DomainEvents.dispatch({ /* ... */}); ``` -- changed: Result properties to private using # to do not serialize private keys - changed: Types for create method: Entity, Aggregate and ValueObject - changed: Clone method in Entity and Aggregate instance. Now It accepts optional props. @@ -785,7 +733,7 @@ util.number(0).divideBy(1); - Change payload ### Breaking Change -- ValueObject, Entity, Aggregate: `clone` method now returns an instance instead `Result` +- ValueObject, Entity, Aggregate: `clone` method now returns an instance instead `Promise` - ValueObject, Entity, Aggregate: `set` and `change` method now returns `true` if the value has changed and returns `false` if the value has not changed. ```ts @@ -887,7 +835,7 @@ The function still works, but it is marked as deprecated. show warning if using. - Now its possible to convert entity on aggregate --- -### [1.14.5] - 2022-11-25 +### [1.14.5] - 2022-11-22 ### Fixed @@ -899,124 +847,7 @@ The function still works, but it is marked as deprecated. show warning if using. - dispatchAll: added fn to dispatch all event by aggregate id --- -### [1.14.4] - 2022-11-22 - -### Changed - -- Types: update types for Result - ---- -### [1.14.3] - 2022-11-22 - -### Changed - -- Result: change to type any result arg on combine function -### Added - -- Result: added Combine function as single import -- Types: added Payload type as Result type - ---- -### [1.14.2] - 2022-11-22 - -### Added - -- validator: added method to validate if all chars in string is number - ---- -### [1.14.1] - 2022-10-03 - -### Updated - -- result: ensure result props to be read only - ---- -### [1.14.0] - 2022-09-27 - -### Change - -- refactor: Fail -- refactor: Ok -- refactor: Result.Ok -- refactor: Result.fail - -Change generic types order for `Result.fail` and `Result.Ok` - -Now each method has your own order -Example: - -```ts - -// for implementation: -IResult; - -// before the generic order was the same for both method. -// now for -Result.Ok - -// the generic order is -Result.Ok(payload metaData); - -// for -Result.fail - -//the generic order is -Result.fail(error, metaData); -``` - -Changes made on Ok - -```ts - -import { Ok } from 'rich-domain'; - -// simple use case for success. no arg required -return Ok(); - -// arg required - -return Ok('my payload'); - -// arg and metaData required - -interface MetaData { - arg: string; -} - -return Ok('payload', { arg: 'sample' }) -``` - -Changes made on Fail - -```ts - -import { Fail } from 'rich-domain'; - -// simple use case for success. no arg required -return Fail(); - -// arg required - -return Fail('my payload'); - -// arg and metaData required - -interface MetaData { - arg: string; -} - -return Fail('payload', { arg: 'sample' }) -``` ---- -### [1.13.0] - 2022-09-26 - -### Added - -- feat: implement function Fail -- feat: implement function Ok - ---- ### [1.12.0] - 2022-09-14 ### Fixed @@ -1081,44 +912,14 @@ const { result, data } = ValueObject.createMany([ Class(Name, props) ]); -result.isOk() // true - -const age = data.next() as IResult; -const price = data.next() as IResult; -const name = data.next() as IResult; - -age.value().get('value') // 21 - -``` - -### Change - -### Result: - -- from `isOK()` to `isOk()` -- from `OK()` to `Ok()` - ---- - -### [1.9.0]-beta - 2022-08-06 - -### Change - -- Result: now you may return Result - -```ts - -const result: Result = Result.Ok(); +const res = await result; +if(res){ + const age = await data.next(); + const price = await data.next(); + const name = await data.next(); + age.get('value') // 21 +} ``` -- Rename methods: -### Result: - -- from `isFailure()` to `isFail()` -- from `isSuccess()` to `isOK()` -- from `isShortID()` to `isShort()` -- from `success()` to `OK()` -- from `createShort()` to `short()` - ---- +--- \ No newline at end of file diff --git a/README.md b/README.md index 222d2fd..24cd0b8 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ Divided by ```ts -import { ValueObject, Ok, Fail, Result } from 'rich-domain'; +import { ValueObject } from 'rich-domain'; interface Props { amount: number; @@ -282,12 +282,12 @@ export default class Money extends ValueObject { } // factory method to create an instance and validate value. - public static create(amount: number): Result { + public static create(amount: number): Promise { const isValid = this.isValidProps({ amount }); - if(!isValid) return Fail("Invalid amount for money"); + if(!isValid) return Promise.resolve(null); - return Ok(new Money({ amount })); + return Promise.resolve(new Money({ amount })); } // try initialize an instance. throw erro if provide an invalid value @@ -307,35 +307,27 @@ How to use value object instance ```ts // operation result -const resA = Money.create(500); +const moneyA = await Money.create(500); // check if provided a valid value -console.log(resA.isOk()); +if(moneyA) { + moneyA.get("amount"); + // 500 -// > true + // using methods + moneyA.isGt(Money.zero()); + // > true + const moneyB = await Money.create(100); -// money instance -const moneyA = resA.value() as Money; + const moneyC = moneyA.sum(moneyB!); -moneyA.get("amount"); + const value = moneyC.get('amount'); -// 500 + console.log(value); -// using methods -moneyA.isGt(Money.zero()); - -// > true - -const moneyB = Money.create(100).value() as Money; - -const moneyC = moneyA.sum(moneyB); - -const value = moneyC.get('amount'); - -console.log(value); - -// > 600 + // > 600 +} ``` @@ -350,7 +342,7 @@ console.log(value); ```ts -import { Entity, Ok, Fail, Result, UID } from 'rich-domain'; +import { Entity, UID } from 'rich-domain'; interface Props { id?: UID; @@ -383,8 +375,8 @@ export default class Payment extends Entity { } // factory method to create a instance. Value must be positive. - public static create(props: Props): Result { - return Ok(new Payment(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Payment(props)); } public static init(props: Props): Payment { @@ -399,22 +391,22 @@ How to use entity instance ```ts // operation result -const total = Money.create(500).value() as Money; +const total = await Money.create(500); const discount = Money.zero(); const fees = Money.zero(); // create a payment -const payment = Payment.create({ total, discount, fees }).value(); +const payment = await Payment.create({ total: total!, discount, fees }); // create fee and discount -const fee = Money.create(17.50).value() as Money; -const disc = Money.create(170.50).value() as Money; +const fee = await Money.create(17.50); +const disc = await Money.create(170.50); // apply fee and discount -const result = payment.applyFees(fee).applyDiscount(disc); +const result = payment!.applyFees(fee!).applyDiscount(disc!); // get object from domain entity -console.log(result.toObject()); +console.log(await result.toObject()); { "id": "d7fc98f5-9711-4ad8-aa16-70cb8a52244a", @@ -448,7 +440,7 @@ In my example, let's use the context of payment. All payment transactions are en ```ts -import { Aggregate, Ok, Fail, Result, UID, EventHandler } from 'rich-domain'; +import { Aggregate, UID, EventHandler } from 'rich-domain'; // Entities and VO that encapsulate context. interface Props { @@ -520,11 +512,11 @@ export default class Order extends Aggregate { } // Static method to create an instance of Order. - // Returns a Result, which can be Ok (success) or Fail (failure). - // The value of the Result is an instance of Order, + // Returns a Promise, which can be resolved (success) or rejected (failure). + // The value of the Promise is an instance of Order, // if creation is successful. - public static create(props: Props): Result { - return Ok(new Order(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Order(props)); } public static init(props: Props): Order { @@ -549,9 +541,10 @@ class OrderCreatedEvent extends EventHandler { super({ eventName: 'ORDER_CREATED' }); } - dispatch(order: Order): void { + async dispatch(order: Order): Promise { // dispatch event to another context - order.context().dispatchEvent('CONTEXT:EVENT', order.toObject()); + const model = await order.toObject(); + order.context().dispatchEvent('CONTEXT:EVENT', model); }; } @@ -616,58 +609,34 @@ context.dispatchEvent('Context-Y:*'); ## Features -### Result +
+Promise -What is Result: +What is Promise: -`Result` is a class that encapsulates the result of an operation and stores the success or failure state without throws the application. +A `Promise` is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. #### Interface and Generic Types -- P = `Payload` optional default `void` -- E = `Error` optional default `string` -- M = `MetaData` optional default `{}` +- T = `Payload` ```ts -Result; +Promise; ``` -You can import like example below +You can use it like example below ```ts -import { Result, Ok, Fail } from "rich-domain"; - // Success use case -return Result.Ok(); - -// OR - -return Ok(); - -// OR - -return Ok(data); - -// OR - -return Ok(data); +return Promise.resolve(data); // Failure use case -return Result.fail('error message here'); - -// OR - -return Fail('error message here'); - -// OR - -return Fail(myCustomError); - +return Promise.resolve(null); ``` @@ -681,29 +650,22 @@ First let's create our interfaces to use as generic type. // Payload type interface Data { data: string }; -// Error type -interface Err { message: string }; - -// MetaData type. Optional -interface Meta { arg: number }; - ``` -Now let's implement a function that return the result below +Now let's implement a function that return the promise below ```ts -Result; +Promise; ``` So let's implement that on a simple function. ```ts -const isEven = (value: number): Result => { +const isEven = async (value: number): Promise => { const isEvenValue = value % 2 === 0; - const metaData: Meta = { arg: value }; if (isEvenValue) { @@ -711,14 +673,11 @@ const isEven = (value: number): Result => { const payload: Data = { data: `${value} is even` }; // return success - return Ok(payload, metaData); + return Promise.resolve(payload); } - // failure payload - const error: Err = { message: `${value} is not even` }; - // return failure - return Fail(error, metaData); + return Promise.resolve(null); }; @@ -729,238 +688,26 @@ Success Case ```ts -const result = isEven(42); +const result = await isEven(42); -console.log(result.isOk()); - -> true - -console.log(result.value()); +console.log(result); > 'Object { data: "42 is even" }' -console.log(result.metaData()); - -> 'Object { arg: 42 }' - -console.log(result.error()); - -> null - ``` Failure Case ```ts -const result = isEven(43); - -console.log(result.isFail()); - -> true - -console.log(result.error()); - -> 'Object { message: "43 is not even" }' - -console.log(result.metaData()); - -> 'Object { arg: 43 }' - -console.log(result.value()); - -> null - -``` - -#### Void - -The most simple void success example.
-Let's see the same example using void. - -```ts - -const checkEven = (value: number): Result => { - - const isEven = value % 2 === 0; - - // success case - if(isEven) return Ok(); - - // failure case - return Fail('not even'); -} - -``` -Using the function as success example - -```ts - -const result: Result = checkEven(42); - -console.log(result.isOk()); - -> true - -console.log(result.isFail()); - -> false - -console.log(result.error()); - -> null - -console.log(result.value()); - -> null - -console.log(result.metaData()); - -> 'Object {}' - -``` - -Fail example - -```ts - -const result: Result = checkEven(43); - -console.log(result.isFail()); - -> true - -console.log(result.isOk()); - -> false - -console.log(result.error()); +const result = await isEven(43); -> "not even" - -console.log(result.value()); +console.log(result); > null -console.log(result.metaData()); - -> 'Object {}' - ``` -#### toObject method -you can get a summarized object with the properties of an instance of a `Result` - -```ts - -console.log(result.toObject()); - -> Object -`{ - "data": null, - "error": "not even", - "isFail": true, - "isOk": false, - "metaData": Object {} - }` - -``` - -#### Hooks - -In the instances of a Result there are two hooks that allow the execution of a command according to the state. - -```ts - -class Command implements ICommand { - execute(): void { - console.log("running command ..."); - } -} - -const myCommand = new Command(); - -const result = Ok(); - -result.execute(myCommand).on('Ok'); - -> "running command ..." - -``` - -You might also want to pass arguments to the command - -```ts - -class Command implements ICommand { - execute(error: string): void { - console.log(error); - } -} - -const myCommand = new Command(); - -const result = Fail('something went wrong'); - -result.execute(myCommand).withData(result.error()).on('fail'); - -> "something went wrong" - -``` - -#### Combine - -You can use the static `combine` function of `Result` to check many instances if any are failed it will return the instance with error state. - -Success example - -```ts - -import { Ok, Combine } from "rich-domain"; - -const resultA = Ok(); -const resultB = Ok(); -const resultC = Ok(); - -const result = Combine([ resultA, resultB, resultC ]); - -console.log(result.isOk()); - -> true - -// OR - -import { Result } from "rich-domain"; - -const resultA = Result.Ok(); -const resultB = Result.Ok(); -const resultC = Result.Ok(); - -const result = Result.combine([ resultA, resultB, resultC ]); - -console.log(result.isOk()); - -> true - -``` -Failure example - -```ts - -const resultA = Ok(); -const resultB = Fail('oops err'); -const resultC = Ok(); - -const result = Combine([ resultA, resultB, resultC ]); - -console.log(result.isOk()); - -> false - -console.log(result.error()); - -> 'oops err' - -``` +
--- @@ -1106,14 +853,15 @@ What is value object: #### Simple Value Object. -Value objects extend to `ValueObject` class have private constructor and public static method called `create`.
+Value objects extend to `ValueObject` class have private constructor and public static method called `create`. + The `create` method receives the props which by default is an object with the key `value`. the value object below is a base example without any kind of validation ```ts -import { Result, ValueObject } from "rich-domain"; +import { ValueObject } from "rich-domain"; export interface NameProps { value: string; @@ -1128,8 +876,8 @@ export class Name extends ValueObject{ return new Name(value); } - public static create(value: string): Result { - return Result.Ok(new Name({ value })); + public static create(value: string): Promise { + return Promise.resolve(new Name({ value })); } } @@ -1138,21 +886,16 @@ export default Name; ``` Now that we have defined our value object class, we can create an instance.
-The `create` method returns an instance of Name encapsulated by the `Result`, so it is important to always assess whether the result is a success before getting the value. +The `create` method returns an instance of Name encapsulated by a `Promise`, so it is important to always assess whether the promise resolved before getting the value. ```ts -const result = Name.create('Jane'); - -console.log(result.isOk()); - -> true - -const name = result.value(); +const name = await Name.create('Jane'); -console.log(name.get('value')); - -> "Jane" +if(name) { + console.log(name.get('value')); + // > "Jane" +} ``` @@ -1198,7 +941,7 @@ A validator instance is available in the "Value Object" domain class. ```ts -import { Result, Ok, Fail, ValueObject } from "rich-domain"; +import { ValueObject } from "rich-domain"; export class Name extends ValueObject{ private constructor(props: string) { @@ -1216,9 +959,9 @@ export class Name extends ValueObject{ return new Name(value); } - public static create(value: string): Result { - if (!this.isValid(value)) return Fail('invalid name'); - return Ok(new Name(value)); + public static create(value: string): Promise { + if (!this.isValid(value)) return Promise.resolve(null); + return Promise.resolve(new Name(value)); } } @@ -1226,25 +969,17 @@ export default Name; ``` -Now when you try to instantiate a name, the value will be checked and if it doesn't meet the validation requirements, a `Result` will be returned with an error state. +Now when you try to instantiate a name, the value will be checked and if it doesn't meet the validation requirements, a `Promise` will be returned with a null state. ```ts const empty = ''; -const result = Name.create(empty); - -console.log(result.isFail()); - -> true - -console.log(result.error()); - -> "invalid name" - -console.log(result.value()); +const name = await Name.create(empty); -> null +if(!name) { + console.log('invalid name'); +} ``` @@ -1270,15 +1005,13 @@ This method is useful for cases where you have value objects inside other value ```ts -const street = Street.create('Dom Juan').value() as Street; - -const complement = Complement.create('n42').value() as Complement; +const street = await Street.create('Dom Juan'); -const result = Address.create({ street, complement }); +const complement = await Complement.create('n42'); -const address = result.value(); +const address = await Address.create({ street: street!, complement: complement! }); -console.log(address.toObject()); +console.log(await address!.toObject()); > Object `{ @@ -1293,17 +1026,15 @@ This method creates a new instance with the same properties as the current value ```ts -const result = Name.create('Sammy') as Name; +const originalName = await Name.create('Sammy'); -const originalName = result.value(); - -console.log(originalName.value()); +console.log(originalName.get('value')); > "Sammy" const clone = originalName.clone(); -console.log(clone); +console.log(clone.get('value')); > "Sammy" @@ -1315,11 +1046,11 @@ Clone being a new instance does not change the properties of the original value clonedName.change('value', 'Jones'); -console.log(clonedName.value()); +console.log(clonedName.get('value')); > "Jones" -console.log(originalName.value()); +console.log(originalName.get('value')); > "Sammy" @@ -1335,17 +1066,18 @@ const itemPrice = Class(ProductPrice, { value: price }); const itemName = Class(ProductName, { value: name }); const itemQtd = Class(ProductQtd, { value: qtd }); -const { data, result } = ValueObject.createMany([ itemPrice, itemName, itemQtd ]); +const { data, result } = await ValueObject.createMany([ itemPrice, itemName, itemQtd ]); // you check if all value objects are ok -if (result.isFail()) return Result.fail(result.error()); +const results = await result; +if (!results) return null; // you can get instances from iterator data. In the same order as the array -const price = data.next().value() as ProductPrice; // index 0 -const name = data.next().value() as ProductName; // index 1 -const quantity = data.next().value() as ProductQtd; // index 2 +const price = await data.next() as ProductPrice; // index 0 +const name = await data.next() as ProductName; // index 1 +const quantity = await data.next() as ProductQtd; // index 2 -const product = Product.create({ name, price, quantity }); +const product = await Product.create({ name, price, quantity }); ``` @@ -1381,8 +1113,8 @@ export class User extends Entity{ super(props) } - public static create(props: UserProps): Result { - return Result.Ok(new User(props)); + public static create(props: UserProps): Promise { + return Promise.resolve(new User(props)); } } @@ -1396,26 +1128,11 @@ All attributes for an entity must be value object except id. ```ts -const nameAttr = Name.create('James'); -const ageAttr = Age.create(21); - -// always check if value objects are success -const results = Combine([ nameAttr, ageAttr ]); - -console.log(results.isOk()); - -> true - -const name = nameAttr.value(); - -const age = ageAttr.value(); +const name = await Name.create('James'); +const age = await Age.create(21); // if you don't provide a value for the id it will be generated automatically -const result = User.create({ name, age }); - -console.log(result.isOk()); - -> true +const user = await User.create({ name: name!, age: age! }); ``` @@ -1426,9 +1143,7 @@ In the entity, this method aims to transform a domain class into a simple object ```ts -const user = result.value(); - -console.log(user.toObject()); +console.log(await user!.toObject()); > Object `{ @@ -1447,19 +1162,14 @@ you can create an instance by entering an id ```ts -const name = nameAttr.value(); +const name = await Name.create('James'); +const age = await Age.create(21); const id = Id('my-id-value-01'); -const result = User.create({ id, age, name }); - -console.log(result.isOk()); +const user = await User.create({ id, age: age!, name: name! }); -> true - -const user = result.value(); - -console.log(user.toObject()); +console.log(await user!.toObject()); > Object `{ @@ -1479,20 +1189,16 @@ Check if instance is a new entity.
if you do not provide an id the entity wi ```ts // no id provided -const newUserResult = User.create({ name, age }); - -cons newUser = newUserResult.value(); +const newUser = await User.create({ name: name!, age: age! }); -console.log(newUser.isNew()); +console.log(newUser!.isNew()); > true // id provided -const userResult = User.create({ id, name, age }); +const user = await User.create({ id, name: name!, age: age! }); -cons user = userResult.value(); - -console.log(user.isNew()); +console.log(user!.isNew()); > false @@ -1534,12 +1240,12 @@ export class User extends Entity{ return isValidName && isValidAge; } - public static create(props: UserProps): Result { + public static create(props: UserProps): Promise { const isValidRules = this.isValidProps(props); - if(!isValidRules) return Result.fail('invalid props'); + if(!isValidRules) return Promise.resolve(null); - return Result.Ok(new User(props)); + return Promise.resolve(new User(props)); } } @@ -1553,13 +1259,11 @@ in entities you can easily change an attribute with `change` or `set` method ```ts -const result = Name.create('Larry'); - -const newName = result.value(); +const newName = await Name.create('Larry'); -const changed = user.change("name", newName); +const changed = user.change("name", newName!); -console.log(user.get("name").value()); +console.log(user.get("name").get('value')); > "Larry" @@ -1619,12 +1323,12 @@ export class User extends Entity{ return isValidName && isValidAge; } - public static create(props: UserProps): Result { + public static create(props: UserProps): Promise { const isValidRules = User.isValidProps(props); - if(!isValidRules) return Result.fail('invalid props'); + if(!isValidRules) return Promise.resolve(null); - return Result.Ok(new User(props)); + return Promise.resolve(new User(props)); } } @@ -1651,23 +1355,15 @@ you can clone an entity and get a new instance ```ts -const result = User.create({ id, age, name }); - -console.log(result.isOk()); +const user = await User.create({ id, age, name }); -> true + const clonedUser = user!.clone(); -const user = result.value(); + const newName = await Name.create('Luke'); - const clonedUser = user.clone(); + const changed = clonedUser.set('name').to(newName!); - const newNameResult = Name.create('Luke'); - - const newName = newNameResult.value(); - - const changed = clonedUser.set('name').to(newName); - - console.log(user.get('name').value()); + console.log(user.get('name').get('value')); > "James" @@ -1675,7 +1371,7 @@ const user = result.value(); > true - console.log(clonedUser.get('name').value()); + console.log(clonedUser.get('name').get('value')); > "Luke" @@ -1705,11 +1401,9 @@ At any time you can return to a previous state ```ts -const result = User.create({ name, age }); +const user = await User.create({ name, age }); -const user = result.value(); - -console.log(user.toObject()); +console.log(await user!.toObject()); > Object `{ @@ -1756,8 +1450,8 @@ export class Product extends Aggregate{ super(props); } - public static create(props: ProductProps): Result { - return Result.Ok(new Product(props)); + public static create(props: ProductProps): Promise { + return Promise.resolve(new Product(props)); } } @@ -1772,12 +1466,10 @@ Events are stored in memory and are deleted after being triggered. ```ts -const result = Product.create({ name, price }); - -const product = result.value(); +const product = await Product.create({ name, price }); -product.addEvent('eventName', (product) => { - console.log(product.toObject()) +product!.addEvent('eventName', async (product) => { + console.log(await product.toObject()) }); // or alternatively you can create a event handler @@ -1785,8 +1477,8 @@ product.addEvent('eventName', (product) => { class Handler extends EventHandler { constructor() { super({ eventName: 'eventName' }) }; - dispatch(product: Product): void { - const model = product.toObject(); + async dispatch(product: Product): Promise { + const model = await product.toObject(); console.log(model); } } @@ -1823,6 +1515,6 @@ class MyAdapterToDomain implements Adapter{ // You can use adapter instance in toObject function const myAdapter = new MyAdapterToInfra(); -const dataUser = domainUser.toObject(myAdapter); +const dataUser = await domainUser.toObject(myAdapter); -``` +``` \ No newline at end of file diff --git a/lib/core/aggregate.ts b/lib/core/aggregate.ts index fe11716..596db71 100644 --- a/lib/core/aggregate.ts +++ b/lib/core/aggregate.ts @@ -1,9 +1,8 @@ -import { EventHandler, _Result, Settings, Options, UID } from "../types"; +import { EventHandler, Settings, Options, UID } from "../types"; import { EntityProps, EventMetrics, Handler, _Aggregate } from "../types"; import TsEvent from "./events"; import Entity from "./entity"; import ID from "./id"; -import Result from "./result"; import Context from "./context"; import { EventManager } from "../types"; @@ -146,35 +145,36 @@ export class Aggregate extends Entity implemen return totalBefore - this._domainEvents.metrics.totalEvents(); } - public static create(props: any): Result; /** - * @description Creates a new aggregate instance wrapped inside a `Result` object. - * If the provided properties are invalid, returns a failure `Result`. + * @description Creates a new aggregate instance wrapped inside a `Promise` object. + * If the provided properties are invalid, returns a failure `Promise`. * * @param props Properties used to create the aggregate. * @param id (optional) A UUID to assign to the aggregate. If not provided, a new one will be generated. - * @returns A `Result` instance containing the new aggregate if successful. On failure, returns a `Result` with null state. + * @returns A `Promise` instance containing the new aggregate if successful. On failure, returns a `Promise` with null state. * * @example * ```typescript - * const result = MyAggregate.create({ name: "example" }); - * if (result.isFailure) { - * console.error(result.error); // More explicit error message guiding the user to fix invalid properties - * } else { - * const aggregate = result.getValue(); + * const aggregate = await MyAggregate.create({ name: "example" }); + * if (aggregate) { * // Use the aggregate + * } else { + * console.error('Failed to create aggregate'); * } * ``` * * @summary On failure, the error message clearly instructs the user to ensure all required properties * are provided and have valid values. */ - public static create(props: {}): Result { - if (!this.isValidProps(props)) return Result.fail( - `Failed to create an instance of ${this.name} due to invalid properties. ` + - `Please ensure that all required fields are provided and that the values are valid.` - ); - return Result.Ok(new this(props)); + public static create(props: {} | null | undefined): Promise { + if (props === null || props === undefined || !this.isValidProps(props)) { + console.log( + `Failed to create an instance of ${this.name} due to invalid properties. ` + + `Please ensure that all required fields are provided and that the values are valid.` + ); + return Promise.resolve(null); + } + return Promise.resolve(new this(props)); }; } export default Aggregate; diff --git a/lib/core/create-many-domain-instance.ts b/lib/core/create-many-domain-instance.ts index dd24c10..bdb6d79 100644 --- a/lib/core/create-many-domain-instance.ts +++ b/lib/core/create-many-domain-instance.ts @@ -1,7 +1,6 @@ -import { IClass, CreateManyDomain, CreateManyResult, _ManyData, _Result } from "../types"; +import { IClass, CreateManyDomain, CreateManyResult, _ManyData } from "../types"; import validator from "../utils/validator"; import Iterator from "./iterator"; -import Result from "./result"; /** * @description Helper function to create a data structure for constructing domain instances. @@ -29,7 +28,7 @@ export const Class = (domainClass: IClass, props: Props): _ManyData => { * @param data An array of objects, each containing a domain class and properties for instance creation. * @returns A `CreateManyResult` object containing: * - `data`: An iterator over the results of each instance creation attempt. - * - `result`: A combined `Result` indicating if all instances were created successfully or if any failed. + * - `result`: A combined `Promise` indicating if all instances were created successfully or if any failed. * * @example * ```typescript @@ -40,41 +39,49 @@ export const Class = (domainClass: IClass, props: Props): _ManyData => { * ]; * * const { data, result } = createManyDomainInstances(classes); - * if (result.isOk()) { - * const userResult = data.next().value; - * const productResult = data.next().value; - * const orderResult = data.next().value; - * - * // userResult, productResult, and orderResult are all successful `Result` instances. - * } else { - * console.error("Failed to create some domain instances:", result.error); - * } + * result.then(res => { + * if(res) { + * const userResult = data.next(); + * const productResult = data.next(); + * const orderResult = data.next(); + * } + * }) + * * ``` */ export const createManyDomainInstances = (data: CreateManyDomain): CreateManyResult => { - const results: Array<_Result> = []; + const promises: Array> = []; - if (validator.isArray(data)) { + if (validator.isArray(data) && data.length > 0) { for (let index = 0; index < data.length; index++) { const domainInfo = data[index]; const domainClass = domainInfo.class; const existsCreateMethod = typeof domainClass?.create === 'function'; if (!existsCreateMethod) { - results.push(Result.fail(`No static 'create' method found in class ${domainClass?.name}.`)); + console.log(`No static 'create' method found in class ${domainClass?.name}.`); + promises.push(Promise.resolve(null)); continue; } const payload = domainClass.create(domainInfo.props); - results.push(payload); + promises.push(payload); } - } + } else { + const iterator = Iterator.create({ initialData: [], returnCurrentOnReversion: true }); + return { data: iterator, result: Promise.resolve(null) }; + } - const iterator = Iterator.create({ initialData: results, returnCurrentOnReversion: true }); - const result = Result.combine(results); + const iterator = Iterator.create({ initialData: promises, returnCurrentOnReversion: true }); + + const combinedPromise = Promise.all(promises).then(results => { + const failed = results.some(r => r === null); + if(failed) return null; + return results; + }); - return { data: iterator, result }; + return { data: iterator, result: combinedPromise }; } -export default createManyDomainInstances; +export default createManyDomainInstances; \ No newline at end of file diff --git a/lib/core/entity.ts b/lib/core/entity.ts index aa98267..9613431 100644 --- a/lib/core/entity.ts +++ b/lib/core/entity.ts @@ -1,10 +1,9 @@ -import { Adapter, AutoMapperSerializer, EntityMapperPayload, EntityProps, _Adapter, _Entity, _Result, Settings, UID } from "../types"; +import { Adapter, AutoMapperSerializer, EntityMapperPayload, EntityProps, _Adapter, _Entity, Settings, UID } from "../types"; import { ReadonlyDeep } from "../types-util"; import { deepFreeze } from "../utils/deep-freeze.util"; import AutoMapper from "./auto-mapper"; import GettersAndSetters from "./entity-getters-and-setters"; import ID from "./id"; -import Result from "./result"; /** * @description Represents a domain entity identified by a unique identifier (ID). @@ -54,15 +53,16 @@ export class Entity extends GettersAndSetters * @returns If an adapter is provided, returns the adapted object. Otherwise, returns a deeply frozen object * representing the entity properties along with entity metadata (`AutoMapperSerializer & EntityMapperPayload`). */ - toObject(adapter?: Adapter | _Adapter) - : T extends {} + async toObject(adapter?: Adapter | _Adapter) + : Promise & EntityMapperPayload> { + : ReadonlyDeep & EntityMapperPayload>> { if(adapter && typeof (adapter as Adapter)?.adaptOne === 'function') { return (adapter as Adapter).adaptOne(this) as any; } if (adapter && typeof (adapter as _Adapter)?.build === 'function') { - return (adapter as _Adapter).build(this).value() as any; + const result = await (adapter as _Adapter).build(this); + return result as any; } const serializedObject = this.autoMapper.entityToObj(this) as ReadonlyDeep>; const frozenObject = deepFreeze(serializedObject); @@ -140,17 +140,19 @@ export class Entity extends GettersAndSetters }); }; - public static create(props: any): Result; /** - * @description Creates a new entity instance wrapped inside a `Result` object. + * @description Creates a new entity instance wrapped inside a `Promise` object. * @param props The properties to create the entity with. Must be valid properties. * @param id (Optional) A UUID to assign to the entity. If not provided, a new one will be generated. - * @returns A `Result` instance containing the new entity if successfully created; otherwise, a failure `Result`. + * @returns A `Promise` instance containing the new entity if successfully created; otherwise, a failure `Promise`. * @summary If the properties are invalid, the result will be a failure with `null` state. */ - public static create(props: {}): Result { - if (!this.isValidProps(props)) return Result.fail('Invalid props to create an instance of ' + this.name); - return Result.Ok(new this(props)); + public static create(props: {} | null | undefined): Promise { + if (props === null || props === undefined || !this.isValidProps(props)) { + console.log('Invalid props to create an instance of ' + this.name); + return Promise.resolve(null); + } + return Promise.resolve(new this(props)); }; } diff --git a/lib/core/fail.ts b/lib/core/fail.ts deleted file mode 100644 index 863bbf0..0000000 --- a/lib/core/fail.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { _Result } from "../types"; -import Result from "./result"; - -/** - * @description Creates a `Result` instance representing a failure state. - * - * The `Fail` function returns a result indicating that an operation has failed, - * and can optionally include an error message and additional metadata. - * - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param error The error information. If not provided, defaults to a generic error message. - * @param metaData Optional metadata providing additional context about the error. - * - * @returns A `Result` instance with error payload or (`null`) and an error state. The `error` and `metaData` - * types are inferred from the provided arguments. - */ - function Fail(): Result; - -/** - * @description Creates a `Result` instance representing a failure state. - * - * The `Fail` function returns a result indicating that an operation has failed, - * and can optionally include an error message and additional metadata. - * - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param error The error information. If not provided, defaults to a generic error message. - * @param metaData Optional metadata providing additional context about the error. - * - * @returns A `Result` instance with error payload or (`null`) and an error state. The `error` and `metaData` - * types are inferred from the provided arguments. - */ -function Fail(): _Result; - -/** - * @description Creates a `Result` instance representing a failure state. - * - * The `Fail` function returns a result indicating that an operation has failed, - * and can optionally include an error message and additional metadata. - * - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param error The error information. If not provided, defaults to a generic error message. - * @param metaData Optional metadata providing additional context about the error. - * - * @returns A `Result` instance with error payload or (`null`) and an error state. The `error` and `metaData` - * types are inferred from the provided arguments. - */ - function Fail(error: E extends void ? null : E, metaData?: M): Result; - - -/** - * @description Creates a `Result` instance representing a failure state. - * - * The `Fail` function returns a result indicating that an operation has failed, - * and can optionally include an error message and additional metadata. - * - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param error The error information. If not provided, defaults to a generic error message. - * @param metaData Optional metadata providing additional context about the error. - * - * @returns A `Result` instance with error payload or (`null`) and an error state. The `error` and `metaData` - * types are inferred from the provided arguments. - */ -function Fail(error: E extends void ? null : E, metaData?: M): _Result; - -/** - * @description Creates a `Result` instance representing a failure state. - * - * The `Fail` function returns a result indicating that an operation has failed, - * and can optionally include an error message and additional metadata. - * - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param error The error information. If not provided, defaults to a generic error message. - * @param metaData Optional metadata providing additional context about the error. - * - * @returns A `Result` instance with error payload or (`null`) and an error state. The `error` and `metaData` - * types are inferred from the provided arguments. - */ -function Fail(error?: E extends void ? null : E, metaData?: M): _Result { - const _error = (typeof error !== 'undefined' && error !== null) ? error : 'void error. no message!'; - return Result.fail(_error as any, metaData); -} - -export default Fail; -export { Fail }; diff --git a/lib/core/index.ts b/lib/core/index.ts index cb50f94..9ad2142 100644 --- a/lib/core/index.ts +++ b/lib/core/index.ts @@ -5,11 +5,8 @@ export * from './events'; export * from './base-getters-and-setters'; export * from './id'; export * from './iterator'; -export * from './result'; export * from './value-object'; export * from './create-many-domain-instance'; export * from './crypto'; -export * from './ok'; -export * from './fail'; export * from './context'; -export * from './entity-getters-and-setters' +export * from './entity-getters-and-setters' \ No newline at end of file diff --git a/lib/core/ok.ts b/lib/core/ok.ts deleted file mode 100644 index a656819..0000000 --- a/lib/core/ok.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { _Result } from "../types"; -import Result from "./result"; - -/** - * @description Creates a `Result` instance representing a success state. - * - * The `Ok` function returns a result indicating that an operation has succeeded. - * Optionally, it can include a payload (`data`) representing the successful result - * and additional metadata (`metaData`) providing context or supplementary information. - * - * @typeParam P - The payload type. Defaults to `void` if not provided. - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param data An optional payload that represents the successful operation's result. - * If no data is provided, defaults to `null` if `P` is `void`. - * @param metaData Optional metadata providing additional context about the success. - * - * @returns A `Result` instance in a success state with the given payload and metadata. - */ - function Ok(): Result; - -/** - * @description Creates a `Result` instance representing a success state. - * - * The `Ok` function returns a result indicating that an operation has succeeded. - * Optionally, it can include a payload (`data`) representing the successful result - * and additional metadata (`metaData`) providing context or supplementary information. - * - * @typeParam P - The payload type. Defaults to `void` if not provided. - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param data An optional payload that represents the successful operation's result. - * If no data is provided, defaults to `null` if `P` is `void`. - * @param metaData Optional metadata providing additional context about the success. - * - * @returns A `Result` instance in a success state with the given payload and metadata. - */ -function Ok(): _Result; - -/** - * @description Creates a `Result` instance representing a success state. - * - * The `Ok` function returns a result indicating that an operation has succeeded. - * Optionally, it can include a payload (`data`) representing the successful result - * and additional metadata (`metaData`) providing context or supplementary information. - * - * @typeParam P - The payload type. Defaults to `void` if not provided. - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param data An optional payload that represents the successful operation's result. - * If no data is provided, defaults to `null` if `P` is `void`. - * @param metaData Optional metadata providing additional context about the success. - * - * @returns A `Result` instance in a success state with the given payload and metadata. - */ -function Ok(data: P extends void ? null : P, metaData?: M): Result; - -/** - * @description Creates a `Result` instance representing a success state. - * - * The `Ok` function returns a result indicating that an operation has succeeded. - * Optionally, it can include a payload (`data`) representing the successful result - * and additional metadata (`metaData`) providing context or supplementary information. - * - * @typeParam P - The payload type. Defaults to `void` if not provided. - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param data An optional payload that represents the successful operation's result. - * If no data is provided, defaults to `null` if `P` is `void`. - * @param metaData Optional metadata providing additional context about the success. - * - * @returns A `Result` instance in a success state with the given payload and metadata. - */ - function Ok(data: P extends void ? null : P, metaData?: M): _Result; - -/** - * @description Creates a `Result` instance representing a success state. - * - * The `Ok` function returns a result indicating that an operation has succeeded. - * Optionally, it can include a payload (`data`) representing the successful result - * and additional metadata (`metaData`) providing context or supplementary information. - * - * @typeParam P - The payload type. Defaults to `void` if not provided. - * @typeParam E - The error type. Defaults to `string`. - * @typeParam M - The metadata type. Defaults to an empty object `{}`. - * - * @param data An optional payload that represents the successful operation's result. - * If no data is provided, defaults to `null` if `P` is `void`. - * @param metaData Optional metadata providing additional context about the success. - * - * @returns A `Result` instance in a success state with the given payload and metadata. - */ -function Ok(data?: P extends void ? null : P, metaData?: M): _Result { - return Result.Ok(data as P, metaData); -} - -export default Ok; -export { Ok }; diff --git a/lib/core/result.ts b/lib/core/result.ts deleted file mode 100644 index 38b5668..0000000 --- a/lib/core/result.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { ICommand, _Iterator, _Result, ResultExecute, ResultHook, ResultObject, IResultOptions } from "../types"; -import Iterator from "./iterator"; - -/** - * @description The `Result` class represents the outcome of an operation, encapsulating both the success or failure state. - * A `Result` instance can contain a payload (`data`), an error, and optional metadata for additional context. - * This pattern encourages explicit handling of operation success or failure, making your code more robust and expressive. - * - * @typeParam T - The type of the payload when the result is successful. - * @typeParam D - The type of the error when the result is a failure. Defaults to `string`. - * @typeParam M - The type of the metadata object. Defaults to an empty object `{}`. - * - * @example - * ```typescript - * // Creating a success result with data - * const successResult = Result.Ok({ name: "Alice" }); - * if (successResult.isOk()) { - * console.log("Success data:", successResult.value()); - * } - * - * // Creating a failure result with a custom error message - * const failResult = Result.fail("An error occurred"); - * if (failResult.isFail()) { - * console.error("Error:", failResult.error()); - * } - * ``` - */ -export class Result implements _Result { - - #isOk: Readonly; - #isFail: Readonly; - #data: Readonly; - #error: Readonly; - #metaData: Readonly; - - private constructor(isSuccess: boolean, data?: T, error?: D, metaData?: M) { - this.#isOk = isSuccess; - this.#isFail = !isSuccess; - this.#data = data ?? null; - this.#error = error ?? null; - this.#metaData = metaData ?? {} as M; - } - - /** - * @description Creates a success `Result` instance, optionally containing data and metadata. - * - * @returns A `Result` instance representing success. - */ - public static Ok(): Result; - public static Ok(): _Result; - public static Ok(data: T, metaData?: M): Result; - public static Ok(data: T, metaData?: M): _Result; - public static Ok(data?: T, metaData?: M): _Result { - const _data = typeof data === 'undefined' ? null : data; - const ok = new Result(true, _data, null, metaData) as unknown as _Result; - return Object.freeze(ok) as _Result; - } - - /** - * @description Creates a failure `Result` instance, optionally containing an error and metadata. - * - * @returns A `Result` instance representing failure. - */ - public static fail(error?: D, metaData?: M): Result; - public static fail(error?: D, metaData?: M): _Result { - const _error = (typeof error !== 'undefined' && error !== null) ? error : 'void error. no message!'; - const fail = new Result(false, null, _error, metaData) as unknown as _Result; - return Object.freeze(fail) as _Result; - } - - /** - * @description Creates an iterator over a collection of `Result` instances. This allows sequential processing of multiple results. - * @param results An array of `Result` instances. - * @returns An iterator over the provided results. - */ - public static iterate(results?: Array<_Result>): _Iterator<_Result> { - return Iterator.create<_Result>({ initialData: results, returnCurrentOnReversion: true }); - } - - /** - * @description Combines multiple `Result` instances into a single `Result`. - * If any of the provided results is a failure, the combined `Result` is a failure. - * If all results are successful, the combined `Result` is considered a success. - * - * @param results An array of `Result` instances to combine. - * @returns A `Result` instance representing the combined outcome. - */ - public static combine(results: Array<_Result>): _Result { - const iterator = Result.iterate(results); - if (iterator.isEmpty()) return Result.fail('No results provided on combine param' as B) as unknown as _Result; - while (iterator.hasNext()) { - const currentResult = iterator.next(); - if (currentResult.isFail()) return currentResult as _Result; - } - return iterator.first() as _Result; - } - - /** - * @description Executes a command based on the result state. You can specify whether the command executes on success, failure, or both. - * Optionally, you can provide data to the command if required. - * - * @param command An object implementing `ICommand` interface. - * @returns An object with methods to configure command execution based on the `Result` state. - */ - execute(command: ICommand): ResultExecute { - return { - on: (option: IResultOptions): Y | undefined => { - if (option === 'Ok' && this.isOk()) return command.execute(); - if (option === 'fail' && this.isFail()) return command.execute(); - }, - withData: (data: X): ResultHook => { - return { - on: (option: IResultOptions): Y | undefined => { - if (option === 'Ok' && this.isOk()) return command.execute(data); - if (option === 'fail' && this.isFail()) return command.execute(data); - } - } - } - }; - } - - /** - * @description Retrieves the payload of the `Result`. If the `Result` is a failure, `value()` returns `null`. - * @returns The payload `T` or `null` if the result is a failure. - */ - value(): T { - return this.#data as T; - } - - /** - * @description Retrieves the error of the `Result`. If the `Result` is a success, `error()` returns `null`. - * @returns The error `D` or `null` if the result is a success. - */ - error(): D { - return this.#error as D; - } - - /** - * @description Determines if the `Result` represents a failure state. - * @returns `true` if the result is a failure, `false` if it is a success. - */ - isFail(): boolean { - return this.#isFail; - } - - /** - * @description Checks if the `Result` payload is `null`. - * This can be useful for confirming the presence or absence of a value before proceeding. - * @returns `true` if the payload is `null`, `false` otherwise. - */ - isNull(): boolean { - return this.#data === null || this.#isFail; - } - - /** - * @description Determines if the `Result` represents a success state. - * @returns `true` if the result is a success, `false` if it is a failure. - */ - isOk(): boolean { - return this.#isOk; - } - - /** - * @description Retrieves the metadata associated with the `Result`. - * @returns The metadata object `M`, or `{}` if no metadata was provided. - */ - metaData(): M { - const metaData = this.#metaData; - return Object.freeze(metaData); - } - - /** - * @description Converts the `Result` instance into a plain object for easier logging or serialization. - * @returns An object containing `isOk`, `isFail`, `data`, `error`, and `metaData`. - */ - toObject(): ResultObject { - const metaData = { - isOk: this.#isOk, - isFail: this.#isFail, - data: this.#data as T | null, - error: this.#error as D | null, - metaData: this.#metaData as M - } - - return Object.freeze(metaData); - } -} - -export default Result; -export const Combine = Result.combine; diff --git a/lib/core/value-object.ts b/lib/core/value-object.ts index 483c789..5d73700 100644 --- a/lib/core/value-object.ts +++ b/lib/core/value-object.ts @@ -1,9 +1,8 @@ -import { Adapter, AutoMapperSerializer, _Adapter, _Result, _ValueObject, _VoSettings, UID } from "../types"; +import { Adapter, AutoMapperSerializer, _Adapter, _ValueObject, _VoSettings, UID } from "../types"; import { ReadonlyDeep } from "../types-util"; import { deepFreeze } from "../utils/deep-freeze.util"; import AutoMapper from "./auto-mapper"; import BaseGettersAndSetters from "./base-getters-and-setters"; -import Result from "./result"; /** * @description A `ValueObject` represents a domain object characterized by its properties rather than a unique identifier. @@ -107,13 +106,14 @@ export class ValueObject extends BaseGettersAndSetters implements * @param adapter Optional adapter to transform the value object into a custom format. * @returns A deeply frozen, plain object representation of the value object properties. */ - toObject(adapter?: Adapter | _Adapter) - : T extends {} ? T : ReadonlyDeep> { + async toObject(adapter?: Adapter | _Adapter) + : Promise>> { if (adapter && typeof (adapter as Adapter)?.adaptOne === 'function') { return (adapter as Adapter).adaptOne(this) as any; } if (adapter && typeof (adapter as _Adapter)?.build === 'function') { - return (adapter as _Adapter).build(this).value() as any; + const result = await (adapter as _Adapter).build(this); + return result as any; } const serializedObject = this.autoMapper.valueObjectToObj(this) as ReadonlyDeep>; const frozenObject = deepFreeze(serializedObject); @@ -151,16 +151,18 @@ export class ValueObject extends BaseGettersAndSetters implements }); } - public static create(props: any): _Result; /** - * @description Creates a new ValueObject instance wrapped inside a `Result`. - * Returns a failure `Result` if the provided properties are invalid. + * @description Creates a new ValueObject instance wrapped inside a `Promise`. + * Returns a failure `Promise` if the provided properties are invalid. * @param props The properties needed to create the value object. - * @returns A `Result` containing the new ValueObject on success, or a failure `Result` on invalid properties. + * @returns A `Promise` containing the new ValueObject on success, or a failure `Promise` on invalid properties. */ - public static create(props: {}): Result { - if (!this.isValidProps(props)) return Result.fail('Invalid props to create an instance of ' + this.name); - return Result.Ok(new this(props)); + public static create(props: {} | null | undefined): Promise { + if (props === null || props === undefined || !this.isValidProps(props)) { + console.log('Invalid props to create an instance of ' + this.name); + return Promise.resolve(null); + } + return Promise.resolve(new this(props)); } } diff --git a/lib/types.ts b/lib/types.ts index 611b3be..1220080 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -49,74 +49,6 @@ export type EventType = { callback: (...args: any[]) => void | Promise; }; -/** - * @interface - * @description Represents the result of an operation, encapsulating its state, value, error, and metadata. - * @template T The type of the result's value. - * @template D The type of the result's error (default: string). - * @template M The type of the result's metadata (default: empty object). - */ -export interface _Result { - /** - * @description Retrieves the value of the result. Returns null if the result represents a failure. - * @returns The result's value or null. - */ - value(): T; - - /** - * @description Retrieves the error of the result. Returns null if the result represents success. - * @returns The result's error or null. - */ - error(): D; - - /** - * @description Checks if the result represents a failure. - * @returns True if the result is a failure, false otherwise. - */ - isFail(): boolean; - - /** - * @description Checks if the result contains a null value. - * @returns True if the value is null, false otherwise. - */ - isNull(): boolean; - - /** - * @description Checks if the result represents success. - * @returns True if the result is a success, false otherwise. - */ - isOk(): boolean; - - /** - * @description Retrieves the metadata associated with the result. - * @returns The result's metadata. - */ - metaData(): M; - - /** - * @description Converts the result into an object representing its current state. - * @returns An object containing the result's value, error, and metadata. - */ - toObject(): ResultObject; - - /** - * @description Executes a command based on the result's state (success or failure). - * @template X The input type for the command. - * @template Y The output type of the command. - * @param command The command to execute. - * @returns An object containing hooks for further execution. - */ - execute: (command: ICommand) => ResultExecute; -} - -export type IResult = _Result - -/** - * @typedef - * @description Alias for `_Result`, used for convenience. - */ -export type Payload = _Result; - /** * @description Represents the payload passed to an event handler. */ @@ -181,17 +113,6 @@ export interface _Iterator { removeItem(item: T): void; } - - - -/** - * @description Represents the possible states of a result: success (`Ok`) or failure (`fail`). - */ -export type IResultOptions = 'fail' | 'Ok'; - -/** Alias for result options, allowing either `fail` or `Ok` states. */ -export type ResultOptions = 'fail' | 'Ok'; - /** * @interface * @description Represents a command that executes an operation with a specific input and output type. @@ -250,46 +171,6 @@ export interface Settings extends _VoSettings { disableSetters?: boolean; } -/** - * @interface - * @description Represents the state of a result, including its value, error, and metadata. - * @template T The type of the result's value. - * @template D The type of the result's error. - * @template M The type of the result's metadata. - */ -export interface ResultObject { - isOk: boolean; // Indicates if the result is successful. - isFail: boolean; // Indicates if the result is a failure. - data: T | null; // The value of the result, or null if failed. - error: D | null; // The error of the result, or null if successful. - metaData: M; // Additional metadata associated with the result. -} - -/** - * @interface - * @description Hook for handling specific result states during execution. - * @template Y The type of the hook's output. - */ -export interface ResultHook { - /** - * Executes a function based on the result state. - * @param option The result state to handle (`Ok` or `fail`). - * @returns The result of the function execution, if applicable. - */ - on(option: IResultOptions): Y | undefined; -} - -/** - * @interface - * @description Extends `ResultHook` with support for data input. - * @template X The input type for the hook. - * @template Y The output type for the hook. - */ -export interface ResultExecute extends ResultHook { - /** Provides data to the hook before executing. */ - withData(data: X): ResultHook; -} - /** Represents an empty object. */ export type OBJ = {}; @@ -320,15 +201,13 @@ export type PropsValidation = { * @description Represents an adapter that transforms one type to another. * @template F The input type. * @template T The output type. - * @template E The error type (default: any). - * @template M The metadata type (default: any). */ -export interface _Adapter { +export interface _Adapter { /** Builds the target type from the input type. */ - build(target: F): _Result; + build(target: F): Promise; } -export type IAdapter = _Adapter; +export type IAdapter = _Adapter; /** * @interface @@ -351,14 +230,14 @@ export interface Adapter { */ export interface _Entity { /** Converts the entity into an object, optionally using an adapter. */ - toObject(adapter?: _Adapter<_Entity, any>): T extends {} + toObject(adapter?: _Adapter): Promise> & EntityMapperPayload; + : ReadonlyDeep> & EntityMapperPayload>; get id(): UID; // The unique identifier of the entity. hashCode(): UID; // Returns a hash code for the entity. isNew(): boolean; // Checks if the entity is newly created. - clone(): _Entity; // Creates a clone of the entity. + clone(props?: Partial): _Entity; // Creates a clone of the entity. } /** @@ -368,10 +247,10 @@ export interface _Entity { */ export interface _ValueObject { /** Clones the value object. */ - clone(): _ValueObject; + clone(props?: Props extends object ? Partial : never): _ValueObject; /** Converts the value object into a serializable format, optionally using an adapter. */ - toObject(adapter?: _Adapter): T extends {} ? T : ReadonlyDeep>; + toObject(adapter?: _Adapter): Promise>>; } @@ -460,9 +339,9 @@ export interface _Aggregate { * @param adapter An optional adapter for transforming the aggregate. * @returns The serialized object with metadata. */ - toObject(adapter?: _Adapter): T extends {} + toObject(adapter?: _Adapter): Promise & EntityMapperPayload>; + : ReadonlyDeep & EntityMapperPayload>>; /** The unique identifier of the aggregate. */ get id(): UID; @@ -474,7 +353,7 @@ export interface _Aggregate { isNew(): boolean; /** Creates a deep clone of the aggregate. */ - clone(): _Entity; + clone(props?: Partial & { copyEvents?: boolean }): _Aggregate; /** Removes an event from the aggregate's event context. */ deleteEvent(eventName: string): void; @@ -539,10 +418,10 @@ export type CreateManyDomain = Array<_ManyData>; */ export interface CreateManyResult { /** Iterator over the results of the creation process. */ - data: _Iterator<_Result>; + data: _Iterator>; /** Combined result of the creation process. */ - result: _Result; + result: Promise; } /** Empty class type. */ @@ -631,7 +510,7 @@ export abstract class EventHandler { /** * Dispatches the event to its handler. * @param aggregate - The associated aggregate instance. - * @param args - Arguments for the event handler. + _ * @param args - Arguments for the event handler. * @returns A promise or void, depending on the handler's implementation. */ abstract dispatch(aggregate: T, args: [DEvent, any[]]): Promise | void; @@ -642,4 +521,4 @@ export abstract class EventHandler { * @returns A promise or void, depending on the handler's implementation. */ abstract dispatch(...args: HandlerArgs): Promise | void; -} +} \ No newline at end of file diff --git a/tests/core/adapter.spec.ts b/tests/core/adapter.spec.ts index e612533..b9b77f3 100644 --- a/tests/core/adapter.spec.ts +++ b/tests/core/adapter.spec.ts @@ -1,5 +1,5 @@ -import { ValueObject, Entity, Result, Ok, Fail } from '../../lib/core'; -import { Adapter, _Adapter, _Result } from '../../lib/types'; +import { ValueObject, Entity } from '../../lib/core'; +import { Adapter, _Adapter } from '../../lib/types'; describe('adapter v1', () => { @@ -10,8 +10,8 @@ describe('adapter v1', () => { super(props); } - public static create(props: NameProps): _Result { - return Result.Ok(new DomainName(props)); + public static create(props: NameProps): Promise { + return Promise.resolve(new DomainName(props)); } } @@ -23,8 +23,8 @@ describe('adapter v1', () => { super(props) } - public static create(props: UserProps): Result { - return Result.Ok(new DomainUser(props)); + public static async create(props: UserProps): Promise { + return Promise.resolve(new DomainUser(props)); } } @@ -36,10 +36,12 @@ describe('adapter v1', () => { } class DomainUserAdapter implements _Adapter { - build(target: Model): _Result { + async build(target: Model): Promise { + const name = await DomainName.create({ value: target.name }); + if(!name) return null; return DomainUser.create({ id: target.id, - name: DomainName.create({ value: target.name }).value(), + name, createdAt: target.createdAt, updatedAt: target.updatedAt }); @@ -47,10 +49,9 @@ describe('adapter v1', () => { } class DataUserAdapter implements _Adapter { - build(target: DomainUser): _Result { - - return Result.Ok({ - id: target.get('id'), + async build(target: DomainUser): Promise { + return Promise.resolve({ + id: target.id.value(), createdAt: target.get('createdAt') as Date, updatedAt: target.get('updatedAt') as Date, name: target.get('name').get('value') @@ -65,34 +66,34 @@ describe('adapter v1', () => { updatedAt: new Date('2020-01-01T05:00:23.000Z') } - const name = DomainName.create({ value: userModel.name }).value(); - const domainUser = DomainUser.create({ ...userModel, name }).value(); - describe('from data layer to domain', () => { - it('should a domain entity from data layer with success', () => { + it('should a domain entity from data layer with success', async () => { const adapter = new DomainUserAdapter(); - const domainUser = adapter.build(userModel); + const domainUser = await adapter.build(userModel); - expect(domainUser.isOk()).toBeTruthy(); - expect(domainUser.value().get('name').get('value')).toBe('John Stuart'); - expect(domainUser.value().id.value()).toBe('valid_id'); - expect(domainUser.value().get('createdAt')).toEqual(new Date('2020-01-01T04:00:23.000Z')); - expect(domainUser.value().get('updatedAt')).toEqual(new Date('2020-01-01T05:00:23.000Z')); + expect(domainUser).not.toBeNull(); + expect(domainUser?.get('name').get('value')).toBe('John Stuart'); + expect(domainUser?.id.value()).toBe('valid_id'); + expect(domainUser?.get('createdAt')).toEqual(new Date('2020-01-01T04:00:23.000Z')); + expect(domainUser?.get('updatedAt')).toEqual(new Date('2020-01-01T05:00:23.000Z')); }); }); describe('from domain to data layer', () => { - it('should create a model from domain with success', () => { + it('should create a model from domain with success', async () => { const adapter = new DataUserAdapter(); + const name = await DomainName.create({ value: userModel.name }); + const domainUser = await DomainUser.create({ ...userModel, name: name! }); + const model = await adapter.build(domainUser!); - const model = adapter.build(domainUser); - - expect(model.value()).toEqual(userModel); + expect(model).toEqual(userModel); }); - it('should toObject method use adapter', () => { + it('should toObject method use adapter', async () => { const adapter = new DataUserAdapter(); - const model = domainUser.toObject(adapter); + const name = await DomainName.create({ value: userModel.name }); + const domainUser = await DomainUser.create({ ...userModel, name: name! }); + const model = await domainUser!.toObject(adapter); expect(model).toEqual(userModel); }) }); @@ -101,27 +102,25 @@ describe('adapter v1', () => { type In = { a: number }; type Out = { b: string }; - type Err = { err: string; stack?: string }; - class CustomAdapter implements _Adapter { - build(target: In): _Result { - if (typeof target.a !== 'number') return Fail({ err: 'target.a is not a number' }); - return Ok({ b: target.a.toString() }); + class CustomAdapter implements _Adapter { + async build(target: In): Promise { + if (typeof target.a !== 'number') return null; + return { b: target.a.toString() }; } } const adapter = new CustomAdapter(); - it('should return a success payload', () => { - const result = adapter.build({ a: 200 }); - expect(result.isOk()).toBeTruthy(); - expect(result.value()).toEqual({ b: '200' }); + it('should return a success payload', async () => { + const result = await adapter.build({ a: 200 }); + expect(result).not.toBeNull(); + expect(result).toEqual({ b: '200' }); }); - it('should return a custom error', () => { - const result = adapter.build({ a: null as any }); - expect(result.isFail()).toBeTruthy(); - expect(result.error()).toEqual({ err: 'target.a is not a number' }); + it('should return a custom error', async () => { + const result = await adapter.build({ a: null as any }); + expect(result).toBeNull(); }); }); }); @@ -162,4 +161,4 @@ describe('adapter v2', () => { expect(values).toEqual(['1', '2', '3']) }); }); -}); +}); \ No newline at end of file diff --git a/tests/core/aggregate.spec.ts b/tests/core/aggregate.spec.ts index f51bf8d..e98ffe3 100644 --- a/tests/core/aggregate.spec.ts +++ b/tests/core/aggregate.spec.ts @@ -1,5 +1,5 @@ -import { Aggregate, ID, Ok, Result, TsEvents, ValueObject } from "../../lib/core"; -import { DEvent, EventHandler, _Result, Settings, UID } from "../../lib/types"; +import { Aggregate, ID, TsEvents, ValueObject } from "../../lib/core"; +import { DEvent, EventHandler, Settings, UID } from "../../lib/types"; describe('aggregate', () => { @@ -16,21 +16,21 @@ describe('aggregate', () => { } } - it('should return fails if provide a null value', () => { - const obj = AggregateErr.create(null); - expect(obj.isFail()).toBeTruthy(); + it('should return fails if provide a null value', async () => { + const obj = await AggregateErr.create(null); + expect(obj).toBeNull(); }); - it('should return fails if provide an undefined value', () => { - const obj = AggregateErr.create(undefined); - expect(obj.isFail()).toBeTruthy(); + it('should return fails if provide an undefined value', async () => { + const obj = await AggregateErr.create(undefined); + expect(obj).toBeNull(); }); - it('should create a valid aggregate', () => { - const obj = AggregateErr.create({ id: '23366cbf-86cd-4de3-874a-5a11b4fe5dac', name: 'Jane' }); - expect(obj.isFail()).toBeFalsy(); - expect(obj.value().get('name')).toBe('Jane'); - expect(obj.value().hashCode().value()).toBe('[Aggregate@AggregateErr]:23366cbf-86cd-4de3-874a-5a11b4fe5dac') + it('should create a valid aggregate', async () => { + const obj = await AggregateErr.create({ id: '23366cbf-86cd-4de3-874a-5a11b4fe5dac', name: 'Jane' }); + expect(obj).not.toBeNull(); + expect(obj?.get('name')).toBe('Jane'); + expect(obj?.hashCode().value()).toBe('[Aggregate@AggregateErr]:23366cbf-86cd-4de3-874a-5a11b4fe5dac') }); }); @@ -47,57 +47,57 @@ describe('aggregate', () => { super(props) } - public static create(props: Props): Result { - return Result.Ok(new BasicAggregate(props)); + public static create(props: Props): Promise { + return Promise.resolve(new BasicAggregate(props)); } } - it('should create a basic aggregate with success', () => { + it('should create a basic aggregate with success', async () => { - const agg = BasicAggregate.create({ name: 'Jane Doe', age: 21 }); + const agg = await BasicAggregate.create({ name: 'Jane Doe', age: 21 }); - expect(agg.value().id).toBeDefined(); + expect(agg?.id).toBeDefined(); - expect(agg.value().isNew()).toBeTruthy(); + expect(agg?.isNew()).toBeTruthy(); - expect(agg.value().get('name')).toBe('Jane Doe'); + expect(agg?.get('name')).toBe('Jane Doe'); }); - it('should create a basic aggregate with a provided id', () => { - const agg = BasicAggregate.create({ + it('should create a basic aggregate with a provided id', async () => { + const agg = await BasicAggregate.create({ id: '8b51a5a2-d47a-4431-884a-4c7d77e1a201', name: 'Jane Doe', age: 18 }); - expect(agg.value().isNew()).toBeFalsy(); + expect(agg?.isNew()).toBeFalsy(); - expect(agg.value().hashCode().value()) + expect(agg?.hashCode().value()) .toBe('[Aggregate@BasicAggregate]:8b51a5a2-d47a-4431-884a-4c7d77e1a201'); }); - it('should change attributes values with default function', () => { - const agg = BasicAggregate.create({ name: 'Jane Doe', age: 23 }); + it('should change attributes values with default function', async () => { + const agg = await BasicAggregate.create({ name: 'Jane Doe', age: 23 }); - expect(agg.value().id.value()).toBeDefined(); + expect(agg?.id.value()).toBeDefined(); - expect(agg.value().get('name')).toBe('Jane Doe'); - expect(agg.value().get('age')).toBe(23); + expect(agg?.get('name')).toBe('Jane Doe'); + expect(agg?.get('age')).toBe(23); - const setAge = agg.value().set('age').to(18); - const setName = agg.value().set('name').to('Anne'); + const setAge = agg?.set('age').to(18); + const setName = agg?.set('name').to('Anne'); expect(setAge).toBeTruthy(); expect(setName).toBeTruthy(); - expect(agg.value().get('age')).toBe(18); - expect(agg.value().get('name')).toBe('Anne'); + expect(agg?.get('age')).toBe(18); + expect(agg?.get('name')).toBe('Anne'); - const changedAge = agg.value().change('age', 21); - const changedName = agg.value().change('name', 'Louse'); + const changedAge = agg?.change('age', 21); + const changedName = agg?.change('name', 'Louse'); expect(changedName).toBeTruthy(); expect(changedAge).toBeTruthy(); - expect(agg.value().get('age')).toBe(21); - expect(agg.value().get('name')).toBe('Louse'); + expect(agg?.get('age')).toBe(21); + expect(agg?.get('name')).toBe('Louse'); }); }); @@ -114,9 +114,9 @@ describe('aggregate', () => { return this.validator.number(value).isBetween(0, 130); } - public static create(props: Props): Result | null> { - if (!this.isValidValue(props.value)) return Result.fail('Invalid value'); - return Result.Ok(new AgeVo(props)); + public static create(props: Props): Promise | null> { + if (!this.isValidValue(props.value)) return Promise.resolve(null); + return Promise.resolve(new AgeVo(props)); } } @@ -142,24 +142,24 @@ describe('aggregate', () => { super(props); } - public static create(props: AggProps): Result | null> { - return Result.Ok(new UserAgg(props)); + public static create(props: AggProps): Promise | null> { + return Promise.resolve(new UserAgg(props)); } } - it('should create a user with success', () => { + it('should create a user with success', async () => { - const age = AgeVo.create({ value: 21 }).value() as AgeVo; - const user = UserAgg.create({ age }); + const age = await AgeVo.create({ value: 21 }) as AgeVo; + const user = await UserAgg.create({ age }); - expect(user.isOk()).toBeTruthy(); + expect(user).not.toBeNull(); }); - it('should get value from age with success', () => { + it('should get value from age with success', async () => { - const age = AgeVo.create({ value: 21 }).value() as AgeVo; - const user = UserAgg.create({ age }).value(); + const age = await AgeVo.create({ value: 21 }) as AgeVo; + const user = await UserAgg.create({ age }); const result = (user as Aggregate) .get('age') @@ -184,131 +184,133 @@ describe('aggregate', () => { super(props); } - public static create(props: AggProps): Result> { - return Result.Ok(new UserAgg(props)); + public static create(props: AggProps): Promise | null> { + return Promise.resolve(new UserAgg(props)); } } - it('should create a new date if props are defined on props', () => { - const agg = UserAgg.create({ name: 'Leticia' }); + it('should create a new date if props are defined on props', async () => { + const agg = await UserAgg.create({ name: 'Leticia' }); - expect(agg.value().get('createdAt')).toBeDefined(); - expect(agg.value().get('createdAt')).toBeDefined(); - expect(agg.value().toObject().name).toBe('Leticia'); + expect(agg?.get('createdAt')).toBeDefined(); + expect(agg?.get('createdAt')).toBeDefined(); + const obj = await agg!.toObject(); + expect(obj.name).toBe('Leticia'); }); - it('should create a date from props if provide value', () => { + it('should create a date from props if provide value', async () => { process.env.TZ = 'UTC'; const createdAt = new Date('2022-01-01T03:00:00.000Z'); const updatedAt = new Date('2022-01-01T03:00:00.000Z'); - const agg = UserAgg.create({ name: 'Leticia', createdAt, updatedAt }); + const agg = await UserAgg.create({ name: 'Leticia', createdAt, updatedAt }); - expect(agg.value().get('createdAt')).toEqual(new Date('2022-01-01T03:00:00.000Z')); - expect(agg.value().get('updatedAt')).toEqual(new Date('2022-01-01T03:00:00.000Z')); + expect(agg?.get('createdAt')).toEqual(new Date('2022-01-01T03:00:00.000Z')); + expect(agg?.get('updatedAt')).toEqual(new Date('2022-01-01T03:00:00.000Z')); }); - it('should update a the value of updatedAt if change some prop', () => { + it('should update a the value of updatedAt if change some prop', async () => { process.env.TZ = 'UTC'; const createdAt = new Date('2022-01-01T03:00:00.000Z'); const updatedAt = new Date('2022-01-01T03:00:00.000Z'); - const agg = UserAgg.create({ name: 'Leticia', createdAt, updatedAt }); - expect(agg.value().get('updatedAt')).toEqual(new Date('2022-01-01T03:00:00.000Z')); - agg.value().set('name').to('Lana'); - expect(agg.value().get('updatedAt')).not.toEqual(new Date('2022-01-01T03:00:00.000Z')); + const agg = await UserAgg.create({ name: 'Leticia', createdAt, updatedAt }); + expect(agg?.get('updatedAt')).toEqual(new Date('2022-01-01T03:00:00.000Z')); + agg?.set('name').to('Lana'); + expect(agg?.get('updatedAt')).not.toEqual(new Date('2022-01-01T03:00:00.000Z')); }); it('should add domain event [3]', async () => { - const agg = UserAgg.create({ name: 'Jane' }).value(); + const agg = await UserAgg.create({ name: 'Jane' }); - agg.addEvent('someEvent', () => { + agg?.addEvent('someEvent', () => { console.log('event'); }); - expect(agg.eventsMetrics.current).toBe(1); - agg.deleteEvent('someEvent'); - expect(agg.eventsMetrics.current).toBe(0); + expect(agg?.eventsMetrics.current).toBe(1); + agg?.deleteEvent('someEvent'); + expect(agg?.eventsMetrics.current).toBe(0); }); it('should dispatch domain event from aggregate', async () => { - const agg = UserAgg.create({ name: 'Jane' }).value(); + const agg = await UserAgg.create({ name: 'Jane' }); - agg.addEvent('hello', (agg) => { + agg?.addEvent('hello', (agg) => { console.log(agg.get('name')); }); - expect(agg.eventsMetrics.total).toBe(1); + expect(agg?.eventsMetrics.total).toBe(1); - await agg.dispatchEvent("hello"); + await agg?.dispatchEvent("hello"); - expect(agg.eventsMetrics.current).toBe(0); + expect(agg?.eventsMetrics.current).toBe(0); }); it('should dispatch all domain events from aggregate', async () => { - const agg = UserAgg.create({ name: 'Jane' }).value(); + const agg = await UserAgg.create({ name: 'Jane' }); - agg.addEvent('event1', () => { }); - agg.addEvent('event2', () => { }); + agg?.addEvent('event1', () => { }); + agg?.addEvent('event2', () => { }); - expect(agg.eventsMetrics.current).toBe(2); + expect(agg?.eventsMetrics.current).toBe(2); - await agg.dispatchAll(); + await agg?.dispatchAll(); - expect(agg.eventsMetrics.current).toBe(0); - expect(agg.eventsMetrics.dispatch).toBe(2); + expect(agg?.eventsMetrics.current).toBe(0); + expect(agg?.eventsMetrics.dispatch).toBe(2); }); it('should add domain event [1] with the same name', async () => { - const agg = UserAgg.create({ name: 'Jane' }).value(); + const agg = await UserAgg.create({ name: 'Jane' }); - agg.addEvent('unique', () => { }); - agg.addEvent('unique', () => { }); + agg?.addEvent('unique', () => { }); + agg?.addEvent('unique', () => { }); - expect(agg.eventsMetrics.current).toBe(1); - await agg.dispatchAll(); - expect(agg.eventsMetrics.current).toBe(0); + expect(agg?.eventsMetrics.current).toBe(1); + await agg?.dispatchAll(); + expect(agg?.eventsMetrics.current).toBe(0); }); - it('should change id', () => { - const agg = UserAgg.create({ + it('should change id', async () => { + const agg = await UserAgg.create({ name: 'James Stuart', id: 'valid_id' }); - const user = agg.value(); - expect(user.id.value()).toBe('valid_id'); - expect(user.get('id')).toBe('valid_id'); + const user = agg; + expect(user?.id.value()).toBe('valid_id'); + expect(user?.get('id')).toBe('valid_id'); - user.set('id').to('changed_id'); - expect(user.id.value()).toBe('changed_id'); - expect(user.get('id')).toBe("changed_id"); + user?.set('id').to('changed_id'); + expect(user?.id.value()).toBe('changed_id'); + expect(user?.get('id')).toBe("changed_id"); - expect(user.toObject().id).toBe('changed_id'); + const obj = await user!.toObject(); + expect(obj.id).toBe('changed_id'); - user.change('id', 'new_changed_id'); + user?.change('id', 'new_changed_id'); - expect(user.id.value()).toBe('new_changed_id'); - expect(user.get('id')).toBe("new_changed_id"); + expect(user?.id.value()).toBe('new_changed_id'); + expect(user?.get('id')).toBe("new_changed_id"); - user.change('id', ID.create('new uuid') as any); + user?.change('id', ID.create('new uuid') as any); - expect(user.get('id')).toBe("new uuid"); + expect(user?.get('id')).toBe("new uuid"); - user.set('id').to(ID.create('new uuid2') as any); + user?.set('id').to(ID.create('new uuid2') as any); - expect(user.get('id')).toBe("new uuid2"); + expect(user?.get('id')).toBe("new uuid2"); - user.change('id', 9887822939 as any); - expect(user.get('id')).toBe("9887822939"); + user?.change('id', 9887822939 as any); + expect(user?.get('id')).toBe("9887822939"); - user.set('id').to(7454 as any); - expect(user.get('id')).toBe("7454"); + user?.set('id').to(7454 as any); + expect(user?.get('id')).toBe("7454"); }) }); describe('aggregate with domain id', () => { - it('should be success if define id as UID', () => { + it('should be success if define id as UID', async () => { interface Props { id: UID; @@ -322,23 +324,24 @@ describe('aggregate', () => { super(props) } - public static create(props: Props): Result { - return Result.Ok(new Product(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Product(props)); } } - const result = Product.create({ + const result = await Product.create({ id: ID.create('fd15df0c-af60-45ce-9976-33c6197e5ca0'), name: 'James', createdAt: new Date(), updatedAt: new Date() }); - const id = result.value().toObject().id; + const obj = await result!.toObject(); + const id = obj.id; expect(id).toBe('fd15df0c-af60-45ce-9976-33c6197e5ca0'); - expect(result.value().id.value()).toBe('fd15df0c-af60-45ce-9976-33c6197e5ca0'); - expect(result.value().get('id').value()).toBe('fd15df0c-af60-45ce-9976-33c6197e5ca0'); + expect(result?.id.value()).toBe('fd15df0c-af60-45ce-9976-33c6197e5ca0'); + expect(result?.get('id').value()).toBe('fd15df0c-af60-45ce-9976-33c6197e5ca0'); }) }); @@ -348,15 +351,15 @@ describe('aggregate', () => { class Agg extends Aggregate<{ key: string }> { }; const spy = jest.fn(); - const agg = Agg.create({ key: 'some' }).value(); - agg.addEvent('event', spy); + const agg = await Agg.create({ key: 'some' }); + agg?.addEvent('event', spy); - expect(agg.eventsMetrics.current).toBe(1); - expect(agg.eventsMetrics.dispatch).toBe(0); + expect(agg?.eventsMetrics.current).toBe(1); + expect(agg?.eventsMetrics.dispatch).toBe(0); - await agg.dispatchAll(); - expect(agg.eventsMetrics.current).toBe(0); - expect(agg.eventsMetrics.dispatch).toBe(1); + await agg?.dispatchAll(); + expect(agg?.eventsMetrics.current).toBe(0); + expect(agg?.eventsMetrics.dispatch).toBe(1); expect(spy).toHaveBeenCalled(); @@ -366,30 +369,30 @@ describe('aggregate', () => { class Agg extends Aggregate<{ key: string }> { }; - const agg = Agg.create({ key: 'some' }).value(); - agg.addEvent('event', () => { }, { priority: 1 }); + const agg = await Agg.create({ key: 'some' }); + agg?.addEvent('event', () => { }, { priority: 1 }); - expect(agg.eventsMetrics.current).toBe(1); - expect(agg.eventsMetrics.dispatch).toBe(0); + expect(agg?.eventsMetrics.current).toBe(1); + expect(agg?.eventsMetrics.dispatch).toBe(0); - agg.clearEvents({ resetMetrics: true }); + agg?.clearEvents({ resetMetrics: true }); - expect(agg.eventsMetrics.current).toBe(0); - expect(agg.eventsMetrics.dispatch).toBe(0); + expect(agg?.eventsMetrics.current).toBe(0); + expect(agg?.eventsMetrics.dispatch).toBe(0); - const aggB = Agg.create({ key: 'some' }).value(); + const aggB = await Agg.create({ key: 'some' }); - aggB.addEvent('event1', () => { }); - aggB.dispatchEvent('event1'); - expect(aggB.eventsMetrics.dispatch).toBe(1); + aggB?.addEvent('event1', () => { }); + aggB?.dispatchEvent('event1'); + expect(aggB?.eventsMetrics.dispatch).toBe(1); - aggB.addEvent('event2', () => { }); - expect(aggB.eventsMetrics.current).toBe(1); - expect(aggB.eventsMetrics.dispatch).toBe(1); + aggB?.addEvent('event2', () => { }); + expect(aggB?.eventsMetrics.current).toBe(1); + expect(aggB?.eventsMetrics.dispatch).toBe(1); - aggB.clearEvents({ resetMetrics: false }); - expect(aggB.eventsMetrics.current).toBe(0); - expect(aggB.eventsMetrics.dispatch).toBe(1); + aggB?.clearEvents({ resetMetrics: false }); + expect(aggB?.eventsMetrics.current).toBe(0); + expect(aggB?.eventsMetrics.dispatch).toBe(1); }); it('should clone aggregate with events', async () => { @@ -397,34 +400,34 @@ describe('aggregate', () => { interface Props { key: string }; class Agg extends Aggregate { - public static create(props: Props): Result { - return Result.Ok(new Agg(props)) + public static create(props: Props): Promise { + return Promise.resolve(new Agg(props)) } }; - const agg = Agg.create({ key: 'some' }).value(); + const agg = await Agg.create({ key: 'some' }); - agg.addEvent('eventA', () => { }); - agg.addEvent('eventB', () => { }); + agg?.addEvent('eventA', () => { }); + agg?.addEvent('eventB', () => { }); - expect(agg.eventsMetrics.current).toBe(2); - expect(agg.eventsMetrics.dispatch).toBe(0); + expect(agg?.eventsMetrics.current).toBe(2); + expect(agg?.eventsMetrics.dispatch).toBe(0); - const copy = agg.clone({ copyEvents: true, key: 'changed' }); + const copy = agg?.clone({ copyEvents: true, key: 'changed' }); - expect(copy.eventsMetrics.current).toBe(2); - expect(copy.eventsMetrics.dispatch).toBe(0); - expect(copy.get('key')).toBe('changed'); + expect(copy?.eventsMetrics.current).toBe(2); + expect(copy?.eventsMetrics.dispatch).toBe(0); + expect(copy?.get('key')).toBe('changed'); - const clean = copy.clone({ copyEvents: false }); - expect(clean.eventsMetrics.current).toBe(0); - expect(clean.eventsMetrics.dispatch).toBe(0); + const clean = copy?.clone({ copyEvents: false }); + expect(clean?.eventsMetrics.current).toBe(0); + expect(clean?.eventsMetrics.dispatch).toBe(0); - const none = copy.clone(); - expect(none.eventsMetrics.current).toBe(0); - expect(none.eventsMetrics.dispatch).toBe(0); + const none = copy?.clone(); + expect(none?.eventsMetrics.current).toBe(0); + expect(none?.eventsMetrics.dispatch).toBe(0); }); }); @@ -436,8 +439,8 @@ describe('aggregate', () => { super(props) } - public static create(value: string): Result { - return Ok(new Name({ value })); + public static create(value: string): Promise { + return Promise.resolve(new Name({ value })); } } @@ -454,26 +457,26 @@ describe('aggregate', () => { private constructor(props: Props) { super(props) } - public static create(props: Props): Result { - return Ok(new Product(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Product(props)); } } - const name = Name.create('orange').value(); - const props: Props = { name, additionalInfo: ['from brazil'], price: 10 }; - const orange = Product.create(props).value(); + const name = await Name.create('orange'); + const props: Props = { name: name!, additionalInfo: ['from brazil'], price: 10 }; + const orange = await Product.create(props); - orange.addEvent('create', () => { + orange?.addEvent('create', () => { console.log('make a juice'); }) - orange.addEvent('save', () => { + orange?.addEvent('save', () => { console.log('make a juice'); }, { priority: 1 }) - await orange.dispatchAll(); + await orange?.dispatchAll(); - const object = orange.toObject(); + const object = await orange!.toObject(); expect(object.additionalInfo).toEqual(['from brazil']); expect(object.name).toEqual({ value: 'orange' }); expect(object.price).toBe(10); @@ -493,13 +496,13 @@ describe('aggregate', () => { private constructor(props: Props) { super(props) } - public static create(props: Props): Result { - return Ok(new Product(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Product(props)); } } const props: Props = { name: 'Orange', price: 1.21 }; - const orange = Product.create(props).value(); + const orange = await Product.create(props); class Handler extends EventHandler { constructor() { super({ eventName: 'event' }) }; @@ -513,10 +516,10 @@ describe('aggregate', () => { } const event = new Handler(); - orange.addEvent(event); + orange?.addEvent(event); - await orange.dispatchEvent('event', { custom: 'params' }); - expect(orange.eventsMetrics.dispatch).toBe(1); + await orange?.dispatchEvent('event', { custom: 'params' }); + expect(orange?.eventsMetrics.dispatch).toBe(1); }); }); @@ -555,12 +558,14 @@ describe('Aggregate', () => { }); describe('clone', () => { - it('should create a new instance of Aggregate', () => { + it('should create a new instance of Aggregate', async () => { const props = { id: '123', name: 'Test Aggregate' }; const aggregate = new Aggregate(props); const clonedAggregate = aggregate.clone(); expect(clonedAggregate).toBeInstanceOf(Aggregate); - expect(clonedAggregate.toObject()).toEqual(aggregate.toObject()); + const obj1 = await clonedAggregate.toObject(); + const obj2 = await aggregate.toObject(); + expect(obj1).toEqual(obj2); }); }); @@ -617,10 +622,10 @@ describe('Aggregate', () => { }); describe('create', () => { - it('should create a new instance of Aggregate', () => { + it('should create a new instance of Aggregate', async () => { const props = { id: '123', name: 'Test Aggregate' }; - const result = Aggregate.create(props); - expect(result).toBeInstanceOf(Result); + const result = await Aggregate.create(props); + expect(result).toBeInstanceOf(Aggregate); }); }); @@ -638,4 +643,4 @@ describe('Aggregate', () => { expect(() => Product.init('jaca')).toThrowError(); }) }) -}); \ No newline at end of file +}); diff --git a/tests/core/auto-mapper.spec.ts b/tests/core/auto-mapper.spec.ts index f6a544e..e09161e 100644 --- a/tests/core/auto-mapper.spec.ts +++ b/tests/core/auto-mapper.spec.ts @@ -1,127 +1,148 @@ -import { Aggregate, AutoMapper, Entity, Id, ID, Iterator, Ok, Result, ValueObject } from "../../lib/core"; +import { Aggregate, AutoMapper, Entity, Id, ID, Iterator, ValueObject } from "../../lib/core"; import { UID } from "../../lib/types"; describe('auto-mapper', () => { describe('value-object', () => { - it('should convert value to a simple string', () => { + it('should convert value to a simple string', async () => { class StringVo extends ValueObject<{ value: string }> { private constructor(props: { value: string }) { super(props); } + public static create(props: { value: string }): Promise { + return Promise.resolve(new StringVo(props)); + } } - const vo = StringVo.create({ value: 'hello' }); + const vo = await StringVo.create({ value: 'hello' }); const autoMapper = new AutoMapper(); - const result = autoMapper.valueObjectToObj(vo.value()); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ value: 'hello' }); }); - it('should convert value to an object if result has more than one key', () => { + it('should convert value to an object if result has more than one key', async () => { class StringVo extends ValueObject<{ value: string, age: number }> { private constructor(props: { value: string, age: number }) { super(props); } + public static create(props: { value: string, age: number }): Promise { + return Promise.resolve(new StringVo(props)); + } } - const vo = StringVo.create({ value: 'hello', age: 21 }); + const vo = await StringVo.create({ value: 'hello', age: 21 }); const autoMapper = new AutoMapper(); - const result = autoMapper.valueObjectToObj(vo.value()); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ value: 'hello', age: 21 }); }); - it('should get boolean with success', () => { + it('should get boolean with success', async () => { class StringVo extends ValueObject<{ value: string, isActive: boolean }> { private constructor(props: { value: string, isActive: boolean }) { super(props); } + public static create(props: { value: string, isActive: boolean }): Promise { + return Promise.resolve(new StringVo(props)); + } } - const vo1 = StringVo.create({ value: 'hello', isActive: true }); - const vo2 = StringVo.create({ value: 'hello', isActive: false }); + const vo1 = await StringVo.create({ value: 'hello', isActive: true }); + const vo2 = await StringVo.create({ value: 'hello', isActive: false }); const autoMapper = new AutoMapper(); - const result1 = autoMapper.valueObjectToObj(vo1.value()); - const result2 = autoMapper.valueObjectToObj(vo2.value()); + const result1 = autoMapper.valueObjectToObj(vo1!); + const result2 = autoMapper.valueObjectToObj(vo2!); expect(result1).toEqual({ value: 'hello', isActive: true }); expect(result2).toEqual({ value: 'hello', isActive: false }); }); - it('should convert array and value to a simple object', () => { + it('should convert array and value to a simple object', async () => { class StringVo extends ValueObject<{ value: string, notes: number[] }> { private constructor(props: { value: string, notes: number[] }) { super(props); } + public static create(props: { value: string, notes: number[] }): Promise { + return Promise.resolve(new StringVo(props)); + } } - const vo = StringVo.create({ value: 'hello', notes: [1, 2, 3, 4, 5, 6, 7] }); + const vo = await StringVo.create({ value: 'hello', notes: [1, 2, 3, 4, 5, 6, 7] }); const autoMapper = new AutoMapper(); - const result = autoMapper.valueObjectToObj(vo.value()); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ value: 'hello', notes: [1, 2, 3, 4, 5, 6, 7] }); }); - it('should get array from value object', () => { + it('should get array from value object', async () => { - class StringVo extends ValueObject<{ value: string }> { - private constructor(props: { value: string }) { + class StringVo extends ValueObject<{ value: any[] }> { + private constructor(props: { value: any[] }) { super(props); } + public static create(props: { value: any[] }): Promise { + return Promise.resolve(new StringVo(props)); + } } - const vo = StringVo.create({ value: [1, 2, 3, 4, 5, 6, 7] }); + const vo = await StringVo.create({ value: [1, 2, 3, 4, 5, 6, 7] }); const autoMapper = new AutoMapper(); - const result = autoMapper.valueObjectToObj(vo.value()); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ value: [1, 2, 3, 4, 5, 6, 7] }); }); - it('should get id value from value object', () => { + it('should get id value from value object', async () => { - class StringVo extends ValueObject<{ value: ID }> { - private constructor(props: { value: ID }) { + class StringVo extends ValueObject<{ value: UID }> { + private constructor(props: { value: UID }) { super(props); } + public static create(props: { value: UID }): Promise { + return Promise.resolve(new StringVo(props)); + } } - const vo = StringVo.create({ value: ID.create('3c5738cf-825e-48b7-884d-927be849b0b6') }); + const vo = await StringVo.create({ value: ID.create('3c5738cf-825e-48b7-884d-927be849b0b6') }); const autoMapper = new AutoMapper(); - const result = autoMapper.valueObjectToObj(vo.value()); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ value: '3c5738cf-825e-48b7-884d-927be849b0b6' }); }); - it('should get ids value from value object', () => { + it('should get ids value from value object', async () => { - class StringVo extends ValueObject<{ value: ID[] }> { - private constructor(props: { value: ID[] }) { + class StringVo extends ValueObject<{ value: UID[] }> { + private constructor(props: { value: UID[] }) { super(props); } + public static create(props: { value: UID[] }): Promise { + return Promise.resolve(new StringVo(props)); + } } const ids = Iterator.create({ initialData: ['927be849b0b1', '927be849b0b2', '927be849b0b3'] }); @@ -132,68 +153,82 @@ describe('auto-mapper', () => { IDS.push(ID.create(ids.next())); } - const vo = StringVo.create({ value: IDS }); + const vo = await StringVo.create({ value: IDS }); const autoMapper = new AutoMapper(); - const result = autoMapper.valueObjectToObj(vo.value()); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ value: ["927be849b0b1", "927be849b0b2", "927be849b0b3"] }); }); - it('should get value object from value object', () => { + it('should get value object from value object', async () => { class StringVo2 extends ValueObject<{ value: string, age: number }> { private constructor(props: { value: string, age: number }) { super(props); } + public static create(props: { value: string, age: number }): Promise { + return Promise.resolve(new StringVo2(props)); + } } class StringVo extends ValueObject<{ value: StringVo2, message: string }> { private constructor(props: { value: StringVo2, message: string }) { super(props); } + public static create(props: { value: StringVo2, message: string }): Promise { + return Promise.resolve(new StringVo(props)); + } } - const vo = StringVo.create({ - value: StringVo2.create({ value: 'hello', age: 21 }).value(), + const vo2 = await StringVo2.create({ value: 'hello', age: 21 }); + const vo = await StringVo.create({ + value: vo2!, message: 'text' }); const autoMapper = new AutoMapper<{ value: StringVo2, message: string }>(); - const result = autoMapper.valueObjectToObj(vo.value()); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ message: "text", value: { value: 'hello', age: 21 } }); }); - it('should get date from object in other value object', () => { + it('should get date from object in other value object', async () => { process.env.TZ = 'UTC'; class StringVo2 extends ValueObject<{ value: Date, age: number }> { private constructor(props: { value: Date, age: number }) { super(props); } + public static create(props: { value: Date, age: number }): Promise { + return Promise.resolve(new StringVo2(props)); + } } class StringVo extends ValueObject<{ value: StringVo2, message: string }> { private constructor(props: { value: StringVo2, message: string }) { super(props); } + public static create(props: { value: StringVo2, message: string }): Promise { + return Promise.resolve(new StringVo(props)); + } } - const vo = StringVo.create({ - value: StringVo2.create({ - value: new Date('2022-01-01T03:00:00.000Z'), - age: 21 - }).value(), + const vo2 = await StringVo2.create({ + value: new Date('2022-01-01T03:00:00.000Z'), + age: 21 + }); + const vo = await StringVo.create({ + value: vo2!, message: 'text' }); const autoMapper = new AutoMapper<{ value: StringVo2, message: string }>(); - const result = autoMapper.valueObjectToObj(vo.value()); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ message: "text", @@ -209,18 +244,24 @@ describe('auto-mapper', () => { describe('entity', () => { - it('should get object from entity', () => { + it('should get object from entity', async () => { class NameVo extends ValueObject<{ value: string }> { private constructor(props: { value: string }) { super(props) } + public static create(props: { value: string }): Promise { + return Promise.resolve(new NameVo(props)); + } } class AgeVo extends ValueObject<{ value: number }> { private constructor(props: { value: number }) { super(props) } + public static create(props: { value: number }): Promise { + return Promise.resolve(new AgeVo(props)); + } } interface Props { @@ -241,14 +282,17 @@ describe('auto-mapper', () => { private constructor(props: Props, config?: any) { super(props, config); } + public static create(props: Props): Promise { + return Promise.resolve(new SimpleEntity(props)); + } } - const age = AgeVo.create({ value: 21 }).value(); - const name = NameVo.create({ value: 'some value' }).value(); - const agg = SimpleEntity.create({ + const age = await AgeVo.create({ value: 21 }); + const name = await NameVo.create({ value: 'some value' }); + const agg = await SimpleEntity.create({ id: "1519cb69-9904-4f2b-84e1-e6e95431cf24", - age, - name, + age: age!, + name: name!, notes: [1, 2, 3], arraySimpleObject: [ { @@ -262,7 +306,7 @@ describe('auto-mapper', () => { } ); - const user = agg.value(); + const user = agg!; expect(user.id.value()).toBe('1519cb69-9904-4f2b-84e1-e6e95431cf24'); @@ -294,18 +338,27 @@ describe('auto-mapper', () => { private constructor(props: { value: number }) { super(props) } + public static create(props: { value: number }): Promise { + return Promise.resolve(new Price(props)); + } } class Name extends ValueObject<{ value: string }> { private constructor(props: { value: string }) { super(props) } + public static create(props: { value: string }): Promise { + return Promise.resolve(new Name(props)); + } } class Item extends ValueObject<{ name: string }> { private constructor(props: { name: string }) { super(props) } + public static create(props: { name: string }): Promise { + return Promise.resolve(new Item(props)); + } } interface Props { id: UID; @@ -325,8 +378,8 @@ describe('auto-mapper', () => { super(props); } - public static create(props: Props): Result { - return Ok(new Product(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Product(props)); } } @@ -349,16 +402,16 @@ describe('auto-mapper', () => { super(props); } - public static create(props: AggProps): Result { - return Ok(new Order(props)); + public static create(props: AggProps): Promise { + return Promise.resolve(new Order(props)); } } - const price = Price.create({ value: 20 }).value(); - const name = Name.create({ value: "jane" }).value(); - const item = Item.create({ name: "some-item" }).value(); + it('should convert an entity to simple object with success', async () => { - it('should convert an entity to simple object with success', () => { + const price = await Price.create({ value: 20 }); + const name = await Name.create({ value: "jane" }); + const item = await Item.create({ name: "some-item" }); const now = new Date('2022-11-27T22:39:58.897Z'); const id = Id('f25a30cb-294c-4269-8e8c-060403f3a971'); @@ -379,24 +432,28 @@ describe('auto-mapper', () => { const props: Props = { id, - name, - item, - price, + name: name!, + item: item!, + price: price!, amount: 42, detail: 'detail info', - lastSales: [item, item, item], + lastSales: [item!, item!, item!], options: ['a', 'b', 'c'], createdAt: now, updatedAt: now, } - const product = Product.create(props); - expect(product.isOk()).toBeTruthy(); - const obj = product.value().toObject(); + const product = await Product.create(props); + expect(product).not.toBeNull(); + const obj = await product!.toObject(); expect(obj).toEqual(expectedResult); expect(obj).toMatchSnapshot(); }); - it('should convert an aggregate to simple object with success', () => { + it('should convert an aggregate to simple object with success', async () => { + const price = await Price.create({ value: 20 }); + const name = await Name.create({ value: "jane" }); + const item = await Item.create({ name: "some-item" }); + const now = new Date('2022-11-27T22:39:58.897Z'); const id = Id('f25a30cb-294c-4269-8e8c-060403f3a971'); const itemObj = "some-item"; @@ -430,22 +487,22 @@ describe('auto-mapper', () => { const props: Props = { id, - name, - item, - price, + name: name!, + item: item!, + price: price!, amount: 42, detail: 'detail info', - lastSales: [item, item, item], + lastSales: [item!, item!, item!], options: ['a', 'b', 'c'], createdAt: now, updatedAt: now, } - const product = Product.create(props).value(); - const order = Order.create({ ...props, product }); + const product = await Product.create(props); + const order = await Order.create({ ...props, product: product! }); - expect(order.isOk()).toBeTruthy(); - const obj = order.value().toObject(); + expect(order).not.toBeNull(); + const obj = await order!.toObject(); expect(obj).toEqual(expectedResult); expect(obj).toMatchSnapshot(); }); @@ -469,8 +526,16 @@ describe('auto-mapper', () => { summary: string[]; } - class Name extends ValueObject { } - class Age extends ValueObject { } + class Name extends ValueObject { + public static create(props: ValueA): Promise { + return Promise.resolve(new Name(props)); + } + } + class Age extends ValueObject { + public static create(props: ValueB): Promise { + return Promise.resolve(new Age(props)); + } + } interface PropsA { id?: UID; @@ -483,7 +548,11 @@ describe('auto-mapper', () => { createdAt: Date; } - class Profile extends Entity { } + class Profile extends Entity { + public static create(props: PropsA): Promise { + return Promise.resolve(new Profile(props)); + } + } interface PropsB { id?: UID; profile: Profile; @@ -493,37 +562,45 @@ describe('auto-mapper', () => { createdAt: Date; } - class Example extends Entity { } - - const profile: PropsA = { - age: Age.create({ value: 21 }).value(), - data: 'lorem ipsum', - name: Name.create({ value: 'Mille' }).value(), - notes: [10, 20, 30], - value: 7, - id: Id('valid-uuid-2'), - createdAt: new Date('2023-01-05T18:20:41.916Z'), - detail: { - likes: 200, - nick: 'Loader', - site: '4dev.com', - summary: ['page1', 'page2'], - }, - }; + class Example extends Entity { + public static create(props: PropsB): Promise { + return Promise.resolve(new Example(props)); + } + } - const props: PropsB = { - cite: 'Lorem', - isMarried: true, - profile: Profile.create(profile).value(), - value: 42, - id: Id('valid-uuid-1'), - createdAt: new Date('2023-01-05T18:20:41.916Z'), - }; + it('should convert object on entity to simple object', async () => { + const age = await Age.create({ value: 21 }); + const name = await Name.create({ value: 'Mille' }); + const profileProps: PropsA = { + age: age!, + data: 'lorem ipsum', + name: name!, + notes: [10, 20, 30], + value: 7, + id: Id('valid-uuid-2'), + createdAt: new Date('2023-01-05T18:20:41.916Z'), + detail: { + likes: 200, + nick: 'Loader', + site: '4dev.com', + summary: ['page1', 'page2'], + }, + }; - const entity = Example.create(props).value(); + const profile = await Profile.create(profileProps); - it('should convert object on entity to simple object', () => { - const object = entity.toObject(); + const props: PropsB = { + cite: 'Lorem', + isMarried: true, + profile: profile!, + value: 42, + id: Id('valid-uuid-1'), + createdAt: new Date('2023-01-05T18:20:41.916Z'), + }; + + const entity = await Example.create(props); + + const object = await entity!.toObject(); expect(object).toEqual({ id: "valid-uuid-1", cite: 'Lorem', @@ -552,7 +629,7 @@ describe('auto-mapper', () => { }); describe('uid', () => { - it('should get value from entity attribute if instance of ID', () => { + it('should get value from entity attribute if instance of ID', async () => { interface Props { id: UID; @@ -566,8 +643,8 @@ describe('auto-mapper', () => { private constructor(props: Props) { super(props) } - public static create(props: Props): Result { - return Ok(new Sample(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Sample(props)); } } @@ -583,18 +660,19 @@ describe('auto-mapper', () => { ] }; - const result = Sample.create({ + const result = await Sample.create({ arr: [Id(t.arr[0]), Id(t.arr[1])], id: Id(t.id), some: 'sample', userId: Id(t.userId), createdAt: t.createdAt, updatedAt: t.updatedAt - }).value() - expect(result.toObject()).toEqual(t); + }); + const obj = await result!.toObject(); + expect(obj).toEqual(t); }); - it('should get value from value object attribute if instance of ID', () => { + it('should get value from value object attribute if instance of ID', async () => { interface Props { userId: UID; @@ -605,8 +683,8 @@ describe('auto-mapper', () => { private constructor(props: Props) { super(props) } - public static create(props: Props): Result { - return Ok(new Sample(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Sample(props)); } } @@ -619,13 +697,14 @@ describe('auto-mapper', () => { ] }; - const result = Sample.create({ + const result = await Sample.create({ arr: [Id(t.arr[0]), Id(t.arr[1])], some: 'sample', userId: Id(t.userId) - }).value() + }); - expect(result.toObject()).toEqual(t); + const obj = await result!.toObject(); + expect(obj).toEqual(t); }); }); @@ -636,8 +715,8 @@ describe('auto-mapper', () => { super(props) } - public static create(text: string): Result { - return Ok(new Vo1({ text })); + public static create(text: string): Promise { + return Promise.resolve(new Vo1({ text })); } }; @@ -647,8 +726,8 @@ describe('auto-mapper', () => { super(props) } - public static create(props: Props2): Result { - return Ok(new Vo2(props)); + public static create(props: Props2): Promise { + return Promise.resolve(new Vo2(props)); } }; @@ -666,15 +745,15 @@ describe('auto-mapper', () => { super(props) } - public static create(props: Props3): Result { - return Ok(new Sample(props)); + public static create(props: Props3): Promise { + return Promise.resolve(new Sample(props)); } } - it('should transform in simple object when value object inside other', () => { - const vo1 = Vo1.create('sub-object').value(); - const vo = Vo2.create({ text: 'example', vo1, nullable: 10 }).value(); - const obj = vo.toObject(); + it('should transform in simple object when value object inside other', async () => { + const vo1 = await Vo1.create('sub-object'); + const vo = await Vo2.create({ text: 'example', vo1: vo1!, nullable: 10 }); + const obj = await vo!.toObject(); expect(obj).toMatchInlineSnapshot(` Object { "nullable": 10, @@ -686,22 +765,23 @@ Object { `); }) - it('should transform on entity', () => { - const vo1 = Vo1.create('sub-object').value(); - const vo2 = Vo2.create({ text: 'example', vo1, nullable: null }).value(); + it('should transform on entity', async () => { + const vo1 = await Vo1.create('sub-object'); + const vo2 = await Vo2.create({ text: 'example', vo1: vo1!, nullable: null }); const date = new Date(); - const sample = Sample.create({ - level1: vo1, - level3: vo2, + const sample = await Sample.create({ + level1: vo1!, + level3: vo2!, nullable: null, simple: 'hey there', id: Id('8280c69f-be52-4918-ada9-f43d4703dbfe'), createdAt: date, updatedAt: date - }).value(); + }); - expect(sample.toObject()).toMatchInlineSnapshot(` + const obj = await sample!.toObject(); + expect(obj).toMatchInlineSnapshot(` Object { "createdAt": ${date.toISOString()}, "id": "8280c69f-be52-4918-ada9-f43d4703dbfe", @@ -765,7 +845,7 @@ describe('should create object with success', () => { } } - it('object', () => { + it('object', async () => { const post = Post.init({ comments: ['lorem', 'test', 'sample001'], likes: 1, @@ -796,7 +876,10 @@ describe('should create object with success', () => { updatedAt: new Date('2024-12-15T18:00:14.761Z') }); - expect(john.toObject()).toEqual({ + const johnObj = await john.toObject(); + const janeObj = await jane.toObject(); + + expect(johnObj).toEqual({ "age": 27, "createdAt": expect.any(Date), "friends": [ @@ -879,7 +962,7 @@ describe('should create object with success', () => { ], "updatedAt": expect.any(Date), }); - expect(jane.toObject()).toEqual({ + expect(janeObj).toEqual({ "age": 25, "createdAt": expect.any(Date), "friends": [], @@ -928,7 +1011,7 @@ describe('should create object with success', () => { }); describe('', () => { - it('', () => { + it('', async () => { class Money extends ValueObject { private constructor(value: number) { @@ -978,7 +1061,8 @@ describe('', () => { updatedAt: new Date('2024-12-15T18:17:17.422Z') }); - expect(payment.toObject()).toEqual({ + const obj = await payment.toObject(); + expect(obj).toEqual({ "createdAt": expect.any(Date), "id": "1", "operations": [ @@ -1005,20 +1089,20 @@ describe('auto-mapper additional tests', () => { private constructor(props: { value: string | null | undefined }) { super(props); } - public static create(value: string | null | undefined): Result { - return Ok(new SimpleVo({ value })); + public static create(value: string | null | undefined): Promise { + return Promise.resolve(new SimpleVo({ value })); } } - it('should return null if value is null', () => { - const vo = SimpleVo.create(null).value(); + it('should return null if value is null', async () => { + const vo = await SimpleVo.create(null); const autoMapper = new AutoMapper<{ value: string | null }>(); const result = autoMapper.valueObjectToObj(vo as any); expect(result).toEqual({ value: null }); }); - it('should return undefined if value is undefined', () => { - const vo = SimpleVo.create(undefined).value(); + it('should return undefined if value is undefined', async () => { + const vo = await SimpleVo.create(undefined); const autoMapper = new AutoMapper<{ value: string | undefined }>(); const result = autoMapper.valueObjectToObj(vo as any); expect(result).toEqual({ value: undefined }); @@ -1031,16 +1115,16 @@ describe('auto-mapper additional tests', () => { private constructor(props: { tag: symbol }) { super(props); } - public static create(tag: symbol): Result { - return Ok(new SymbolVo({ tag })); + public static create(tag: symbol): Promise { + return Promise.resolve(new SymbolVo({ tag })); } } - it('should convert symbol to its description', () => { + it('should convert symbol to its description', async () => { const sym = Symbol("myTag"); - const vo = SymbolVo.create(sym).value(); + const vo = await SymbolVo.create(sym); const autoMapper = new AutoMapper<{ tag: symbol }>(); - const result = autoMapper.valueObjectToObj(vo); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ tag: "myTag" }); }); }); @@ -1052,16 +1136,16 @@ describe('auto-mapper additional tests', () => { private constructor(props: { data: any[] }) { super(props); } - public static create(data: any[]): Result { - return Ok(new MixedVo({ data })); + public static create(data: any[]): Promise { + return Promise.resolve(new MixedVo({ data })); } } - it('should handle arrays with mixed data types', () => { + it('should handle arrays with mixed data types', async () => { const arr = [ID.create('123'), 'hello', 42, new Date('2020-01-01')]; - const vo = MixedVo.create(arr).value(); + const vo = await MixedVo.create(arr); const autoMapper = new AutoMapper<{ data: any[] }>(); - const result = autoMapper.valueObjectToObj(vo); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ data: [ '123', @@ -1080,8 +1164,8 @@ describe('auto-mapper additional tests', () => { private constructor(props: { message: string }) { super(props); } - public static create(message: string): Result { - return Ok(new InnerVo({ message })); + public static create(message: string): Promise { + return Promise.resolve(new InnerVo({ message })); } } @@ -1089,16 +1173,16 @@ describe('auto-mapper additional tests', () => { private constructor(props: { data: InnerVo }) { super(props); } - public static create(data: InnerVo): Result { - return Ok(new OuterVo({ data })); + public static create(data: InnerVo): Promise { + return Promise.resolve(new OuterVo({ data })); } } - it('should recursively convert nested value objects', () => { - const inner = InnerVo.create('inner text').value(); - const outer = OuterVo.create(inner).value(); + it('should recursively convert nested value objects', async () => { + const inner = await InnerVo.create('inner text'); + const outer = await OuterVo.create(inner!); const autoMapper = new AutoMapper<{ data: InnerVo }>(); - const result = autoMapper.valueObjectToObj(outer); + const result = autoMapper.valueObjectToObj(outer!); expect(result).toEqual({ data: { message: 'inner text' } }); @@ -1114,15 +1198,15 @@ describe('auto-mapper additional tests', () => { private constructor(props: EmptyProps) { super(props); } - public static create(): Result { - return Ok(new EmptyEntity({})); + public static create(): Promise { + return Promise.resolve(new EmptyEntity({})); } } - it('should handle entity with no props gracefully', () => { - const entity = EmptyEntity.create().value(); + it('should handle entity with no props gracefully', async () => { + const entity = await EmptyEntity.create(); const autoMapper = new AutoMapper(); - const result = autoMapper.entityToObj(entity); + const result = autoMapper.entityToObj(entity!); // result deve ter apenas id, createdAt, updatedAt expect(result).toHaveProperty('id'); expect(result).toHaveProperty('createdAt'); @@ -1138,8 +1222,8 @@ describe('auto-mapper additional tests', () => { private constructor(props: { name: string }) { super(props); } - public static create(name: string): Result { - return Ok(new ChildVo({ name })); + public static create(name: string): Promise { + return Promise.resolve(new ChildVo({ name })); } } @@ -1152,8 +1236,9 @@ describe('auto-mapper additional tests', () => { private constructor(props: ChildProps) { super(props); } - public static create(name: string): Result { - return Ok(new ChildEntity({ childName: ChildVo.create(name).value() })); + public static async create(name: string): Promise { + const childVo = await ChildVo.create(name); + return Promise.resolve(new ChildEntity({ childName: childVo! })); } } @@ -1166,19 +1251,19 @@ describe('auto-mapper additional tests', () => { private constructor(props: ParentProps) { super(props); } - public static create(children: ChildEntity[]): Result { - return Ok(new ParentEntity({ children })); + public static create(children: ChildEntity[]): Promise { + return Promise.resolve(new ParentEntity({ children })); } } - it('should convert entity with array of child entities', () => { - const child1 = ChildEntity.create('child1').value(); - const child2 = ChildEntity.create('child2').value(); + it('should convert entity with array of child entities', async () => { + const child1 = await ChildEntity.create('child1'); + const child2 = await ChildEntity.create('child2'); - const parent = ParentEntity.create([child1, child2]).value(); + const parent = await ParentEntity.create([child1!, child2!]); const autoMapper = new AutoMapper(); - const result = autoMapper.entityToObj(parent); + const result = autoMapper.entityToObj(parent!); expect(result.children).toEqual([ { id: expect.any(String), @@ -1203,8 +1288,8 @@ describe('auto-mapper additional tests', () => { private constructor(props: { text: string }) { super(props); } - public static create(text: string): Result { - return Ok(new SimpleVo({ text })); + public static create(text: string): Promise { + return Promise.resolve(new SimpleVo({ text })); } } @@ -1217,9 +1302,10 @@ describe('auto-mapper additional tests', () => { private constructor(props: SimpleProps) { super(props); } - public static create(desc: string): Result { - return Ok(new SimpleEntity({ - description: SimpleVo.create(desc).value() + public static async create(desc: string): Promise { + const simpleVo = await SimpleVo.create(desc); + return Promise.resolve(new SimpleEntity({ + description: simpleVo! })); } } @@ -1234,16 +1320,16 @@ describe('auto-mapper additional tests', () => { private constructor(props: AggProps) { super(props); } - public static create(props: AggProps): Result { - return Ok(new SampleAggregate(props)); + public static create(props: AggProps): Promise { + return Promise.resolve(new SampleAggregate(props)); } } - it('should convert aggregate with nested entity', () => { - const entity = SimpleEntity.create('desc').value(); - const agg = SampleAggregate.create({ entity, name: 'agg-name' }).value(); + it('should convert aggregate with nested entity', async () => { + const entity = await SimpleEntity.create('desc'); + const agg = await SampleAggregate.create({ entity: entity!, name: 'agg-name' }); - const result = agg.toObject(); + const result = await agg!.toObject(); expect(result).toEqual({ id: expect.any(String), createdAt: expect.any(Date), @@ -1272,20 +1358,20 @@ describe('auto-mapper additional tests', () => { expect(typeof result).toBe('object'); }); - it('should handle undefined props in value object', () => { + it('should handle undefined props in value object', async () => { class PartialVo extends ValueObject<{ text?: string, count?: number }> { private constructor(props: { text?: string, count?: number }) { super(props); } - public static create(props: { text?: string, count?: number }): Result { - return Ok(new PartialVo(props)); + public static create(props: { text?: string, count?: number }): Promise { + return Promise.resolve(new PartialVo(props)); } } - const vo = PartialVo.create({ text: 'partial' }).value(); + const vo = await PartialVo.create({ text: 'partial' }); const autoMapper = new AutoMapper<{ text?: string, count?: number }>(); - const result = autoMapper.valueObjectToObj(vo); + const result = autoMapper.valueObjectToObj(vo!); expect(result).toEqual({ text: 'partial', count: undefined }); }); }); -}); +}); \ No newline at end of file diff --git a/tests/core/context.spec.ts b/tests/core/context.spec.ts index c80c607..635c835 100644 --- a/tests/core/context.spec.ts +++ b/tests/core/context.spec.ts @@ -1,4 +1,4 @@ -import { Aggregate, Ok, Result, Context } from "../../lib/core"; +import { Aggregate, Context } from "../../lib/core"; import { EventHandler } from "../../lib/types"; describe('context', () => { @@ -15,8 +15,8 @@ describe('context', () => { return new User({ name }); } - public static create(props: Props): Result { - return Ok(new User(props)); + public static create(props: Props): Promise { + return Promise.resolve(new User(props)); } } @@ -28,12 +28,13 @@ describe('context', () => { super({ eventName: 'CONTEXT:HANDLER' }) } - dispatch(user: User): void { - contextY.dispatchEvent(this.params.eventName, user.toObject()); + async dispatch(user: User): Promise { + const model = await user.toObject(); + contextY.dispatchEvent(this.params.eventName, model); }; } - it('should dispatch global event when user signs up', () => { + it('should dispatch global event when user signs up', async () => { // Mock event handler const mockEventHandler = jest.fn(); @@ -44,7 +45,7 @@ describe('context', () => { // User signs up const user = User.signUp('Jane Doe'); - const model = user.toObject(); + const model = await user.toObject(); // Dispatch REGISTER event with user data context.dispatchEvent('CONTEXT:REGISTER', model); @@ -53,7 +54,7 @@ describe('context', () => { expect(mockEventHandler).toHaveBeenCalledWith({ detail: [model] }); }); - it('should dispatch global event on handler when user signs up', () => { + it('should dispatch global event on handler when user signs up', async () => { // Mock event handler const mockGlobalEventHandler = jest.fn(); @@ -64,7 +65,7 @@ describe('context', () => { // User signs up const user = User.signUp('John Doe'); - const model = user.toObject(); + const model = await user.toObject(); Context.events().dispatchEvent('CONTEXT:SIGNUP', model); @@ -72,7 +73,7 @@ describe('context', () => { expect(mockGlobalEventHandler).toHaveBeenCalledWith({ detail: [model] }); }); - it('should dispatch global event on handler when user signs up', () => { + it('should dispatch global event on handler when user signs up', async () => { // Mock event handler const mockGlobalEventHandler = jest.fn(); @@ -84,9 +85,9 @@ describe('context', () => { const user = User.signUp('John Doe'); user.addEvent(new SignUpEvent()); - const model = user.toObject(); + const model = await user.toObject(); - user.dispatchEvent('CONTEXT:HANDLER'); + await user.dispatchEvent('CONTEXT:HANDLER'); // Expect event handler to have been called expect(mockGlobalEventHandler).toHaveBeenCalledWith({ detail: [model] }); @@ -135,4 +136,4 @@ describe('context', () => { const err = () => context.dispatchEvent('invalid-name', () => { }); expect(err).toThrowError('Validation failed: Event name must follow the pattern "contextName:EventName". Please ensure to include a colon (":") in the event name to separate the context name and the event name itself.') }); -}); +}); \ No newline at end of file diff --git a/tests/core/entity.spec.ts b/tests/core/entity.spec.ts index 4041ca7..6a3da72 100644 --- a/tests/core/entity.spec.ts +++ b/tests/core/entity.spec.ts @@ -1,5 +1,5 @@ -import { Entity, Fail, Id, Ok, Result, ValueObject } from "../../lib/core"; -import { Adapter, _Result, UID } from "../../lib/types"; +import { Entity, Id, ValueObject } from "../../lib/core"; +import { Adapter, UID } from "../../lib/types"; describe("entity", () => { @@ -16,17 +16,17 @@ describe("entity", () => { return value !== undefined; } - public static create(props: Props): Result { - if (!props) return Fail('props is required') - return Result.Ok(new EntitySample(props)) + public static create(props: Props): Promise { + if (!props) return Promise.resolve(null); + return Promise.resolve(new EntitySample(props)) } } - it('should get prototype', () => { - const ent = EntitySample.create({ foo: 'bar' }); + it('should get prototype', async () => { + const ent = await EntitySample.create({ foo: 'bar' }); - ent.value()?.change('foo', 'changed'); - expect(ent.isOk()).toBeTruthy(); + ent?.change('foo', 'changed'); + expect(ent).not.toBeNull(); }); }); @@ -36,21 +36,25 @@ describe("entity", () => { private constructor(props: { key: string }) { super(props) } + public static create(props: { key: string, id?: string, createdAt?: Date, updatedAt?: Date }): Promise { + if (props === null || props === undefined) return Promise.resolve(null); + return Promise.resolve(new En(props)); + } } const id = '973e6c78-6771-4a86-ba55-f759a1e68f8c'; - const entity = En.create( - { - id, - key: 'value', - createdAt: new Date('2022-07-20T15:46:54.373Z'), - updatedAt: new Date('2022-07-20T15:46:54.373Z') - } - ); - - it('should get object with success', () => { - expect(entity.value().toObject()).toEqual({ + it('should get object with success', async () => { + const entity = await En.create( + { + id, + key: 'value', + createdAt: new Date('2022-07-20T15:46:54.373Z'), + updatedAt: new Date('2022-07-20T15:46:54.373Z') + } + ); + const obj = await entity!.toObject(); + expect(obj).toEqual({ id, key: 'value', createdAt: new Date('2022-07-20T15:46:54.373Z'), @@ -58,19 +62,21 @@ describe("entity", () => { }); }); - it('should get hash code with success', () => { - expect(entity.value().hashCode().value()).toBe('[Entity@En]:973e6c78-6771-4a86-ba55-f759a1e68f8c'); + it('should get hash code with success', async () => { + const entity = await En.create({ key: 'value', id }); + expect(entity?.hashCode().value()).toBe('[Entity@En]:973e6c78-6771-4a86-ba55-f759a1e68f8c'); }); - it('should clone entity with success and keep the same id', () => { - const clone = entity.value().clone(); - expect(clone.id.value()).toBe(id); - expect(clone.get('key')).toBe('value'); + it('should clone entity with success and keep the same id', async () => { + const entity = await En.create({ key: 'value', id }); + const clone = entity?.clone(); + expect(clone?.id.value()).toBe(id); + expect(clone?.get('key')).toBe('value'); }); - it('should return fail if provide null props', () => { - const result = En.create(null); - expect(result.isFail()).toBeTruthy(); + it('should return fail if provide null props', async () => { + const result = await En.create(null as any); + expect(result).toBeNull(); }); }); @@ -94,15 +100,8 @@ describe("entity", () => { name: new Username('John Doe') }) }) - it('should access resolved primitive values prototype', () => { - /** - * Since we have access to the resolved primitive value - * returned by the `toObject` method, we can access the - * prototype of the resolved value and manipulate it. - * - * Point here is that if we can consume it prototype that means typescript is infering the correct type. - */ - const personObject = person.toObject(); + it('should access resolved primitive values prototype', async () => { + const personObject = await person.toObject(); const defaultPersonName = 'John Doe'; const personObjectName = personObject.name @@ -150,15 +149,8 @@ describe("entity", () => { }) }) - it('should not be able to mutate any level of data on personObject', () => { - /** - * Typescript it self already infered an DeepReadonly type on any level of the object. - * So, at type checking level you cant even try to set a new value to any property. - * - * BUT, at runtime, we should still have the same behavior. That means we'll check if - * the object is really immutable. - */ - const personObject = person.toObject(); + it('should not be able to mutate any level of data on personObject', async () => { + const personObject = await person.toObject(); expect(Object.isFrozen(personObject)).toBeTruthy(); expect(Object.isFrozen(personObject.fullname)).toBeTruthy(); expect(Object.isFrozen(personObject.skills)).toBeTruthy(); @@ -241,8 +233,8 @@ describe("entity", () => { }) }) - it('should return object with all values', () => { - const proposalObject = proposal.toObject(); + it('should return object with all values', async () => { + const proposalObject = await proposal.toObject(); expect(proposalObject).toEqual({ id: expect.any(String), createdAt: expect.any(Date), @@ -291,8 +283,8 @@ describe("entity", () => { describe('should access props', () => { - it('should access activities', () => { - const proposalObject = proposal.toObject(); + it('should access activities', async () => { + const proposalObject = await proposal.toObject(); expect(proposalObject.activities).toEqual([ { name: 'Activity 1', done: true }, { name: 'Activity 2', done: false } @@ -302,8 +294,8 @@ describe("entity", () => { expect(proposalObject.activities[0].done).toBe(true); }) - it('should access companies', () => { - const proposalObject = proposal.toObject(); + it('should access companies', async () => { + const proposalObject = await proposal.toObject(); expect(proposalObject.companies).toEqual([ { corporateName: 'Company 1', @@ -324,8 +316,8 @@ describe("entity", () => { expect(proposalObject.companies[0].fantasyName).toBe('Fantasy 1'); }) - it('should access lead', () => { - const proposalObject = proposal.toObject(); + it('should access lead', async () => { + const proposalObject = await proposal.toObject(); expect(proposalObject.lead).toEqual({ id: expect.any(String), @@ -348,8 +340,8 @@ describe("entity", () => { expect(proposalObject.lead.user.createdAt).toEqual(expect.any(Date)); }) - it('should access primitive props and plain objects', () => { - const proposalObject = proposal.toObject(); + it('should access primitive props and plain objects', async () => { + const proposalObject = await proposal.toObject(); expect(proposalObject.budget).toBe(2000); expect(proposalObject.deadline).toEqual(expect.any(Date)); expect(proposalObject.description).toBe('Proposal description'); @@ -373,8 +365,8 @@ describe("entity", () => { person = new Person({ age: 20, married: false, name: 'John Doe', skills: ['JS', 'TS'] }) }) - it('should return object with all values', () => { - const personObject = person.toObject(); + it('should return object with all values', async () => { + const personObject = await person.toObject(); expect(personObject).toEqual({ id: expect.any(String), createdAt: expect.any(Date), @@ -386,8 +378,8 @@ describe("entity", () => { }); }); - it('should access props', () => { - const personObject = person.toObject(); + it('should access props', async () => { + const personObject = await person.toObject(); expect(personObject.age).toBe(20); expect(personObject.married).toBe(false); expect(personObject.name).toBe('John Doe'); @@ -419,8 +411,8 @@ describe("entity", () => { }) }) - it('should return object with all values', () => { - const personObject = person.toObject(); + it('should return object with all values', async () => { + const personObject = await person.toObject(); expect(personObject).toEqual({ id: expect.any(String), createdAt: expect.any(Date), @@ -430,8 +422,8 @@ describe("entity", () => { }); }); - it('should access props', () => { - const personObject = person.toObject(); + it('should access props', async () => { + const personObject = await person.toObject(); expect(personObject.address).toEqual({ city: 'New York', street: '5th Ave', zip: '10001' }); expect(personObject.name).toEqual({ firstName: 'John', lastName: 'Doe' }); @@ -462,8 +454,8 @@ describe("entity", () => { }) }) - it('should return object with all values', () => { - const personObject = person.toObject(); + it('should return object with all values', async () => { + const personObject = await person.toObject(); expect(personObject).toEqual({ id: expect.any(String), createdAt: expect.any(Date), @@ -474,8 +466,8 @@ describe("entity", () => { }); }); - it('should access props', () => { - const personObject = person.toObject(); + it('should access props', async () => { + const personObject = await person.toObject(); expect(personObject.age).toBe(20); expect(personObject.married).toBe(false); expect(personObject.name).toBe('John Doe'); @@ -498,32 +490,33 @@ describe("entity", () => { return value !== undefined; } - public static create(props: Props): Result { - return Result.Ok(new EntitySample(props)) + public static create(props: Props): Promise { + return Promise.resolve(new EntitySample(props)) } } - it('should get prototype', () => { - const ent = EntitySample.create({ foo: 'bar' }); + it('should get prototype', async () => { + const ent = await EntitySample.create({ foo: 'bar' }); - ent.value().change('foo', 'changed'); - expect(ent.isOk()).toBeTruthy(); + ent?.change('foo', 'changed'); + expect(ent).not.toBeNull(); - const throws = () => ent.value().change('id', 'changed'); + const throws = () => ent?.change('id', 'changed'); expect(throws).toThrowError(); }); - it('should set prototype', () => { - const ent = EntitySample.create({ foo: 'bar' }); - expect(ent.isOk()).toBeTruthy(); - expect(ent.value().get('foo')).toBe('bar'); - ent.value().set('foo').to('changed'); - expect(ent.value().get('foo')).toBe('changed'); + it('should set prototype', async () => { + const ent = await EntitySample.create({ foo: 'bar' }); + expect(ent).not.toBeNull(); + expect(ent?.get('foo')).toBe('bar'); + ent?.set('foo').to('changed'); + expect(ent?.get('foo')).toBe('changed'); }); - it('should create many entities', () => { - const payload = EntitySample.createMany([]); - expect(payload.result.isFail()).toBeTruthy(); + it('should create many entities', async () => { + const payload = await EntitySample.createMany([]); + const result = await payload.result; + expect(result).toBeNull(); }); }); @@ -544,74 +537,74 @@ describe("entity", () => { super(props) } - public static create(props: Props): Result { - return Ok(new EntityExample(props)); + public static create(props: Props): Promise { + return Promise.resolve(new EntityExample(props)); } } - it("should to be equal", () => { + it("should to be equal", async () => { const props: Props = { key: 200, values: [{ name: 'abc' }, { name: 'def' }] }; const id = Id(); - const a = EntityExample.create({ ...props, id }).value(); - const b = EntityExample.create({ ...props, id }).value(); + const a = await EntityExample.create({ ...props, id }); + const b = await EntityExample.create({ ...props, id }); - expect(a.isEqual(b)).toBeTruthy(); + expect(a?.isEqual(b!)).toBeTruthy(); }); - it("should to be equal", () => { + it("should to be equal", async () => { const id = Id(); const props: Props = { key: 200, values: [{ name: 'abc' }, { name: 'def' }] }; - const a = EntityExample.create({ ...props, id }).value(); - const b = a.clone(); + const a = await EntityExample.create({ ...props, id }); + const b = a?.clone(); - expect(a.isEqual(b)).toBeTruthy(); + expect(a?.isEqual(b!)).toBeTruthy(); }); - it("should not to be equal if change state", () => { + it("should not to be equal if change state", async () => { const id = Id(); const props: Props = { key: 200, values: [{ name: 'abc' }, { name: 'def' }] }; - const a = EntityExample.create({ ...props, id }).value(); - const b = a.clone(); - b.set('key').to(201); + const a = await EntityExample.create({ ...props, id }); + const b = a?.clone(); + b?.set('key').to(201); - expect(a.isEqual(b)).toBeFalsy(); + expect(a?.isEqual(b!)).toBeFalsy(); }); - it("should not to be equal if state is different", () => { + it("should not to be equal if state is different", async () => { const id = Id(); const propsA: Props = { id, key: 200, values: [{ name: 'abc' }, { name: 'def' }] }; const propsB: Props = { id, key: 200, values: [{ name: 'abc' }, { name: 'dif' }] }; - const a = EntityExample.create(propsA).value(); - const b = EntityExample.create(propsB).value(); + const a = await EntityExample.create(propsA); + const b = await EntityExample.create(propsB); - expect(a.isEqual(b)).toBeFalsy(); + expect(a?.isEqual(b!)).toBeFalsy(); }); - it("should not to be equal if id is different", () => { + it("should not to be equal if id is different", async () => { const propsA: Props = { key: 200, values: [{ name: 'abc' }, { name: 'def' }] } const propsB: Props = { key: 200, values: [{ name: 'abc' }, { name: 'dif' }] } - const a = EntityExample.create(propsA).value(); - const b = EntityExample.create(propsB).value(); + const a = await EntityExample.create(propsA); + const b = await EntityExample.create(propsB); - expect(a.isEqual(b)).toBeFalsy(); + expect(a?.isEqual(b!)).toBeFalsy(); }); - it("should compare null and undefined", () => { + it("should compare null and undefined", async () => { const propsA: Props = { key: 200, values: [{ name: 'abc' }, { name: 'def' }] }; - const a = EntityExample.create(propsA).value(); - expect(a.isEqual(null as unknown as EntityExample)).toBeFalsy(); - expect(a.isEqual(undefined as unknown as EntityExample)).toBeFalsy(); + const a = await EntityExample.create(propsA); + expect(a?.isEqual(null as unknown as EntityExample)).toBeFalsy(); + expect(a?.isEqual(undefined as unknown as EntityExample)).toBeFalsy(); }); }); describe("util", () => { @@ -631,35 +624,35 @@ describe("entity", () => { return this.util.string(this.props.foo).removeSpaces(); } - public static create(props: Props): Result { + public static create(props: Props): Promise { const isValid = this.isValidProps(props.foo); - if (!isValid) return Result.fail('Erro'); - return Result.Ok(new ValSamp(props)) + if (!isValid) return Promise.resolve(null); + return Promise.resolve(new ValSamp(props)) } } - it('should fail if provide an invalid value', () => { - const ent = ValSamp.create({ foo: '' }); - expect(ent.isFail()).toBeTruthy(); + it('should fail if provide an invalid value', async () => { + const ent = await ValSamp.create({ foo: '' }); + expect(ent).toBeNull(); }); - it('should remove space from value', () => { - const ent = ValSamp.create({ foo: ' Some Value With Spaces ' }); - expect(ent.isOk()).toBeTruthy(); - expect(ent.value()?.RemoveSpace()).toBe('SomeValueWithSpaces'); + it('should remove space from value', async () => { + const ent = await ValSamp.create({ foo: ' Some Value With Spaces ' }); + expect(ent).not.toBeNull(); + expect(ent?.RemoveSpace()).toBe('SomeValueWithSpaces'); }); }); describe('toObject', () => { - it('should infer types to aggregate on toObject method', () => { + it('should infer types to aggregate on toObject method', async () => { class Name extends ValueObject<{ value: string }> { private constructor(props: { value: string }) { super(props) } - public static create(value: string): Result { - return Ok(new Name({ value })); + public static create(value: string): Promise { + return Promise.resolve(new Name({ value })); } } @@ -676,20 +669,20 @@ describe("entity", () => { private constructor(props: Props) { super(props) } - public static create(props: Props): Result { - return Ok(new Product(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Product(props)); } } - const name = Name.create('orange').value(); - const props: Props = { name, additionalInfo: ['from brazil'], price: 10 }; - const orange = Product.create(props).value(); + const name = await Name.create('orange'); + const props: Props = { name: name!, additionalInfo: ['from brazil'], price: 10 }; + const orange = await Product.create(props); - const object = orange.toObject(); + const object = await orange!.toObject(); expect(object.additionalInfo).toEqual(['from brazil']); expect(object.name).toEqual({ value: 'orange' }); expect(object.price).toBe(10); - expect(object.name.value).toBe('orange'); + expect((object.name as any).value).toBe('orange'); }); }); @@ -707,6 +700,7 @@ describe("entity", () => { private constructor(props: Props) { super(props) } + public static init(props: Props): Product { return new Product(props); } @@ -721,7 +715,7 @@ describe("entity", () => { } } - it('should clone string with success', () => { + it('should clone string with success', async () => { const product = Product.init({ additionalInfo: ['lorem'], price: 20, @@ -730,7 +724,8 @@ describe("entity", () => { updatedAt: new Date('2024-05-01T19:07:45.698Z') }); const copy = product.clone({ price: 21 }); - expect(copy.toObject()).toMatchInlineSnapshot(` + const obj = await copy.toObject(); + expect(obj).toMatchInlineSnapshot(` Object { "additionalInfo": Array [ "lorem", @@ -743,7 +738,7 @@ Object { `); }); - it('should clone string with success', () => { + it('should clone string with success', async () => { const product = Product.init({ additionalInfo: ['lorem'], price: 20, @@ -752,7 +747,8 @@ Object { updatedAt: new Date('2024-05-01T19:07:45.698Z') }); const copy = product.clone({ additionalInfo: ['TESTING...'] }); - expect(copy.toObject()).toMatchInlineSnapshot(` + const obj = await copy.toObject(); + expect(obj).toMatchInlineSnapshot(` Object { "additionalInfo": Array [ "TESTING...", @@ -765,7 +761,7 @@ Object { `); }); - it('should clone string with success', () => { + it('should clone string with success', async () => { const product = Product.init({ additionalInfo: ['lorem'], price: 20, @@ -774,7 +770,8 @@ Object { updatedAt: new Date('2024-05-01T19:07:45.698Z') }); const copy = product.clone(); - expect(copy.toObject()).toMatchInlineSnapshot(` + const obj = await copy.toObject(); + expect(obj).toMatchInlineSnapshot(` Object { "additionalInfo": Array [ "lorem", @@ -812,9 +809,9 @@ Object { } } - it('should init a new user', () => { + it('should init a new user', async () => { const user = User.init({ name: 'Jane' }); - const model = user.toObject(new UAdapter()); + const model = await user.toObject(new UAdapter()); expect(model).toEqual({ name: 'Jane' }); }); @@ -842,12 +839,12 @@ Object { super(props); } - public static create(props: Props): Result { + public static create(props: Props): Promise { // Explicit typing allows the programmer to handle `null` as a valid case if (!props.name || props.name.trim() === '') { - return Fail('name is required'); + return Promise.resolve(null); } - return Ok(new SampleNullish(props)); + return Promise.resolve(new SampleNullish(props)); } } @@ -856,81 +853,70 @@ Object { super(props); } - public static create(props: Props): Result { + public static create(props: Props): Promise { // Without `null` as a possibility, the programmer does not need to handle optional cases if (!props.name || props.name.trim() === '') { - return Fail('name is required'); + return Promise.resolve(null); } - return Ok(new Sample(props)); + return Promise.resolve(new Sample(props)); } } describe('SampleNullish.create', () => { - it('should return a result with a nullish value when name is empty', () => { + it('should return a result with a nullish value when name is empty', async () => { // Arrange const invalidProps = { name: '' }; // Act - const result = SampleNullish.create(invalidProps); + const result = await SampleNullish.create(invalidProps); // Assert - expect(result.isFail()).toBe(true); - expect(result.error()).toBe('name is required'); - - // The Developer must explicitly handle the possibility of `null` - const value = result.value(); - expect(value).toBeNull(); // Explicitly null due to failure + expect(result).toBeNull(); }); - it('should return a valid instance when name is provided', () => { + it('should return a valid instance when name is provided', async () => { // Arrange const validProps = { name: 'Valid Name' }; // Act - const result = SampleNullish.create(validProps); + const result = await SampleNullish.create(validProps); // Assert - expect(result.isOk()).toBe(true); + expect(result).not.toBeNull(); // The Developer must handle the value as potentially null - const value = result.value(); - expect(value?.get('name')).toBe('Valid Name'); // Safe access with optional chaining + const value = result!; + expect(value.get('name')).toBe('Valid Name'); // Safe access with optional chaining }); }); describe('Sample.create', () => { - it('should return a failure result when name is empty', () => { + it('should return a failure result when name is empty', async () => { // Arrange const invalidProps = { name: '' }; // Act - const result = Sample.create(invalidProps); + const result = await Sample.create(invalidProps); // Assert - expect(result.isFail()).toBe(true); - expect(result.error()).toBe('name is required'); - - // With no possibility of `null`, the Developer does not need to handle it - const value = result.value(); - expect(value).toBeNull(); // Since the result is a failure + expect(result).toBeNull(); }); - it('should return a valid instance when name is provided', () => { + it('should return a valid instance when name is provided', async () => { // Arrange const validProps = { name: 'Valid Name' }; // Act - const result = Sample.create(validProps); + const result = await Sample.create(validProps); // Assert - expect(result.isOk()).toBe(true); + expect(result).not.toBeNull(); // Developer does not need to use optional chaining - const value = result.value(); + const value = result!; expect(value.get('name')).toBe('Valid Name'); // Confident non-null access }); }); }); - }); diff --git a/tests/core/fail.spec.ts b/tests/core/fail.spec.ts deleted file mode 100644 index 9adf361..0000000 --- a/tests/core/fail.spec.ts +++ /dev/null @@ -1,166 +0,0 @@ -import Fail from "../../lib/core/fail"; -import Result from "../../lib/core/result"; - -describe('fail', () => { - - it('should create a simple no args failure', () => { - const result = Fail(); - expect(result.isOk()).toBeFalsy(); - expect(result.isFail()).toBeTruthy(); - }); - - it('should create a simple failure', () => { - const result = Fail('internal server error'); - expect(result.isOk()).toBeFalsy(); - expect(result.isFail()).toBeTruthy(); - }); - - it('should create a failure result as void', () => { - const result = Fail(null); - expect(result.isOk()).toBeFalsy(); - expect(result.isFail()).toBeTruthy(); - expect(result.toObject()).toEqual({ - "data": null, - "error": 'void error. no message!', - "isFail": true, - "isOk": false, - "metaData": {}, - }); - }); - - it('should create a failure result as void and metaData', () => { - - interface MetaData { - ping: string; - } - - const result = Fail(null, { ping: 'pong' }); - expect(result.isOk()).toBeFalsy(); - expect(result.isFail()).toBeTruthy(); - expect(result.toObject()).toEqual({ - "data": null, - "error": 'void error. no message!', - "isFail": true, - "isOk": false, - "metaData": { ping: 'pong' }, - }); - }); - - it('should create a failure result as generic type', () => { - - interface Generic { - message: string; - statusCode: number; - } - - const result = Fail({ message: 'internal server error', statusCode: 500 }); - expect(result.isOk()).toBeFalsy(); - expect(result.isFail()).toBeTruthy(); - expect(result.toObject()).toEqual({ - "data": null, - "error": { message: 'internal server error', statusCode: 500 }, - "isFail": true, - "isOk": false, - "metaData": {}, - }); - }); - - it('should create a failure result as generic type and metaData', () => { - - interface Generic { - message: string; - } - - interface MetaData { - statusCode: number; - } - - const result = Fail({ message: 'bad request' }, { statusCode: 400 }); - expect(result.isOk()).toBeFalsy(); - expect(result.isFail()).toBeTruthy(); - expect(result.toObject()).toEqual({ - "data": null, - "error": { message: 'bad request' }, - "isFail": true, - "isOk": false, - "metaData": { statusCode: 400 }, - }); - }); - - it('should create a failure result as generic type and metaData and error', () => { - - interface Generic { - message: string; - } - - interface MetaData { - arg: string; - } - - const result = Fail({ message: 'invalid email' }, { arg: 'invalid@mail.com' }); - expect(result.isOk()).toBeFalsy(); - expect(result.isFail()).toBeTruthy(); - expect(result.toObject()).toEqual({ - "data": null, - "error": { message: 'invalid email' }, - "isFail": true, - "isOk": false, - "metaData": { arg: 'invalid@mail.com' }, - }); - }); - - describe('generic types', () => { - - type Error = { message: string }; - type MetaData = { args: number }; - - it('should fail generate the same payload as result', () => { - - const status: number = 400; - const metaData: MetaData = { args: status }; - const error: Error = { message: 'something went wrong!' }; - - const resultInstance = Result.fail(error, metaData); - const failInstance = Fail(error, metaData); - - expect(resultInstance.toObject()).toEqual(failInstance.toObject()); - - }); - - it('should fail generate the same payload as result', () => { - - const resultInstance = Result.fail(); - const okInstance = Fail(); - - expect(resultInstance.toObject()).toEqual(okInstance.toObject()); - - }); - - - it('should fail generate the same payload as result', () => { - - const resultInstance = Result.fail('hey there'); - const okInstance = Fail('hey there'); - - expect(resultInstance.toObject()).toEqual(okInstance.toObject()); - - }); - - it('should fail generate the same payload as result', () => { - - const resultInstance = Result.fail('hey there', { status: 400 }); - const okInstance = Fail('hey there', { status: 400 }); - - expect(resultInstance.toObject()).toEqual(okInstance.toObject()); - - }); - - - it('should Result type to be valid if use IResult', () => { - - const testingA = (): Result => Fail('should return string'); - expect(testingA().isFail()).toBeTruthy(); - - }); - }); -}); diff --git a/tests/core/ok.spec.ts b/tests/core/ok.spec.ts deleted file mode 100644 index e575481..0000000 --- a/tests/core/ok.spec.ts +++ /dev/null @@ -1,172 +0,0 @@ -import Ok from "../../lib/core/ok"; -import Result from "../../lib/core/result"; - -describe('ok', () => { - - it('should create a simple success with no args', () => { - const result = Ok(); - expect(result.isOk()).toBeTruthy(); - expect(result.isFail()).toBeFalsy(); - }); - - it('should create a simple success with null value', () => { - const result = Ok(null); - expect(result.isOk()).toBeTruthy(); - expect(result.isFail()).toBeFalsy(); - }); - - it('should create a success result as void', () => { - const result = Ok(null); - expect(result.isOk()).toBeTruthy(); - expect(result.isFail()).toBeFalsy(); - expect(result.toObject()).toEqual({ - "data": null, - "error": null, - "isFail": false, - "isOk": true, - "metaData": {}, - }); - }); - - it('should create a success result as void and metaData', () => { - - interface MetaData { - ping: string; - } - - const result = Ok(null, { ping: 'pong' }); - expect(result.isOk()).toBeTruthy(); - expect(result.isFail()).toBeFalsy(); - expect(result.toObject()).toEqual({ - "data": null, - "error": null, - "isFail": false, - "isOk": true, - "metaData": { ping: 'pong' }, - }); - }); - - it('should create a success result as generic type', () => { - - interface Generic { - name: string; - age: number; - } - - const result = Ok({ age: 21, name: 'Jane' }); - expect(result.isOk()).toBeTruthy(); - expect(result.isFail()).toBeFalsy(); - expect(result.toObject()).toEqual({ - "data": { age: 21, name: 'Jane' }, - "error": null, - "isFail": false, - "isOk": true, - "metaData": {}, - }); - }); - - it('should create a success result as generic type and metaData', () => { - - interface Generic { - name: string; - age: number; - } - - interface MetaData { - arg: string; - } - - const result = Ok({ age: 23, name: 'James' }, { arg: 'my argument' }); - expect(result.isOk()).toBeTruthy(); - expect(result.isFail()).toBeFalsy(); - expect(result.toObject()).toEqual({ - "data": { age: 23, name: 'James' }, - "error": null, - "isFail": false, - "isOk": true, - "metaData": { arg: 'my argument' }, - }); - }); - - it('should create a success result as generic type and metaData and error', () => { - - interface Generic { - name: string; - age: number; - } - - interface MetaData { - arg: string; - } - - interface Error { - message: string; - } - - const result = Ok({ age: 2, name: 'Panda' }, { arg: 'my argument' }); - expect(result.isOk()).toBeTruthy(); - expect(result.isFail()).toBeFalsy(); - expect(result.toObject()).toEqual({ - "data": { age: 2, name: 'Panda' }, - "error": null, - "isFail": false, - "isOk": true, - "metaData": { arg: 'my argument' }, - }); - }); - - describe('generic types', () => { - - type Error = { message: string }; - type Payload = { data: { status: number } }; - type MetaData = { args: number }; - - it('should ok generate the same payload as result', () => { - - const status: number = 200; - const payload: Payload = { data: { status } }; - const metaData: MetaData = { args: status }; - - const resultInstance = Result.Ok(payload, metaData); - const okInstance = Ok(payload, metaData); - - expect(resultInstance.toObject()).toEqual(okInstance.toObject()); - - }); - - it('should ok generate the same payload as result', () => { - - const resultInstance = Result.Ok(); - const okInstance = Ok(); - - expect(resultInstance.toObject()).toEqual(okInstance.toObject()); - - }); - - - it('should ok generate the same payload as result', () => { - - const resultInstance = Result.Ok('hey there'); - const okInstance = Ok('hey there'); - - expect(resultInstance.toObject()).toEqual(okInstance.toObject()); - - }); - - it('should ok generate the same payload as result', () => { - - const resultInstance = Result.Ok('hey there', { status: 200 }); - const okInstance = Ok('hey there', { status: 200 }); - - expect(resultInstance.toObject()).toEqual(okInstance.toObject()); - - }); - - it('should Result type to be valid if use IResult', () => { - - const testingA = (): Result => Ok(); - expect(testingA().isOk()).toBeTruthy(); - - }); - }); -}); diff --git a/tests/core/result.spec.ts b/tests/core/result.spec.ts deleted file mode 100644 index 2d067d7..0000000 --- a/tests/core/result.spec.ts +++ /dev/null @@ -1,325 +0,0 @@ -import { Fail, Ok, Result } from "../../lib/core"; -import { ICommand, Payload } from "../../lib/types"; - -describe('result', () => { - - type Args = string | void; - type CustomPayload = string; - - class Command implements ICommand { - execute(args?: Args): CustomPayload { - return args ?? 'no args provided'; - } - } - - describe('failure', () => { - it('should be fail', () => { - - const result = Result.fail('fail', { message: 'some metadata info' }); - - expect(result.error()).toBe('fail'); - expect(result.isOk()).toBeFalsy(); - expect(result.isFail()).toBeTruthy(); - const payloadA = result.execute(new Command()).on('fail') - const payloadB = result.execute(new Command()).withData('args provided').on('fail'); - expect(payloadA).toBe('no args provided'); - expect(payloadB).toBe('args provided'); - const payloadC = Result.combine([result]).execute(new Command()).on('fail'); - expect(payloadC).toBe('no args provided'); - }); - - it('should fails if provide an empty state to combine function', () => { - expect(Result.combine([]).isFail()).toBeTruthy(); - }); - }); - - describe('success', () => { - const success1 = Result.Ok(1); - const success2 = Result.Ok(2); - const success3 = Result.Ok(3); - - it('should return first if success', () => { - expect(Result.combine([success1, success2, success3]).value()).toBe(1); - }); - - it('should execute a command on success', () => { - - class Command implements ICommand { - execute(): number { - return 1; - } - } - - const command = new Command(); - const commandSpy = jest.spyOn(command, 'execute'); - - const success = Result.Ok(1); - - const payload = success.execute(command).on('Ok'); - expect(commandSpy).toHaveBeenCalled(); - expect(payload).toBe(1); - }); - - it('should execute a command on success and provide data', () => { - - class Command implements ICommand { - execute(data: number): number { - return data + 1; - } - } - - const command = new Command(); - const commandSpy = jest.spyOn(command, 'execute'); - - const success = Result.Ok(1); - - const payload = success.execute(command).withData(1).on('Ok'); - expect(commandSpy).toHaveBeenCalled(); - expect(payload).toBe(2); - }); - - it('should get an {} if metadata is not provided', () => { - const success = Result.Ok(1); - expect(success.metaData()).toEqual({}); - }); - - it('should get metadata if provided', () => { - const success = Result.Ok(1, { meta: 'Data' }); - expect(success.metaData()).toEqual({ meta: 'Data' }); - }); - - it('should get object result', () => { - const success = Result.Ok(1, { meta: 'Data' }); - expect(success.toObject()).toEqual({ - "data": 1, "error": null, "isFail": false, "isOk": true, "metaData": { "meta": "Data" } - }); - }); - - it('should accept void', () => { - - const result: Result = Result.Ok(); - - expect(result.isOk()).toBeTruthy(); - - expect(result.isFail()).toBeFalsy(); - - expect(result.metaData()).toEqual({}); - - expect(result.error()).toBe(null); - - expect(result.value()).toBe(null); - - }); - }); - - describe('read-only', () => { - it('result must be read-only', () => { - const fail = Result.fail('error message'); - - const errObj = fail.toObject(); - - expect(errObj.error).toBe('error message'); - - const error = () => errObj.error = 'new changed message'; - - expect(error).toThrowError("Cannot assign to read only property 'error' of object '#'") - - expect(errObj.error).toBe('error message'); - }) - }); - - describe('Payload type', () => { - - it('should payload to be a valid type for Result', () => { - - const IsOK = (): Payload => Result.Ok(); - expect(IsOK().isOk()).toBeTruthy(); - - }); - - it('should payload to be a valid type for Result', () => { - - const IsOK = (): Payload => Result.fail(); - expect(IsOK().isOk()).toBeFalsy(); - - }); - - it('should payload to be a valid type for Result', () => { - - const IsOK = (): Payload => Ok(); - expect(IsOK().isOk()).toBeTruthy(); - - }); - - it('should payload to be a valid type for Result', () => { - - const IsOK = (): Payload => Fail(); - expect(IsOK().isOk()).toBeFalsy(); - - }); - - }); - - describe('result serialized', () => { - it('should Ok do not have none public key', () => { - const result = Ok(); - expect(JSON.stringify(result)).toMatchInlineSnapshot(`"{}"`); - }); - - it('should Fail do not have none public key', () => { - const result = Fail(); - expect(JSON.stringify(result)).toMatchInlineSnapshot(`"{}"`); - }); - }); -}); - -describe('Result', () => { - describe('Ok', () => { - it('should create an instance of Result in success state without data', () => { - const result = Result.Ok(); - expect(result.isOk()).toBe(true); - expect(result.value()).toBe(null); - expect(result.error()).toBe(null); - expect(result.metaData()).toEqual({}); - }); - - it('should create an instance of Result in success state with data and metadata', () => { - const data = { key: 'value' }; - const metaData = { metaKey: 'metaValue' }; - const result = Result.Ok(data, metaData); - expect(result.isOk()).toBe(true); - expect(result.value()).toBe(data); - expect(result.error()).toBe(null); - expect(result.metaData()).toEqual(metaData); - }); - }); - - describe('fail', () => { - it('should create an instance of Result in failure state without error', () => { - const result = Result.fail(); - expect(result.isFail()).toBe(true); - expect(result.value()).toBe(null); - expect(result.error()).toBe('void error. no message!'); - expect(result.metaData()).toEqual({}); - }); - - it('should create an instance of Result in failure state with error and metadata', () => { - const error = 'Custom error message'; - const metaData = { metaKey: 'metaValue' }; - const result = Result.fail(error, metaData); - expect(result.isFail()).toBe(true); - expect(result.value()).toBe(null); - expect(result.error()).toBe(error); - expect(result.metaData()).toEqual(metaData); - }); - }); - - describe('iterate', () => { - it('should create an Iterator instance from an array of Results', () => { - const results = [Result.Ok(), Result.fail()]; - const iterator = Result.iterate(results); - expect(iterator).toBeDefined(); - expect(iterator.total()).toBe(2); - }); - }); - - describe('combine', () => { - it('should return the first failure if provided with an array of results', () => { - const results = [Result.Ok(), Result.fail('Error 1'), Result.fail('Error 2')]; - const combinedResult = Result.combine(results); - expect(combinedResult.isFail()).toBe(true); - expect(combinedResult.error()).toBe('Error 1'); - }); - - it('should return the first success if provided with an array of results', () => { - const results = [Result.Ok(), Result.Ok(), Result.Ok()]; - const combinedResult = Result.combine(results); - expect(combinedResult.isOk()).toBe(true); - expect(combinedResult.value()).toBe(null); - }); - - it('should return a failure if no results are provided', () => { - const combinedResult = Result.combine([]); - expect(combinedResult.isFail()).toBe(true); - expect(combinedResult.error()).toBe('No results provided on combine param'); - }); - }); - - describe('execute', () => { - it('should execute a command without data based on result state', () => { - const command = { - execute: jest.fn().mockReturnValue('Command result') - }; - const result = Result.Ok(); - const resultExecute = result.execute(command); - expect(resultExecute.on('Ok')).toBe('Command result'); - }); - - it('should execute a command with data based on result state', () => { - const command = { - execute: jest.fn().mockReturnValue('Command result') - }; - const result = Result.Ok(); - const resultExecute = result.execute(command); - expect(resultExecute.withData('Data').on('Ok')).toBe('Command result'); - }); - }); - - describe('value', () => { - it('should return the value of the result', () => { - const result = Result.Ok('Value'); - expect(result.value()).toBe('Value'); - }); - }); - - describe('error', () => { - it('should return the error of the result', () => { - const result = Result.fail('Error'); - expect(result.error()).toBe('Error'); - }); - }); - - describe('isFail', () => { - it('should return true if the result is a failure', () => { - const result = Result.fail(); - expect(result.isFail()).toBe(true); - }); - - it('should return false if the result is a success', () => { - const result = Result.Ok(); - expect(result.isFail()).toBe(false); - }); - }); - - describe('isOk', () => { - it('should return true if the result is a success', () => { - const result = Result.Ok(); - expect(result.isOk()).toBe(true); - }); - - it('should return false if the result is a failure', () => { - const result = Result.fail(); - expect(result.isOk()).toBe(false); - }); - }); - - describe('metaData', () => { - it('should return the metadata of the result', () => { - const metaData = { key: 'value' }; - const result = Result.Ok(null, metaData); - expect(result.metaData()).toEqual(metaData); - }); - }); - - describe('toObject', () => { - it('should return the state of the result as an object', () => { - const result = Result.Ok('Value', { key: 'value' }); - const resultObject = result.toObject(); - expect(resultObject.isOk).toBe(true); - expect(resultObject.isFail).toBe(false); - expect(resultObject.data).toBe('Value'); - expect(resultObject.error).toBe(null); - expect(resultObject.metaData).toEqual({ key: 'value' }); - }); - }); -}); diff --git a/tests/core/value-object.spec.ts b/tests/core/value-object.spec.ts index 00832ff..f9c3cc2 100644 --- a/tests/core/value-object.spec.ts +++ b/tests/core/value-object.spec.ts @@ -1,5 +1,5 @@ -import { Class, Ok, Result, ValueObject } from "../../lib/core"; -import { Adapter, ICommand, _Result } from "../../lib/types"; +import { Class, ValueObject } from "../../lib/core"; +import { Adapter } from "../../lib/types"; import { Utils, Validator } from "../../lib/utils"; describe('value-object', () => { @@ -33,8 +33,9 @@ describe('value-object', () => { } - public static create(props: Props): Result { - return Ok(new GenericVo(props)) + public static create(props: Props): Promise { + if(props === null || typeof props === 'undefined') return Promise.resolve(null); + return Promise.resolve(new GenericVo(props)) } } @@ -51,20 +52,20 @@ describe('value-object', () => { expect(GenericVo.tools().validator).toBeInstanceOf(Validator); }); - it('should return fails if provide a null value', () => { - const obj = GenericVo.create(null as any); - expect(obj.isFail()).toBeFalsy(); + it('should return fails if provide a null value', async () => { + const obj = await GenericVo.create(null as any); + expect(obj).toBeNull(); }); - it('should return fails if provide an undefined value', () => { - const obj = GenericVo.create(undefined as any); - expect(obj.isFail()).toBeFalsy(); + it('should return fails if provide an undefined value', async () => { + const obj = await GenericVo.create(undefined as any); + expect(obj).toBeNull(); }); - it('should create a valid value-object', () => { - const obj = GenericVo.create({ value: 'Hello World' }); - expect(obj.isFail()).toBeFalsy(); - expect(obj.value().get('value')).toBe('Hello World'); + it('should create a valid value-object', async () => { + const obj = await GenericVo.create({ value: 'Hello World' }); + expect(obj).not.toBeNull(); + expect(obj?.get('value')).toBe('Hello World'); }); }); @@ -82,22 +83,26 @@ describe('value-object', () => { public static isValidProps(): boolean { return true; } + + public static create(props: any): Promise { + return Promise.resolve(new GenericVo(props)); + } } - it('should return success if provide a null value', () => { - const obj = GenericVo.create(null); - expect(obj.isOk()).toBeTruthy(); + it('should return success if provide a null value', async () => { + const obj = await GenericVo.create(null); + expect(obj).not.toBeNull(); }); - it('should return success if provide an undefined value', () => { - const obj = GenericVo.create(undefined); - expect(obj.isOk()).toBeTruthy(); + it('should return success if provide an undefined value', async () => { + const obj = await GenericVo.create(undefined); + expect(obj).not.toBeNull(); }); - it('should create a valid value-object', () => { - const obj = GenericVo.create({ value: 'Hello World' }); - expect(obj.isFail()).toBeFalsy(); - expect(obj.value().get('value')).toBe('Hello World'); + it('should create a valid value-object', async () => { + const obj = await GenericVo.create({ value: 'Hello World' }); + expect(obj).not.toBeNull(); + expect(obj?.get('value')).toBe('Hello World'); }); }); @@ -111,13 +116,13 @@ describe('value-object', () => { class City extends ValueObject<'A' | 'B' | 'C'> { } class Address extends ValueObject { } - it('should verify resolved types', () => { + it('should verify resolved types', async () => { const address = new Address({ city: new City('A'), number: 123, street: '5th Avenue' }); - const addressObject = address.toObject() + const addressObject = await address.toObject() expect(addressObject).toEqual({ city: 'A', @@ -134,13 +139,13 @@ describe('value-object', () => { expect(addressObject.street.toUpperCase()).toBe('5TH AVENUE'); }); - it('should be immutable', () => { + it('should be immutable', async () => { const address = new Address({ city: new City('A'), number: 123, street: '5th Avenue' }); - const addressObject = address.toObject() + const addressObject = await address.toObject() expect(Object.isFrozen(addressObject)).toBeTruthy(); expect(() => (addressObject as any).city = 'B').toThrowError(); }); @@ -158,15 +163,15 @@ describe('value-object', () => { super(props); } - public static create(props: Props): _Result { - return Result.Ok(new StringVo(props)); + public static create(props: Props): Promise { + return Promise.resolve(new StringVo(props)); } } - it('should create a valid value-object', () => { - const obj = StringVo.create({ value: 'Hello World' }); - expect(obj.isFail()).toBeFalsy(); - expect(obj.value().getRaw().value).toBe('Hello World'); + it('should create a valid value-object', async () => { + const obj = await StringVo.create({ value: 'Hello World' }); + expect(obj).not.toBeNull(); + expect(obj?.getRaw().value).toBe('Hello World'); }); }); @@ -182,22 +187,14 @@ describe('value-object', () => { super(props); } - public static create(props: Props): _Result { - return Result.Ok(new StringVo(props)); - } - } - - class Command implements ICommand { - execute(data: string): string { - return data; + public static create(props: Props): Promise { + return Promise.resolve(new StringVo(props)); } } - it('should execute hook on create a valid value object', () => { - const data = 'value object created with success'; - const obj = StringVo.create({ value: 'Hello World' }); - const payload = obj.execute(new Command()).withData(data).on('Ok'); - expect(payload).toBe('value object created with success'); + it('should execute hook on create a valid value object', async () => { + const obj = await StringVo.create({ value: 'Hello World' }); + expect(obj).not.toBeNull(); }); }) @@ -213,80 +210,95 @@ describe('value-object', () => { super(props, { disableGetters: true }); } - public static create(props: Props): _Result { - return Result.Ok(new StringVo(props)); + public static create(props: Props): Promise { + return Promise.resolve(new StringVo(props)); } } - it('should disable getter', () => { - const str = StringVo.create({ value: 'hello', age: 7 }); - expect(() => str.value().get('value')).toThrow(); + it('should disable getter', async () => { + const str = await StringVo.create({ value: 'hello', age: 7 }); + expect(() => str!.get('value')).toThrow(); }); - it('should transform value object to object', () => { + it('should transform value object to object', async () => { class Sample extends ValueObject { private constructor(props: string) { super(props); } + public static create(props: string): Promise { + return Promise.resolve(new Sample(props)); + } }; - const valueObject = Sample.create('Example'); + const valueObject = await Sample.create('Example'); - expect(valueObject.value().toObject()).toBe('Example'); + expect(await valueObject!.toObject()).toBe('Example'); }); - it('should transform value object to object', () => { + it('should transform value object to object', async () => { class Sample extends ValueObject<{ value: string }> { private constructor(props: { value: string }) { super(props); } + public static create(props: { value: string }): Promise { + return Promise.resolve(new Sample(props)); + } }; - const valueObject = Sample.create({ value: 'Sample' }); + const valueObject = await Sample.create({ value: 'Sample' }); - expect(valueObject.value().toObject()).toEqual({ value: 'Sample' }); + expect(await valueObject!.toObject()).toEqual({ value: 'Sample' }); }); - it('should transform value object to object', () => { + it('should transform value object to object', async () => { class Sample extends ValueObject<{ value: string, foo: string }> { private constructor(props: { value: string, foo: string }) { super(props); } + public static create(props: { value: string, foo: string }): Promise { + return Promise.resolve(new Sample(props)); + } }; - const sample = Sample.create({ value: 'Sample', foo: 'bar' }); + const sample = await Sample.create({ value: 'Sample', foo: 'bar' }); class Obj extends ValueObject<{ value: Sample, other: string }> { private constructor(props: { value: Sample, other: string }) { super(props); } + public static create(props: { value: Sample, other: string }): Promise { + return Promise.resolve(new Obj(props)); + } }; - const result = Obj.create({ value: sample.value(), other: 'Other Sample' }); + const result = await Obj.create({ value: sample!, other: 'Other Sample' }); - expect(result.value().toObject()).toEqual({ + expect(await result!.toObject()).toEqual({ value: { value: 'Sample', foo: 'bar' }, other: 'Other Sample' }) }); - it('should clone a value object with success', () => { + it('should clone a value object with success', async () => { class Sample extends ValueObject<{ value: string, foo: string }> { private constructor(props: { value: string, foo: string }) { super(props); } + public static create(props: { value: string, foo: string }): Promise { + return Promise.resolve(new Sample(props)); + } }; - const sample = Sample.create({ value: 'Sample', foo: 'bar' }); + const sample = await Sample.create({ value: 'Sample', foo: 'bar' }); - const result = sample.value().clone(); + const result = sample!.clone(); - expect(sample.value().toObject()).toEqual(result.toObject()) + expect(await sample!.toObject()).toEqual(await result.toObject()) }); - it('should clone a value object with custom props', () => { + it('should clone a value object with custom props', async () => { interface Props { value: string; foo: string; } class Sample extends ValueObject { @@ -294,16 +306,16 @@ describe('value-object', () => { super(props); } - public static create(props: Props): Result { - return Ok(new Sample(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Sample(props)); } }; - const sample = Sample.create({ value: 'Sample', foo: 'bar' }); + const sample = await Sample.create({ value: 'Sample', foo: 'bar' }); - const result = sample.value().clone({ foo: 'other' }); + const result = sample!.clone({ foo: 'other' }); - expect(result.toObject()).toEqual({ foo: 'other', value: 'Sample' }); + expect(await result.toObject()).toEqual({ foo: 'other', value: 'Sample' }); }); }); @@ -328,9 +340,9 @@ describe('value-object', () => { return isValidAge && isValidDate; } - public static create(props: Props1): _Result { - if (!HumanAge.isValidProps(props)) return Result.fail('Invalid props'); - return Result.Ok(new HumanAge(props)); + public static create(props: Props1): Promise { + if (!HumanAge.isValidProps(props)) return Promise.resolve(null); + return Promise.resolve(new HumanAge(props)); } } @@ -350,14 +362,14 @@ describe('value-object', () => { super(props); } - public static create(props: Props3): _Result { - return Result.Ok(new Sample(props)); + public static create(props: Props3): Promise { + return Promise.resolve(new Sample(props)); } }; - it('should create many value objects', () => { + it('should create many value objects', async () => { - const payload = ValueObject.createMany([ + const payload = await ValueObject.createMany([ { class: HumanAge, props: { value: 21, birthDay: new Date('2021-01-01') } @@ -372,13 +384,14 @@ describe('value-object', () => { } ]); - expect(payload.result.isOk()).toBeTruthy(); + const result = await payload.result; + expect(result).not.toBeNull(); expect(payload.data.total()).toBe(3); }); - it('should add fails if does not exists create function on class', () => { + it('should add fails if does not exists create function on class', async () => { - const payload = ValueObject.createMany([ + const payload = await ValueObject.createMany([ { class: {}, props: { value: 21, birthDay: new Date() } @@ -393,54 +406,58 @@ describe('value-object', () => { } ]); - expect(payload.result.error()).toBe(`No static 'create' method found in class undefined.`) - expect(payload.result.isFail()).toBeTruthy(); + const result = await payload.result; + expect(result).toBeNull(); expect(payload.data.total()).toBe(3); }); - it('should create many using DomainClass helper', () => { - const { result, data } = ValueObject.createMany([ + it('should create many using DomainClass helper', async () => { + const { result, data } = await ValueObject.createMany([ Class(HumanAge, { value: 21, birthDay: new Date('2021-01-01') }), Class(GenericVo, { value: 'Hello' }), Class(Sample, { value: 'hello', foo: 'testing' }) ]); - expect(result.isOk()).toBeTruthy(); + const res = await result; + expect(res).not.toBeNull(); expect(data.total()).toBe(3); - const age = data.next() as _Result; - const generic = data.next() as _Result; - const sample = data.next() as _Result; + const age = await data.next() as HumanAge; + const generic = await data.next() as GenericVo; + const sample = await data.next() as Sample; - expect(age.isOk()).toBeTruthy(); - expect(generic.isOk()).toBeTruthy(); - expect(sample.isOk()).toBeTruthy(); + expect(age).not.toBeNull(); + expect(generic).not.toBeNull(); + expect(sample).not.toBeNull(); - expect(age.value().getRaw().value).toBe(21); - expect(generic.value().getRaw().value).toBe('Hello'); - expect(sample.value().getRaw().value).toBe('hello'); + expect(age.getRaw().value).toBe(21); + expect(generic.getRaw().value).toBe('Hello'); + expect(sample.getRaw().value).toBe('hello'); }); - it('should fails if provide an empty array', () => { - const { result, data: iterator } = ValueObject.createMany([]); + it('should fails if provide an empty array', async () => { + const { result, data: iterator } = await ValueObject.createMany([]); - expect(result.isFail()).toBeTruthy(); + const res = await result; + expect(res).toBeNull(); expect(iterator.total()).toBe(0); }); - it('should fails if provide an empty array', () => { - const { result, data: iterator } = ValueObject.createMany({} as any); + it('should fails if provide an empty array', async () => { + const { result, data: iterator } = await ValueObject.createMany({} as any); - expect(result.isFail()).toBeTruthy(); + const res = await result; + expect(res).toBeNull(); expect(iterator.total()).toBe(0); }); - it('should fails if provide an invalid props', () => { - const { result, data: iterator } = ValueObject.createMany([ + it('should fails if provide an invalid props', async () => { + const { result, data: iterator } = await ValueObject.createMany([ Class(HumanAge, { value: 210 } as any), ]); - expect(result.isFail()).toBeTruthy(); + const res = await result; + expect(res).toBeNull(); expect(iterator.total()).toBe(1); }) }); @@ -455,30 +472,30 @@ describe('value-object', () => { super(props) } - public static create(props: Props): Result { - return Ok(new Exam(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Exam(props)); } }; - it('should to be equal another instance', () => { - const a = Exam.create({ value: "hello there" }).value(); - const b = Exam.create({ value: "hello there" }).value(); + it('should to be equal another instance', async () => { + const a = await Exam.create({ value: "hello there" }); + const b = await Exam.create({ value: "hello there" }); - expect(a.isEqual(b)).toBeTruthy(); + expect(a!.isEqual(b!)).toBeTruthy(); }); - it('should to be equal another instance', () => { - const a = Exam.create({ value: "hello there" }).value(); - const b = a.clone(); + it('should to be equal another instance', async () => { + const a = await Exam.create({ value: "hello there" }); + const b = a!.clone(); - expect(a.isEqual(b)).toBeTruthy(); + expect(a!.isEqual(b)).toBeTruthy(); }); - it('should not to be equal another instance', () => { - const a = Exam.create({ value: "hello there 1" }).value(); - const b = Exam.create({ value: "hello there 2" }).value(); + it('should not to be equal another instance', async () => { + const a = await Exam.create({ value: "hello there 1" }); + const b = await Exam.create({ value: "hello there 2" }); - expect(a.isEqual(b)).toBeFalsy(); + expect(a!.isEqual(b!)).toBeFalsy(); }); }); @@ -501,24 +518,24 @@ describe('value-object', () => { return this.util.string(this.props.value).removeSpecialChars(); } - public static create(props: Props): Result { - return Ok(new Exam(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Exam(props)); } }; - it('should remove spaces', () => { - const a = Exam.create({ value: " Some Value With Many Space" }).value(); - expect(a.RemoveSpaces()).toBe('SomeValueWithManySpace'); + it('should remove spaces', async () => { + const a = await Exam.create({ value: " Some Value With Many Space" }); + expect(a!.RemoveSpaces()).toBe('SomeValueWithManySpace'); }); - it('should remove special chars', () => { - const a = Exam.create({ value: "#Some@Value&With%Many*Special-Chars" }).value(); - expect(a.RemoveSpecialChars()).toBe('SomeValueWithManySpecialChars'); + it('should remove special chars', async () => { + const a = await Exam.create({ value: "#Some@Value&With%Many*Special-Chars" }); + expect(a!.RemoveSpecialChars()).toBe('SomeValueWithManySpecialChars'); }); - it('should remove special chars and spaces', () => { - const a = Exam.create({ value: "#Some @Value &With %Many *Special-Chars" }).value(); - expect(a.RemoveSpaces(a.RemoveSpecialChars())).toBe('SomeValueWithManySpecialChars'); + it('should remove special chars and spaces', async () => { + const a = await Exam.create({ value: "#Some @Value &With %Many *Special-Chars" }); + expect(a!.RemoveSpaces(a!.RemoveSpecialChars())).toBe('SomeValueWithManySpecialChars'); }); }); @@ -530,38 +547,38 @@ describe('value-object', () => { super(props) } - public static create(props: Props): _Result { - return Result.Ok(new Simple(props)); + public static create(props: Props): Promise { + return Promise.resolve(new Simple(props)); } } - it('should infer type on compare', () => { - const a = Simple.create({ value: 'a' }).value(); - const b = Simple.create({ value: 'b' }).value(); - const c = Simple.create({ value: 'a' }).value(); + it('should infer type on compare', async () => { + const a = await Simple.create({ value: 'a' }); + const b = await Simple.create({ value: 'b' }); + const c = await Simple.create({ value: 'a' }); - expect(a.isEqual(b)).toBeFalsy(); - expect(a.isEqual(c)).toBeTruthy(); + expect(a!.isEqual(b!)).toBeFalsy(); + expect(a!.isEqual(c!)).toBeTruthy(); }); - it('should compare nullable or undefined', () => { - const a = Simple.create({ value: 'a' }).value(); - const b = Simple.create({ value: 'b' }).value(); + it('should compare nullable or undefined', async () => { + const a = await Simple.create({ value: 'a' }); + const b = await Simple.create({ value: 'b' }); - expect(a.isEqual(null as unknown as Simple)).toBeFalsy(); - expect(b.isEqual(undefined as unknown as Simple)).toBeFalsy(); + expect(a!.isEqual(null as unknown as Simple)).toBeFalsy(); + expect(b!.isEqual(undefined as unknown as Simple)).toBeFalsy(); }); - it('should create a valid props object as value object', () => { - const primitive = Simple.create({ value: 'TEST' }).value(); - expect(typeof primitive.getRaw().value).toBe('string'); - expect(typeof primitive.get('value')).toBe('string'); - expect(typeof primitive.get('value')).toBe('string'); - expect(typeof primitive.toObject()).toBe('object'); + it('should create a valid props object as value object', async () => { + const primitive = await Simple.create({ value: 'TEST' }); + expect(typeof primitive!.getRaw().value).toBe('string'); + expect(typeof primitive!.get('value')).toBe('string'); + const obj = await primitive!.toObject(); + expect(typeof obj).toBe('object'); - expect(primitive.getRaw().value).toBe('TEST'); - expect(primitive.get('value')).toBe('TEST'); - expect(primitive.toObject()).toEqual({ value: 'TEST' }); + expect(primitive!.getRaw().value).toBe('TEST'); + expect(primitive!.get('value')).toBe('TEST'); + expect(await primitive!.toObject()).toEqual({ value: 'TEST' }); }); }); @@ -573,20 +590,21 @@ describe('value-object', () => { super(value) } - public static create(value: string): Result { - return Ok(new Primitive(value)); + public static create(value: string): Promise { + return Promise.resolve(new Primitive(value)); } }; - it('should create a valid primitive value object', () => { - const primitive = Primitive.create('TEST').value(); - expect(typeof primitive.getRaw()).toBe('string'); - expect(typeof primitive.get('value')).toBe('string'); - expect(typeof primitive.toObject()).toBe('string'); + it('should create a valid primitive value object', async () => { + const primitive = await Primitive.create('TEST'); + expect(typeof primitive!.getRaw()).toBe('string'); + expect(typeof primitive!.get('value')).toBe('string'); + const obj = await primitive!.toObject(); + expect(typeof obj).toBe('string'); - expect(primitive.getRaw()).toBe('TEST'); - expect(primitive.get('value')).toBe('TEST'); - expect(primitive.toObject()).toBe('TEST'); + expect(primitive!.getRaw()).toBe('TEST'); + expect(primitive!.get('value')).toBe('TEST'); + expect(await primitive!.toObject()).toBe('TEST'); }); }); @@ -597,21 +615,21 @@ describe('value-object', () => { super(value) } - public static create(value: Date): Result { - return Ok(new Primitive(value)); + public static create(value: Date): Promise { + return Promise.resolve(new Primitive(value)); } }; - it('should create a valid primitive value object', () => { + it('should create a valid primitive value object', async () => { const date = new Date('2024-04-01T00:00:00'); - const primitive = Primitive.create(date).value(); - expect(primitive.getRaw()).toBeInstanceOf(Date); - expect(primitive.get('value')).toBeInstanceOf(Date); - expect(primitive.toObject()).toEqual(expect.any(Date)); + const primitive = await Primitive.create(date); + expect(primitive!.getRaw()).toBeInstanceOf(Date); + expect(primitive!.get('value')).toBeInstanceOf(Date); + expect(await primitive!.toObject()).toEqual(expect.any(Date)); - expect(primitive.getRaw()).toBe(date); - expect(primitive.get('value')).toBe(date); - expect(primitive.toObject()).toBe(date); + expect(primitive!.getRaw()).toBe(date); + expect(primitive!.get('value')).toBe(date); + expect(await primitive!.toObject()).toBe(date); }); }); @@ -622,20 +640,20 @@ describe('value-object', () => { super(value) } - public static create(value: Array): Result { - return Ok(new Primitive(value)); + public static create(value: Array): Promise { + return Promise.resolve(new Primitive(value)); } }; - it('should create a valid primitive value object', () => { - const primitive = Primitive.create([1, 2, 3]).value(); - expect(primitive.getRaw()).toEqual([1, 2, 3]); - expect(primitive.get('value')).toEqual([1, 2, 3]); - expect(primitive.toObject()).toEqual([1, 2, 3]); + it('should create a valid primitive value object', async () => { + const primitive = await Primitive.create([1, 2, 3]); + expect(primitive!.getRaw()).toEqual([1, 2, 3]); + expect(primitive!.get('value')).toEqual([1, 2, 3]); + expect(await primitive!.toObject()).toEqual([1, 2, 3]); }); - it('should create many primitive', () => { - const payload = ValueObject.createMany([ + it('should create many primitive', async () => { + const payload = await ValueObject.createMany([ { class: Primitive, props: [1, 2], @@ -646,8 +664,10 @@ describe('value-object', () => { } ]); - expect(payload.result.isOk()).toBeTruthy(); - expect(payload.data.next().value()).toMatchInlineSnapshot(` + const result = await payload.result; + expect(result).not.toBeNull(); + const first = await payload.data.next(); + expect(first).toMatchInlineSnapshot(` Primitive { "autoMapper": AutoMapper { "validator": Validator {}, @@ -721,98 +741,98 @@ Primitive { public static init(props: CProps): Complex { return new Complex(props); } - public static create(props: CProps): Result { - return Ok(new Complex(props)); + public static create(props: CProps): Promise { + return Promise.resolve(new Complex(props)); } } - it('should clone string vo with success', () => { + it('should clone string vo with success', async () => { const str = StringVo.init('sample'); expect(str.get('value')).toBe('sample'); - expect(str.toObject()).toBe('sample'); + expect(await str.toObject()).toBe('sample'); const copy = str.clone(); expect(copy.get('value')).toBe('sample'); - expect(copy.toObject()).toBe('sample'); + expect(await copy.toObject()).toBe('sample'); expect(copy.isEqual(str)).toBeTruthy(); expect(copy.isEqual(StringVo.init('other'))).toBeFalsy(); }); // Test for NumberVo - it('should clone number vo with success', () => { + it('should clone number vo with success', async () => { const num = NumberVo.init(42); expect(num.get('value')).toBe(42); - expect(num.toObject()).toBe(42); + expect(await num.toObject()).toBe(42); const copy = num.clone(); expect(copy.get('value')).toBe(42); - expect(copy.toObject()).toBe(42); + expect(await copy.toObject()).toBe(42); expect(copy.isEqual(num)).toBeTruthy(); expect(copy.isEqual(NumberVo.init(43))).toBeFalsy(); }); // Test for ArrayVo - it('should clone array vo with success', () => { + it('should clone array vo with success', async () => { const arr = ArrayVo.init([1, 2, 3]); expect(arr.get('value')).toEqual([1, 2, 3]); - expect(arr.toObject()).toEqual([1, 2, 3]); + expect(await arr.toObject()).toEqual([1, 2, 3]); const copy = arr.clone(); expect(copy.get('value')).toEqual([1, 2, 3]); - expect(copy.toObject()).toEqual([1, 2, 3]); + expect(await copy.toObject()).toEqual([1, 2, 3]); expect(copy.isEqual(arr)).toBeTruthy(); expect(copy.isEqual(ArrayVo.init([4, 5, 6]))).toBeFalsy(); }); // Test for SymbolVo - it('should clone symbol vo with success', () => { + it('should clone symbol vo with success', async () => { const sym = SymbolVo.init(Symbol('test')); expect(sym.get('value')).toBe('test'); - expect(sym.toObject()).toBe('test'); + expect(await sym.toObject()).toBe('test'); const copy = sym.clone(); expect(copy.get('value')).toBe('test'); - expect(copy.toObject()).toBe('test'); + expect(await copy.toObject()).toBe('test'); expect(copy.isEqual(sym)).toBeTruthy(); expect(copy.isEqual(SymbolVo.init(Symbol('other')))).toBeFalsy(); }); // Test for DateVo - it('should clone date vo with success', () => { + it('should clone date vo with success', async () => { const date = new Date(); const dateVo = DateVo.init(date); expect(dateVo.get('value')).toEqual(date); - expect(dateVo.toObject()).toEqual(date); + expect(await dateVo.toObject()).toEqual(date); const copy = dateVo.clone(); expect(copy.get('value')).toEqual(date); - expect(copy.toObject()).toEqual(date); + expect(await copy.toObject()).toEqual(date); expect(copy.isEqual(dateVo)).toBeTruthy(); expect(copy.isEqual(DateVo.init(new Date('2020-01-01')))).toBeFalsy(); }); // Test for ObjectVo - it('should clone object vo with success', () => { + it('should clone object vo with success', async () => { const obj = { value: 'sample' }; const objVo = ObjectVo.init(obj); expect(objVo.get('value')).toEqual('sample'); - expect(objVo.toObject()).toEqual(obj); + expect(await objVo.toObject()).toEqual(obj); const copy = objVo.clone(); expect(copy.get('value')).toEqual('sample'); - expect(copy.toObject()).toEqual(obj); + expect(await copy.toObject()).toEqual(obj); expect(copy.isEqual(objVo)).toBeTruthy(); expect(copy.isEqual(ObjectVo.init({ value: 'other' }))).toBeFalsy(); }); // Test for Complex - it('should clone object vo with success', () => { + it('should clone object vo with success', async () => { const props: CProps = { index: NumberVo.init(1), items: ArrayVo.init([1, 2, 3]), @@ -821,7 +841,8 @@ Primitive { type: SymbolVo.init(Symbol('lorem')) }; const objVo = Complex.init(props); - expect(objVo.toObject()).toMatchInlineSnapshot(` + const obj = await objVo.toObject(); + expect(obj).toMatchInlineSnapshot(` Object { "index": 1, "items": Array [ @@ -840,7 +861,7 @@ Object { expect(objVo.get('items').get('value')) expect(objVo.get('type').get('value')).toBe('lorem'); // expect(objVo.get('value')).toEqual(props); - expect(objVo.toObject()).toEqual({ + expect(await objVo.toObject()).toEqual({ "index": 1, "items": [ 1, @@ -856,7 +877,7 @@ Object { const copy: Complex = objVo.clone(); - expect(copy.toObject()).toEqual({ + expect(await copy.toObject()).toEqual({ "index": 1, "items": [ 1, @@ -904,14 +925,14 @@ Object { }); - it('should adapt using adapter', () => { + it('should adapt using adapter', async () => { class AdaptName implements Adapter { adaptOne(item: Custom): string { return item.get('value') + ' Doe'; } } const name = Custom.init('Jane'); - expect(name.toObject(new AdaptName())).toBe('Jane Doe'); + expect(await name.toObject(new AdaptName())).toBe('Jane Doe'); }); it('should adapt many', () => { diff --git a/tests/utils/validator.spec.ts b/tests/utils/validator.spec.ts index 3cabc2e..2426df1 100644 --- a/tests/utils/validator.spec.ts +++ b/tests/utils/validator.spec.ts @@ -1,5 +1,4 @@ -import { Aggregate, Entity, id, Id, ID, Result, ValueObject } from "../../lib/core"; -import { _Result } from "../../lib/types"; +import { Aggregate, Entity, id, Id, ID, ValueObject } from "../../lib/core"; import { Validator } from "../../lib/utils"; describe('check-types', () => { @@ -10,8 +9,8 @@ describe('check-types', () => { super(props) } - public static create(): Result, string> { - return Result.Ok(new Agg({ value: 'hello' })); + public static create(): Promise | null> { + return Promise.resolve(new Agg({ value: 'hello' })); } }; @@ -20,8 +19,8 @@ describe('check-types', () => { super(props) } - public static create(props: any = { value: 'hello' }): Result, string> { - return Result.Ok(new Ent(props)); + public static create(props: any = { value: 'hello' }): Promise | null> { + return Promise.resolve(new Ent(props)); } }; @@ -30,8 +29,8 @@ describe('check-types', () => { super(props) } - public static create(): _Result, string> { - return Result.Ok(new Vo('hello')); + public static create(): Promise | null> { + return Promise.resolve(new Vo('hello')); } }; @@ -92,21 +91,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isString(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isString(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isString(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isString(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isString(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isString(ent); expect(result).toBeFalsy(); }); }); @@ -169,21 +168,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isValueObject(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isValueObject(agg); expect(result).toBeFalsy(); }); - it('should return true if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isValueObject(vo.value()); + it('should return true if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isValueObject(vo); expect(result).toBeTruthy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isValueObject(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isValueObject(ent); expect(result).toBeFalsy(); }); }); @@ -246,21 +245,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isEntity(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isEntity(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isEntity(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isEntity(vo); expect(result).toBeFalsy(); }); - it('should return true if is Entity', () => { - const ent = Ent.create(); - const result = checker.isEntity(ent.value()); + it('should return true if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isEntity(ent); expect(result).toBeTruthy(); }); }); @@ -322,21 +321,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return true if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isAggregate(agg.value()); + it('should return true if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isAggregate(agg); expect(result).toBeTruthy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isAggregate(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isAggregate(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isAggregate(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isAggregate(ent); expect(result).toBeFalsy(); }); }); @@ -398,21 +397,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isArray(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isArray(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isArray(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isArray(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isArray(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isArray(ent); expect(result).toBeFalsy(); }); }); @@ -474,21 +473,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isBoolean(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isBoolean(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isBoolean(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isBoolean(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isBoolean(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isBoolean(ent); expect(result).toBeFalsy(); }); }); @@ -551,21 +550,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isNumber(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isNumber(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isNumber(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isNumber(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isNumber(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isNumber(ent); expect(result).toBeFalsy(); }); @@ -667,21 +666,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isDate(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isDate(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isDate(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isDate(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isDate(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isDate(ent); expect(result).toBeFalsy(); }); }); @@ -744,21 +743,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isNull(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isNull(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isNull(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isNull(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isNull(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isNull(ent); expect(result).toBeFalsy(); }); }); @@ -821,21 +820,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isUndefined(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isUndefined(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isUndefined(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isUndefined(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isUndefined(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isUndefined(ent); expect(result).toBeFalsy(); }); }); @@ -898,21 +897,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isFunction(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isFunction(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isFunction(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isFunction(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isFunction(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isFunction(ent); expect(result).toBeFalsy(); }); }); @@ -975,30 +974,30 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isObject(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isObject(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isObject(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isObject(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isObject(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isObject(ent); expect(result).toBeFalsy(); }); - it('should return false if is Entity with Circular Reference', () => { - const ent1 = Ent.create(); - const ent2 = Ent.create({ value: ent1 }); + it('should return false if is Entity with Circular Reference', async () => { + const ent1 = await Ent.create(); + const ent2 = await Ent.create({ value: ent1 }); console.log('should return false if is Entity with Circular Reference') - console.log(ent2.toObject()) - const result = checker.isObject(ent2.value()); + console.log(await ent2!.toObject()) + const result = checker.isObject(ent2); expect(result).toBeFalsy(); }); @@ -1077,21 +1076,21 @@ describe('check-types', () => { expect(result).toBeFalsy(); }); - it('should return false if is Aggregate', () => { - const agg = Agg.create(); - const result = checker.isID(agg.value()); + it('should return false if is Aggregate', async () => { + const agg = await Agg.create(); + const result = checker.isID(agg); expect(result).toBeFalsy(); }); - it('should return false if is ValueObject', () => { - const vo = Vo.create(); - const result = checker.isID(vo.value()); + it('should return false if is ValueObject', async () => { + const vo = await Vo.create(); + const result = checker.isID(vo); expect(result).toBeFalsy(); }); - it('should return false if is Entity', () => { - const ent = Ent.create(); - const result = checker.isID(ent.value()); + it('should return false if is Entity', async () => { + const ent = await Ent.create(); + const result = checker.isID(ent); expect(result).toBeFalsy(); }); }); @@ -1457,4 +1456,4 @@ describe('check-types', () => { }) }) }) -}); +}); \ No newline at end of file