afv-library/skills/platform-data-manage/assets/soql/polymorphic.soql

199 lines
11 KiB
Plaintext

-- ═══════════════════════════════════════════════════════════════════════════════
-- POLYMORPHIC RELATIONSHIP QUERIES (TYPEOF Pattern)
-- ═══════════════════════════════════════════════════════════════════════════════
--
-- Polymorphic lookups can point to multiple object types.
-- Use TYPEOF to access object-specific fields based on the actual type.
--
-- COMMON POLYMORPHIC FIELDS:
-- • Who (WhoId) - Task/Event → Contact OR Lead
-- • What (WhatId) - Task/Event → Account, Opportunity, Case, etc.
-- • Owner (OwnerId) - Most objects → User OR Queue
-- • Related (RelatedToId) - Various → Multiple objects
--
-- USE WHEN:
-- • Querying Task, Event, or other objects with polymorphic lookups
-- • Need type-specific fields from the related record
-- • Building reports that span multiple related object types
--
-- ═══════════════════════════════════════════════════════════════════════════════
-- ───────────────────────────────────────────────────────────────────────────────
-- BASIC TYPEOF: Task with Who (Contact vs Lead)
-- ───────────────────────────────────────────────────────────────────────────────
SELECT Id, Subject, Status, ActivityDate,
TYPEOF Who
WHEN Contact THEN FirstName, LastName, Email, Account.Name
WHEN Lead THEN FirstName, LastName, Email, Company
END
FROM Task
WHERE Status != 'Completed'
AND ActivityDate >= TODAY
-- ───────────────────────────────────────────────────────────────────────────────
-- TYPEOF with What (Account, Opportunity, Case)
-- ───────────────────────────────────────────────────────────────────────────────
SELECT Id, Subject, Status, Priority,
TYPEOF What
WHEN Account THEN Name, Industry, AnnualRevenue, Type
WHEN Opportunity THEN Name, StageName, Amount, CloseDate
WHEN Case THEN CaseNumber, Subject, Status, Priority
END
FROM Task
WHERE CreatedDate = THIS_WEEK
ORDER BY ActivityDate ASC
-- ───────────────────────────────────────────────────────────────────────────────
-- FULL TYPEOF: Both Who and What in same query
-- ───────────────────────────────────────────────────────────────────────────────
SELECT Id, Subject, Status, ActivityDate, Priority,
Owner.Name,
TYPEOF Who
WHEN Contact THEN
FirstName, LastName, Email, Phone,
Account.Name, Account.Industry
WHEN Lead THEN
FirstName, LastName, Email, Company, Status
END,
TYPEOF What
WHEN Account THEN Name, Industry, Type, BillingCity
WHEN Opportunity THEN Name, StageName, Amount, Probability
WHEN Case THEN CaseNumber, Subject, Status
WHEN Campaign THEN Name, Status, Type
END
FROM Task
WHERE OwnerId = :currentUserId
AND Status = 'Not Started'
ORDER BY ActivityDate ASC
LIMIT 100
-- ───────────────────────────────────────────────────────────────────────────────
-- EVENT with polymorphic relationships
-- ───────────────────────────────────────────────────────────────────────────────
SELECT Id, Subject, StartDateTime, EndDateTime, Location,
TYPEOF Who
WHEN Contact THEN FirstName, LastName, Email, Title
WHEN Lead THEN FirstName, LastName, Company
END,
TYPEOF What
WHEN Account THEN Name, Phone, Website
WHEN Opportunity THEN Name, StageName, Amount
END
FROM Event
WHERE StartDateTime >= TODAY
AND StartDateTime <= NEXT_MONTH
ORDER BY StartDateTime ASC
-- ───────────────────────────────────────────────────────────────────────────────
-- Using ELSE clause for unhandled types
-- ───────────────────────────────────────────────────────────────────────────────
SELECT Id, Subject, Status,
TYPEOF What
WHEN Account THEN Name, Industry
WHEN Opportunity THEN Name, StageName
WHEN Case THEN CaseNumber
ELSE Name
END
FROM Task
WHERE ActivityDate = TODAY
-- ───────────────────────────────────────────────────────────────────────────────
-- FeedItem with polymorphic Parent
-- ───────────────────────────────────────────────────────────────────────────────
SELECT Id, Body, CreatedDate, CreatedBy.Name,
TYPEOF Parent
WHEN Account THEN Name, Industry
WHEN Opportunity THEN Name, StageName
WHEN Case THEN CaseNumber, Subject
WHEN Contact THEN FirstName, LastName
WHEN Lead THEN FirstName, LastName, Company
WHEN User THEN Name, Title
END
FROM FeedItem
WHERE CreatedDate = THIS_WEEK
ORDER BY CreatedDate DESC
LIMIT 50
-- ───────────────────────────────────────────────────────────────────────────────
-- ContentDocumentLink with polymorphic LinkedEntity
-- ───────────────────────────────────────────────────────────────────────────────
SELECT Id, ContentDocument.Title, ContentDocument.FileType,
TYPEOF LinkedEntity
WHEN Account THEN Name, Industry
WHEN Contact THEN FirstName, LastName
WHEN Opportunity THEN Name, Amount
WHEN Case THEN CaseNumber, Subject
END
FROM ContentDocumentLink
WHERE ContentDocument.FileType = 'PDF'
ORDER BY ContentDocument.CreatedDate DESC
LIMIT 100
-- ═══════════════════════════════════════════════════════════════════════════════
-- ALTERNATIVE: Check Type.Name without TYPEOF
-- Use when you only need to identify the type, not access specific fields
-- ═══════════════════════════════════════════════════════════════════════════════
SELECT Id, Subject, Status,
Who.Type,
Who.Name,
What.Type,
What.Name
FROM Task
WHERE ActivityDate = TODAY
-- ═══════════════════════════════════════════════════════════════════════════════
-- APEX PROCESSING PATTERN
-- ═══════════════════════════════════════════════════════════════════════════════
/*
// Query with TYPEOF
List<Task> tasks = [
SELECT Id, Subject,
TYPEOF Who
WHEN Contact THEN FirstName, LastName, Email
WHEN Lead THEN FirstName, LastName, Company
END
FROM Task
WHERE ActivityDate = TODAY
];
// Process based on type
for (Task t : tasks) {
if (t.WhoId != null) {
Schema.SObjectType whoType = t.WhoId.getSObjectType();
if (whoType == Contact.SObjectType) {
Contact con = (Contact) t.getSObject('Who');
System.debug('Contact: ' + con.FirstName + ' ' + con.LastName);
}
else if (whoType == Lead.SObjectType) {
Lead lead = (Lead) t.getSObject('Who');
System.debug('Lead: ' + lead.FirstName + ' at ' + lead.Company);
}
}
}
*/
-- ═══════════════════════════════════════════════════════════════════════════════
-- APEX ALTERNATIVE: Using instanceof
-- ═══════════════════════════════════════════════════════════════════════════════
/*
for (Task t : tasks) {
SObject who = t.getSObject('Who');
if (who instanceof Contact) {
Contact con = (Contact) who;
System.debug('Contact: ' + con.Email);
} else if (who instanceof Lead) {
Lead lead = (Lead) who;
System.debug('Lead Company: ' + lead.Company);
}
}
*/
-- ═══════════════════════════════════════════════════════════════════════════════
-- SF CLI USAGE
-- ═══════════════════════════════════════════════════════════════════════════════
-- sf data query \
-- --query "SELECT Id, Subject, TYPEOF Who WHEN Contact THEN FirstName, LastName WHEN Lead THEN Company END FROM Task WHERE ActivityDate = TODAY LIMIT 10" \
-- --target-org myorg \
-- --json