framework-do-dede 4.0.5 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Framework do Dedé
2
2
 
3
- Um framework TypeScript simples para construir APIs HTTP com controllers, use cases e entities, com suporte a Express ou Elysia, DI leve e serialização de entidades.
3
+ Um framework TypeScript simples para construir APIs HTTP com controllers, use cases e entities, com suporte a Express ou Elysia, DI leve e camada de Model.
4
4
 
5
5
  ## Índice
6
6
 
@@ -12,8 +12,8 @@ Um framework TypeScript simples para construir APIs HTTP com controllers, use ca
12
12
  - Middlewares
13
13
  - Tracing
14
14
  - UseCase e Decorators
15
- - Entity e Serialização
16
- - Hooks Before/After ToEntity
15
+ - Entity e Model
16
+ - Event Dispatcher
17
17
  - Storage Gateway
18
18
  - DI (Container/Inject)
19
19
  - Errors
@@ -21,7 +21,7 @@ Um framework TypeScript simples para construir APIs HTTP com controllers, use ca
21
21
  - Exemplos
22
22
  - Express
23
23
  - Elysia
24
- - Fila com AfterToEntity
24
+ - Background com EventDispatcher
25
25
  - Testes
26
26
  - Benchmark
27
27
 
@@ -250,87 +250,44 @@ class CreateUserUseCase extends UseCase<{ name: string }, { id: string }> {
250
250
  }
251
251
  ```
252
252
 
253
- ### Entity e Serializacao
253
+ ### Entity e Model
254
254
 
255
- Entities suportam:
256
-
257
- - `toEntity()` e `toAsyncEntity()`
258
- - `toData()` e `toAsyncData()`
259
- - `@Serialize`, `@Restrict`, `@VirtualProperty`, `@GetterPrefix`
260
-
261
- Obs: a serializacao fica na camada de infraestrutura, mas a API continua sendo exposta pelo framework (importe direto de `./src`).
255
+ Entities sao dominio puro. Use `Model` para converter entre Entity e o objeto do banco.
262
256
 
263
257
  ```ts
264
- import { Entity, Serialize, Restrict, VirtualProperty, GetterPrefix } from './src';
258
+ import { Entity, Model } from './src';
265
259
 
