framework-do-dede 4.1.0 → 5.2.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,57 @@ 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 mapear coluna/property e construir o objeto de persistencia.
262
256
 
263
257
  ```ts
264
- import { Entity, Serialize, Restrict, VirtualProperty, GetterPrefix } from './src';
265
-
266
- class User extends Entity {
267
- @Serialize((value: Email) => value.getValue())
268
- private readonly email: Email;
258
+ import { Entity, Model, model, column } from './src';
269
259
 
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
- }
260
+ class Order extends Entity {
261
+ private readonly id: string;
262
+ private readonly name: string;
263
+ private readonly amount: number;
280
264
 
281
- constructor(email: string, passwordHash: string) {
265
+ constructor(id: string, name: string, amount: number) {
282
266
  super();
283
- this.email = new Email(email);
284
- this.passwordHash = passwordHash;
267
+ this.id = id;
268
+ this.name = name;
269
+ this.amount = amount;
285
270
  this.generateGetters();
286
271
  }
287
272
  }
288
273
 
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.
274
+ type OrderTable = 'orders';
303
275
 
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
276
+ @model<OrderTable>('orders')
277
+ class OrderModel extends Model<OrderTable> {
278
+ @column('id')
279
+ id!: string;
308
280
 
309
- ```ts
310
- import { Entity, AfterToEntity, BeforeToEntity } from './src';
281
+ @column('name')
282
+ name!: string;
311
283
 
312
- class FileEntity extends Entity {
313
- private readonly name: string;
314
- private readonly s3Key: string;
284
+ @column('amount')
285
+ amount!: number;
315
286
 
316
- constructor(name: string, s3Key: string) {
287
+ constructor(order?: Order) {
317
288
  super();
318
- this.name = name;
319
- this.s3Key = s3Key;
320
- }
321
-
322
- @BeforeToEntity()
323
- private before(payload: Record<string, any>) {
324
- payload.rawTouched = true;
325
- }
326
-
327
- @AfterToEntity()
328
- private async after(payload: Record<string, any>) {
329
- await saveToS3(payload.s3Key);
289
+ if (order) {
290
+ this.id = order.getId();
291
+ this.name = order.getName();
292
+ this.amount = order.getAmount();
293
+ }
330
294
  }
331
295
  }
332
296
  ```
333
297
 
298
+ Regras principais:
299
+
300
+ - `Model` guarda metadados de coluna (via `@column`) e nome da tabela (via `@model`)
301
+ - a conversao entity -> model acontece no construtor do Model (ou em um factory)
302
+ - `generateGetters()` cria getters para campos (ex.: `getName`, `isActive`, `hasProfile`)
303
+
334
304
  ### Storage Gateway
335
305
 
336
306
  Use `@Storage` para injetar gateways com interface `StorageGateway`.
@@ -350,6 +320,25 @@ class FileService {
350
320
  }
351
321
  ```
352
322
 
323
+ ### Event Dispatcher
324
+
325
+ Use `@EventDispatcher` para enfileirar tarefas ou eventos de background com interface `EventDispatcher`.
326
+
327
+ ```ts
328
+ import { EventDispatcher } from './src';
329
+
330
+ type QueueEvent = { name: string; payload?: Record<string, any> };
331
+
332
+ class QueueService {
333
+ @EventDispatcher('QueueDispatcher')
334
+ private readonly dispatcher!: { dispatch: (event: QueueEvent) => Promise<void> };
335
+
336
+ async enqueue(payload: Record<string, any>) {
337
+ await this.dispatcher.dispatch({ name: 'jobs.create', payload });
338
+ }
339
+ }
340
+ ```
341
+
353
342
  ### DI (Container/Inject)
354
343
 
355
344
  Registre dependencias ao iniciar o server (usando o container padrão):
@@ -447,49 +436,24 @@ app.registerControllers([ExampleController]);
447
436
  app.listen();
448
437
  ```
449
438
 
450
- ### Fila com AfterToEntity
439
+ ### Background com EventDispatcher
451
440
 
452
441
  ```ts
453
- import { Entity, AfterToEntity } from './src';
442
+ import { EventDispatcher } from './src';
454
443
 
455
- type QueueJob = { type: string; payload: Record<string, any> };
444
+ type QueueEvent = { name: string; payload: Record<string, any> };
456
445
 
457
- type Queue = { enqueue(job: QueueJob): Promise<void> };
458
-
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;
468
-
469
- private constructor({ name, s3Key }: { name: string; s3Key: string }) {
470
- super();
471
- this.name = name;
472
- this.s3Key = s3Key;
473
- }
446
+ class FileService {
447
+ @EventDispatcher('QueueDispatcher')
448
+ private readonly dispatcher!: { dispatch: (event: QueueEvent) => Promise<void> };
474
449
 
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
- }
450
+ async enqueueFile(input: { name: string; s3Key: string }) {
451
+ await this.dispatcher.dispatch({
452
+ name: 'files.create',
453
+ payload: input
483
454
  });
484
455
  }
485
-
486
- static create(input: { name: string; s3Key: string }) {
487
- return new FileEntity(input);
488
- }
489
456
  }
