mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-07-30 03:09:50 +08:00
220 lines
8.4 KiB
OpenEdge ABL
220 lines
8.4 KiB
OpenEdge ABL
/**
|
|
* ${OBJECT_NAME}Selector - Centralized SOQL queries for ${OBJECT_NAME}
|
|
*
|
|
* This selector class follows the Selector Layer pattern to:
|
|
* - Centralize all ${OBJECT_NAME} queries in one place
|
|
* - Enforce Field-Level Security (FLS) by default
|
|
* - Support query mocking in unit tests
|
|
* - Provide consistent field selection across the codebase
|
|
*
|
|
* @see https://blog.beyondthecloud.dev/blog/why-do-you-need-selector-layer
|
|
* @see https://www.jamessimone.net/blog/joys-of-apex/repository-pattern/
|
|
*/
|
|
public inherited sharing class ${OBJECT_NAME}Selector {
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// FIELD DEFINITIONS
|
|
// Centralize field lists to make updates easy
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
/**
|
|
* Standard fields queried in most operations
|
|
*/
|
|
private static final List<SObjectField> STANDARD_FIELDS = new List<SObjectField>{
|
|
${OBJECT_NAME}.Id,
|
|
${OBJECT_NAME}.Name,
|
|
${OBJECT_NAME}.OwnerId,
|
|
${OBJECT_NAME}.CreatedDate,
|
|
${OBJECT_NAME}.LastModifiedDate
|
|
// Add commonly needed fields here
|
|
};
|
|
|
|
/**
|
|
* Extended fields for detail views
|
|
*/
|
|
private static final List<SObjectField> DETAIL_FIELDS = new List<SObjectField>{
|
|
${OBJECT_NAME}.Id,
|
|
${OBJECT_NAME}.Name,
|
|
${OBJECT_NAME}.OwnerId,
|
|
${OBJECT_NAME}.CreatedDate,
|
|
${OBJECT_NAME}.LastModifiedDate
|
|
// Add detail-specific fields here
|
|
};
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// MOCKING SUPPORT (for unit tests)
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
@TestVisible
|
|
private static List<${OBJECT_NAME}> mockResults;
|
|
|
|
@TestVisible
|
|
private static void setMockResults(List<${OBJECT_NAME}> records) {
|
|
mockResults = records;
|
|
}
|
|
|
|
@TestVisible
|
|
private static void clearMockResults() {
|
|
mockResults = null;
|
|
}
|
|
|
|
private static Boolean useMock() {
|
|
return Test.isRunningTest() && mockResults != null;
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// QUERY METHODS
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
/**
|
|
* Query records by their IDs
|
|
*
|
|
* @param recordIds Set of record IDs to query
|
|
* @return List of matching records with standard fields
|
|
*/
|
|
public static List<${OBJECT_NAME}> byIds(Set<Id> recordIds) {
|
|
if (recordIds == null || recordIds.isEmpty()) {
|
|
return new List<${OBJECT_NAME}>();
|
|
}
|
|
if (useMock()) {
|
|
return mockResults;
|
|
}
|
|
return [
|
|
SELECT Id, Name, OwnerId, CreatedDate, LastModifiedDate
|
|
FROM ${OBJECT_NAME}
|
|
WHERE Id IN :recordIds
|
|
WITH SECURITY_ENFORCED
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Query records by their IDs, returning a Map for O(1) lookups
|
|
*
|
|
* @param recordIds Set of record IDs to query
|
|
* @return Map of Id to record
|
|
*/
|
|
public static Map<Id, ${OBJECT_NAME}> byIdsAsMap(Set<Id> recordIds) {
|
|
return new Map<Id, ${OBJECT_NAME}>(byIds(recordIds));
|
|
}
|
|
|
|
/**
|
|
* Query records by Owner
|
|
*
|
|
* @param ownerId The owner's User Id
|
|
* @return List of records owned by the specified user
|
|
*/
|
|
public static List<${OBJECT_NAME}> byOwnerId(Id ownerId) {
|
|
if (ownerId == null) {
|
|
return new List<${OBJECT_NAME}>();
|
|
}
|
|
if (useMock()) {
|
|
return mockResults;
|
|
}
|
|
return [
|
|
SELECT Id, Name, OwnerId, CreatedDate, LastModifiedDate
|
|
FROM ${OBJECT_NAME}
|
|
WHERE OwnerId = :ownerId
|
|
WITH SECURITY_ENFORCED
|
|
ORDER BY LastModifiedDate DESC
|
|
LIMIT 1000
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Query records created within a date range
|
|
*
|
|
* @param startDate Start of date range (inclusive)
|
|
* @param endDate End of date range (inclusive)
|
|
* @return List of records created within the range
|
|
*/
|
|
public static List<${OBJECT_NAME}> byCreatedDateRange(Date startDate, Date endDate) {
|
|
if (startDate == null || endDate == null) {
|
|
return new List<${OBJECT_NAME}>();
|
|
}
|
|
if (useMock()) {
|
|
return mockResults;
|
|
}
|
|
return [
|
|
SELECT Id, Name, OwnerId, CreatedDate, LastModifiedDate
|
|
FROM ${OBJECT_NAME}
|
|
WHERE CreatedDate >= :startDate
|
|
AND CreatedDate <= :endDate
|
|
WITH SECURITY_ENFORCED
|
|
ORDER BY CreatedDate DESC
|
|
LIMIT 10000
|
|
];
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// RELATIONSHIP QUERIES
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
/**
|
|
* Query records with related child records
|
|
* Customize the subquery for your object relationships
|
|
*
|
|
* @param recordIds Set of parent record IDs
|
|
* @return List of parent records with child records populated
|
|
*/
|
|
public static List<${OBJECT_NAME}> withChildRecordsByIds(Set<Id> recordIds) {
|
|
if (recordIds == null || recordIds.isEmpty()) {
|
|
return new List<${OBJECT_NAME}>();
|
|
}
|
|
if (useMock()) {
|
|
return mockResults;
|
|
}
|
|
return [
|
|
SELECT Id, Name, OwnerId,
|
|
(SELECT Id, Name
|
|
FROM ChildRelationshipName__r // Replace with actual relationship
|
|
WHERE IsActive__c = true
|
|
LIMIT 50)
|
|
FROM ${OBJECT_NAME}
|
|
WHERE Id IN :recordIds
|
|
WITH SECURITY_ENFORCED
|
|
];
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// AGGREGATE QUERIES
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
/**
|
|
* Count records by a grouping field
|
|
*
|
|
* @return List of AggregateResult with grouping and count
|
|
*/
|
|
public static List<AggregateResult> countByOwner() {
|
|
return [
|
|
SELECT OwnerId, COUNT(Id) recordCount
|
|
FROM ${OBJECT_NAME}
|
|
GROUP BY OwnerId
|
|
HAVING COUNT(Id) > 0
|
|
];
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
// EXISTENCE CHECK
|
|
// ═══════════════════════════════════════════════════════════════════
|
|
|
|
/**
|
|
* Check if a record exists by ID (efficient single record lookup)
|
|
*
|
|
* @param recordId The record ID to check
|
|
* @return true if the record exists
|
|
*/
|
|
public static Boolean existsById(Id recordId) {
|
|
if (recordId == null) {
|
|
return false;
|
|
}
|
|
List<${OBJECT_NAME}> results = [
|
|
SELECT Id
|
|
FROM ${OBJECT_NAME}
|
|
WHERE Id = :recordId
|
|
WITH SECURITY_ENFORCED
|
|
LIMIT 1
|
|
];
|
|
return !results.isEmpty();
|
|
}
|
|
}
|