Skip to content
This repository was archived by the owner on Feb 6, 2025. It is now read-only.

Commit 4df869e

Browse files
authored
Merge branch 'main' into docs/update-amplication-branch-info
2 parents d7d8684 + 6c896ba commit 4df869e

20 files changed

+472
-297
lines changed

docs/plugins/before-after.md

+27-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ slug: /plugins/plugin-events/plugin-events-before-after
77

88
# Before and After Lifecycle Functions
99

10-
All events expose an identical interface with two functions that can be handled by the plugin and responsible for a different step in the lifecycle of the event. One for “before” the event is emitted and another for “after” the event is emitted.
10+
All events expose an identical interface with two functions that can be handled by the plugin and responsible for a different step in the lifecycle of the event. One for "before" the event is emitted and another for "after" the event is emitted.
11+
12+
## Event Structure and Parameters
1113

1214
```tsx
1315
export interface PluginEventType<T extends EventParams> {
@@ -20,26 +22,48 @@ For each event, the type of `EventParams` is different, providing access to rele
2022

2123
```tsx
2224
export interface EventParams {}
25+
```
26+
27+
## Before and After Function Signatures
2328

29+
```tsx
2430
export type PluginBeforeEvent<T extends EventParams> = (
2531
dsgContext: DsgContext,
2632
eventParams: T
2733
) => Promisable<T>;
2834

35+
// Node.js [version](https://github.com/amplication/amplication/blob/master/libs/util/code-gen-types/src/plugins.types.ts#L21)
2936
export type PluginAfterEvent<T extends EventParams> = (
3037
dsgContext: DsgContext,
3138
eventParams: T,
3239
modules: ModuleMap
3340
) => Promisable<ModuleMap>;
41+
42+
// .NET [version](https://github.com/amplication/amplication/blob/master/libs/util/code-gen-types/src/dotnet-plugins.types.ts#L22)
43+
export type PluginAfterEvent<T extends EventParams, F> = (
44+
dsgContext: DsgContext,
45+
eventParams: T,
46+
files: FileMap<F>
47+
) => Promisable<FileMap<F>>;
3448
```
3549

3650
In the `before` and `after` functions, we have an access to the context and the event params.
3751
The [context](docs\plugins\context.md) is used to gather common parts between events.
3852
The event params manipulate the default behavior by passing different values.
3953

40-
In the `after` function, we also have access to the generated modules. An example of using this parameter is when you want to restructure the generated modules in a different folder structure.
54+
## Accessing and Modifying Generated Files
55+
56+
In the `after` function, we also have access to the generated files. An example of using this parameter is when you want to restructure the generated files in a different folder structure.
57+
58+
:::info
59+
In the `after` function for .NET plugins, we use a [`FileMap`](https://github.com/amplication/amplication/blob/master/libs/util/code-gen-types/src/files/file-map.ts). For Node.js plugins' `after` function we use a [`ModuleMap`](https://github.com/amplication/amplication/blob/master/libs/util/code-gen-types/src/code-gen-types.ts#L149).
60+
:::
61+
62+
## Function Examples
63+
64+
Most of the functions include examples. But, if you're looking for more comprehensive and real-world examples, you can explore the [code of the Amplication plugins](https://github.com/amplication/plugins/tree/master/plugins) directly. These plugins showcase various implementations and use cases for the before and after lifecycle functions.
4165

42-
## Cautionary Guidelines
66+
## Best Practices and Cautions
4367

4468
1. In the `after` function, avoid unintentionally overriding the entire generated file. Opt for smaller changes instead.
4569
2. In the `before` function, take care when modifying templates to not unintentionally affect code generation.

docs/plugins/dotnet-plugin-events/create-dtos.md

+15-24
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,24 @@ export interface CreateDTOsParams extends EventParams {
2525
}
2626
```
2727

28-
Example:
28+
### Example
2929

3030
```ts
31-
async afterCreateDTOs(
32-
context: DsgContext,
33-
eventParams: CreateDTOsParams,
34-
modules: ModuleMap
35-
) {
36-
const { entity, dtoName, dtoBasePath } = eventParams;
37-
const dtoPath = join(dtoBasePath, `${dtoName}.cs`);
38-
const dtoFile = modules.get(dtoPath);
39-
31+
afterCreateDTOs(
32+
context: dotnetTypes.DsgContext,
33+
eventParams: dotnet.CreateDTOsParams,
34+
files: FileMap<Class>
35+
): Promise<FileMap<Class>> {
36+
const { entity, dtoName } = eventParams;
37+
const dtoFile = files.get(`DTOs/${dtoName}.cs`);
4038
if (dtoFile) {
41-
const updatedCode = dtoFile.code + `
42-
public class ${entity.name}SummaryDTO
43-
{
44-
public int Id { get; set; }
45-
public string Name { get; set; }
46-
}
47-
`;
48-
49-
modules.set({
50-
path: dtoPath,
51-
code: updatedCode
52-
});
39+
dtoFile.code.addProperty(
40+
CsharpSupport.property({
41+
name: "LastModified",
42+
type: CsharpSupport.Types.dateTime(),
43+
})
44+
);
5345
}
54-
55-
return modules;
46+
return files;
5647
}
5748
```