490
-
491
- const entity = FileEntity.create({ name: 'report', s3Key: 's3://bucket/report.pdf' });
492
- const serialized = entity.toEntity();
493
457
  ```
494
458
 
495
459
  ## Testes
@@ -1,7 +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, Transform } from '../infra/serialization/entity';
3
+ import { Model, model, column } from '../infra/model/model';
3
4
  import { DecorateUseCase, UseCase } from './usecase';
4
- export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity, };
5
- export { Storage, CacheGateway } from './services';
5
+ export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Entity, Restrict, VirtualProperty, GetterPrefix, Transform, Model, model, column, };
6
+ export { Storage, CacheGateway, EventDispatcher } from './services';
6
7
  export type { Middleware, Input, Tracer, TracerData };
7
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, Transform } from '../infra/serialization/entity';
3
+ import { Model, model, column } from '../infra/model/model';
3
4
  import { DecorateUseCase, UseCase } from './usecase';
4
- export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Entity, Restrict, VirtualProperty, Serialize, GetterPrefix, BeforeToEntity, AfterToEntity, };
5
- export { Storage, CacheGateway } from './services';
5
+ export { Controller, UseMiddleware, UseMiddlewares, Post, Get, Put, Delete, Patch, Tracing, DecorateUseCase, UseCase, Entity, Restrict, VirtualProperty, GetterPrefix, Transform, Model, model, column, };
6
+ export { Storage, CacheGateway, EventDispatcher } from './services';
@@ -10,5 +10,14 @@ export interface CacheGateway {
10
10
  set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> | void;
11
11
  delete(key: string): Promise<boolean> | boolean;
12
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
+ }
13
21
  export declare function Storage(gatewayName: string, container?: Container): (target: any, propertyKey: string) => void;
14
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;
@@ -30,3 +30,10 @@ export function CacheGateway(gatewayName, container) {
30
30
  defineGatewayProperty(resolvedTarget, resolvedProperty, gatewayName, container, (dependency) => !!dependency?.get && !!dependency?.set && !!dependency?.delete, `${gatewayName} is not a valid CacheGateway`);
31
31
  };
32
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`);
38
+ };
39
+ }
package/dist/index.d.ts CHANGED
@@ -1,10 +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, CacheGateway } from "./application";
1
+ import { Post, Get, Put, Delete, Patch, Controller, Input, Middleware, UseMiddleware, UseMiddlewares, Tracer, Tracing, TracerData, Entity, Restrict, VirtualProperty, GetterPrefix, Model, model, column, 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 { StorageGateway } from './application';
7
+ import type { StorageGateway, Event, EventPayload } from './application';
8
8
  import type { 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, Serialize, UseCase, DecorateUseCase, Storage, CacheGateway, 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 };
10
- export type { ValidatorDefinition, StorageGateway };
9
+ export { Controller, Post, Get, Put, Delete, Patch, Input, Middleware, UseMiddleware, UseMiddlewares, Tracer, Tracing, TracerData, Entity, Restrict, VirtualProperty, GetterPrefix, Model, model, column, UseCase, DecorateUseCase, Storage, CacheGateway, EventDispatcher, 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 };
10
+ export type { ValidatorDefinition, StorageGateway, Event, EventPayload };
package/dist/index.js CHANGED
@@ -3,17 +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, model, column,
7
7
  // entity
8
8
  // usecase
9
9
  UseCase, DecorateUseCase,
10
10
  // usecase
11
11
  // storage
12
- Storage, CacheGateway
12
+ Storage, CacheGateway, EventDispatcher
13
13
  // storage
14
14
  } from "./application";
