@salesforce/afv-skills 1.5.0 → 1.5.1
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/package.json +3 -3
- package/skills/creating-webapp/SKILL.md +0 -2
- package/skills/generating-apex/SKILL.md +253 -0
- package/skills/generating-apex/assets/abstract.cls +128 -0
- package/skills/generating-apex/assets/batch.cls +125 -0
- package/skills/generating-apex/assets/domain.cls +102 -0
- package/skills/generating-apex/assets/dto.cls +108 -0
- package/skills/generating-apex/assets/exception.cls +51 -0
- package/skills/generating-apex/assets/interface.cls +25 -0
- package/skills/generating-apex/assets/queueable.cls +92 -0
- package/skills/generating-apex/assets/schedulable.cls +75 -0
- package/skills/generating-apex/assets/selector.cls +92 -0
- package/skills/generating-apex/assets/service.cls +69 -0
- package/skills/generating-apex/assets/utility.cls +97 -0
- package/skills/generating-apex/references/AccountDeduplicationBatch.cls +148 -0
- package/skills/generating-apex/references/AccountSelector.cls +193 -0
- package/skills/generating-apex/references/AccountService.cls +201 -0
- package/skills/generating-apex-test/SKILL.md +108 -0
- package/skills/generating-apex-test/assets/test-class-template.cls +124 -0
- package/skills/generating-apex-test/assets/test-data-factory-template.cls +112 -0
- package/skills/generating-apex-test/references/assertion-patterns.md +165 -0
- package/skills/generating-apex-test/references/async-testing.md +276 -0
- package/skills/generating-apex-test/references/mocking-patterns.md +219 -0
- package/skills/generating-apex-test/references/test-data-factory.md +176 -0
- package/skills/generating-experience-react-site/SKILL.md +11 -0
- package/skills/generating-flexipage/SKILL.md +39 -57
- package/skills/searching-media/SKILL.md +342 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/afv-skills",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Salesforce skills for Agentforce Vibes",
|
|
5
5
|
"license": "CC-BY-NC-4.0",
|
|
6
6
|
"files": [
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"registry": "https://registry.npmjs.org"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@salesforce/webapp-template-app-react-sample-b2e-experimental": "^1.
|
|
15
|
-
"@salesforce/webapp-template-app-react-sample-b2x-experimental": "^1.
|
|
14
|
+
"@salesforce/webapp-template-app-react-sample-b2e-experimental": "^1.116.6",
|
|
15
|
+
"@salesforce/webapp-template-app-react-sample-b2x-experimental": "^1.116.6",
|
|
16
16
|
"@types/js-yaml": "^4.0.9",
|
|
17
17
|
"js-yaml": "^4.1.1",
|
|
18
18
|
"tsx": "^4.21.0"
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: creating-webapp
|
|
3
3
|
description: "Use this skill when creating or setting up a new SFDX React web application. Covers first steps, npm install, skills-first protocol, deployment order, and core web app rules."
|
|
4
|
-
paths:
|
|
5
|
-
- "**/webapplications/**/*"
|
|
6
4
|
---
|
|
7
5
|
|
|
8
6
|
# First Steps (MUST FOLLOW)
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: generating-apex
|
|
3
|
+
description: Generate production-ready Apex classes for Salesforce following enterprise best practices. Covers service, selector, domain, batch, queueable, schedulable, DTO, utility, interface, abstract, and custom exception classes. Use this skill when the user asks to create, build, generate, scaffold, or refactor an Apex class. SCOPE Apex classes only — does not apply to triggers or unit tests.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Apex Class
|
|
7
|
+
|
|
8
|
+
Generate well-structured, production-ready Apex classes for Salesforce development.
|
|
9
|
+
|
|
10
|
+
## Scope
|
|
11
|
+
|
|
12
|
+
**Generates:**
|
|
13
|
+
- Service classes (business logic layer)
|
|
14
|
+
- Selector / query classes (SOQL encapsulation)
|
|
15
|
+
- Domain classes (SObject-specific logic)
|
|
16
|
+
- Batch Apex classes (`Database.Batchable`)
|
|
17
|
+
- Queueable Apex classes (`Queueable`, optionally `Finalizer`)
|
|
18
|
+
- Schedulable Apex classes (`Schedulable`)
|
|
19
|
+
- DTO / wrapper / request-response classes
|
|
20
|
+
- Utility / helper classes
|
|
21
|
+
- Custom exception classes
|
|
22
|
+
- Interfaces and abstract classes
|
|
23
|
+
|
|
24
|
+
**Does NOT generate:**
|
|
25
|
+
- Triggers (use a trigger framework skill)
|
|
26
|
+
- Unit tests (use a test writer skill)
|
|
27
|
+
- Aura controllers
|
|
28
|
+
- LWC JavaScript controllers
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Gathering Requirements
|
|
33
|
+
|
|
34
|
+
Before generating code, gather these inputs from the user (ask if not provided):
|
|
35
|
+
|
|
36
|
+
1. **Class type** — Service, Selector, Batch, Queueable, Schedulable, Domain, DTO, Utility, Interface, Abstract, Exception
|
|
37
|
+
2. **Class name** — or enough context to derive a meaningful name
|
|
38
|
+
3. **SObject(s) involved** — if applicable
|
|
39
|
+
4. **Business requirements** — plain-language description of what the class should do
|
|
40
|
+
5. **Optional preferences:**
|
|
41
|
+
- Sharing model (`with sharing`, `without sharing`, `inherited sharing`)
|
|
42
|
+
- Access modifier (`public` or `global`)
|
|
43
|
+
- API version (default: `62.0`)
|
|
44
|
+
- Whether to include ApexDoc comments (default: yes)
|
|
45
|
+
|
|
46
|
+
If the user provides a clear, complete request, generate immediately without unnecessary back-and-forth.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Code Standards — ALWAYS Follow These
|
|
51
|
+
|
|
52
|
+
### Separation of Concerns
|
|
53
|
+
- **Service classes** contain business logic. They call Selectors for data and may call Domain classes for SObject-specific behavior.
|
|
54
|
+
- **Selector classes** encapsulate all SOQL queries. Services never contain inline SOQL.
|
|
55
|
+
- **Domain classes** encapsulate SObject-specific logic (field defaults, validation, transformation).
|
|
56
|
+
- Keep classes focused on a single responsibility.
|
|
57
|
+
|
|
58
|
+
### Bulkification
|
|
59
|
+
- All methods must operate on collections (`List`, `Set`, `Map`) by default.
|
|
60
|
+
- Never accept a single SObject when a `List<SObject>` is appropriate.
|
|
61
|
+
- Provide convenience overloads for single-record callers only when it makes the API cleaner, and have them delegate to the bulk method.
|
|
62
|
+
|
|
63
|
+
### Governor Limit Safety
|
|
64
|
+
- **No SOQL or DML inside loops.** Ever.
|
|
65
|
+
- Collect IDs/records first, query/DML once outside the loop.
|
|
66
|
+
- Use `Limits` class checks in batch/bulk operations where appropriate.
|
|
67
|
+
- Prefer `Database.insert(records, false)` with error handling in batch contexts.
|
|
68
|
+
|
|
69
|
+
### Sharing Model
|
|
70
|
+
- Default to `with sharing` unless the user specifies otherwise.
|
|
71
|
+
- If `without sharing` or `inherited sharing` is used, add an ApexDoc `@description` comment explaining WHY.
|
|
72
|
+
|
|
73
|
+
### Naming Conventions
|
|
74
|
+
|
|
75
|
+
| Class Type | Pattern | Example |
|
|
76
|
+
|-------------|-------------------------------|-------------------------------|
|
|
77
|
+
| Service | `{SObject}Service` | `AccountService` |
|
|
78
|
+
| Selector | `{SObject}Selector` | `AccountSelector` |
|
|
79
|
+
| Domain | `{SObject}Domain` | `OpportunityDomain` |
|
|
80
|
+
| Batch | `{Descriptive}Batch` | `AccountDeduplicationBatch` |
|
|
81
|
+
| Queueable | `{Descriptive}Queueable` | `ExternalSyncQueueable` |
|
|
82
|
+
| Schedulable | `{Descriptive}Schedulable` | `DailyCleanupSchedulable` |
|
|
83
|
+
| DTO | `{Descriptive}DTO` | `AccountMergeRequestDTO` |
|
|
84
|
+
| Wrapper | `{Descriptive}Wrapper` | `OpportunityLineWrapper` |
|
|
85
|
+
| Utility | `{Descriptive}Util` | `StringUtil`, `DateUtil` |
|
|
86
|
+
| Interface | `I{Descriptive}` | `INotificationService` |
|
|
87
|
+
| Abstract | `Abstract{Descriptive}` | `AbstractIntegrationService` |
|
|
88
|
+
| Exception | `{Descriptive}Exception` | `AccountServiceException` |
|
|
89
|
+
|
|
90
|
+
### ApexDoc Comments
|
|
91
|
+
Include ApexDoc on every `public` and `global` method and on the class itself:
|
|
92
|
+
|
|
93
|
+
```apex
|
|
94
|
+
/**
|
|
95
|
+
* @description Brief description of what the class does
|
|
96
|
+
* @author Generated by Apex Class Writer Skill
|
|
97
|
+
*/
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```apex
|
|
101
|
+
/**
|
|
102
|
+
* @description Brief description of what the method does
|
|
103
|
+
* @param paramName Description of the parameter
|
|
104
|
+
* @return Description of the return value
|
|
105
|
+
* @example
|
|
106
|
+
* List<Account> results = AccountService.deduplicateAccounts(accountIds);
|
|
107
|
+
*/
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Null Safety
|
|
111
|
+
- Use guard clauses at the top of methods for null/empty inputs.
|
|
112
|
+
- Use safe navigation (`?.`) where appropriate.
|
|
113
|
+
- Return empty collections rather than `null`.
|
|
114
|
+
|
|
115
|
+
### Constants
|
|
116
|
+
- No magic strings or numbers in logic.
|
|
117
|
+
- Use `private static final` constants or a dedicated constants class.
|
|
118
|
+
- Use `Label.` custom labels for user-facing strings when appropriate.
|
|
119
|
+
|
|
120
|
+
### Custom Exceptions
|
|
121
|
+
- Each service class should define or reference a corresponding custom exception.
|
|
122
|
+
- Inner exception classes are preferred for simple cases: `public class AccountServiceException extends Exception {}`
|
|
123
|
+
- Include meaningful error messages with context.
|
|
124
|
+
|
|
125
|
+
### Error Handling
|
|
126
|
+
- Catch specific exceptions, not generic `Exception` unless re-throwing.
|
|
127
|
+
- Log errors meaningfully (assume a logging utility exists or stub one).
|
|
128
|
+
- In batch contexts, use `Database.SaveResult` / `Database.UpsertResult` with partial success.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Output Format
|
|
133
|
+
|
|
134
|
+
For every class, produce TWO files:
|
|
135
|
+
|
|
136
|
+
1. **`{ClassName}.cls`** — The Apex class source code
|
|
137
|
+
2. **`{ClassName}.cls-meta.xml`** — The metadata file
|
|
138
|
+
|
|
139
|
+
### Meta XML Template
|
|
140
|
+
|
|
141
|
+
```xml
|
|
142
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
143
|
+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
144
|
+
<apiVersion>{API_VERSION}</apiVersion>
|
|
145
|
+
<status>Active</status>
|
|
146
|
+
</ApexClass>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Default `apiVersion` is `62.0` unless the user specifies otherwise.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Class Type–Specific Instructions
|
|
154
|
+
|
|
155
|
+
### Service Classes
|
|
156
|
+
- Read and follow: `assets/service.cls`
|
|
157
|
+
- Stateless — no instance variables holding mutable state
|
|
158
|
+
- All public methods should be `static` unless there's a compelling reason for instance methods
|
|
159
|
+
- Delegate queries to a Selector class
|
|
160
|
+
- Wrap business logic errors in a custom exception
|
|
161
|
+
|
|
162
|
+
### Selector Classes
|
|
163
|
+
- Read and follow: `assets/selector.cls`
|
|
164
|
+
- One Selector per SObject (or per logical query domain)
|
|
165
|
+
- Return `List<SObject>` or `Map<Id, SObject>`
|
|
166
|
+
- Accept filter criteria as method parameters, not hardcoded
|
|
167
|
+
- Include a private method that returns the base field list to keep DRY
|
|
168
|
+
|
|
169
|
+
### Domain Classes
|
|
170
|
+
- Read and follow: `assets/domain.cls`
|
|
171
|
+
- Encapsulate field-level defaults, derivations, and validations
|
|
172
|
+
- Operate on `List<SObject>` — designed to be called from triggers or services
|
|
173
|
+
- No SOQL or DML — only in-memory SObject manipulation
|
|
174
|
+
|
|
175
|
+
### Batch Classes
|
|
176
|
+
- Read and follow: `assets/batch.cls`
|
|
177
|
+
- Implement `Database.Batchable<SObject>` and optionally `Database.Stateful`
|
|
178
|
+
- Use `Database.QueryLocator` in `start()` for large datasets
|
|
179
|
+
- Handle partial failures in `execute()` using `Database.SaveResult`
|
|
180
|
+
- Implement meaningful `finish()` — at minimum, log completion
|
|
181
|
+
|
|
182
|
+
### Queueable Classes
|
|
183
|
+
- Read and follow: `assets/queueable.cls`
|
|
184
|
+
- Implement `Queueable` and optionally `Database.AllowsCallouts`
|
|
185
|
+
- Accept data through the constructor — queueables are stateful
|
|
186
|
+
- For chaining, include guard logic to prevent infinite chains
|
|
187
|
+
- Optionally implement `Finalizer` for error recovery
|
|
188
|
+
|
|
189
|
+
### Schedulable Classes
|
|
190
|
+
- Read and follow: `assets/schedulable.cls`
|
|
191
|
+
- Implement `Schedulable`
|
|
192
|
+
- Keep `execute()` lightweight — delegate to a Batch or Queueable
|
|
193
|
+
- Include a static method that returns a CRON expression for convenience
|
|
194
|
+
- Document the expected schedule in ApexDoc
|
|
195
|
+
|
|
196
|
+
### DTO / Wrapper Classes
|
|
197
|
+
- Read and follow: `assets/dto.cls`
|
|
198
|
+
- Use `public` properties — no getters/setters unless validation is needed
|
|
199
|
+
- Include a no-arg constructor and optionally a parameterized constructor
|
|
200
|
+
- Implement `Comparable` if sorting is needed
|
|
201
|
+
- Keep them serialization-friendly (no transient state unless intentional)
|
|
202
|
+
|
|
203
|
+
### Utility Classes
|
|
204
|
+
- Read and follow: `assets/utility.cls`
|
|
205
|
+
- All methods `public static`
|
|
206
|
+
- Class should be `public with sharing` with a `private` constructor to prevent instantiation
|
|
207
|
+
- Group related utilities (e.g., `StringUtil`, `DateUtil`, `CollectionUtil`)
|
|
208
|
+
- Every method must be side-effect-free (no DML, no SOQL)
|
|
209
|
+
|
|
210
|
+
### Interfaces
|
|
211
|
+
- Read and follow: `assets/interface.cls`
|
|
212
|
+
- Define the contract clearly with ApexDoc on every method signature
|
|
213
|
+
- Use meaningful names that describe the capability: `INotificationService`, `IRetryable`
|
|
214
|
+
|
|
215
|
+
### Abstract Classes
|
|
216
|
+
- Read and follow: `assets/abstract.cls`
|
|
217
|
+
- Provide default implementations for common behavior
|
|
218
|
+
- Mark extension points as `protected virtual` or `protected abstract`
|
|
219
|
+
- Include a concrete example in the ApexDoc showing how to extend
|
|
220
|
+
|
|
221
|
+
### Custom Exceptions
|
|
222
|
+
- Read and follow: `assets/exception.cls`
|
|
223
|
+
- Extend `Exception`
|
|
224
|
+
- Keep them simple — Apex exceptions don't support custom constructors well
|
|
225
|
+
- Name them descriptively: `AccountServiceException`, `IntegrationTimeoutException`
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Generation Workflow
|
|
230
|
+
|
|
231
|
+
1. Determine the class type from the user's request
|
|
232
|
+
2. Read the corresponding template from `assets/`
|
|
233
|
+
3. Read relevant examples from `references/` if the class type has one
|
|
234
|
+
4. Apply the user's requirements to the template pattern
|
|
235
|
+
5. Generate the `.cls` file with full ApexDoc
|
|
236
|
+
6. Generate the `.cls-meta.xml` file
|
|
237
|
+
7. Present both files to the user
|
|
238
|
+
8. Include a brief note on design decisions if any non-obvious choices were made
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Anti-Patterns to Avoid
|
|
243
|
+
|
|
244
|
+
- ❌ SOQL or DML inside loops
|
|
245
|
+
- ❌ Hardcoded IDs or record type names (use `Schema.SObjectType` or Custom Metadata)
|
|
246
|
+
- ❌ God classes that mix query + logic + DML
|
|
247
|
+
- ❌ `public` fields on service classes
|
|
248
|
+
- ❌ Returning `null` from methods that should return collections
|
|
249
|
+
- ❌ Generic `catch (Exception e)` without re-throwing or meaningful handling
|
|
250
|
+
- ❌ Business logic in Batch `start()` methods
|
|
251
|
+
- ❌ Tight coupling between classes — use interfaces for extensibility
|
|
252
|
+
- ❌ Magic strings or numbers
|
|
253
|
+
- ❌ Methods longer than ~40 lines — break them into private helpers
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Abstract base class for {describe the family of classes this serves}.
|
|
3
|
+
* Provides common behavior and defines extension points for subclasses.
|
|
4
|
+
* Subclasses must implement the abstract methods to provide specific behavior.
|
|
5
|
+
* @author Generated by Apex Class Writer Skill
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Extending this abstract class:
|
|
9
|
+
* public class SalesforceIntegrationService extends {ClassName} {
|
|
10
|
+
* protected override String getEndpoint() {
|
|
11
|
+
* return 'callout:Salesforce_API/services/data/v62.0';
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* protected override Map<String, String> getHeaders() {
|
|
15
|
+
* return new Map<String, String>{
|
|
16
|
+
* 'Content-Type' => 'application/json'
|
|
17
|
+
* };
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*/
|
|
21
|
+
public abstract with sharing class {ClassName} {
|
|
22
|
+
|
|
23
|
+
// ─── Constants ───────────────────────────────────────────────────────
|
|
24
|
+
private static final Integer DEFAULT_TIMEOUT_MS = 30000;
|
|
25
|
+
|
|
26
|
+
// ─── Protected State ─────────────────────────────────────────────────
|
|
27
|
+
protected Integer timeoutMs;
|
|
28
|
+
|
|
29
|
+
// ─── Constructor ─────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @description Initializes the base class with default configuration
|
|
33
|
+
*/
|
|
34
|
+
protected {ClassName}() {
|
|
35
|
+
this.timeoutMs = DEFAULT_TIMEOUT_MS;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─── Abstract Methods (must be implemented by subclasses) ────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @description Returns the endpoint URL for this integration.
|
|
42
|
+
* Subclasses must provide their specific endpoint.
|
|
43
|
+
* @return The endpoint URL as a String
|
|
44
|
+
*/
|
|
45
|
+
protected abstract String getEndpoint();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @description Returns the HTTP headers for this integration.
|
|
49
|
+
* Subclasses define their own required headers.
|
|
50
|
+
* @return Map of header name to header value
|
|
51
|
+
*/
|
|
52
|
+
protected abstract Map<String, String> getHeaders();
|
|
53
|
+
|
|
54
|
+
// ─── Virtual Methods (can be overridden by subclasses) ───────────────
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @description Hook called before the main operation executes.
|
|
58
|
+
* Override to add pre-processing logic.
|
|
59
|
+
* Default implementation does nothing.
|
|
60
|
+
* @param context Map of contextual data
|
|
61
|
+
*/
|
|
62
|
+
protected virtual void beforeExecute(Map<String, Object> context) {
|
|
63
|
+
// Default: no-op — override in subclass if needed
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @description Hook called after the main operation completes.
|
|
68
|
+
* Override to add post-processing logic.
|
|
69
|
+
* Default implementation does nothing.
|
|
70
|
+
* @param context Map of contextual data
|
|
71
|
+
* @param result The result from the operation
|
|
72
|
+
*/
|
|
73
|
+
protected virtual void afterExecute(Map<String, Object> context, Object result) {
|
|
74
|
+
// Default: no-op — override in subclass if needed
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ─── Template Method (common workflow) ───────────────────────────────
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @description Executes the operation using the template method pattern.
|
|
81
|
+
* Calls beforeExecute → doExecute → afterExecute in sequence.
|
|
82
|
+
* @param context Map of data needed for the operation
|
|
83
|
+
* @return The result of the operation
|
|
84
|
+
*/
|
|
85
|
+
public Object execute(Map<String, Object> context) {
|
|
86
|
+
beforeExecute(context);
|
|
87
|
+
|
|
88
|
+
Object result;
|
|
89
|
+
try {
|
|
90
|
+
result = doExecute(context);
|
|
91
|
+
} catch (Exception e) {
|
|
92
|
+
handleError(e);
|
|
93
|
+
throw e;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
afterExecute(context, result);
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ─── Protected Helpers ───────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @description Core execution logic — override this for the main operation.
|
|
104
|
+
* Default implementation throws — subclass must provide implementation.
|
|
105
|
+
* @param context Map of data needed for the operation
|
|
106
|
+
* @return The result of the operation
|
|
107
|
+
*/
|
|
108
|
+
protected virtual Object doExecute(Map<String, Object> context) {
|
|
109
|
+
throw new UnsupportedOperationException(
|
|
110
|
+
'Subclass must override doExecute()'
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @description Error handler called when doExecute throws.
|
|
116
|
+
* Override to customize error handling (e.g., logging, retry).
|
|
117
|
+
* @param e The exception that was thrown
|
|
118
|
+
*/
|
|
119
|
+
protected virtual void handleError(Exception e) {
|
|
120
|
+
System.debug(LoggingLevel.ERROR,
|
|
121
|
+
this.toString() + ' error: ' + e.getMessage() + '\n' + e.getStackTraceString()
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ─── Exception ───────────────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
public class UnsupportedOperationException extends Exception {}
|
|
128
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Batch Apex class for {describe the batch operation}.
|
|
3
|
+
* Processes {SObject} records in configurable batch sizes.
|
|
4
|
+
* Implements Database.Stateful to track cumulative results across chunks.
|
|
5
|
+
* @author Generated by Apex Class Writer Skill
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Execute with default batch size
|
|
9
|
+
* Database.executeBatch(new {ClassName}());
|
|
10
|
+
*
|
|
11
|
+
* // Execute with custom batch size
|
|
12
|
+
* Database.executeBatch(new {ClassName}(), 100);
|
|
13
|
+
*/
|
|
14
|
+
public with sharing class {ClassName} implements Database.Batchable<SObject>, Database.Stateful {
|
|
15
|
+
|
|
16
|
+
// ─── Constants ───────────────────────────────────────────────────────
|
|
17
|
+
private static final Integer DEFAULT_BATCH_SIZE = 200;
|
|
18
|
+
|
|
19
|
+
// ─── Stateful Tracking ───────────────────────────────────────────────
|
|
20
|
+
private Integer totalProcessed = 0;
|
|
21
|
+
private Integer totalErrors = 0;
|
|
22
|
+
private List<String> errorMessages = new List<String>();
|
|
23
|
+
|
|
24
|
+
// ─── Constructor ─────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @description Default constructor
|
|
28
|
+
*/
|
|
29
|
+
public {ClassName}() {
|
|
30
|
+
// Default configuration
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ─── Batchable Interface ─────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @description Defines the scope of records to process.
|
|
37
|
+
* Uses Database.QueryLocator for efficient large-dataset processing.
|
|
38
|
+
* @param bc The batch context
|
|
39
|
+
* @return QueryLocator for the records to process
|
|
40
|
+
*/
|
|
41
|
+
public Database.QueryLocator start(Database.BatchableContext bc) {
|
|
42
|
+
return Database.getQueryLocator([
|
|
43
|
+
SELECT Id, Name
|
|
44
|
+
// TODO: Add fields needed for processing
|
|
45
|
+
FROM {SObject}
|
|
46
|
+
// TODO: Add WHERE clause to scope the records
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @description Processes each batch of records.
|
|
52
|
+
* Uses Database.update with allOrNone=false for partial success handling.
|
|
53
|
+
* @param bc The batch context
|
|
54
|
+
* @param scope List of {SObject} records in the current batch
|
|
55
|
+
*/
|
|
56
|
+
public void execute(Database.BatchableContext bc, List<{SObject}> scope) {
|
|
57
|
+
List<{SObject}> recordsToUpdate = new List<{SObject}>();
|
|
58
|
+
|
|
59
|
+
for ({SObject} record : scope) {
|
|
60
|
+
// TODO: Apply business logic to each record
|
|
61
|
+
recordsToUpdate.add(record);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!recordsToUpdate.isEmpty()) {
|
|
65
|
+
List<Database.SaveResult> results = Database.update(recordsToUpdate, false);
|
|
66
|
+
processResults(results);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @description Performs post-processing after all batches complete.
|
|
72
|
+
* Logs a summary of the batch execution.
|
|
73
|
+
* @param bc The batch context
|
|
74
|
+
*/
|
|
75
|
+
public void finish(Database.BatchableContext bc) {
|
|
76
|
+
String summary = String.format(
|
|
77
|
+
'{0} completed. Processed: {1}, Errors: {2}',
|
|
78
|
+
new List<Object>{
|
|
79
|
+
{ClassName}.class.getName(),
|
|
80
|
+
totalProcessed,
|
|
81
|
+
totalErrors
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
System.debug(LoggingLevel.INFO, summary);
|
|
86
|
+
|
|
87
|
+
if (!errorMessages.isEmpty()) {
|
|
88
|
+
System.debug(LoggingLevel.ERROR, 'Error details: ' + String.join(errorMessages, '\n'));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// TODO: Send completion notification email or post to chatter if needed
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ─── Private Helpers ─────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @description Processes Database.SaveResult list, tracking successes and failures
|
|
98
|
+
* @param results List of SaveResult from a DML operation
|
|
99
|
+
*/
|
|
100
|
+
private void processResults(List<Database.SaveResult> results) {
|
|
101
|
+
for (Database.SaveResult result : results) {
|
|
102
|
+
if (result.isSuccess()) {
|
|
103
|
+
totalProcessed++;
|
|
104
|
+
} else {
|
|
105
|
+
totalErrors++;
|
|
106
|
+
for (Database.Error err : result.getErrors()) {
|
|
107
|
+
errorMessages.add(
|
|
108
|
+
'Record ' + result.getId() + ': ' +
|
|
109
|
+
err.getStatusCode() + ' - ' + err.getMessage()
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─── Static Helpers ──────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @description Convenience method to execute with default batch size
|
|
120
|
+
* @return The batch job Id
|
|
121
|
+
*/
|
|
122
|
+
public static Id run() {
|
|
123
|
+
return Database.executeBatch(new {ClassName}(), DEFAULT_BATCH_SIZE);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Domain class for {SObject}.
|
|
3
|
+
* Encapsulates field-level defaults, derivations, and validations.
|
|
4
|
+
* Operates only on in-memory SObject data — no SOQL or DML.
|
|
5
|
+
* @author Generated by Apex Class Writer Skill
|
|
6
|
+
*/
|
|
7
|
+
public with sharing class {SObject}Domain {
|
|
8
|
+
|
|
9
|
+
// ─── Constants ───────────────────────────────────────────────────────
|
|
10
|
+
// TODO: Add constants for default values, statuses, etc.
|
|
11
|
+
|
|
12
|
+
// ─── Field Defaults ──────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @description Applies default field values to new {SObject} records.
|
|
16
|
+
* Call this before insert to ensure consistent defaults.
|
|
17
|
+
* @param records List of {SObject} records to apply defaults to
|
|
18
|
+
*/
|
|
19
|
+
public static void applyDefaults(List<{SObject}> records) {
|
|
20
|
+
if (records == null || records.isEmpty()) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
for ({SObject} record : records) {
|
|
25
|
+
// TODO: Set default field values
|
|
26
|
+
// Example:
|
|
27
|
+
// if (record.Status__c == null) {
|
|
28
|
+
// record.Status__c = DEFAULT_STATUS;
|
|
29
|
+
// }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ─── Derivations ────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @description Derives calculated field values based on other fields.
|
|
37
|
+
* Call this before insert and before update.
|
|
38
|
+
* @param records List of {SObject} records to derive values for
|
|
39
|
+
*/
|
|
40
|
+
public static void deriveFields(List<{SObject}> records) {
|
|
41
|
+
if (records == null || records.isEmpty()) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for ({SObject} record : records) {
|
|
46
|
+
// TODO: Derive calculated field values
|
|
47
|
+
// Example:
|
|
48
|
+
// record.FullAddress__c = buildFullAddress(record);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ─── Validations ────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @description Validates {SObject} records and adds errors for any violations.
|
|
56
|
+
* Call this before insert and before update.
|
|
57
|
+
* @param records List of {SObject} records to validate
|
|
58
|
+
*/
|
|
59
|
+
public static void validate(List<{SObject}> records) {
|
|
60
|
+
if (records == null || records.isEmpty()) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for ({SObject} record : records) {
|
|
65
|
+
// TODO: Add validation rules
|
|
66
|
+
// Example:
|
|
67
|
+
// if (String.isBlank(record.Name)) {
|
|
68
|
+
// record.addError('Name is required.');
|
|
69
|
+
// }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ─── Comparisons ────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @description Determines which fields have changed between old and new record versions.
|
|
77
|
+
* Useful in before update context.
|
|
78
|
+
* @param oldRecord The previous version of the record
|
|
79
|
+
* @param newRecord The current version of the record
|
|
80
|
+
* @return Set of field API names that have changed
|
|
81
|
+
*/
|
|
82
|
+
public static Set<String> getChangedFields({SObject} oldRecord, {SObject} newRecord) {
|
|
83
|
+
Set<String> changedFields = new Set<String>();
|
|
84
|
+
|
|
85
|
+
if (oldRecord == null || newRecord == null) {
|
|
86
|
+
return changedFields;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
Map<String, Schema.SObjectField> fieldMap = Schema.SObjectType.{SObject}.fields.getMap();
|
|
90
|
+
for (String fieldName : fieldMap.keySet()) {
|
|
91
|
+
if (oldRecord.get(fieldName) != newRecord.get(fieldName)) {
|
|
92
|
+
changedFields.add(fieldName);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return changedFields;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─── Private Helpers ─────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
// TODO: Add private helper methods as needed
|
|
102
|
+
}
|