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
|
-
|
|
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
|
-
|
|
165
|
-
|
|
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, {
|
|
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
|
}
|