docs/plugins/dotnet-plugin-events/create-entity-controller-base.md

+42-16
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,56 @@ An array of module actions available for the entity.
3535

3636
An array of all entities in the application.
3737

38-
Example:
38+
### Example
3939

4040
```ts
41-
async afterCreateEntityControllerBase(
42-
context: DsgContext,
43-
eventParams: CreateEntityControllerBaseParams,
44-
modules: ModuleMap
45-
) {
46-
const { resourceName, apisDir } = eventParams;
47-
const controllerBasePath = join(apisDir, `${resourceName}ControllerBase.cs`);
48-
const controllerBaseFile = modules.get(controllerBasePath);
41+
afterCreateEntityControllerBase(
42+
context: dotnetTypes.DsgContext,
43+
eventParams: dotnet.CreateEntityControllerBaseParams,
44+
files: FileMap<Class>
45+
): Promise<FileMap<Class>> {
46+
const { entity, resourceName, apisDir } = eventParams;
47+
const controllerBasePath = `${apisDir}/${entity.name}/Base/${pascalCase(entity.name)}ControllerBase.cs`;
48+
const controllerBaseFile = files.get(controllerBasePath);
4949

5050
if (controllerBaseFile) {
51-
const updatedCode = controllerBaseFile.code.replace(
52-
"public abstract class",
53-
"[ApiController]\n[Route(\"api/[controller]\")]\npublic abstract class"
51+
// Add a protected method to the base controller
52+
controllerBaseFile.code.addMethod(
53+
CsharpSupport.method({
54+
name: "ValidateEntityState",
55+
access: "protected",
56+
returnType: CsharpSupport.Types.boolean(),
57+
parameters: [
58+
CsharpSupport.parameter({
59+
name: "entity",
60+
type: CsharpSupport.Types.reference(entity.name),
61+
}),
62+
],
63+
body: `
64+
if (entity == null)
65+
return false;
66+
67+
// Add custom validation logic here
68+
return true;
69+
`,
70+
})
5471
);
5572

56-
modules.set({
57-
path: controllerBasePath,
58-
code: updatedCode
73+
// Modify existing methods to use the new validation
74+
const methods = controllerBaseFile.code.getMethods();
75+
methods.forEach(method => {
76+
if (method.name === `Create${entity.name}` || method.name === `Update${entity.name}`) {
77+
const existingBody = method.body;
78+
method.body = `
79+
if (!ValidateEntityState(${camelCase(entity.name)}))
80+
return BadRequest("Invalid entity state");
81+
82+
${existingBody}
83+
`;
84+
}
5985
});
6086
}
6187

62-
return modules;
88+
return files;
6389
}
6490
```

docs/plugins/dotnet-plugin-events/create-entity-controller.md

+31-16
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,45 @@ The directory where the API controllers are being generated.
4242

4343
An object containing the CRUD actions available for the entity.
4444

45-
Example:
45+
### Example
4646

4747
```ts
48-
async afterCreateEntityController(
49-
context: DsgContext,
50-
eventParams: CreateEntityControllerParams,
51-
modules: ModuleMap
52-
) {
48+
afterCreateEntityController(
49+
context: dotnetTypes.DsgContext,
50+
eventParams: dotnet.CreateEntityControllerParams,
51+
files: FileMap<Class>
52+
): Promise<FileMap<Class>> {
5353
const { entity, resourceName, apisDir } = eventParams;
54-
const controllerPath = join(apisDir, `${resourceName}Controller.cs`);
55-
const controllerFile = modules.get(controllerPath);
54+
const controllerPath = `${apisDir}/${entity.name}/${pascalCase(entity.name)}Controller.cs`;
55+
const controllerFile = files.get(controllerPath);
5656

5757
if (controllerFile) {
58-
const updatedCode = controllerFile.code.replace(
59-
"public class",
60-
"[ApiVersion(\"1.0\")]\npublic class"
58+
// Add a custom action to the controller
59+
controllerFile.code.addMethod(
60+
CsharpSupport.method({
61+
name: "ExportToCsv",
62+
access: "public",
63+
isAsync: true,
64+
returnType: CsharpSupport.Types.task(CsharpSupport.Types.reference("IActionResult")),
65+
decorators: [
66+
CsharpSupport.decorator({
67+
name: "HttpGet",
68+
arguments: ["export-csv"],
69+
}),
70+
],
71+
body: `
72+
var allItems = await _service.List();
73+
var csv = ConvertToCsv(allItems);
74+
return File(Encoding.UTF8.GetBytes(csv), "text/csv", "${entity.name}Export.csv");
75+
`,
76+
})
6177
);
6278

63-
modules.set({
64-
path: controllerPath,
65-
code: updatedCode
66-
});
79+
// Add necessary imports
80+
controllerFile.code.addImport("System.Text");
81+
controllerFile.code.addImport("Microsoft.AspNetCore.Mvc");
6782
}
6883

69-
return modules;
84+
return files;
7085
}
7186
```

