framework-do-dede 6.0.5 → 6.1.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
@@ -341,6 +341,26 @@ class CreatePhotoUseCase extends UseCase<void, void> {
341
341
  }
342
342
  ```
343
343
 
344
+ Quando `@DecorateUseCase` está presente, `HookAfter` roda **depois de todo o fluxo** por padrão
345
+ (use cases decoradores + use case principal), independentemente da ordem dos decorators.
346
+
347
+ ```ts
348
+ @DecorateUseCase({ useCase: AuditUseCase })
349
+ @HookAfter(SavePhoto)
350
+ class CreateUserUseCase extends UseCase<void, void> {}
351
+ // ordem: AuditUseCase -> CreateUserUseCase -> SavePhoto
352
+ ```
353
+
354
+ Se precisar executar o HookAfter **logo após os use cases decoradores** (antes do principal),
355
+ defina `after: 'decorator'`.
356
+
357
+ ```ts
358
+ @HookAfter(SavePhoto, { after: 'decorator' })
359
+ @DecorateUseCase({ useCase: AuditUseCase })
360
+ class CreateUserUseCase extends UseCase<void, void> {}
361
+ // ordem: AuditUseCase -> SavePhoto -> CreateUserUseCase
362
+ ```
363
+
344
364
  ### Entity e Model
345
365
 
346
366
  Entities sao dominio puro. `Model` vive na borda e faz o mapeamento banco <-> model, alem de converter `Entity` <-> `Model`. Repositorios trabalham com `Model`, nao com `Entity`.
@@ -11,8 +11,10 @@ export declare abstract class UseCase<UseCaseInput, UseCaseOutput, UseCaseContex
11
11
  type UseCaseConstructor = new (...args: any[]) => UseCase<any, any>;
12
12
  type HookConstructor = new (...args: any[]) => Hook<any, any>;
13
13
  type HookPosition = 'before' | 'after';
14
+ type HookAfterStage = 'decorator' | 'main';
14
15
  interface HookOptions {
15
16
  runOnError?: boolean;
17
+ after?: HookAfterStage;
16
18
  }
17
19
  interface DecorateUseCaseOptions {
18
20
  useCase: UseCaseConstructor | UseCaseConstructor[];
@@ -37,7 +39,7 @@ declare class HookManager {
37
39
  use(payload: unknown): void;
38
40
  useIfUnset(payload: unknown): void;
39
41
  notifyBefore(): Promise<void>;
40
- notifyAfter(onError: boolean): Promise<void>;
42
+ notifyAfter(onError: boolean, stage?: HookAfterStage): Promise<void>;
41
43
  private buildEntry;
42
44
  private notifyEntry;
43
45
  }
@@ -44,7 +44,7 @@ function ensureHookedExecution(target) {
44
44
  originalError = error;
45
45
  }
46
46
  afterHook.useIfUnset(this.data);
47
- await afterHook.notifyAfter(!!originalError);
47
+ await afterHook.notifyAfter(!!originalError, 'main');
48
48
  if (originalError) {
49
49
  throw originalError;
50
50
  }
@@ -94,10 +94,14 @@ class HookManager {
94
94
  await this.notifyEntry(this.entry);
95
95
  }
96
96
  }
97
- async notifyAfter(onError) {
97
+ async notifyAfter(onError, stage = 'main') {
98
98
  if (!this.entry || this.position !== 'after' || this.entry.metadata.position !== 'after') {
99
99
  return;
100
100
  }
101
+ const hookStage = this.entry.metadata.after ?? 'main';
102
+ if (hookStage !== stage) {
103
+ return;
104
+ }
101
105
  if (onError && !this.entry.metadata.runOnError) {
102
106
  return;
103
107
  }
@@ -151,7 +155,7 @@ function buildUseCaseInstances(owner, options) {
151
155
  export function DecorateUseCase(options) {
152
156
  return (target) => {
153
157
  const stateKey = Symbol('decoratorUseCases');
154
- return class extends target {
158
+ const decorated = class extends target {
155
159
  constructor(...args) {
156
160
  super(...args);
157
161
  this[stateKey] = {
@@ -161,12 +165,29 @@ export function DecorateUseCase(options) {
161
165
  }
162
166
  async execute() {
163
167
  const state = this[stateKey];
164
- for (const useCase of state.useCases) {
165
- await useCase.execute();
168
+ let decoratorError;
169
+ try {
170
+ for (const useCase of state.useCases) {
171
+ await useCase.execute();
172
+ }
173
+ }
174
+ catch (error) {
175
+ decoratorError = error;
176
+ }
177
+ const afterHook = this.afterHook;
178
+ afterHook.useIfUnset(this.data);
179
+ await afterHook.notifyAfter(!!decoratorError, 'decorator');
180
+ if (decoratorError) {
181
+ throw decoratorError;
166
182
  }
167
183
  return await state.original.call(this);
168
184
  }
169
185
  };
186
+ const hooks = getHookMetadata(target);
187
+ if (hooks.length) {
188
+ decorated[USE_CASE_HOOKS] = [...hooks];
189
+ }
190
+ return ensureHookedExecution(decorated);
170
191
  };
171
192
  }
172
193
  export function HookBefore(hookClass) {
@@ -177,7 +198,12 @@ export function HookBefore(hookClass) {
177
198
  }
178
199
  export function HookAfter(hookClass, options = {}) {
179
200
  return (target) => {
180
- registerHook(target, { hookClass, position: 'after', runOnError: options.runOnError });
201
+ registerHook(target, {
202
+ hookClass,
203
+ position: 'after',
204
+ runOnError: options.runOnError,
205
+ after: options.after,
206
+ });
181
207
  return ensureHookedExecution(target);
182
208
  };
183
209
  }
@@ -9,7 +9,7 @@ export declare abstract class Model<TEntity extends Entity = Entity> extends Rep
9
9
  [property: string]: any;
10
10
  fromModel(input: Record<string, any> | null | undefined): this;
11
11
  abstract fromEntity(entity: TEntity): this;
12
- toModel(): Record<string, any>;
12
+ toModel(ignoreId?: boolean, namedId?: string): Record<string, any>;
13
13
  abstract toEntity(): TEntity;
14
14
  }
15
15
  export declare function column(columnName: string): (target: any, propertyKey: string) => void;
@@ -12,10 +12,11 @@ export class Model extends RepositoryModel {
12
12
  }
13
13
  return this;
14
14
  }
15
- toModel() {
15
+ toModel(ignoreId = false, namedId) {
16
16
  const record = {};
17
17
  const columns = this.columns ?? [];
18
18
  const mappedProperties = new Set();
19
+ const idColumn = columns.find((column) => column.property === "id")?.column ?? "id";
19
20
  for (const column of columns) {
20
21
  record[column.column] = this[column.property];
21
22
  mappedProperties.add(column.property);
@@ -29,6 +30,13 @@ export class Model extends RepositoryModel {
29
30
  }
30
31
  record[property] = this[property];
31
32
  }
33
+ const idValue = this.id ?? record[idColumn];
34
+ if (namedId && idValue !== undefined) {
35
+ record[namedId] = idValue;
36
+ }
37
+ if (ignoreId) {
38
+ delete record[idColumn];
39
+ }
32
40
  return record;
33
41
  }
34
42
  }
@@ -1,6 +1,6 @@
1
1
  export declare abstract class RepositoryModel<TEntity = any> {
2
2
  abstract fromModel(input: Record<string, any> | null | undefined): this;
3
- abstract toModel(): Record<string, any>;
3
+ abstract toModel(ignoreId?: boolean, namedId?: string): Record<string, any>;
4
4
  abstract fromEntity(entity: TEntity): this;
5
5
  abstract toEntity(): TEntity;
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "framework-do-dede",
3
- "version": "6.0.5",
3
+ "version": "6.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",