Skip to content

Commit

Permalink
feat: rework cqrs + common upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
Mararok committed Oct 5, 2024
1 parent 821f6db commit 443c505
Show file tree
Hide file tree
Showing 36 changed files with 267 additions and 95 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
"@fastify/multipart": "^8.3.0",
"@fastify/static": "^7.0.4",
"@fastify/swagger": "^8.14.0",
"class-transformer": "^0.5.1",
"deep-equal": "^2.2.3",
"fastest-validator": "^1.18.0",
"fastify": "^4.28.0",
Expand All @@ -103,7 +102,7 @@
"tslib": "^2.6.3"
},
"devDependencies": {
"@hexancore/common": "0.16.1",
"@hexancore/common": "0.16.2",
"@hexancore/mocker": "^1.1.2",
"@nestjs/cli": "^10.3.2",
"@nestjs/common": "^10.3.9",
Expand Down
18 changes: 13 additions & 5 deletions src/Application/DefaultGeneralBus.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { AR, ARW, OKA, AnyHCommand, AnyHQuery, AnyHEvent } from '@hexancore/common';
import {
type AR,
ARW,
type AnyHCommand,
type AnyHQuery,
type HEvent,
type HCommandAsyncResultType,
type HQueryAsyncResultType
} from '@hexancore/common';
import { Injectable } from '@nestjs/common';
import { CommandBus, EventBus, QueryBus } from '@nestjs/cqrs';
import { GeneralBus, type HCommandHandleResult, type HQueryHandleResult } from './GeneralBus';
import { GeneralBus } from './GeneralBus';

@Injectable()
export class DefaultGeneralBus extends GeneralBus {
Expand All @@ -16,15 +24,15 @@ export class DefaultGeneralBus extends GeneralBus {
this.queryBus = queryBus;
}

public handleCommand<T extends AnyHCommand>(command: T): HCommandHandleResult<T> {
public handleCommand<T extends AnyHCommand>(command: T): HCommandAsyncResultType<T> {
return ARW(this.commandBus.execute(command)) as any;
}

public handleEvent(event: AnyHEvent): AR<boolean> {
public handleEvent(event: HEvent): AR<boolean> {
return ARW(this.eventBus.publish(event)).mapToTrue();
}

public handleQuery<T extends AnyHQuery>(query: T): HQueryHandleResult<T> {
public handleQuery<T extends AnyHQuery>(query: T): HQueryAsyncResultType<T> {
return ARW(this.queryBus.execute(query)) as any;
}
}
21 changes: 9 additions & 12 deletions src/Application/GeneralBus.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import {
AR,
AnyHCommand,
ExtractHCommandResultValueType,
AnyHQuery,
ExtractHQueryResultValueType,
AnyHEvent
type AR,
type AnyHCommand,
type HEvent,
type AnyHQuery,
type HCommandAsyncResultType,
type HQueryAsyncResultType
} from '@hexancore/common';


export type HCommandHandleResult<T extends AnyHCommand> = AR<ExtractHCommandResultValueType<T>>;
export type HQueryHandleResult<T extends AnyHQuery> = AR<ExtractHQueryResultValueType<T>>;

export abstract class GeneralBus {
public abstract handleCommand<T extends AnyHCommand>(command: T): HCommandHandleResult<T>;
public abstract handleEvent(event: AnyHEvent): AR<boolean>;
public abstract handleQuery<T extends AnyHQuery>(query: T): HQueryHandleResult<T>;
public abstract handleCommand<T extends AnyHCommand>(command: T): HCommandAsyncResultType<T>;
public abstract handleEvent(event: HEvent): AR<boolean>;
public abstract handleQuery<T extends AnyHQuery>(query: T): HQueryAsyncResultType<T>;
}
10 changes: 10 additions & 0 deletions src/Application/HCommandHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ICommandHandler } from "@nestjs/cqrs";
import { type AnyHCommand, type HCommandResultType, type HCommandAsyncResultType, type HCommandAsyncResultPromiseType } from "@hexancore/common";

export abstract class HCommandHandler<T extends AnyHCommand> implements ICommandHandler<T, HCommandResultType<T>> {
public execute(command: T): HCommandAsyncResultPromiseType<T> {
return this.handle(command).p;
}

protected abstract handle(command: T): HCommandAsyncResultType<T>;
}
6 changes: 6 additions & 0 deletions src/Application/HEventHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type IEventHandler } from "@nestjs/cqrs";
import { type HEvent, type AR } from "@hexancore/common";

export abstract class HEventHandler<T extends HEvent> implements IEventHandler<T> {
public abstract handle(event: T): AR<unknown>;
}
10 changes: 10 additions & 0 deletions src/Application/HQueryHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { type AnyHQuery, HQueryResultType, HQueryAsyncResultType } from "@hexancore/common";
import { type IQueryHandler } from "@nestjs/cqrs";

export abstract class HQueryHandler<T extends AnyHQuery> implements IQueryHandler<T, HQueryResultType<T>> {
public execute(query: T): Promise<HQueryResultType<T>> {
return this.handle(query).p;
}

protected abstract handle(query: T): HQueryAsyncResultType<T>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import ts, { type Identifier } from "typescript";
import ts from "typescript";
import type { HObjectPropertyTsMeta } from "./HObjectPropertyTsMeta";

import type { ImportDeclarationWrapper } from "../../Helper/ImportDeclarationWrapper";
Expand Down
4 changes: 2 additions & 2 deletions src/Domain/Entity/AbstractAggregateRoot.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/ban-types */
import { AbstractValueObject } from '@hexancore/common';
import { HValueObject } from '@hexancore/common';
import { AbstractEntityCommon } from './AbstractEntityCommon';
import { AbstractEntity } from './AbstractEntity';

Expand All @@ -10,4 +10,4 @@ export type AggregateRootConstructor<T extends AnyAggregateRoot = AnyAggregateRo
/**
* Base of AggregateRoot in domain
*/
export abstract class AbstractAggregateRoot<ID extends AbstractValueObject<ID>> extends AbstractEntityCommon<ID> {}
export abstract class AbstractAggregateRoot<ID extends HValueObject> extends AbstractEntityCommon<ID> {}
4 changes: 2 additions & 2 deletions src/Domain/Entity/AbstractEntity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/ban-types */
import { AbstractValueObject } from '@hexancore/common';
import { HValueObject } from '@hexancore/common';
import { AbstractAggregateRoot, AggregateRootConstructor } from './AbstractAggregateRoot';
import { AbstractEntityCommon, EntityIdTypeOf } from './AbstractEntityCommon';
import { ENTITY_META_PROPERTY } from './EntityDecorator';
Expand All @@ -21,7 +21,7 @@ export type EntityConstructor<T extends AnyEntity = AnyEntity> = new (...args: a
/**
* Base for create Entity attached to selected AggregateRoot type in domain.
*/
export abstract class AbstractEntity<IDT extends AbstractValueObject<IDT>, ART extends AbstractAggregateRoot<any>> extends AbstractEntityCommon<IDT> {
export abstract class AbstractEntity<IDT extends HValueObject, ART extends AbstractAggregateRoot<any>> extends AbstractEntityCommon<IDT> {
public getAggregateRootClass(): AggregateRootConstructor<ART> {
return this.constructor[ENTITY_META_PROPERTY].aggregateRoot;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Domain/Entity/AbstractEntityCommon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AbstractValueObject } from '@hexancore/common';
import { HValueObject } from '@hexancore/common';

/**
* Entity Id type alias
Expand All @@ -9,7 +9,7 @@ export type EntityIdTypeOf<T extends AbstractEntityCommon<any>> = T extends Abst
* Common base of Entity and AggregateRoot
* Can track changes in entity for use in persistance libs
*/
export abstract class AbstractEntityCommon<ID extends AbstractValueObject<ID>> {
export abstract class AbstractEntityCommon<ID extends HValueObject> {
/**
* Entity id
*/
Expand Down
13 changes: 9 additions & 4 deletions src/Infrastructure/Http/Controller/AbstractAppController.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { AnyHCommand, AnyHQuery } from '@hexancore/common';
import { GeneralBus, type HCommandHandleResult, type HQueryHandleResult } from '../../../Application';
import {
type AnyHCommand,
type AnyHQuery,
type HCommandAsyncResultType,
type HQueryAsyncResultType
} from '@hexancore/common';
import { GeneralBus } from '../../../Application';
import { Inject } from '@nestjs/common';
import { AbstractController } from './AbstractController';

Expand All @@ -8,11 +13,11 @@ export abstract class AbstractAppController extends AbstractController {
super();
}

protected handleCommand<T extends AnyHCommand>(command: T): HCommandHandleResult<T> {
protected handleCommand<T extends AnyHCommand>(command: T): HCommandAsyncResultType<T> {
return this.gb.handleCommand(command);
}

protected handleQuery<T extends AnyHQuery>(query: T): HQueryHandleResult<T> {
protected handleQuery<T extends AnyHQuery>(query: T): HQueryAsyncResultType<T> {
return this.gb.handleQuery(query);
}
}
2 changes: 1 addition & 1 deletion src/Infrastructure/Http/Controller/AbstractController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { OK, type R } from "@hexancore/common";
import { HttpStatus } from "@nestjs/common";
import { RedirectResult } from "../RedirectResult";

export class AbstractController {
export abstract class AbstractController {

protected redirect(url: string, statusCode: HttpStatus = HttpStatus.FOUND): R<RedirectResult> {
return OK(RedirectResult.create(url, statusCode));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AbstractEntityCommon, EntityMetaCommon, EntityIdTypeOf } from '@/Domain';
import { AR, AbstractValueObject, AsyncResult, CurrentTime, OK, OKA, wrapToArray } from '@hexancore/common';
import { AR, HValueObject, AsyncResult, CurrentTime, OK, OKA, wrapToArray } from '@hexancore/common';
import { AbstractEntityPersister, AbstractEntityRepositoryCommon } from '../Generic';

export const MEMORY_PERSISTER_TYPE = "memory";
Expand Down Expand Up @@ -88,7 +88,7 @@ export class MemoryEntityPersister<T extends AbstractEntityCommon<any>, M extend
public getBy(criteria: Record<string, any>): AR<T[]> {
const result = this.persisted.filter((e) => {
for (const prop in criteria) {
if (criteria[prop] instanceof AbstractValueObject) {
if (criteria[prop] instanceof HValueObject) {
if (!criteria[prop].equals(e[prop])) {
return false;
}
Expand Down
27 changes: 17 additions & 10 deletions src/Test/Application/MockGeneralBus.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { AR, OKA, AnyHCommand, AnyHQuery, AnyHEvent } from '@hexancore/common';
import {
AR,
OKA,
AnyHCommand,
AnyHQuery,
HEvent,
type HCommandAsyncResultType,
type HQueryAsyncResultType
} from '@hexancore/common';
import { Injectable } from '@nestjs/common';
import { IEvent } from '@nestjs/cqrs';
import deepEqual from 'deep-equal';
import type { HCommandHandleResult, HQueryHandleResult } from "../../Application";
import { GeneralBus } from '../../Application/GeneralBus';

interface HandleExpectation {
Expand All @@ -23,28 +30,28 @@ export class MockGeneralBus extends GeneralBus {
this.queriesToHandle = [];
}

public expectHandleCommand<T extends AnyHCommand>(command: T, result: HCommandHandleResult<T>): void {
public expectHandleCommand<T extends AnyHCommand>(command: T, result: HCommandAsyncResultType<T>): void {
this.commandsToHandle.unshift({ message: command as any, result });
}

public expectHandleEvent(event: AnyHEvent | ((event: AnyHEvent) => boolean)): void {
public expectHandleEvent(event: HEvent | ((event: HEvent) => boolean)): void {
this.eventsToHandle.unshift(event);
}

public expectHandleQuery<T extends AnyHQuery>(query: T, result: HQueryHandleResult<T>): void {
public expectHandleQuery<T extends AnyHQuery>(query: T, result: HQueryAsyncResultType<T>): void {
this.queriesToHandle.unshift({ message: query as any, result });
}

public handleCommand<T extends AnyHCommand>(command: T): HCommandHandleResult<T> {
public handleCommand<T extends AnyHCommand>(command: T): HCommandAsyncResultType<T> {
const expectation = this.commandsToHandle.pop();
if (expectation && deepEqual(expectation.message, command)) {
return expectation.result;
return expectation.result as any;
}

throw new Error('Unexpected command to handle: ' + command.constructor.name + ' ' + JSON.stringify(command, null, 1));
}

public handleEvent(event: AnyHEvent): AR<boolean> {
public handleEvent(event: HEvent): AR<boolean> {
const expectation = this.eventsToHandle.pop();
if (typeof expectation == 'function') {
if (!expectation(event)) {
Expand All @@ -57,10 +64,10 @@ export class MockGeneralBus extends GeneralBus {
return OKA(true);
}

public handleQuery<T extends AnyHQuery>(query: T): HQueryHandleResult<T> {
public handleQuery<T extends AnyHQuery>(query: T): HQueryAsyncResultType<T> {
const expectation = this.queriesToHandle.pop();
if (expectation && deepEqual(expectation.message, query)) {
return expectation.result;
return expectation.result as any;
}

throw new Error('Unexpected query to handle: ' + query.constructor.name + ' ' + JSON.stringify(query, null, 1));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { HCommand } from "@hexancore/common";
import { BookDto } from "../../Dto/BookDto";

export class BookCreateCommand extends HCommand<BookCreateCommand, void> {
export class BookCreateCommand extends HCommand<BookDto> {
public title!: string;
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { CommandHandler, type ICommandHandler } from "@nestjs/cqrs";
import { BookCreateCommand } from "./BookCreateCommand";
import { OKAP, type ARP } from "@hexancore/common";
import { HCommandHandler } from "@/Application/HCommandHandler";
import { OKA, ERRA, type HCommandAsyncResultType } from "@hexancore/common";
import { BookDto } from "../../Dto/BookDto";
import { BookCreateCommand } from "./BookCreateCommand";
import { CommandHandler } from "@nestjs/cqrs";

@CommandHandler(BookCreateCommand)
export class BookCreateCommandHandler implements ICommandHandler<BookCreateCommand> {
public execute(command: BookCreateCommand): ARP<BookDto> {
return OKAP(BookDto.cs({
title: command.title,
export class BookCreateCommandHandler extends HCommandHandler<BookCreateCommand> {
protected handle(command: BookCreateCommand): HCommandAsyncResultType<BookCreateCommand> {
if (command.title === "error") {
return ERRA("error");
}

return OKA(BookDto.cs({
title: command.title,
}));
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Dto, v } from '@hexancore/common';

export class ArrayItemsTestDto extends Dto<ArrayItemsTestDto> {
export class ArrayItemsTestDto extends Dto {

public arrayMinItemsField!: v.int[] & v.items.min<2>;
public arrayMaxItemsField!: v.int[] & v.items.max<2>;
public arrayExaclyItemsField!: v.int[] & v.items.exactly<2>;
public arrayBetweenItemsField!: v.int[] & v.items.between<0, 2>;

public optionalArrayItemsField?: v.int[] & v.items.min<2>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dto } from "@hexancore/common";

export class BookDto extends Dto<BookDto> {
export class BookDto extends Dto {
public title?: string;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Dto, v } from '@hexancore/common';

export class FloatTestDto extends Dto<FloatTestDto> {
export class FloatTestDto extends Dto {

public field!: v.float;
public optionalField?: v.float;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Dto, v } from '@hexancore/common';

export class IntTestDto extends Dto<IntTestDto> {
export class IntTestDto extends Dto {

public field!: v.int;
public optionalField?: v.int;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Dto, v } from '@hexancore/common';

export class StringTestDto extends Dto<StringTestDto> {
export class StringTestDto extends Dto {

public field!: string;
public optionalField?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Dto, v, RefId } from '@hexancore/common';

export class TestTransformDto extends Dto<TestTransformDto> {
export class TestTransformDto extends Dto {

public optionalStringField?: string;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Dto, v } from '@hexancore/common';

export class UIntTestDto extends Dto<UIntTestDto> {
export class UIntTestDto extends Dto {

public field!: v.uint;
public optionalField?: v.uint;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HQuery } from "@hexancore/common";
import type { BookDto } from "../../Dto/BookDto";

export class BookGetByIdQuery extends HQuery<BookGetByIdQuery, BookDto> {
export class BookGetByIdQuery extends HQuery<BookDto> {
public title!: string;
}
Loading

0 comments on commit 443c505

Please sign in to comment.