266
260
  class User extends Entity {
267
- @Serialize((value: Email) => value.getValue())
268
- private readonly email: Email;
269
-
270
- @Restrict()
271
- private readonly passwordHash: string;
272
-
273
- @GetterPrefix('has')
274
- private readonly profile?: Profile;
275
-
276
- @VirtualProperty('displayName')
277
- private display() {
278
- return 'User ' + this.email.getValue();
279
- }
261
+ private readonly id: string;
262
+ private readonly email: string;
280
263
 
281
- constructor(email: string, passwordHash: string) {
264
+ constructor(id: string, email: string) {
282
265
  super();
283
- this.email = new Email(email);
284
- this.passwordHash = passwordHash;
266
+ this.id = id;
267
+ this.email = email;
285
268
  this.generateGetters();
286
269
  }
287
270
  }
288
271
 
289
- const user = new User('a@b.com', 'hash');
290
- const serialized = user.toEntity();
291
- ```
292
-
293
- Regras principais:
294
-
295
- - `@Serialize` pode retornar objeto: cada chave vira uma propriedade do resultado
296
- - `@Restrict` remove campo em `toData`
297
- - `@VirtualProperty` mapeia metodos para campos virtuais
298
- - `generateGetters()` cria getters para campos (ex.: `getName`, `isActive`, `hasProfile`)
299
-
300
- ### Hooks Before/After ToEntity
301
-
302
- Use `@BeforeToEntity()` e `@AfterToEntity()` em metodos de Entities.
303
-
304
- - Before recebe objeto bruto (antes de serializacao)
305
- - After recebe objeto tratado (resultado final)
306
- - `toEntity()` executa hooks sem aguardar promessas
307
- - `toAsyncEntity()` aguarda hooks async
308
-
309
- ```ts
310
- import { Entity, AfterToEntity, BeforeToEntity } from './src';
311
-
312
- class FileEntity extends Entity {
313
- private readonly name: string;
314
- private readonly s3Key: string;
272
+ type UserRow = { id: string; email: string };
315
273
 
316
- constructor(name: string, s3Key: string) {
317
- super();
318
- this.name = name;
319
- this.s3Key = s3Key;
320
- }
321
-
322
- @BeforeToEntity()
323
- private before(payload: Record<string, any>) {
324
- payload.rawTouched = true;
274
+ class UserModel extends Model<User, UserRow> {
275
+ toModel(entity: User): UserRow {
276
+ return { id: entity.getId(), email: entity.getEmail() };
325
277
  }
326
278
 
327
- @AfterToEntity()
328
- private async after(payload: Record<string, any>) {
329
- await saveToS3(payload.s3Key);
279
+ toEntity(model: UserRow): User {
280
+ return new User(model.id, model.email);
330
281
  }
331
282
  }
332
283
  ```
333
284
 
285
+ Regras principais:
286
+
287
+ - `Model` centraliza conversoes entre dominio e persistencia
288
+ - use `toModel` e `toEntity`
289
+ - `generateGetters()` cria getters para campos (ex.: `getName`, `isActive`, `hasProfile`)
290
+
334
291
  ### Storage Gateway
335
292
 
336
293
  Use `@Storage` para injetar gateways com interface `StorageGateway`.
@@ -350,6 +307,25 @@ class FileService {
350
307
  }
351
308
  ```
352
309
 
310
+ ### Event Dispatcher
311
+
312
+ Use `@EventDispatcher` para enfileirar tarefas ou eventos de background com interface `EventDispatcher`.
313
+
314
+ ```ts
315
+ import { EventDispatcher } from './src';
316
+
317
+ type QueueEvent = { name: string; payload?: Record<string, any> };
318
+
319
+ class QueueService {
320
+ @EventDispatcher('QueueDispatcher')
321
+ private readonly dispatcher!: { dispatch: (event: QueueEvent) => Promise<void> };
322
+
323
+ async enqueue(payload: Record<string, any>) {
324
+ await this.dispatcher.dispatch({ name: 'jobs.create', payload });
325
+ }
326
+ }
327
+ ```
328
+
353
329
  ### DI (Container/Inject)
354
330
 
355
331
  Registre dependencias ao iniciar o server (usando o container padrão):
@@ -401,15 +377,16 @@ Quando um erro e lancado, o handler padroniza a resposta. Erros de dominio (`App
401
377
 
402
378
  Interfaces tipadas para padrao de repositorio:
403
379
 
404
- - `RepositoryCreate<T extends Entity>`
405
- - `RepositoryUpdate<T extends Entity>`
380
+ - `RepositoryModel<E extends Entity, M>`
381
+ - `RepositoryCreate<E extends Entity, M>`
382
+ - `RepositoryUpdate<E extends Entity, M>`
406
383
  - `RepositoryRemove`
407
- - `RepositoryRestore<T extends Entity>`
408
- - `RepositoryRemoveBy<T>`
409
- - `RepositoryRestoreBy<T>`
410
- - `RepositoryExistsBy<T>`
411
- - `RepositoryNotExistsBy<T>`
412
- - `RepositoryPagination<T>`
384
+ - `RepositoryRestore<E extends Entity, M>`
385
+ - `RepositoryRemoveBy<E>`
386
+ - `RepositoryRestoreBy<E>`
387
+ - `RepositoryExistsBy<E>`
388
+ - `RepositoryNotExistsBy<E>`
389
+ - `RepositoryPagination<E extends Entity, M>`
413
390
 
414
391
  ## Exemplos
415
392
 
@@ -447,49 +424,24 @@ app.registerControllers([ExampleController]);
447
424
  app.listen();
448
425
  ```
449
426
 
450
- ### Fila com AfterToEntity
427
+ ### Background com EventDispatcher
451
428
 
452
429
  ```ts
453
- import { Entity, AfterToEntity } from './src';
454
-
455
- type QueueJob = { type: string; payload: Record<string, any> };
456
-
457
- type Queue = { enqueue(job: QueueJob): Promise<void> };
430
+ import { EventDispatcher } from './src';
458
431
 
459
- const queue: Queue = {
460
- async enqueue(job) {
461
- console.log('queued job', job);
462
- }
463
- };
464
-
465
- class FileEntity extends Entity {
466
- private readonly name: string;
467
- private readonly s3Key: string;
432
+ type QueueEvent = { name: string; payload: Record<string, any> };
468
433
 
469
- private constructor({ name, s3Key }: { name: string; s3Key: string }) {
470
- super();
471
- this.name = name;
472
- this.s3Key = s3Key;
473
- }
434
+ class FileService {
435
+ @EventDispatcher('QueueDispatcher')
436
+ private readonly dispatcher!: { dispatch: (event: QueueEvent) => Promise<void> };
474
437
 
475
- @AfterToEntity()
476
- private async enqueueFileSync(payload: Record<string, any>) {
477
- await queue.enqueue({
478
- type: 'files.create',
479
- payload: {
480
- name: payload.name,
481
- s3Key: payload.s3Key
482
- }
438
+ async enqueueFile(input: { name: string; s3Key: string }) {
439
+ await this.dispatcher.dispatch({
440
+ name: 'files.create',
441
+ payload: input
483
442
  });
484
443
  }
485
-
486
- static create(input: { name: string; s3Key: string }) {
487
- return new FileEntity(input);
488
- }
489
444
  }
490
-
491
- const entity = FileEntity.create({ name: 'report', s3Key: 's3://bucket/report.pdf' });
492
- const serialized = entity.toEntity();
493
445
  ```
494
446
 
495
447
  ## Testes
@@ -1,6 +1,9 @@
1
1
  import { Controller, Post, Get, Put, Delete, Patch, UseMiddleware, UseMiddlewares, Tracing, type Middleware, type Input, type Tracer, type TracerData } from './controller';
2
- import { Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity } from '../infra/serialization/entity';
2
+ import { Entity, Restrict, VirtualProperty, GetterPrefix, Serialize } from '../infra/serialization/entity';
3
+ import { Model } from '../infra/model/model';
3
4
  import { DecorateUseCase, UseCase } from './usecase';
4
- import { Storage, type StorageGateway } from './services';
5
- export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Storage, Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity, };
6
- export type { Middleware, Input, StorageGateway, Tracer, TracerData };
5
+ export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Entity, Restrict, VirtualProperty, GetterPrefix, Serialize, Model, };
6
+ export { Storage, CacheGateway, EventDispatcher } from './services';
7
+ export type { Middleware, Input, Tracer, TracerData };
8
+ export type { StorageGateway } from './services';
9
+ export type { Event, EventPayload } from './services';
@@ -1,5 +1,6 @@
1
1
  import { Controller, Post, Get, Put, Delete, Patch, UseMiddleware, UseMiddlewares, Tracing } from './controller';
2
- import { Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity } from '../infra/serialization/entity';
2
+ import { Entity, Restrict, VirtualProperty, GetterPrefix, Serialize } from '../infra/serialization/entity';
3
+ import { Model } from '../infra/model/model';
3
4
  import { DecorateUseCase, UseCase } from './usecase';
4
- import { Storage } from './services';
5
- export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Storage, Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity, };
5
+ export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Entity, Restrict, VirtualProperty, GetterPrefix, Serialize, Model, };
6
+ export { Storage, CacheGateway, EventDispatcher } from './services';
@@ -5,4 +5,19 @@ export interface StorageGateway {
5
5
  get(key: string): Promise<string>;
6
6
  delete(key: string): Promise<boolean>;
7
7
  }
8
+ export interface CacheGateway {
9
+ get<T = unknown>(key: string): Promise<T | null> | T | null;
10
+ set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> | void;
11
+ delete(key: string): Promise<boolean> | boolean;
12
+ }
13
+ export type EventPayload = Record<string, any>;
14
+ export type Event = {
15
+ name: string;
16
+ payload?: EventPayload;
17
+ };
18
+ export interface EventDispatcher {
19
+ dispatch(event: Event): Promise<void> | void;
20
+ }
8
21
  export declare function Storage(gatewayName: string, container?: Container): (target: any, propertyKey: string) => void;
22
+ export declare function CacheGateway(gatewayName: string, container?: Container): (target: any, propertyKey?: string) => void;
23
+ export declare function EventDispatcher(dispatcherName: string, container?: Container): (target: any, propertyKey?: string) => void;
@@ -1,22 +1,39 @@
1
1
  import { DefaultContainer } from "../infra/di/registry";
2
2
  import 'reflect-metadata';
3
+ function defineGatewayProperty(target, propertyKey, gatewayName, container, validator, errorMessage) {
4
+ Object.defineProperty(target, propertyKey, {
5
+ get: function () {
6
+ return new Proxy({}, {
7
+ get(_, prop) {
8
+ const resolvedContainer = container ?? DefaultContainer;
9
+ const dependency = resolvedContainer.inject(gatewayName);
10
+ if (validator && !validator(dependency)) {
11
+ throw new Error(errorMessage ?? `${gatewayName} is not a valid dependency`);
12
+ }
13
+ return dependency[prop];
14
+ }
15
+ });
16
+ },
17
+ enumerable: true,
18
+ configurable: true
19
+ });
20
+ }
3
21
  export function Storage(gatewayName, container) {
4
22
  return function (target, propertyKey) {
5
- Object.defineProperty(target, propertyKey, {
6
- get: function () {
7
- return new Proxy({}, {
8
- get(_, prop) {
9
- const resolvedContainer = container ?? DefaultContainer;
10
- const dependency = resolvedContainer.inject(gatewayName);
11
- if (!dependency?.save || !dependency?.get || !dependency?.delete) {
12
- throw new Error(`${gatewayName} is not a valid StorageGateway`);
13
- }
14
- return dependency[prop];
15
- }
16
- });
17
- },
18
- enumerable: true,
19
- configurable: true
20
- });
23
+ defineGatewayProperty(target, propertyKey, gatewayName, container, (dependency) => !!dependency?.save && !!dependency?.get && !!dependency?.delete, `${gatewayName} is not a valid StorageGateway`);
24
+ };
25
+ }
26
+ export function CacheGateway(gatewayName, container) {
27
+ return function (target, propertyKey) {
28
+ const resolvedProperty = propertyKey ?? 'cache';
29
+ const resolvedTarget = propertyKey ? target : target.prototype;
30
+ defineGatewayProperty(resolvedTarget, resolvedProperty, gatewayName, container, (dependency) => !!dependency?.get && !!dependency?.set && !!dependency?.delete, `${gatewayName} is not a valid CacheGateway`);
31
+ };
32
+ }
33
+ export function EventDispatcher(dispatcherName, container) {
34
+ return function (target, propertyKey) {
35
+ const resolvedProperty = propertyKey ?? 'eventDispatcher';
36
+ const resolvedTarget = propertyKey ? target : target.prototype;
37
+ defineGatewayProperty(resolvedTarget, resolvedProperty, dispatcherName, container, (dependency) => !!dependency?.dispatch, `${dispatcherName} is not a valid EventDispatcher`);
21
38
  };
22
39
  }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { Post, Get, Put, Delete, Patch, Controller, Input, Middleware, UseMiddleware, UseMiddlewares, Tracer, Tracing, TracerData, Entity, Restrict, VirtualProperty, GetterPrefix, Serialize, UseCase, DecorateUseCase, Storage, StorageGateway } from "./application";
1
+ import { Post, Get, Put, Delete, Patch, Controller, Input, Middleware, UseMiddleware, UseMiddlewares, Tracer, Tracing, TracerData, Entity, Restrict, VirtualProperty, GetterPrefix, Model, UseCase, DecorateUseCase, Storage, CacheGateway, EventDispatcher } from "./application";
2
2
  import { Container, DefaultContainer, Inject, setDefaultContainer } from './infra/di/registry';
3
3
  import { Dede, type Options, Register } from './dede';
4
4
  import { ServerError, NotFound, Forbidden, Conflict, Unauthorized, UnprocessableEntity, BadRequest, InternalServerError, CustomServerError } from './http/errors/server';
5
5
  import { AppError } from './domain/errors/app-error';
6
6
  import type { ValidatorDefinition } from './interface/validation/validator';
7
- import type { RepositoryCreate, RepositoryUpdate, RepositoryRemove, RepositoryRemoveBy, RepositoryExistsBy, RepositoryRestore, RepositoryRestoreBy, RepositoryNotExistsBy, RepositoryPagination } from './protocols/repository';
8
- export { Controller, Post, Get, Put, Delete, Patch, Input, Middleware, UseMiddleware, UseMiddlewares, Tracer, Tracing, TracerData, Entity, Restrict, VirtualProperty, GetterPrefix, Serialize, UseCase, DecorateUseCase, Storage, StorageGateway, Inject, Container, DefaultContainer, setDefaultContainer, Dede, Options, Register, ServerError, NotFound, Forbidden, Conflict, Unauthorized, UnprocessableEntity, BadRequest, InternalServerError, CustomServerError, AppError, RepositoryCreate, RepositoryUpdate, RepositoryRemove, RepositoryRemoveBy, RepositoryRestore, RepositoryExistsBy, RepositoryRestoreBy, RepositoryNotExistsBy, RepositoryPagination };
9
- export type { ValidatorDefinition };
7
+ import type { StorageGateway, Event, EventPayload } from './application';
8
+ import type { RepositoryModel, RepositoryCreate, RepositoryUpdate, RepositoryRemove, RepositoryRemoveBy, RepositoryExistsBy, RepositoryRestore, RepositoryRestoreBy, RepositoryNotExistsBy, RepositoryPagination } from './protocols/repository';
9
+ export { Controller, Post, Get, Put, Delete, Patch, Input, Middleware, UseMiddleware, UseMiddlewares, Tracer, Tracing, TracerData, Entity, Restrict, VirtualProperty, GetterPrefix, Model, UseCase, DecorateUseCase, Storage, CacheGateway, EventDispatcher, Inject, Container, DefaultContainer, setDefaultContainer, Dede, Options, Register, ServerError, NotFound, Forbidden, Conflict, Unauthorized, UnprocessableEntity, BadRequest, InternalServerError, CustomServerError, AppError, RepositoryModel, RepositoryCreate, RepositoryUpdate, RepositoryRemove, RepositoryRemoveBy, RepositoryRestore, RepositoryExistsBy, RepositoryRestoreBy, RepositoryNotExistsBy, RepositoryPagination };
10
+ export type { ValidatorDefinition, StorageGateway, Event, EventPayload };
package/dist/index.js CHANGED
@@ -3,15 +3,17 @@ import {
3
3
  Post, Get, Put, Delete, Patch, Controller, UseMiddleware, UseMiddlewares, Tracing,
4
4
  // controller
5
5
  // entity
6
- Entity, Restrict, VirtualProperty, GetterPrefix, Serialize,
6
+ Entity, Restrict, VirtualProperty, GetterPrefix, Model,
7
7
  // entity
8
8
  // usecase
9
9
  UseCase, DecorateUseCase,
10
10
  // usecase
11
11
  // storage
12
- Storage } from "./application";
12
+ Storage, CacheGateway, EventDispatcher
13
+ // storage
14
+ } from "./application";
13
15
  import { Container, DefaultContainer, Inject, setDefaultContainer } from './infra/di/registry';