15
15
  import { Container, DefaultContainer, Inject, setDefaultContainer } from './infra/di/registry';
16
16
  import { Dede } from './dede';
17
17
  import { ServerError, NotFound, Forbidden, Conflict, Unauthorized, UnprocessableEntity, BadRequest, InternalServerError, CustomServerError } from './http/errors/server';
18
18
  import { AppError } from './domain/errors/app-error';
19
- export { Controller, Post, Get, Put, Delete, Patch, UseMiddleware, UseMiddlewares, Tracing, Entity, Restrict, VirtualProperty, GetterPrefix, Serialize, UseCase, DecorateUseCase, Storage, CacheGateway, 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, model, column, UseCase, DecorateUseCase, Storage, CacheGateway, EventDispatcher, Inject, Container, DefaultContainer, setDefaultContainer, Dede, ServerError, NotFound, Forbidden, Conflict, Unauthorized, UnprocessableEntity, BadRequest, InternalServerError, CustomServerError, AppError };
@@ -0,0 +1,12 @@
1
+ export type ColumnDefinition = {
2
+ column: string;
3
+ property: string;
4
+ };
5
+ export declare abstract class Model<TTable = string> {
6
+ table: TTable;
7
+ columns: ColumnDefinition[];
8
+ [property: string]: any;
9
+ toPersistence(): Record<string, any>;
10
+ }
11
+ export declare function model<TTable>(table: TTable): (target: any) => void;
12
+ export declare function column(columnName: string): (target: any, propertyKey: string) => void;
@@ -0,0 +1,21 @@
1
+ export class Model {
2
+ toPersistence() {
3
+ const record = {};
4
+ const columns = this.columns ?? [];
5
+ for (const column of columns) {
6
+ record[column.column] = this[column.property];
7
+ }
8
+ return record;
9
+ }
10
+ }
11
+ export function model(table) {
12
+ return function (target) {
13
+ target.prototype.table = table;
14
+ };
15
+ }
16
+ export function column(columnName) {
17
+ return function (target, propertyKey) {
18
+ target.columns = target.columns || [];
19
+ target.columns.push({ column: columnName, property: propertyKey });
20
+ };
21
+ }
@@ -1,23 +1,11 @@
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
- toEntity(): Record<string, any>;
8
- toAsyncEntity(): Promise<Record<string, any>>;
9
- toData({ serialize }?: {
10
- serialize?: boolean;
11
- }): Record<string, any>;
12
- toAsyncData({ serialize }?: {
13
- serialize?: boolean;
14
- }): Promise<Record<string, any>>;
4
+ from(): Record<string, any>;
5
+ to(transform?: boolean): Record<string, any>;
15
6
  protected generateGetters(): void;
16
7
  }
17
8
  export declare function Restrict(): (target: any, propertyKey: string) => void;
18
9
  export declare function VirtualProperty(propertyName: string): (target: any, methodName: string) => void;
19
- export declare function Serialize(callback: (value: any) => any): PropertyDecorator;
10
+ export declare function Transform(callback: (value: any) => any): PropertyDecorator;
20
11
  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,98 +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