docs/plugins/dotnet-plugin-events/create-entity-extensions.md

+52-21
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,63 @@ export interface CreateEntityExtensionsParams extends EventParams {
2525
}
2626
```
2727

28-
Example:
28+
### Example
2929

3030
```ts
31-
async afterCreateEntityExtensions(
32-
context: DsgContext,
33-
eventParams: CreateEntityExtensionsParams,
34-
modules: ModuleMap
35-
) {
36-
const { entity, apisDir } = eventParams;
37-
const extensionsPath = join(apisDir, "Extensions", `${entity.name}Extensions.cs`);
38-
const extensionsFile = modules.get(extensionsPath);
31+
afterCreateEntityExtensions(
32+
context: dotnetTypes.DsgContext,
33+
eventParams: dotnet.CreateEntityExtensionsParams,
34+
files: FileMap<Class>
35+
): Promise<FileMap<Class>> {
36+
const { entity, resourceName, apisDir } = eventParams;
37+
const extensionsPath = `${apisDir}/${entity.name}/${pascalCase(entity.name)}Extensions.cs`;
38+
const extensionsFile = files.get(extensionsPath);
3939

4040
if (extensionsFile) {
41-
const updatedCode = extensionsFile.code + `
42-
public static string GetDisplayName(this ${entity.name} entity)
43-
{
44-
return $"{entity.FirstName} {entity.LastName}";
45-
}
46-
`;
47-
48-
modules.set({
49-
path: extensionsPath,
50-
code: updatedCode
51-
});
41+
// Add a custom extension method
42+
extensionsFile.code.addMethod(
43+
CsharpSupport.method({
44+
name: "ToAuditString",
45+
isStatic: true,
46+
returnType: CsharpSupport.Types.string(),
47+
parameters: [
48+
CsharpSupport.parameter({
49+
name: "this",
50+
type: CsharpSupport.Types.reference(entity.name),
51+
isThis: true,
52+
}),
53+
],
54+
body: `
55+
return $"{entity.Id}|{entity.CreatedAt}|{entity.UpdatedAt}";
56+
`,
57+
})
58+
);
59+
60+
// Add a custom mapper extension
61+
extensionsFile.code.addMethod(
62+
CsharpSupport.method({
63+
name: "ToDto",
64+
isStatic: true,
65+
returnType: CsharpSupport.Types.reference(`${entity.name}Dto`),
66+
parameters: [
67+
CsharpSupport.parameter({
68+
name: "this",
69+
type: CsharpSupport.Types.reference(entity.name),
70+
isThis: true,
71+
}),
72+
],
73+
body: `
74+
return new ${entity.name}Dto
75+
{
76+
Id = entity.Id,
77+
// Map other properties here
78+
AuditString = entity.ToAuditString()
79+
};
80+
`,
81+
})
82+
);
5283
}
5384

54-
return modules;
85+
return files;
5586
}
5687
```

docs/plugins/dotnet-plugin-events/create-entity-interface.md

+15-20
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,24 @@ export interface CreateEntityInterfaceParams extends EventParams {
2828
}
2929
```
3030

31-
Example:
31+
### Example
3232

3333
```ts
34-
async afterCreateEntityInterface(
35-
context: DsgContext,
36-
eventParams: CreateEntityInterfaceParams,
37-
modules: ModuleMap
38-
) {
39-
const { entity, apisDir } = eventParams;
40-
const interfacePath = join(apisDir, "Interfaces", `I${entity.name}.cs`);
41-
const interfaceFile = modules.get(interfacePath);
42-
34+
afterCreateEntityInterface(
35+
context: dotnetTypes.DsgContext,
36+
eventParams: dotnet.CreateEntityInterfaceParams,
37+
files: FileMap<Interface>
38+
): Promise<FileMap<Interface>> {
39+
const { entity } = eventParams;
40+
const interfaceFile = files.get(`Interfaces/I${entity.name}.cs`);
4341
if (interfaceFile) {
44-
const updatedCode = interfaceFile.code + `
45-
Task<bool> IsUnique(string name);
46-
`;
47-
48-
modules.set({
49-
path: interfacePath,
50-
code: updatedCode
51-
});
42+
interfaceFile.code.addMethod(
43+
CsharpSupport.method({
44+
name: "Validate",
45+
returnType: CsharpSupport.Types.boolean(),
46+
})
47+
);
5248
}
53-
54-
return modules;
49+
return files;
5550
}
5651
```

0 commit comments

Comments
 (0)