14
16
  import { Dede } from './dede';
15
17
  import { ServerError, NotFound, Forbidden, Conflict, Unauthorized, UnprocessableEntity, BadRequest, InternalServerError, CustomServerError } from './http/errors/server';
16
18
  import { AppError } from './domain/errors/app-error';
17
- export { Controller, Post, Get, Put, Delete, Patch, UseMiddleware, UseMiddlewares, Tracing, Entity, Restrict, VirtualProperty, GetterPrefix, Serialize, UseCase, DecorateUseCase, Storage, Inject, Container, DefaultContainer, setDefaultContainer, Dede, ServerError, NotFound, Forbidden, Conflict, Unauthorized, UnprocessableEntity, BadRequest, InternalServerError, CustomServerError, AppError };
19
+ export { Controller, Post, Get, Put, Delete, Patch, UseMiddleware, UseMiddlewares, Tracing, Entity, Restrict, VirtualProperty, GetterPrefix, Model, UseCase, DecorateUseCase, Storage, CacheGateway, EventDispatcher, Inject, Container, DefaultContainer, setDefaultContainer, Dede, ServerError, NotFound, Forbidden, Conflict, Unauthorized, UnprocessableEntity, BadRequest, InternalServerError, CustomServerError, AppError };
@@ -0,0 +1,5 @@
1
+ import { Entity } from '../../domain/entity';
2
+ export declare abstract class Model<E extends Entity, D> {
3
+ abstract toModel(entity: E): D;
4
+ abstract toEntity(model: D): E;
5
+ }
@@ -0,0 +1,2 @@
1
+ export class Model {
2
+ }
@@ -1,23 +1,13 @@
1
1
  import { Entity as DomainEntity } from "../../domain/entity";