- }
56
- toEntity() {
57
- const raw = this.buildRawEntityObject();
58
- this.runEntityHooks(BEFORE_TO_ENTITY, raw, false);
59
- // @ts-ignore
60
- const propertiesConfigs = this.constructor.propertiesConfigs;
61
- const result = {};
62
- for (const [propName] of Object.entries(this)) {
63
- let propertyName = propName;
64
- let value = this[propName];
65
- if (typeof value === 'function')
66
- continue;
67
- if (value === undefined)
68
- continue;
69
- // @ts-ignore
70
- if (propertiesConfigs && propertiesConfigs[propName]?.serialize && value) {
71
- const serializedValue = propertiesConfigs[propName].serialize(value);
72
- if (serializedValue && typeof serializedValue === 'object' && !Array.isArray(serializedValue)) {
73
- const entries = Object.entries(serializedValue);
74
- for (const [serializedKey, serializedPropValue] of entries) {
75
- let currentValue = serializedPropValue;
76
- if (!currentValue)
77
- currentValue = null;
78
- result[serializedKey] = currentValue;
79
- }
80
- continue;
81
- }
82
- else {
83
- value = serializedValue;
84
- }
85
- }
86
- if (value === undefined || value === null)
87
- value = null;
88
- result[propertyName] = value;
89
- }
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);
2
+ export class Entity extends DomainEntity {
3
+ from() {
96
4
  // @ts-ignore
97
5
  const propertiesConfigs = this.constructor.propertiesConfigs;
98
6
  const result = {};
@@ -104,30 +12,29 @@ export class SerializableEntity extends DomainEntity {
104
12
  if (value === undefined)
105
13
  continue;
106
14
  // @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;
15
+ if (propertiesConfigs && propertiesConfigs[propName]?.transform && value) {
16
+ const transformedValue = propertiesConfigs[propName].transform(value);
17
+ if (transformedValue && typeof transformedValue === 'object' && !Array.isArray(transformedValue)) {
18
+ const entries = Object.entries(transformedValue);
19
+ for (const [transformedKey, transformedPropValue] of entries) {
20
+ let currentValue = transformedPropValue;
113
21
  if (!currentValue)
114
22
  currentValue = null;
115
- result[serializedKey] = currentValue;
23
+ result[transformedKey] = currentValue;
116
24
  }
117
25
  continue;
118
26
  }
119
27
  else {
120
- value = serializedValue;
28
+ value = transformedValue;
121
29
  }
122
30
  }
123
31
  if (value === undefined || value === null)
124
32
  value = null;
125
33
  result[propertyName] = value;
126
34
  }
127
- await this.runEntityHooks(AFTER_TO_ENTITY, result, true);
128
35
  return result;
129
36
  }
130
- toData({ serialize = false } = {}) {
37
+ to(transform = true) {
131
38
  // @ts-ignore
132
39
  const propertiesConfigs = this.constructor.propertiesConfigs;
133
40
  // @ts-ignore
@@ -140,8 +47,8 @@ export class SerializableEntity extends DomainEntity {
140
47
  continue;
141
48
  // @ts-ignore
142
49
  let value = this[propName];
143
- if (serialize && propertiesConfigs && propertiesConfigs[propName]?.serialize && value) {
144
- value = propertiesConfigs[propName].serialize(value);
50
+ if (transform && propertiesConfigs && propertiesConfigs[propName]?.transform && value) {
51
+ value = propertiesConfigs[propName].transform(value);
145
52
  }
146
53
  result[propName] = value;
147
54
  }
@@ -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
  }
@@ -198,10 +78,10 @@ export function VirtualProperty(propertyName) {
198
78
  cls.virtualProperties[methodName] = propertyName;
199
79
  };
200
80
  }
201
- export function Serialize(callback) {
81
+ export function Transform(callback) {
202
82
  return function (target, propertyKey) {
203
83
  loadPropertiesConfig(target, propertyKey);
204
- target.constructor.propertiesConfigs[propertyKey].serialize = callback;
84
+ target.constructor.propertiesConfigs[propertyKey].transform = callback;
205
85
  };
206
86
  }
207
87
  export function GetterPrefix(prefix) {
@@ -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
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "framework-do-dede",
3
- "version": "4.1.0",
3
+ "version": "5.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",