2
- export declare abstract class SerializableEntity extends DomainEntity {
2
+ export declare abstract class Entity extends DomainEntity {
3
3
  [x: string]: any;
4
- private buildRawEntityObject;
5
- private getEntityHooks;
6
- private runEntityHooks;
7
4
  toEntity(): Record<string, any>;
8
- toAsyncEntity(): Promise<Record<string, any>>;
9
5
  toData({ serialize }?: {
10
6
  serialize?: boolean;
11
7
  }): Record<string, any>;
12
- toAsyncData({ serialize }?: {
13
- serialize?: boolean;
14
- }): Promise<Record<string, any>>;
15
8
  protected generateGetters(): void;
16
9
  }
17
10
  export declare function Restrict(): (target: any, propertyKey: string) => void;
18
11
  export declare function VirtualProperty(propertyName: string): (target: any, methodName: string) => void;
19
12
  export declare function Serialize(callback: (value: any) => any): PropertyDecorator;
20
13
  export declare function GetterPrefix(prefix: string): (target: any, propertyKey: string) => void;
21
- export { SerializableEntity as Entity };
22
- export declare function BeforeToEntity(): MethodDecorator;
23
- export declare function AfterToEntity(): MethodDecorator;
@@ -1,61 +1,6 @@
1
1
  import { Entity as DomainEntity } from "../../domain/entity";
2
- export class SerializableEntity extends DomainEntity {
3
- buildRawEntityObject() {
4
- const result = {};
5
- for (const [propName] of Object.entries(this)) {
6
- let value = this[propName];
7
- if (typeof value === 'function')
8
- continue;
9
- if (value === undefined)
10
- continue;
11
- result[propName] = value;
12
- }
13
- return result;
14
- }
15
- getEntityHooks(hookKey) {
16
- const hooks = [];
17
- let current = this.constructor;
18
- while (current && current !== SerializableEntity) {
19
- const currentHooks = current[hookKey];
20
- if (currentHooks && currentHooks.length) {
21
- hooks.unshift(...currentHooks);
22
- }
23
- current = Object.getPrototypeOf(current);
24
- }
25
- return hooks;
26
- }
27
- runEntityHooks(hookKey, payload, awaitHooks) {
28
- const hooks = this.getEntityHooks(hookKey);
29
- if (!hooks.length)
30
- return;
31
- if (awaitHooks) {
32
- return (async () => {
33
- for (const hookName of hooks) {
34
- const hook = this[hookName];
35
- if (typeof hook !== 'function')
36
- continue;
37
- await hook.call(this, payload);
38
- }
39
- })();
40
- }
41
- for (const hookName of hooks) {
42
- const hook = this[hookName];
43
- if (typeof hook !== 'function')
44
- continue;
45
- try {
46
- const result = hook.call(this, payload);
47
- if (result && typeof result.then === 'function') {
48
- void result.catch(() => undefined);
49
- }
50
- }
51
- catch (error) {
52
- throw error;
53
- }
54
- }
55
- }
2
+ export class Entity extends DomainEntity {
56
3
  toEntity() {
57
- const raw = this.buildRawEntityObject();
58
- this.runEntityHooks(BEFORE_TO_ENTITY, raw, false);
59
4
  // @ts-ignore
60
5
  const propertiesConfigs = this.constructor.propertiesConfigs;
61
6
  const result = {};
@@ -87,44 +32,6 @@ export class SerializableEntity extends DomainEntity {
87
32
  value = null;
88
33
  result[propertyName] = value;
89
34
  }
90
- this.runEntityHooks(AFTER_TO_ENTITY, result, false);
91
- return result;
92
- }
93
- async toAsyncEntity() {
94
- const raw = this.buildRawEntityObject();
95
- await this.runEntityHooks(BEFORE_TO_ENTITY, raw, true);
96
- // @ts-ignore
97
- const propertiesConfigs = this.constructor.propertiesConfigs;
98
- const result = {};
99
- for (const [propName] of Object.entries(this)) {
100
- let propertyName = propName;
101
- let value = this[propName];
102
- if (typeof value === 'function')
103
- continue;
104
- if (value === undefined)
105
- continue;
106
- // @ts-ignore
107
- if (propertiesConfigs && propertiesConfigs[propName]?.serialize && (value || value === 0)) {
108
- const serializedValue = await propertiesConfigs[propName].serialize(value);
109
- if (serializedValue && typeof serializedValue === 'object' && !Array.isArray(serializedValue)) {
110
- const entries = Object.entries(serializedValue);
111
- for (const [serializedKey, serializedPropValue] of entries) {
112
- let currentValue = serializedPropValue;
113
- if (!currentValue)
114
- currentValue = null;
115
- result[serializedKey] = currentValue;
116
- }
117
- continue;
118
- }
119
- else {
120
- value = serializedValue;
121
- }
122
- }
123
- if (value === undefined || value === null)
124
- value = null;
125
- result[propertyName] = value;
126
- }
127
- await this.runEntityHooks(AFTER_TO_ENTITY, result, true);
128
35
  return result;
129
36
  }
130
37
  toData({ serialize = false } = {}) {
@@ -154,33 +61,6 @@ export class SerializableEntity extends DomainEntity {
154
61
  }
155
62
  return result;
156
63
  }
157
- async toAsyncData({ serialize = true } = {}) {
158
- // @ts-ignore
159
- const propertiesConfigs = this.constructor.propertiesConfigs;
160
- // @ts-ignore
161
- const virtualProperties = this.constructor.virtualProperties;
162
- const result = {};
163
- for (const [propName] of Object.entries(this)) {
164
- if (typeof this[propName] === 'function')
165
- continue;
166
- if (propertiesConfigs && propertiesConfigs[propName]?.restrict)
167
- continue;
168
- // @ts-ignore
169
- let value = this[propName];
170
- if (serialize && propertiesConfigs && propertiesConfigs[propName]?.serialize && value) {
171
- value = await propertiesConfigs[propName].serialize(value);
172
- }
173
- result[propName] = value;
174
- }
175
- if (virtualProperties) {
176
- for (const [methodName, propName] of Object.entries(virtualProperties)) {
177
- if (this.__proto__[methodName]) {
178
- result[propName] = await this[methodName]();
179
- }
180
- }
181
- }
182
- return result;
183
- }
184
64
  generateGetters() {
185
65
  super.generateGetters();
186
66
  }
@@ -218,27 +98,3 @@ const loadPropertiesConfig = (target, propertyKey) => {
218
98
  target.constructor.propertiesConfigs[propertyKey] = {};
219
99
  }
220
100
  };
221
- const BEFORE_TO_ENTITY = Symbol('beforeToEntity');
222
- const AFTER_TO_ENTITY = Symbol('afterToEntity');
223
- const assertEntityDecoratorTarget = (target, decoratorName) => {
224
- if (!SerializableEntity.prototype.isPrototypeOf(target)) {
225
- throw new Error(`${decoratorName} can only be used on Entity classes`);
226
- }
227
- };
228
- export { SerializableEntity as Entity };
229
- export function BeforeToEntity() {
230
- return function (target, propertyKey) {
231
- assertEntityDecoratorTarget(target, 'BeforeToEntity');
232
- const cls = target.constructor;
233
- cls[BEFORE_TO_ENTITY] = cls[BEFORE_TO_ENTITY] || [];
234
- cls[BEFORE_TO_ENTITY].push(propertyKey);
235
- };
236
- }
237
- export function AfterToEntity() {
238
- return function (target, propertyKey) {
239
- assertEntityDecoratorTarget(target, 'AfterToEntity');
240
- const cls = target.constructor;
241
- cls[AFTER_TO_ENTITY] = cls[AFTER_TO_ENTITY] || [];
242
- cls[AFTER_TO_ENTITY].push(propertyKey);
243
- };
244
- }
@@ -1,34 +1,38 @@
1
1
  import { Entity } from "../domain";
2
- export interface RepositoryCreate<T extends Entity> {
3
- create(input: T): Promise<void>;
2
+ import { Model } from "../infra/model/model";
3
+ export interface RepositoryModel<E extends Entity, M> {
4
+ model: Model<E, M>;
4
5
  }
5
- export interface RepositoryUpdate<T extends Entity> {
6
- update(input: T): Promise<void>;
6
+ export interface RepositoryCreate<E extends Entity, M> extends RepositoryModel<E, M> {
7
+ create(input: E): Promise<void>;
8
+ }
9
+ export interface RepositoryUpdate<E extends Entity, M> extends RepositoryModel<E, M> {
10
+ update(input: E): Promise<void>;
7
11
  }
8
12
  export interface RepositoryRemove {
9
13
  remove(id: string | number): Promise<void>;
10
14
  }
11
- export interface RepositoryRestore<T extends Entity> {
12
- restore(id: string | number): Promise<T>;
15
+ export interface RepositoryRestore<E extends Entity, M> extends RepositoryModel<E, M> {
16
+ restore(id: string | number): Promise<E>;
13
17
  }
14
- export type RepositoryRemoveBy<T> = {
15
- [K in keyof T & string as `removeBy${Capitalize<K>}`]: (value: T[K]) => Promise<void>;
18
+ export type RepositoryRemoveBy<E> = {
19
+ [K in keyof E & string as `removeBy${Capitalize<K>}`]: (value: E[K]) => Promise<void>;
16
20
  };
17
- export type RepositoryRestoreBy<T> = {
18
- [K in keyof T & string as `restoreBy${Capitalize<K>}`]: (value: T[K]) => Promise<any>;
21
+ export type RepositoryRestoreBy<E> = {
22
+ [K in keyof E & string as `restoreBy${Capitalize<K>}`]: (value: E[K]) => Promise<any>;
19
23
  };
20
- export type RepositoryExistsBy<T> = {
21
- [K in keyof T & string as `existsBy${Capitalize<K>}`]: (value: T[K]) => Promise<boolean>;
24
+ export type RepositoryExistsBy<E> = {
25
+ [K in keyof E & string as `existsBy${Capitalize<K>}`]: (value: E[K]) => Promise<boolean>;
22
26
  };
23
- export type RepositoryNotExistsBy<T> = {
24
- [K in keyof T & string as `notExistsBy${Capitalize<K>}`]: (value: T[K]) => Promise<boolean>;
27
+ export type RepositoryNotExistsBy<E> = {
28
+ [K in keyof E & string as `notExistsBy${Capitalize<K>}`]: (value: E[K]) => Promise<boolean>;
25
29
  };
26
- export interface RepositoryPagination<T> {
30
+ export interface RepositoryPagination<E extends Entity, M> extends RepositoryModel<E, M> {
27
31
  restoreMany({ filter, pagination }: {
28
32
  filter?: Record<string, any>;
29
33
  pagination?: {
30
34
  offset: number;
31
35
  limit: number;
32
36
  };
33
- }): Promise<T>;
37
+ }): Promise<E[]>;
34
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "framework-do-dede",
3
- "version": "4.0.5",
3
+ "version": "5.0.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",