├── .codeclimate.yml
├── .gitattributes
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
└── src
├── classes
├── ContextMetadata.cls
├── ContextMetadata.cls-meta.xml
├── ContextMetadata_Tests.cls
├── ContextMetadata_Tests.cls-meta.xml
├── EnvironmentMetadata.cls
├── EnvironmentMetadata.cls-meta.xml
├── EnvironmentMetadata_Tests.cls
├── EnvironmentMetadata_Tests.cls-meta.xml
├── FieldMetadata.cls
├── FieldMetadata.cls-meta.xml
├── FieldMetadata_Tests.cls
├── FieldMetadata_Tests.cls-meta.xml
├── FieldSetMetadata.cls
├── FieldSetMetadata.cls-meta.xml
├── FieldSetMetadata_Tests.cls
├── FieldSetMetadata_Tests.cls-meta.xml
├── LimitsMetadata.cls
├── LimitsMetadata.cls-meta.xml
├── LimitsMetadata_Tests.cls
├── LimitsMetadata_Tests.cls-meta.xml
├── QueueMetadata.cls
├── QueueMetadata.cls-meta.xml
├── QueueMetadata_Tests.cls
├── QueueMetadata_Tests.cls-meta.xml
├── RecordTypeMetadata.cls
├── RecordTypeMetadata.cls-meta.xml
├── RecordTypeMetadata_Tests.cls
├── RecordTypeMetadata_Tests.cls-meta.xml
├── SobjectMetadata.cls
├── SobjectMetadata.cls-meta.xml
├── SobjectMetadata_Tests.cls
└── SobjectMetadata_Tests.cls-meta.xml
└── package.xml
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | apexmetrics:
3 | enabled: true
4 | duplication:
5 | enabled: true
6 | eslint:
7 | enabled: true
8 | checks:
9 | no-unused-expressions:
10 | enabled: false
11 | ratings:
12 | paths:
13 | - "**.cls"
14 | - "**.trigger"
15 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default line return behavior, in case people don't have core.autocrlf set.
2 | * text=auto eol=lf
3 |
4 | # Common git file types
5 | .gitattributes text
6 | .gitignore text
7 | *.md text
8 |
9 | # Salesforce-specfic file types
10 | *.app text
11 | *.cls text
12 | *.cmp text
13 | *.component text
14 | *.css text
15 | *.html text
16 | *.js text
17 | *.page text
18 | *.resource text binary
19 | *.trigger text
20 | *.xml text
21 |
22 | ## Specific Salesforce static resources that should be treated like text
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Folders to exclude
2 | .settings/
3 | config/
4 | debug/
5 | deploy/
6 |
7 | #Files to exclude
8 | *.log
9 | *.sublime-project
10 | *.sublime-workspace
11 | *.sublime-settings
12 |
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "7"
4 | install:
5 | - npm install -g jsforce-metadata-tools
6 | script:
7 | - jsforce-deploy --checkOnly -u $DEPLOYMENT_USERNAME -p $DEPLOYMENT_PASSWORD$DEPLOYMENT_TOKEN -D $TRAVIS_BUILD_DIR/src -l $DEPLOYMENT_LOGIN_URL --rollbackOnError true --testLevel $DEPLOYMENT_TEST_LEVEL --pollTimeout $POLL_TIMEOUT --pollInterval $POLL_INTERVAL--verbose
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Jonathan Gillespie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SimpleMetadata
2 | [](https://travis-ci.org/jongpie/SimpleMetadata)
3 |
4 | A lightweight library of Apex classes for Salesforce that provide easy access to metadata information
5 |
6 |
7 |
8 |
10 |
11 |
12 | ## Overview
13 | Each class has at least 2 contstructors
14 | 1. Constructor that accepts strings parameters - ideal for Lightning components/Javascript where strings are needed
15 | 2. Constructor that accepts Apex metadata classes, like Schema.SObjectType and Schema.SObjectField - ideal for Apex development where you want something safer than strings
16 |
17 | Each class returns an immutable DTO with no public methods. Each member variables follows these naming conventions:
18 | 1. Variables are named using camelCase - this is less important in Apex development since Apex is case-insensitive, but important to note for Lightning development since Javascript is case-sensitive.
19 | 2. Variables called 'apiName' refer to the API name or Developer Name, including the namespace prefix. Example: sobjectName = 'MyNameSpace__MyObject__c';
20 | 3. Variables called 'localApiName' refer to the API name or Developer Name, excluding the namespace prefix. Example: sobjectName = 'MyObject__c';
21 | 4. Variables called 'label' refer to the label displayed to the user - if translations are available, then the label is translated to the user's language. Example: new SobjectMetadata('MyObject__c').label; // Gets the localized/translated label for your custom object
22 | 5. Variables called 'displayFieldApiName' refer to the name field of an SObject - typically, the field is actually called Name, but there are exceptions, like Case.CaseNumber, Task.Subject, Order.OrderNumber, etc.
23 |
24 | ## EnvironmentMetadata.cls
25 | * Contains metadata information for the current environment. No parameters are needed to construct it.
26 |
27 | ```
28 | new EnvironmentMetadata()
29 | ```
30 |
31 | See Sample JSON
32 |
33 | {
34 | "BaseUrl": "https://mydomain.my.salesforce.com",
35 | "InstanceName": "EU11",
36 | "IsChatterEnabled": true,
37 | "IsKnowledgeEnabled": false,
38 | "IsMultiCurrencyEnabled": false,
39 | "IsPersonAccountEnabled": false,
40 | "IsProduction": true,
41 | "IsSandbox": false,
42 | "IsTerritoryManagementEnabled": false,
43 | "Name": "Jonathan Gillespie's Org",
44 | "OrganizationId": "00D0Y0000019999999",
45 | "OrganizationType": "Developer Edition",
46 | "QueueApiNames": [
47 | "My_Queue"
48 | ]
49 | "SobjectApiNames": [
50 | "AcceptedEventRelation",
51 | "Account",
52 | "AccountCleanInfo",
53 | "AccountContactRole",
54 | "AccountFeed",
55 | "AccountHistory",
56 | "AccountPartner",
57 | "AccountShare",
58 | "ActionLinkGroupTemplate",
59 | "ActionLinkTemplate",
60 | "ActivityExtension",
61 | "ActivityHistory",
62 | "ActivityRecurrence",
63 | "ActivityRecurrenceException",
64 | "AdditionalNumber",
65 | "AggregateResult",
66 | "Announcement",
67 | "ApexClass",
68 | "ApexComponent",
69 | "ApexEmailNotification",
70 | "ApexLog",
71 | "ApexPage",
72 | "ApexPageInfo",
73 | "ApexTestQueueItem",
74 | "ApexTestResult",
75 | "ApexTestResultLimits",
76 | "ApexTestRunResult",
77 | "ApexTestSuite",
78 | "ApexTrigger",
79 | "AppMenuItem",
80 | "Asset",
81 | "AssetFeed",
82 | "AssetHistory",
83 | "AssetRelationship",
84 | "AssetRelationshipFeed",
85 | "AssetRelationshipHistory",
86 | "AssetShare",
87 | "AssetTokenEvent",
88 | "AssignmentRule",
89 | "AsyncApexJob",
90 | "AttachedContentDocument",
91 | "Attachment",
92 | "AuraDefinition",
93 | "AuraDefinitionBundle",
94 | "AuraDefinitionBundleInfo",
95 | "AuraDefinitionInfo",
96 | "AuthConfig",
97 | "AuthConfigProviders",
98 | "AuthProvider",
99 | "AuthSession",
100 | "BackgroundOperation",
101 | "BrandTemplate",
102 | "BusinessHours",
103 | "BusinessProcess",
104 | "CallCenter",
105 | "Campaign",
106 | "CampaignFeed",
107 | "CampaignHistory",
108 | "CampaignMember",
109 | "CampaignMemberStatus",
110 | "CampaignShare",
111 | "Case",
112 | "CaseComment",
113 | "CaseContactRole",
114 | "CaseFeed",
115 | "CaseHistory",
116 | "CaseShare",
117 | "CaseSolution",
118 | "CaseStatus",
119 | "CaseTeamMember",
120 | "CaseTeamRole",
121 | "CaseTeamTemplate",
122 | "CaseTeamTemplateMember",
123 | "CaseTeamTemplateRecord",
124 | "CategoryData",
125 | "CategoryNode",
126 | "CategoryNodeLocalization",
127 | "ChatterActivity",
128 | "ChatterConversation",
129 | "ChatterConversationMember",
130 | "ChatterExtension",
131 | "ChatterExtensionConfig",
132 | "ChatterExtensionLocalization",
133 | "ChatterMessage",
134 | "ClientBrowser",
135 | "CollaborationGroup",
136 | "CollaborationGroupFeed",
137 | "CollaborationGroupMember",
138 | "CollaborationGroupMemberRequest",
139 | "CollaborationGroupRecord",
140 | "CollaborationInvitation",
141 | "CombinedAttachment",
142 | "Community",
143 | "ConnectedApplication",
144 | "Contact",
145 | "ContactCleanInfo",
146 | "ContactFeed",
147 | "ContactHistory",
148 | "ContactShare",
149 | "ContentAsset",
150 | "ContentBody",
151 | "ContentDistribution",
152 | "ContentDistributionView",
153 | "ContentDocument",
154 | "ContentDocumentFeed",
155 | "ContentDocumentHistory",
156 | "ContentDocumentLink",
157 | "ContentFolder",
158 | "ContentFolderItem",
159 | "ContentFolderLink",
160 | "ContentFolderMember",
161 | "ContentVersion",
162 | "ContentVersionHistory",
163 | "ContentWorkspace",
164 | "ContentWorkspaceDoc",
165 | "ContentWorkspaceMember",
166 | "ContentWorkspacePermission",
167 | "ContractContactRole",
168 | "Contract",
169 | "ContractFeed",
170 | "ContractHistory",
171 | "ContractStatus",
172 | "CorsWhitelistEntry",
173 | "CronJobDetail",
174 | "CronTrigger",
175 | "CspTrustedSite",
176 | "CustomBrand",
177 | "CustomBrandAsset",
178 | "CustomObjectUserLicenseMetrics",
179 | "CustomPermission",
180 | "CustomPermissionDependency",
181 | "DandBCompany",
182 | "Dashboard",
183 | "DashboardComponent",
184 | "DashboardComponentFeed",
185 | "DashboardFeed",
186 | "DataAssessmentFieldMetric",
187 | "DataAssessmentMetric",
188 | "DataAssessmentValueMetric",
189 | "DatacloudAddress",
190 | "DatacloudCompany",
191 | "DatacloudContact",
192 | "DatacloudDandBCompany",
193 | "DatacloudOwnedEntity",
194 | "DatacloudPurchaseUsage",
195 | "DataStatistics",
196 | "DataType",
197 | "DeclinedEventRelation",
198 | "DirectMessage",
199 | "DirectMessageFeed",
200 | "DirectMessageMember",
201 | "Document",
202 | "DocumentAttachmentMap",
203 | "Domain",
204 | "DomainSite",
205 | "DuplicateRecordItem",
206 | "DuplicateRecordSet",
207 | "DuplicateRule",
208 | "EmailCapture",
209 | "EmailDomainKey",
210 | "EmailMessage",
211 | "EmailMessageRelation",
212 | "EmailServicesAddress",
213 | "EmailServicesFunction",
214 | "EmailStatus",
215 | "EmailTemplate",
216 | "EmbeddedServiceDetail",
217 | "EntityDefinition",
218 | "EntityParticle",
219 | "EntitySubscription",
220 | "Event",
221 | "EventBusSubscriber",
222 | "EventFeed",
223 | "EventLogFile",
224 | "EventRelation",
225 | "ExternalDataSource",
226 | "ExternalDataUserAuth",
227 | "FeedAttachment",
228 | "FeedComment",
229 | "FeedItem",
230 | "FeedLike",
231 | "FeedPollChoice",
232 | "FeedPollVote",
233 | "FeedRevision",
234 | "FeedSignal",
235 | "FeedTrackedChange",
236 | "FieldDefinition",
237 | "FieldPermissions",
238 | "FileSearchActivity",
239 | "FiscalYearSettings",
240 | "FlexQueueItem",
241 | "FlowInterview",
242 | "FlowInterviewShare",
243 | "Folder",
244 | "FolderedContentDocument",
245 | "ForecastShare",
246 | "Goal",
247 | "GoalFeed",
248 | "GoalHistory",
249 | "GoalLink",
250 | "GoalShare",
251 | "GrantedByLicense",
252 | "Group",
253 | "GroupMember",
254 | "Holiday",
255 | "Idea",
256 | "IdeaComment",
257 | "IdpEventLog",
258 | "InstalledMobileApp",
259 | "KnowledgeableUser",
260 | "Lead",
261 | "LeadCleanInfo",
262 | "LeadFeed",
263 | "LeadHistory",
264 | "LeadShare",
265 | "LeadStatus",
266 | "ListEmail",
267 | "ListEmailRecipientSource",
268 | "ListEmailShare",
269 | "ListView",
270 | "ListViewChart",
271 | "ListViewChartInstance",
272 | "LoginGeo",
273 | "LoginHistory",
274 | "LoginIp",
275 | "LookedUpFromActivity",
276 | "Macro",
277 | "MacroHistory",
278 | "MacroInstruction",
279 | "MacroShare",
280 | "MailmergeTemplate",
281 | "MatchingRule",
282 | "MatchingRuleItem",
283 | "Metric",
284 | "MetricDataLink",
285 | "MetricDataLinkHistory",
286 | "MetricFeed",
287 | "MetricHistory",
288 | "MetricShare",
289 | "Name",
290 | "NamedCredential",
291 | "Note",
292 | "NoteAndAttachment",
293 | "OauthToken",
294 | "ObjectPermissions",
295 | "OpenActivity",
296 | "Opportunity",
297 | "OpportunityCompetitor",
298 | "OpportunityContactRole",
299 | "OpportunityFeed",
300 | "OpportunityFieldHistory",
301 | "OpportunityHistory",
302 | "OpportunityLineItem",
303 | "OpportunityPartner",
304 | "OpportunityShare",
305 | "OpportunityStage",
306 | "Order",
307 | "OrderFeed",
308 | "OrderHistory",
309 | "OrderItem",
310 | "OrderItemFeed",
311 | "OrderItemHistory",
312 | "OrderShare",
313 | "Organization",
314 | "OrgLifecycleNotification",
315 | "OrgWideEmailAddress",
316 | "OutgoingEmail",
317 | "OutgoingEmailRelation",
318 | "OwnedContentDocument",
319 | "OwnerChangeOptionInfo",
320 | "PackageLicense",
321 | "Partner",
322 | "PartnerRole",
323 | "Period",
324 | "PermissionSet",
325 | "PermissionSetAssignment",
326 | "PermissionSetLicense",
327 | "PermissionSetLicenseAssign",
328 | "PicklistValueInfo",
329 | "PlatformAction",
330 | "PlatformCachePartition",
331 | "PlatformCachePartitionType",
332 | "Pricebook2",
333 | "Pricebook2History",
334 | "PricebookEntry",
335 | "ProcessDefinition",
336 | "ProcessInstance",
337 | "ProcessInstanceHistory",
338 | "ProcessInstanceNode",
339 | "ProcessInstanceStep",
340 | "ProcessInstanceWorkitem",
341 | "ProcessNode",
342 | "Product2",
343 | "Product2Feed",
344 | "Product2History",
345 | "Profile",
346 | "Publisher",
347 | "PushTopic",
348 | "QueueSobject",
349 | "QuoteTemplateRichTextData",
350 | "RecentlyViewed",
351 | "RecordType",
352 | "RecordTypeLocalization",
353 | "RelationshipDomain",
354 | "RelationshipInfo",
355 | "Report",
356 | "ReportFeed",
357 | "SamlSsoConfig",
358 | "Scontrol",
359 | "ScontrolLocalization",
360 | "SearchActivity",
361 | "SearchLayout",
362 | "SearchPromotionRule",
363 | "SecureAgent",
364 | "SecureAgentPlugin",
365 | "SecureAgentPluginProperty",
366 | "SecureAgentsCluster",
367 | "SecurityCustomBaseline",
368 | "SessionPermSetActivation",
369 | "SetupAuditTrail",
370 | "SetupEntityAccess",
371 | "Site",
372 | "SiteFeed",
373 | "SiteHistory",
374 | "Solution",
375 | "SolutionFeed",
376 | "SolutionHistory",
377 | "SolutionStatus",
378 | "Stamp",
379 | "StampAssignment",
380 | "StampLocalization",
381 | "StaticResource",
382 | "StreamingChannel",
383 | "StreamingChannelShare",
384 | "Task",
385 | "TaskFeed",
386 | "TaskPriority",
387 | "TaskStatus",
388 | "TenantSecret",
389 | "TenantUsageEntitlement",
390 | "TestSuiteMembership",
391 | "ThirdPartyAccountLink",
392 | "TodayGoal",
393 | "TodayGoalShare",
394 | "Topic",
395 | "TopicAssignment",
396 | "TopicFeed",
397 | "TopicLocalization",
398 | "TwoFactorInfo",
399 | "TwoFactorMethodsInfo",
400 | "TwoFactorTempCode",
401 | "UndecidedEventRelation",
402 | "User",
403 | "UserAppInfo",
404 | "UserAppMenuCustomization",
405 | "UserAppMenuCustomizationShare",
406 | "UserAppMenuItem",
407 | "UserEntityAccess",
408 | "UserFeed",
409 | "UserFieldAccess",
410 | "UserLicense",
411 | "UserListView",
412 | "UserListViewCriterion",
413 | "UserLogin",
414 | "UserPackageLicense",
415 | "UserPermissionAccess",
416 | "UserPreference",
417 | "UserProvAccount",
418 | "UserProvAccountStaging",
419 | "UserProvisioningConfig",
420 | "UserProvisioningLog",
421 | "UserProvisioningRequest",
422 | "UserProvisioningRequestShare",
423 | "UserProvMockTarget",
424 | "UserRecordAccess",
425 | "UserRole",
426 | "UserShare",
427 | "VerificationHistory",
428 | "VisualforceAccessMetrics",
429 | "Vote",
430 | "WaveCompatibilityCheckItem",
431 | "WebLink",
432 | "WebLinkLocalization",
433 | "WorkCoaching",
434 | "WorkCoachingFeed",
435 | "WorkCoachingHistory",
436 | "WorkCoachingShare",
437 | "WorkFeedback",
438 | "WorkFeedbackHistory",
439 | "WorkFeedbackQuestion",
440 | "WorkFeedbackQuestionHistory",
441 | "WorkFeedbackQuestionSet",
442 | "WorkFeedbackQuestionSetHistory",
443 | "WorkFeedbackQuestionSetShare",
444 | "WorkFeedbackQuestionShare",
445 | "WorkFeedbackRequest",
446 | "WorkFeedbackRequestFeed",
447 | "WorkFeedbackRequestHistory",
448 | "WorkFeedbackRequestShare",
449 | "WorkFeedbackShare",
450 | "WorkFeedbackTemplate",
451 | "WorkFeedbackTemplateShare",
452 | "WorkPerformanceCycle",
453 | "WorkPerformanceCycleFeed",
454 | "WorkPerformanceCycleHistory",
455 | "WorkPerformanceCycleShare"
456 | ]
457 | }
458 |
459 |
460 |
461 | ## SobjectMetadata.cls
462 | * Contains metadata information for the specified SObject. There are 2 ways to create an instance of SobjectMetadata
463 |
464 | 1. By passing the SObject's API name as a string in the constructor
465 | ```
466 | new SobjectMetadata('Account')
467 | ```
468 |
469 | 2. By passing the SObject Type in the constructor
470 | ```
471 | new SobjectMetadata(Schema.Account.SObjectType)
472 | ```
473 |
474 | ### Sample Usage
475 | Scenario: if the user has access to delete an SObject, then delete it
476 |
477 | ```
478 | public class MyClass {
479 |
480 | public void deleteRecord(MyCustomObject__c myRecord) {
481 | // If the user does not have access to delete, then stop
482 | if(new SobjectMetadata('MyCustomObject__c').isDeletable == false) return;
483 |
484 | //Otherwise, delete the record
485 | delete myRecord.MyCustomField__c;
486 | }
487 |
488 | }
489 | ```
490 |
491 | ## FieldMetadata.cls
492 | * Contains metadata information for the specified field. There are 2 ways to create an instance of FieldMetadata
493 |
494 | 1. By passing the SObject's API name and the field's API name as strings in the constructor
495 | ```
496 | new FieldMetadata('Account', 'Type')
497 | ```
498 |
499 | 2. By passing the SObject Type and the SObject Field in the constructor
500 | ```
501 | new FieldMetadata(Schema.Account.SObjectType, Schema.Account.Type)
502 | ```
503 |
504 | ### Sample Usage
505 | Scenario: if the user has access to edit a field, set the value
506 |
507 | ```
508 | public class MyClass {
509 |
510 | public void setMyField(MyCustomObject__c myRecord) {
511 | // If the user does not have access to delete, then stop
512 | if(new FieldMetadata('MyCustomObject__c', 'MyCustomField__c').isUpdateable) {
513 |
514 | // Otherwise, set the field
515 | myRecord.MyCustomField__c = 'some value';
516 | }
517 |
518 | }
519 | ```
520 |
521 | ## FieldSetMetadata.cls
522 | * Contains metadata information for the specified field set, as well as the field set's SObject and the field metadata for each field set member. There are 2 ways to create an instance of FieldMetadata
523 |
524 | 1. By passing the SObject's API name and the field set's API name as strings in the constructor
525 | ```
526 | new FieldSetMetadata('Lead', 'MyFieldSet')
527 | ```
528 |
529 | 2. By passing the FieldSet in the constructor
530 | ```
531 | new FieldSetMetadata(SObjectType.Lead.FieldSets.MyFieldSet);
532 | ```
533 |
534 | ## RecordTypeMetadata.cls
535 | * Contains metadata information for a record type by combinging RecordTypeInfo and RecordType objects together. There are 3 ways to create an instance of RecordTypeMetadata
536 |
537 | 1. By passing the SObject's API name and the RecordType's API name (DeveloperName) in the constructor
538 | ```
539 | new RecordTypeMetadata('Account', 'My_RecordType_Developer_Name');
540 | ```
541 |
542 | 2. By passing the RecordType's ID in the constructor
543 | ```
544 | new RecordTypeMetadata(myAccountRecord.RecordTypeId);
545 | ```
546 |
547 | 3. By passing the Schema.SObjectType and the Schema.RecordTypeInfo in the constructor
548 | ```
549 | Schema.SObjectType accountSObjectType = Schema.Account.SObjectType;
550 | Schema.RecordTypeInfo someAccountRecordTypeInfo;
551 | new RecordTypeMetadata(accountSObjectType, someAccountRecordTypeInfo);
552 | ```
553 |
554 | See Sample JSON
555 |
556 | {
557 | "ApiName": "MyNamespace__My_RecordType_Developer_Name"
558 | "Id": "0120Y000000EEEEE",
559 | "IsActive": true,
560 | "IsAvailable": true,
561 | "IsDefaultRecordTypeMapping": true,
562 | "IsMaster": false,
563 | "Label": "My Record Type",
564 | "LocalName": "My_RecordType_Developer_Name"
565 | "Namespace": "MyNamespace",
566 | "SobjectApiName": "Account"
567 | }
568 |
569 |
570 |
571 | ## QueueMetadata.cls
572 | * Contains metadata information for a queue, including the queue members and the supported SObject names. There are 2 ways to create an instance of QueueMetadata
573 |
574 | 1. By passing the Queue's API name (DeveloperName) in the constructor
575 | ```
576 | new QueueMetadata('My_Queue_Developer_Name');
577 | ```
578 |
579 | 2. By passing the Queue's ID in the constructor
580 | ```
581 | Id myQueueId = '00G0Y0000000000';
582 | new QueueMetadata(myQueueId);
583 | ```
584 |
585 | See Sample JSON
586 |
587 | {
588 | "ApiName": "My_Queue",
589 | "DoesIncludeBosses": true,
590 | "DoesSendEmailToMembers": true,
591 | "Email": "fake@test.com",
592 | "Label": "My Queue",
593 | "Id": "00G0Y0000011111111",
594 | "QueueMembers": [
595 | {
596 | "QueueId": "00G0Y0000011111111",
597 | "QueueMemberId": "0110Y000000fHUyQAM",
598 | "Type": "User",
599 | "UserOrGroupId": "0050Y000001LrM3QAK"
600 | },
601 | {
602 | "QueueId": "00G0Y0000011111111",
603 | "QueueMemberId": "0110Y0000000000000",
604 | "Type": "User",
605 | "UserOrGroupId": "0050Y0000000000000"
606 | },
607 | {
608 | "QueueId": "00G0Y0000011111111",
609 | "QueueMemberId": "0110Y000001q5sUQAQ",
610 | "Type": "Group",
611 | "UserOrGroupId": "00G0Y000001inOQUAY"
612 | }
613 | ],
614 | "SobjectApiNames": [
615 | "Case",
616 | "Lead"
617 | ]
618 | }
619 |
620 |
--------------------------------------------------------------------------------
/src/classes/ContextMetadata.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | global class ContextMetadata {
6 |
7 | @AuraEnabled global final Boolean IsApexRest {get; private set;}
8 | @AuraEnabled global final Boolean IsBatch {get; private set;}
9 | @AuraEnabled global final Boolean IsExecuting {get; private set;}
10 | @AuraEnabled global final Boolean IsFuture {get; private set;}
11 | @AuraEnabled global final Boolean IsLightning {get; private set;}
12 | @AuraEnabled global final Boolean IsLightningConsole {get; private set;}
13 | @AuraEnabled global final Boolean IsQueueable {get; private set;}
14 | @AuraEnabled global final Boolean IsSalesforce1 {get; private set;}
15 | @AuraEnabled global final Boolean IsScheduled {get; private set;}
16 | @AuraEnabled global final Boolean IsVisualforce {get; private set;}
17 |
18 | global ContextMetadata() {
19 | this.IsApexRest = RestContext.request != null;
20 | this.IsBatch = System.isBatch();
21 | this.IsExecuting = Trigger.isExecuting;
22 | this.IsFuture = System.isFuture();
23 | this.IsLightning = UserInfo.getUiThemeDisplayed() == 'Theme4d';
24 | this.IsLightningConsole = UserInfo.getUiThemeDisplayed() == 'Theme4u';
25 | this.IsQueueable = System.isQueueable();
26 | this.IsSalesforce1 = UserInfo.getUiThemeDisplayed() == 'Theme4t';
27 | this.IsScheduled = System.isScheduled();
28 | this.IsVisualforce = ApexPages.currentPage() != null;
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/src/classes/ContextMetadata.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/ContextMetadata_Tests.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | @isTest
6 | private class ContextMetadata_Tests {
7 |
8 | @isTest
9 | static void it_should_return_context_metadata() {
10 | ContextMetadata contextMetadata = new ContextMetadata();
11 | validateAttributesAreSet(contextMetadata);
12 | validateCaseSentivityForJavascript(contextMetadata);
13 | }
14 |
15 | private static void validateAttributesAreSet(ContextMetadata contextMetadata) {
16 | System.assertEquals(RestContext.request != null, contextMetadata.IsApexRest);
17 | System.assertEquals(System.isBatch(), contextMetadata.IsBatch);
18 | System.assertEquals(Trigger.isExecuting, contextMetadata.IsExecuting);
19 | System.assertEquals(System.isFuture(), contextMetadata.IsFuture);
20 | System.assertEquals(UserInfo.getUiThemeDisplayed() == 'Theme4d', contextMetadata.IsLightning);
21 | System.assertEquals(UserInfo.getUiThemeDisplayed() == 'Theme4u', contextMetadata.IsLightningConsole);
22 | System.assertEquals(System.isQueueable(), contextMetadata.IsQueueable);
23 | System.assertEquals(UserInfo.getUiThemeDisplayed() == 'Theme4t', contextMetadata.IsSalesforce1);
24 | System.assertEquals(System.isScheduled(), contextMetadata.IsScheduled);
25 | System.assertEquals(ApexPages.currentPage() != null, contextMetadata.IsVisualforce);
26 | }
27 |
28 | private static void validateCaseSentivityForJavascript(ContextMetadata contextMetadata) {
29 | // Validate that the attributes are named exactly as expected so that javascript can rely on them
30 | String jsonContextMetadata = JSON.serialize(contextMetadata);
31 | Map untypedContextMetadata = (Map)JSON.deserializeUntyped(jsonContextMetadata);
32 |
33 | // One negative to confirm that the strings in our map are case sensitive
34 | System.assert(untypedContextMetadata.containsKey('ISAPEXREST') == false);
35 | // Now for the 'real' tests
36 | System.assert(untypedContextMetadata.containsKey('IsApexRest'));
37 | System.assert(untypedContextMetadata.containsKey('IsBatch'));
38 | System.assert(untypedContextMetadata.containsKey('IsExecuting'));
39 | System.assert(untypedContextMetadata.containsKey('IsFuture'));
40 | System.assert(untypedContextMetadata.containsKey('IsLightning'));
41 | System.assert(untypedContextMetadata.containsKey('IsLightningConsole'));
42 | System.assert(untypedContextMetadata.containsKey('IsQueueable'));
43 | System.assert(untypedContextMetadata.containsKey('IsSalesforce1'));
44 | System.assert(untypedContextMetadata.containsKey('IsScheduled'));
45 | System.assert(untypedContextMetadata.containsKey('IsVisualforce'));
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/src/classes/ContextMetadata_Tests.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/EnvironmentMetadata.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | global class EnvironmentMetadata {
6 |
7 | // Some info must be queried from the Organization object, so cache the results to limit query count to 1
8 | private static final Organization ORGANIZATION;
9 |
10 | static {
11 | ORGANIZATION = [SELECT Id, Name, InstanceName, NamespacePrefix, OrganizationType, IsSandbox FROM Organization LIMIT 1];
12 | }
13 |
14 | @AuraEnabled global final String BaseUrl {get; private set;}
15 | @AuraEnabled global final String InstanceName {get; private set;}
16 | @AuraEnabled global final Boolean IsChatterEnabled {get; private set;}
17 | @AuraEnabled global final Boolean IsKnowledgeEnabled {get; private set;}
18 | @AuraEnabled global final Boolean IsMultiCurrencyEnabled {get; private set;}
19 | @AuraEnabled global final Boolean IsPersonAccountEnabled {get; private set;}
20 | @AuraEnabled global final Boolean IsProduction {get; private set;}
21 | @AuraEnabled global final Boolean IsSandbox {get; private set;}
22 | @AuraEnabled global final Boolean IsTerritoryManagementEnabled {get; private set;}
23 | @AuraEnabled global final String Namespace {get; private set;}
24 | @AuraEnabled global final Id OrganizationId {get; private set;}
25 | @AuraEnabled global final String OrganizationName {get; private set;}
26 | @AuraEnabled global final String OrganizationType {get; private set;}
27 | @AuraEnabled global final List QueueApiNames {get; private set;}
28 | @AuraEnabled global final List SobjectApiNames {get; private set;}
29 |
30 | global EnvironmentMetadata() {
31 | Map sobjectTypes = Schema.getGlobalDescribe();
32 |
33 | this.BaseUrl = Url.getSalesforceBaseUrl().toExternalForm();
34 | this.InstanceName = ORGANIZATION.InstanceName;
35 | this.IsChatterEnabled = sobjectTypes.containsKey('FeedItem');
36 | this.IsKnowledgeEnabled = sobjectTypes.containsKey('KnowledgeArticle');
37 | this.IsMultiCurrencyEnabled = UserInfo.isMultiCurrencyOrganization();
38 | this.IsPersonAccountEnabled = sobjectTypes.get('Account').getDescribe().fields.getMap().containsKey('IsPersonAccount');
39 | this.IsProduction = ORGANIZATION.IsSandbox == false;
40 | this.IsSandbox = ORGANIZATION.IsSandbox;
41 | this.IsTerritoryManagementEnabled = sobjectTypes.containsKey('Territory');
42 | this.Namespace = ORGANIZATION.NamespacePrefix;
43 | this.OrganizationId = ORGANIZATION.Id;
44 | this.OrganizationName = ORGANIZATION.Name;
45 | this.OrganizationType = ORGANIZATION.OrganizationType;
46 | this.QueueApiNames = QueueMetadata.getQueueApiNames();
47 | this.SobjectApiNames = this.getSobjectApiNames(sobjectTypes);
48 | }
49 |
50 | private List getSobjectApiNames(Map sobjectTypes) {
51 | // We could just use this.sobjectApiNames = new List(sobjectTypes.keySet());
52 | // However, it returns the names in lowercase, which can cause problems with Javascript/Lightning since it's case-sensitive
53 | List sobjectApiNames = new List();
54 | for(Schema.SobjectType sobjectType : sobjectTypes.values()) {
55 | sobjectApiNames.add(String.valueOf(sobjectType));
56 | }
57 | sobjectApiNames.sort();
58 | return sobjectApiNames;
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/src/classes/EnvironmentMetadata.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/EnvironmentMetadata_Tests.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | @isTest
6 | private class EnvironmentMetadata_Tests {
7 |
8 | @isTest
9 | static void it_should_return_environment_metadata() {
10 | Test.startTest();
11 |
12 | EnvironmentMetadata environmentMetadata = new EnvironmentMetadata();
13 | validateAttributesAreSet(environmentMetadata);
14 | validateCaseSentivityForJavascript(environmentMetadata);
15 |
16 | Test.stopTest();
17 | }
18 |
19 | @isTest
20 | static void it_should_cache_organization_object_query() {
21 | Test.startTest();
22 |
23 | System.assertEquals(0, Limits.getQueries());
24 | new EnvironmentMetadata();
25 | Integer initialQueryCount = Limits.getQueries();
26 | // Only the first initialization should use queries, multiple initializations should use cached results
27 | for(Integer i = 0; i < 10; i++) {
28 | new EnvironmentMetadata();
29 | }
30 | System.assertEquals(initialQueryCount, Limits.getQueries());
31 |
32 | Test.stopTest();
33 | }
34 |
35 | private static void validateAttributesAreSet(EnvironmentMetadata environmentMetadata) {
36 | Organization organization = [SELECT Id, Name, InstanceName, NamespacePrefix, OrganizationType, IsSandbox FROM Organization LIMIT 1];
37 | Map sobjectTypes = Schema.getGlobalDescribe();
38 |
39 | System.assertEquals(URL.getSalesforceBaseUrl().toExternalForm(), environmentMetadata.BaseUrl);
40 | System.assertEquals(organization.InstanceName, environmentMetadata.InstanceName);
41 | System.assertEquals(sobjectTypes.containsKey('FeedItem'), environmentMetadata.IsChatterEnabled);
42 | System.assertEquals(sobjectTypes.containsKey('KnowledgeArticle'), environmentMetadata.IsKnowledgeEnabled);
43 | System.assertEquals(UserInfo.isMultiCurrencyOrganization(), environmentMetadata.IsMultiCurrencyEnabled);
44 | System.assertEquals(sobjectTypes.get('Account').getDescribe().fields.getMap().containsKey('IsPersonAccount'), environmentMetadata.IsPersonAccountEnabled);
45 | System.assertEquals(organization.IsSandbox == false, environmentMetadata.IsProduction);
46 | System.assertEquals(organization.IsSandbox, environmentMetadata.IsSandbox);
47 | System.assertEquals(sobjectTypes.containsKey('Territory'), environmentMetadata.IsTerritoryManagementEnabled);
48 | System.assertEquals(organization.NamespacePrefix, environmentMetadata.Namespace);
49 | System.assertEquals(organization.Id, environmentMetadata.OrganizationId);
50 | System.assertEquals(organization.Name, environmentMetadata.OrganizationName);
51 | System.assertEquals(organization.OrganizationType, environmentMetadata.OrganizationType);
52 | //System.assert(environmentMetadata.SobjectTypeNames.containsAll(sobjectTypes.keySet()));
53 | }
54 |
55 | private static void validateCaseSentivityForJavascript(EnvironmentMetadata environmentMetadata) {
56 | // Validate that the attributes are named exactly as expected so that javascript can rely on them
57 | String jsonEnvironmentMetadata = JSON.serialize(environmentMetadata);
58 | Map untypedEnvironmentMetadata = (Map)JSON.deserializeUntyped(jsonEnvironmentMetadata);
59 |
60 | // One negative to confirm that the strings in our map are case sensitive
61 | System.assert(untypedEnvironmentMetadata.containsKey('BASEURL') == false);
62 | // Now for the 'real' tests
63 | System.assert(untypedEnvironmentMetadata.containsKey('BaseUrl'));
64 | System.assert(untypedEnvironmentMetadata.containsKey('InstanceName'));
65 | System.assert(untypedEnvironmentMetadata.containsKey('IsChatterEnabled'));
66 | System.assert(untypedEnvironmentMetadata.containsKey('IsKnowledgeEnabled'));
67 | System.assert(untypedEnvironmentMetadata.containsKey('IsMultiCurrencyEnabled'));
68 | System.assert(untypedEnvironmentMetadata.containsKey('IsPersonAccountEnabled'));
69 | System.assert(untypedEnvironmentMetadata.containsKey('IsProduction'));
70 | System.assert(untypedEnvironmentMetadata.containsKey('IsSandbox'));
71 | System.assert(untypedEnvironmentMetadata.containsKey('IsTerritoryManagementEnabled'));
72 | System.assert(untypedEnvironmentMetadata.containsKey('Namespace'));
73 | System.assert(untypedEnvironmentMetadata.containsKey('OrganizationId'));
74 | System.assert(untypedEnvironmentMetadata.containsKey('OrganizationName'));
75 | System.assert(untypedEnvironmentMetadata.containsKey('OrganizationType'));
76 | System.assert(untypedEnvironmentMetadata.containsKey('SobjectApiNames'));
77 | }
78 |
79 | }
--------------------------------------------------------------------------------
/src/classes/EnvironmentMetadata_Tests.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/FieldMetadata.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | global class FieldMetadata {
6 |
7 | @AuraEnabled global final String ApiName {get; private set;}
8 | @AuraEnabled global final Integer ByteLength {get; private set;}
9 | @AuraEnabled global final Object DefaultValue {get; private set;}
10 | @AuraEnabled global final Integer Digits {get; private set;}
11 | @AuraEnabled global final String DisplayType {get; private set;}
12 | @AuraEnabled global final String InlineHelpText {get; private set;}
13 | @AuraEnabled global final Boolean IsAccessible {get; private set;}
14 | @AuraEnabled global final Boolean IsAutoNumber {get; private set;}
15 | @AuraEnabled global final Boolean IsCalculated {get; private set;}
16 | @AuraEnabled global final Boolean IsCaseSensitive {get; private set;}
17 | @AuraEnabled global final Boolean IsCreateable {get; private set;}
18 | @AuraEnabled global final Boolean IsCustom {get; private set;}
19 | @AuraEnabled global final Boolean IsDefaultedOnCreate {get; private set;}
20 | @AuraEnabled global final Boolean IsFilterable {get; private set;}
21 | @AuraEnabled global final Boolean IsGroupable {get; private set;}
22 | @AuraEnabled global final Boolean IsNameField {get; private set;}
23 | @AuraEnabled global final Boolean IsNillable {get; private set;}
24 | @AuraEnabled global final Boolean IsNamePointing {get; private set;}
25 | @AuraEnabled global final Boolean IsRequired {get; private set;}
26 | @AuraEnabled global final Boolean IsSortable {get; private set;}
27 | @AuraEnabled global final Boolean IsUpdateable {get; private set;}
28 | @AuraEnabled global final String Label {get; private set;}
29 | @AuraEnabled global final String LocalApiName {get; private set;}
30 | @AuraEnabled global final Integer MaxLength {get; private set;}
31 | @AuraEnabled global final String Namespace {get; private set;}
32 | @AuraEnabled global final List PicklistOptions {get; private set;}
33 | @AuraEnabled global final Integer Precision {get; private set;}
34 | @AuraEnabled global final String RelationshipApiName {get; private set;}
35 | @AuraEnabled global final Integer RelationshipOrder {get; private set;}
36 | @AuraEnabled global final List RelationshipReferences {get; private set;}
37 | @AuraEnabled global final Integer Scale {get; private set;}
38 | @AuraEnabled global final String SobjectApiName {get; private set;}
39 |
40 | global FieldMetadata(String sobjectApiName, String fieldApiName) {
41 | this(
42 | Schema.getGlobalDescribe().get(sobjectApiName),
43 | Schema.getGlobalDescribe().get(sobjectApiName).getDescribe().fields.getMap().get(fieldApiName)
44 | );
45 | }
46 |
47 | global FieldMetadata(Schema.SobjectType sobjectType, Schema.SobjectField sobjectField) {
48 | Schema.DescribeSobjectResult sobjectDescribe = sobjectType.getDescribe();
49 | Schema.DescribeFieldResult fieldDescribe = sobjectField.getDescribe();
50 |
51 | this.ApiName = String.valueOf(sobjectField);
52 | this.ByteLength = fieldDescribe.getByteLength();
53 | this.DefaultValue = fieldDescribe.getDefaultValue();
54 | this.Digits = fieldDescribe.getDigits();
55 | this.DisplayType = fieldDescribe.getType().name();
56 | this.InlineHelpText = fieldDescribe.getInlineHelpText();
57 | this.IsAccessible = fieldDescribe.isAccessible();
58 | this.IsAutoNumber = fieldDescribe.isAutoNumber();
59 | this.IsCalculated = fieldDescribe.isCalculated();
60 | this.IsCaseSensitive = fieldDescribe.isCaseSensitive();
61 | this.IsCreateable = fieldDescribe.isCreateable();
62 | this.IsCustom = fieldDescribe.isCustom();
63 | this.IsDefaultedOnCreate = fieldDescribe.isDefaultedOnCreate();
64 | this.IsFilterable = fieldDescribe.isFilterable();
65 | this.IsGroupable = fieldDescribe.isGroupable();
66 | this.IsNameField = fieldDescribe.isNameField();
67 | this.IsNillable = fieldDescribe.isNillable();
68 | this.IsNamePointing = fieldDescribe.isNamePointing();
69 | this.IsRequired = fieldDescribe.isNillable() == false && fieldDescribe.isCreateable(); // If a field is NOT nillable, then it's required
70 | this.IsSortable = fieldDescribe.isSortable();
71 | this.IsUpdateable = fieldDescribe.isUpdateable();
72 | this.Label = fieldDescribe.getLabel();
73 | this.LocalApiName = fieldDescribe.getLocalName();
74 | this.MaxLength = fieldDescribe.getLength();
75 | this.Namespace = this.getNamespace();
76 | this.PicklistOptions = this.getPicklistOptions(fieldDescribe);
77 | this.Precision = fieldDescribe.getPrecision();
78 | this.RelationshipApiName = fieldDescribe.getRelationshipName();
79 | this.RelationshipOrder = fieldDescribe.getRelationshipOrder();
80 | this.RelationshipReferences = this.getRelationshipReferences(fieldDescribe);
81 | this.Scale = fieldDescribe.getScale();
82 | this.SobjectApiName = String.valueOf(sobjectType);
83 | }
84 |
85 | private String getNamespace() {
86 | Integer localNameIndex = this.apiName.replace('__c', '').indexOf('__');
87 | return localNameIndex < 0 ? null : this.apiName.substring(0, localNameIndex);
88 | }
89 |
90 | private List getPicklistOptions(Schema.DescribeFieldResult fieldDescribe) {
91 | List picklistOptions = new List();
92 |
93 | if(fieldDescribe.getPickListValues().isEmpty()) return picklistOptions;
94 |
95 | picklistOptions.add(new PicklistEntryMetadata()); // Add an empty picklist value
96 | for(Schema.PicklistEntry picklistEntry : fieldDescribe.getPickListValues()) {
97 | picklistOptions.add(new PicklistEntryMetadata(picklistEntry));
98 | }
99 | return picklistOptions;
100 | }
101 |
102 | private List getRelationshipReferences(Schema.DescribeFieldResult fieldDescribe) {
103 | List relationshipReferences = new List();
104 | for(Schema.SobjectType sobjectType : fieldDescribe.getReferenceTo()) {
105 | relationshipReferences.add(new SobjectMetadata(sobjectType));
106 | }
107 | return relationshipReferences;
108 | }
109 |
110 | global class PicklistEntryMetadata {
111 |
112 | @AuraEnabled global final Boolean IsDefaultValue {get; private set;}
113 | @AuraEnabled global final String Label {get; private set;}
114 | @AuraEnabled global final String Value {get; private set;}
115 |
116 | global PicklistEntryMetadata() {
117 | this.IsDefaultValue = false;
118 | this.Label = '';
119 | this.Value = '';
120 | }
121 |
122 | global PicklistEntryMetadata(Schema.PicklistEntry picklistEntry) {
123 | this.IsDefaultValue = picklistEntry.isDefaultValue();
124 | this.Label = picklistEntry.getLabel();
125 | this.Value = picklistEntry.getValue();
126 | }
127 |
128 | }
129 |
130 | }
--------------------------------------------------------------------------------
/src/classes/FieldMetadata.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/FieldMetadata_Tests.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | @isTest
6 | private class FieldMetadata_Tests {
7 |
8 | @isTest
9 | static void it_should_return_metadata_for_sobject_name_and_field_api_name() {
10 | String sobjectname = 'Account';
11 | String fieldName = 'Name';
12 |
13 | Test.startTest();
14 |
15 | FieldMetadata accountFieldMetadata = new FieldMetadata(sobjectName, fieldName);
16 | validateAttributesAreSet(String.valueOf(fieldName), accountFieldMetadata);
17 | validateCaseSentivityForJavascript(accountFieldMetadata);
18 |
19 | Test.stopTest();
20 | }
21 |
22 | @isTest
23 | static void it_should_return_metadata_for_sobject_type_token_and_field_token() {
24 | SobjectType accountSobjectType = Account.SobjectType;
25 | SobjectField accountNameField = Account.Name;
26 |
27 | Test.startTest();
28 |
29 | FieldMetadata accountFieldMetadata = new FieldMetadata(accountSobjectType, accountNameField);
30 | validateAttributesAreSet(String.valueOf(accountNameField), accountFieldMetadata);
31 | validateCaseSentivityForJavascript(accountFieldMetadata);
32 |
33 | Test.stopTest();
34 | }
35 |
36 | @isTest
37 | static void it_should_return_metadata_for_account_parentid_lookup_field_token() {
38 | SobjectField parentIdField = Account.ParentId;
39 |
40 | Test.startTest();
41 |
42 | FieldMetadata accountFieldMetadata = new FieldMetadata(Account.SobjectType, parentIdField);
43 | validateAttributesAreSet(String.valueOf(parentIdField), accountFieldMetadata);
44 | validateCaseSentivityForJavascript(accountFieldMetadata);
45 |
46 | Test.stopTest();
47 | }
48 |
49 | @isTest
50 | static void it_should_return_metadata_for_account_type_picklist_field_token() {
51 | SobjectField typeField = Account.Type;
52 |
53 | Test.startTest();
54 |
55 | FieldMetadata accountFieldMetadata = new FieldMetadata(Account.SobjectType, typeField);
56 | validateAttributesAreSet(String.valueOf(typeField), accountFieldMetadata);
57 | validateCaseSentivityForJavascript(accountFieldMetadata);
58 |
59 | Test.stopTest();
60 | }
61 |
62 | private static void validateAttributesAreSet(String fieldName, FieldMetadata fieldMetadata) {
63 | String sobjectName = 'Account';
64 | DescribeFieldResult fieldDescribe = Schema.SobjectType.Account.fields.getMap().get(fieldName).getDescribe();
65 |
66 | System.assertEquals(fieldDescribe.getName(), fieldMetadata.ApiName);
67 | System.assertEquals(fieldDescribe.getByteLength(), fieldMetadata.ByteLength);
68 | System.assertEquals(fieldDescribe.getDefaultValue(), fieldMetadata.DefaultValue);
69 | System.assertEquals(fieldDescribe.getDigits(), fieldMetadata.Digits);
70 | System.assertEquals(fieldDescribe.getType().name(), fieldMetadata.DisplayType);
71 | System.assertEquals(fieldDescribe.getInlineHelpText(), fieldMetadata.InlineHelpText);
72 | System.assertEquals(fieldDescribe.isAccessible(), fieldMetadata.IsAccessible);
73 | System.assertEquals(fieldDescribe.isAutoNumber(), fieldMetadata.IsAutoNumber);
74 | System.assertEquals(fieldDescribe.isCalculated(), fieldMetadata.IsCalculated);
75 | System.assertEquals(fieldDescribe.isCaseSensitive(), fieldMetadata.IsCaseSensitive);
76 | System.assertEquals(fieldDescribe.isCreateable(), fieldMetadata.IsCreateable);
77 | System.assertEquals(fieldDescribe.isCustom(), fieldMetadata.IsCustom);
78 | System.assertEquals(fieldDescribe.isDefaultedOnCreate(), fieldMetadata.IsDefaultedOnCreate);
79 | System.assertEquals(fieldDescribe.isFilterable(), fieldMetadata.IsFilterable);
80 | System.assertEquals(fieldDescribe.isGroupable(), fieldMetadata.IsGroupable);
81 | System.assertEquals(fieldDescribe.isNameField(), fieldMetadata.IsNameField);
82 | System.assertEquals(fieldDescribe.isNillable(), fieldMetadata.IsNillable);
83 | System.assertEquals(fieldDescribe.isNillable() == false && fieldDescribe.isCreateable(), fieldMetadata.IsRequired);
84 | System.assertEquals(fieldDescribe.isSortable(), fieldMetadata.IsSortable);
85 | System.assertEquals(fieldDescribe.isUpdateable(), fieldMetadata.IsUpdateable);
86 | System.assertEquals(fieldDescribe.getLabel(), fieldMetadata.Label);
87 | System.assertEquals(fieldDescribe.getLocalName(), fieldMetadata.LocalApiName);
88 | System.assertEquals(fieldDescribe.getLength(), fieldMetadata.MaxLength);
89 | //System.assertEquals(this.getNamespace(), fieldMetadata.namespace);
90 | //System.assertEquals(this.getPicklistOptions(fieldDescribe), fieldMetadata.picklistOptions);
91 | System.assertEquals(fieldDescribe.getPrecision(), fieldMetadata.Precision);
92 | System.assertEquals(fieldDescribe.getRelationshipName(), fieldMetadata.RelationshipApiName);
93 | System.assertEquals(fieldDescribe.getRelationshipOrder(), fieldMetadata.RelationshipOrder);
94 | //System.assertEquals( this.getRelationshipReferences(fieldDescribe), fieldMetadata.RelationshipReferences);
95 | System.assertEquals(fieldDescribe.getScale(), fieldMetadata.Scale);
96 | System.assertEquals(sobjectName, fieldMetadata.SobjectApiName);
97 | }
98 |
99 | private static void validateCaseSentivityForJavascript(FieldMetadata fieldMetadata) {
100 | // Validate that the attributes are named exactly as expected so that javascript can rely on them
101 | String jsonFieldMetadata = JSON.serialize(fieldMetadata);
102 | Map untypedFieldMetadata = (Map)JSON.deserializeUntyped(jsonFieldMetadata);
103 |
104 | // One negative to confirm that the strings in our map are case sensitive
105 | System.assert(untypedFieldMetadata.containsKey('APINAME') == false);
106 | // Now for the 'real' tests
107 | System.assert(untypedFieldMetadata.containsKey('ApiName'));
108 | System.assert(untypedFieldMetadata.containsKey('ByteLength'));
109 | System.assert(untypedFieldMetadata.containsKey('DefaultValue'));
110 | System.assert(untypedFieldMetadata.containsKey('Digits'));
111 | System.assert(untypedFieldMetadata.containsKey('DisplayType'));
112 | System.assert(untypedFieldMetadata.containsKey('InlineHelpText'));
113 | System.assert(untypedFieldMetadata.containsKey('IsAccessible'));
114 | System.assert(untypedFieldMetadata.containsKey('IsAutoNumber'));
115 | System.assert(untypedFieldMetadata.containsKey('IsCalculated'));
116 | System.assert(untypedFieldMetadata.containsKey('IsCaseSensitive'));
117 | System.assert(untypedFieldMetadata.containsKey('IsCreateable'));
118 | System.assert(untypedFieldMetadata.containsKey('IsCustom'));
119 | System.assert(untypedFieldMetadata.containsKey('IsDefaultedOnCreate'));
120 | System.assert(untypedFieldMetadata.containsKey('IsFilterable'));
121 | System.assert(untypedFieldMetadata.containsKey('IsGroupable'));
122 | System.assert(untypedFieldMetadata.containsKey('IsNameField'));
123 | System.assert(untypedFieldMetadata.containsKey('IsNillable'));
124 | System.assert(untypedFieldMetadata.containsKey('IsRequired'));
125 | System.assert(untypedFieldMetadata.containsKey('IsSortable'));
126 | System.assert(untypedFieldMetadata.containsKey('IsUpdateable'));
127 | System.assert(untypedFieldMetadata.containsKey('Label'));
128 | System.assert(untypedFieldMetadata.containsKey('LocalApiName'));
129 | System.assert(untypedFieldMetadata.containsKey('MaxLength'));
130 | System.assert(untypedFieldMetadata.containsKey('Namespace'));
131 | System.assert(untypedFieldMetadata.containsKey('PicklistOptions'));
132 | System.assert(untypedFieldMetadata.containsKey('Precision'));
133 | System.assert(untypedFieldMetadata.containsKey('RelationshipApiName'));
134 | System.assert(untypedFieldMetadata.containsKey('RelationshipOrder'));
135 | System.assert(untypedFieldMetadata.containsKey('RelationshipReferences'));
136 | System.assert(untypedFieldMetadata.containsKey('Scale'));
137 | System.assert(untypedFieldMetadata.containsKey('SobjectApiName'));
138 | }
139 |
140 | }
--------------------------------------------------------------------------------
/src/classes/FieldMetadata_Tests.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/FieldSetMetadata.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | global class FieldSetMetadata {
6 |
7 | @AuraEnabled global final String ApiName {get; private set;}
8 | @AuraEnabled global final String Description {get; private set;}
9 | @AuraEnabled global final List FieldSetMembers {get; private set;}
10 | @AuraEnabled global final String Label {get; private set;}
11 | @AuraEnabled global final String LocalApiName {get; private set;}
12 | @AuraEnabled global final String Namespace {get; private set;}
13 | @AuraEnabled global final String SobjectApiName {get; private set;}
14 |
15 | global FieldSetMetadata(String sobjectApiName, String fieldSetApiName) {
16 | this(Schema.getGlobalDescribe().get(sobjectApiName).getDescribe().fieldSets.getMap().get(fieldSetApiName));
17 | }
18 |
19 | global FieldSetMetadata(Schema.FieldSet fieldSet) {
20 | this.ApiName = this.getApiName(fieldSet);
21 | this.Description = fieldSet.getDescription();
22 | this.FieldSetMembers = this.getFieldSetMembers(fieldSet);
23 | this.Label = fieldSet.getLabel();
24 | this.LocalApiName = fieldSet.getName();
25 | this.Namespace = fieldSet.getNamespace();
26 | this.SobjectApiName = String.valueOf(fieldSet.getSobjectType());
27 | }
28 |
29 | private String getApiName(Schema.FieldSet fieldSet) {
30 | String namespace = fieldSet.getNamespace() == null ? '' : fieldSet.getNamespace() + '__';
31 | return namespace + fieldSet.getName();
32 | }
33 |
34 | private List getFieldSetMembers(Schema.FieldSet fieldSet) {
35 | List fieldSetMembers = new List();
36 | for(Schema.FieldSetMember fieldSetMember : fieldSet.getFields()) {
37 | FieldSetMemberMetadata fieldSetMemberMetadata = new FieldSetMemberMetadata(fieldSet.getSobjectType(), fieldSetMember);
38 |
39 | fieldSetMembers.add(fieldSetMemberMetadata);
40 | }
41 | fieldSetMembers.sort();
42 | return fieldSetMembers;
43 | }
44 |
45 | global class FieldSetMemberMetadata implements Comparable {
46 |
47 | @AuraEnabled global final String DisplayType {get; private set;}
48 | @AuraEnabled global final FieldMetadata Field {get; private set;}
49 | @AuraEnabled global final String FieldPath {get; private set;}
50 | @AuraEnabled global final Boolean IsDbRequired {get; private set;}
51 | @AuraEnabled global final Boolean IsRequired {get; private set;}
52 | @AuraEnabled global final String Label {get; private set;}
53 | @AuraEnabled global final String SobjectApiName {get; private set;}
54 |
55 | global Integer compareTo(Object compareTo) {
56 | FieldSetMemberMetadata compareToFieldSetMember = (FieldSetMemberMetadata)compareTo;
57 |
58 | if(this.FieldPath == compareToFieldSetMember.FieldPath) return 0;
59 | else if(this.FieldPath > compareToFieldSetMember.FieldPath) return 1;
60 | else return -1;
61 | }
62 |
63 | private FieldSetMemberMetadata(Schema.SobjectType sobjectType, Schema.FieldSetMember fieldSetMember) {
64 | this.DisplayType = fieldSetMember.getType().name();
65 | this.Field = this.getFieldMetadata(sobjectType, fieldSetMember);
66 | this.FieldPath = fieldSetMember.getFieldPath();
67 | this.IsDbRequired = fieldSetMember.getDbRequired();
68 | this.IsRequired = fieldSetMember.getRequired();
69 | this.Label = fieldSetMember.getLabel();
70 | this.SobjectApiName = String.valueOf(sobjectType);
71 | }
72 |
73 | private FieldMetadata getFieldMetadata(Schema.SobjectType sobjectType, Schema.FieldSetMember fieldSetMember) {
74 | FieldMetadata fieldMetadata;
75 |
76 | List fieldChain = fieldSetMember.getFieldPath().split('\\.');
77 |
78 | if(fieldChain.size() == 0) return fieldMetadata;
79 |
80 | Schema.SobjectType currentFieldSobjectType = Schema.getGlobalDescribe().get(this.sobjectApiName);
81 | String currentFieldSobjectApiName = String.valueOf(sobjectType);
82 | String currentFieldApiName;
83 |
84 | for(Integer i = 0; i < fieldChain.size(); i++) {
85 | currentFieldApiName = fieldChain[i];
86 |
87 | for(Schema.SobjectField sobjectField : Schema.getGlobalDescribe().get(currentFieldSobjectApiName).getDescribe().fields.getMap().values()) {
88 | DescribeFieldResult fieldDescribe = sobjectField.getDescribe();
89 |
90 | if(fieldDescribe.getRelationshipName() != currentFieldApiName) continue;
91 | if(fieldDescribe.getReferenceTo().isEmpty()) continue;
92 |
93 | currentFieldSobjectType = fieldDescribe.getReferenceTo()[0];
94 | currentFieldSobjectApiName = currentFieldSobjectType.getDescribe().getName();
95 | break;
96 | }
97 | }
98 |
99 | return new FieldMetadata(currentFieldSobjectApiName, currentFieldApiName);
100 | }
101 |
102 | }
103 |
104 | }
--------------------------------------------------------------------------------
/src/classes/FieldSetMetadata.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/FieldSetMetadata_Tests.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | @isTest
6 | private class FieldSetMetadata_Tests {
7 |
8 | @isTest
9 | static void it_should_return_metadata_for_sobject_api_name_and_field_set_api_name() {
10 | Schema.FieldSet fieldSet = getFieldSet();
11 | if(fieldSet == null) return;
12 |
13 | Test.startTest();
14 |
15 | String sobjectName = String.valueOf(fieldSet.getSobjectType());
16 | String fieldSetNamespace = fieldSet.getNamespace() == null ? '' : fieldSet.getNamespace() + '__';
17 | String fieldSetName = fieldSetNamespace + fieldSet.getName();
18 | FieldSetMetadata fieldSetMetadata = new FieldSetMetadata(sobjectName, fieldSetName);
19 | validateAttributesAreSet(fieldSet, fieldSetMetadata);
20 | validateCaseSentivityForJavascript(fieldSetMetadata);
21 |
22 | Test.stopTest();
23 | }
24 |
25 | @isTest
26 | static void it_should_return_metadata_for_field_set_token() {
27 | Schema.FieldSet fieldSet = getFieldSet();
28 | if(fieldSet == null) return;
29 |
30 | Test.startTest();
31 |
32 | FieldSetMetadata fieldSetMetadata = new FieldSetMetadata(fieldSet);
33 | validateAttributesAreSet(fieldSet, fieldSetMetadata);
34 | validateCaseSentivityForJavascript(fieldSetMetadata);
35 |
36 | Test.stopTest();
37 | }
38 |
39 | private static Schema.FieldSet getFieldSet() {
40 | // Dynamically check for field sets in some of the most commonly used objects
41 | // If not results are found, then test coverage will drop
42 | List commonSobjectNames = new List{
43 | 'Account', 'Lead', 'Contact', 'Opportunity'
44 | };
45 | for(String sobjectName : commonSobjectNames) {
46 | Schema.DescribeSobjectResult sobjectDescribe = Schema.getGlobalDescribe().get(sobjectName).getDescribe();
47 | // If there are any fields sets found, return the first one
48 | if(sobjectDescribe.fieldSets.getMap().isEmpty() == false) return sobjectDescribe.fieldSets.getMap().values()[0];
49 | }
50 | return null;
51 | }
52 |
53 | private static void validateAttributesAreSet(Schema.FieldSet fieldSet, FieldSetMetadata fieldSetMetadata) {
54 | String namespacePrefix = '';
55 | if(fieldSet.getNamespace() != null) namespacePrefix = fieldSet.getNamespace() + '__';
56 | String fieldSetName = namespacePrefix + fieldSet.getName();
57 |
58 | System.assertEquals(fieldSetName, fieldSetMetadata.ApiName);
59 | System.assertEquals(fieldSet.getDescription(), fieldSetMetadata.Description);
60 | System.assertEquals(fieldSet.getFields().size(), fieldSetMetadata.FieldSetMembers.size());
61 | // TODO add asserts for field set members' field metadata
62 | System.assertEquals(fieldSet.getLabel(), fieldSetMetadata.Label);
63 | // TODO add assert for localName
64 | System.assertEquals(fieldSet.getNamespace(), fieldSetMetadata.Namespace);
65 | System.assertEquals(String.valueOf(fieldSet.getSobjectType()), fieldSetMetadata.SobjectApiName);
66 | }
67 |
68 | private static void validateCaseSentivityForJavascript(FieldSetMetadata fieldSetMetadata) {
69 | // Validate that the attributes are named exactly as expected so that javascript can rely on them
70 | String jsonFieldSetMetadata = JSON.serialize(fieldSetMetadata);
71 | Map untypedFieldSetMetadata = (Map)JSON.deserializeUntyped(jsonFieldSetMetadata);
72 |
73 | // One negative to confirm that the strings in our map are case sensitive
74 | System.assert(untypedFieldSetMetadata.containsKey('APINAME') == false);
75 | // Now for the 'real' tests
76 | System.assert(untypedFieldSetMetadata.containsKey('ApiName'));
77 | System.assert(untypedFieldSetMetadata.containsKey('Description'));
78 | System.assert(untypedFieldSetMetadata.containsKey('FieldSetMembers'));
79 | System.assert(untypedFieldSetMetadata.containsKey('Label'));
80 | System.assert(untypedFieldSetMetadata.containsKey('LocalApiName'));
81 | System.assert(untypedFieldSetMetadata.containsKey('Namespace'));
82 | System.assert(untypedFieldSetMetadata.containsKey('SobjectApiName'));
83 | // TODO add asserts for FieldSetMembers
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/src/classes/FieldSetMetadata_Tests.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/LimitsMetadata.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | global class LimitsMetadata {
6 |
7 | @AuraEnabled global final LimitUsageMetadata AggregateQueries {get; private set;}
8 | @AuraEnabled global final LimitUsageMetadata AsyncCalls {get; private set;}
9 | @AuraEnabled global final LimitUsageMetadata Callouts {get; private set;}
10 | @AuraEnabled global final LimitUsageMetadata CpuTime {get; private set;}
11 | @AuraEnabled global final LimitUsageMetadata DmlRows {get; private set;}
12 | @AuraEnabled global final LimitUsageMetadata DmlStatements {get; private set;}
13 | @AuraEnabled global final LimitUsageMetadata EmailInvocations {get; private set;}
14 | @AuraEnabled global final LimitUsageMetadata FutureCalls {get; private set;}
15 | @AuraEnabled global final LimitUsageMetadata HeapSize {get; private set;}
16 | @AuraEnabled global final LimitUsageMetadata MobilePushApexCalls {get; private set;}
17 | @AuraEnabled global final LimitUsageMetadata QueueableJobs {get; private set;}
18 | @AuraEnabled global final LimitUsageMetadata SoqlQueryLocatorRows {get; private set;}
19 | @AuraEnabled global final LimitUsageMetadata SoqlQueryRows {get; private set;}
20 | @AuraEnabled global final LimitUsageMetadata SoqlQueries {get; private set;}
21 | @AuraEnabled global final LimitUsageMetadata SoslSearches {get; private set;}
22 |
23 | global LimitsMetadata() {
24 | this.AggregateQueries = new LimitUsageMetadata(Limits.getAggregateQueries(), Limits.getLimitAggregateQueries());
25 | this.AsyncCalls = new LimitUsageMetadata(Limits.getAsyncCalls(), Limits.getLimitAsyncCalls());
26 | this.Callouts = new LimitUsageMetadata(Limits.getCallouts(), Limits.getLimitCallouts());
27 | this.CpuTime = new LimitUsageMetadata(Limits.getCPUTime(), Limits.getLimitCPUTime());
28 | this.DmlRows = new LimitUsageMetadata(Limits.getDmlRows(), Limits.getLimitDmlRows());
29 | this.DmlStatements = new LimitUsageMetadata(Limits.getDmlStatements(), Limits.getLimitDmlStatements());
30 | this.EmailInvocations = new LimitUsageMetadata(Limits.getEmailInvocations(), Limits.getLimitEmailInvocations());
31 | this.FutureCalls = new LimitUsageMetadata(Limits.getFutureCalls(), Limits.getLimitFutureCalls());
32 | this.HeapSize = new LimitUsageMetadata(Limits.getHeapSize(), Limits.getLimitHeapSize());
33 | this.MobilePushApexCalls = new LimitUsageMetadata(Limits.getMobilePushApexCalls(), Limits.getLimitMobilePushApexCalls());
34 | this.QueueableJobs = new LimitUsageMetadata(Limits.getQueueableJobs(), Limits.getLimitQueueableJobs());
35 | this.SoqlQueries = new LimitUsageMetadata(Limits.getQueries(), Limits.getLimitQueries());
36 | this.SoqlQueryLocatorRows = new LimitUsageMetadata(Limits.getQueryLocatorRows(), Limits.getLimitQueryLocatorRows());
37 | this.SoqlQueryRows = new LimitUsageMetadata(Limits.getQueryRows(), Limits.getLimitQueryRows());
38 | this.SoslSearches = new LimitUsageMetadata(Limits.getSoslQueries(), Limits.getLimitSoslQueries());
39 | }
40 |
41 | global class LimitUsageMetadata {
42 |
43 | @AuraEnabled global final Integer Max {get; private set;}
44 | @AuraEnabled global final Integer Used {get; private set;}
45 |
46 | global LimitUsageMetadata(Integer used, Integer max){
47 | this.Max = max;
48 | this.Used = used;
49 | }
50 |
51 | }
52 |
53 | }
--------------------------------------------------------------------------------
/src/classes/LimitsMetadata.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/LimitsMetadata_Tests.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | @isTest
6 | private class LimitsMetadata_Tests {
7 |
8 | @isTest
9 | static void it_should_return_limits_metadata() {
10 | LimitsMetadata limitsMetadata = new LimitsMetadata();
11 | validateAttributesAreSet(limitsMetadata);
12 | validateCaseSentivityForJavascript(limitsMetadata);
13 | }
14 |
15 | private static void validateAttributesAreSet(LimitsMetadata limitsMetadata) {
16 | System.assertEquals(Limits.getAggregateQueries(), limitsMetadata.AggregateQueries.Used);
17 | System.assertEquals(Limits.getLimitAggregateQueries(), limitsMetadata.AggregateQueries.Max);
18 | System.assertEquals(Limits.getAsyncCalls(), limitsMetadata.AsyncCalls.Used);
19 | System.assertEquals(Limits.getLimitAsyncCalls(), limitsMetadata.AsyncCalls.Max);
20 | System.assertEquals(Limits.getCallouts(), limitsMetadata.Callouts.Used);
21 | System.assertEquals(Limits.getLimitCallouts(), limitsMetadata.Callouts.Max);
22 | //System.assertEquals(Limits.getCPUTime(), limitsMetadata.CpuTime.Used);
23 | System.assertEquals(Limits.getLimitCPUTime(), limitsMetadata.CpuTime.Max);
24 | System.assertEquals(Limits.getDMLRows(), limitsMetadata.DmlRows.Used);
25 | System.assertEquals(Limits.getLimitDMLRows(), limitsMetadata.DmlRows.Max);
26 | System.assertEquals(Limits.getDMLStatements(), limitsMetadata.DmlStatements.Used);
27 | System.assertEquals(Limits.getLimitDMLStatements(), limitsMetadata.DmlStatements.Max);
28 | System.assertEquals(Limits.getEmailInvocations(), limitsMetadata.EmailInvocations.Used);
29 | System.assertEquals(Limits.getLimitEmailInvocations(), limitsMetadata.EmailInvocations.Max);
30 | System.assertEquals(Limits.getFutureCalls(), limitsMetadata.FutureCalls.Used);
31 | System.assertEquals(Limits.getLimitFutureCalls(), limitsMetadata.FutureCalls.Max);
32 | //System.assertEquals(Limits.getHeapSize(), limitsMetadata.HeapSize.Used);
33 | System.assertEquals(Limits.getLimitHeapSize(), limitsMetadata.HeapSize.Max);
34 | System.assertEquals(Limits.getMobilePushApexCalls(), limitsMetadata.MobilePushApexCalls.Used);
35 | System.assertEquals(Limits.getLimitMobilePushApexCalls(), limitsMetadata.MobilePushApexCalls.Max);
36 | System.assertEquals(Limits.getQueueableJobs(), limitsMetadata.QueueableJobs.Used);
37 | System.assertEquals(Limits.getLimitQueueableJobs(), limitsMetadata.QueueableJobs.Max);
38 | System.assertEquals(Limits.getQueries(), limitsMetadata.SoqlQueries.Used);
39 | System.assertEquals(Limits.getLimitQueries(), limitsMetadata.SoqlQueries.Max);
40 | System.assertEquals(Limits.getQueryLocatorRows(), limitsMetadata.SoqlQueryLocatorRows.Used);
41 | System.assertEquals(Limits.getLimitQueryLocatorRows(), limitsMetadata.SoqlQueryLocatorRows.Max);
42 | System.assertEquals(Limits.getQueryRows(), limitsMetadata.SoqlQueryRows.Used);
43 | System.assertEquals(Limits.getLimitQueryRows(), limitsMetadata.SoqlQueryRows.Max);
44 | System.assertEquals(Limits.getSOSLQueries(), limitsMetadata.SoslSearches.Used);
45 | System.assertEquals(Limits.getLimitSoslQueries(), limitsMetadata.SoslSearches.Max);
46 | }
47 |
48 | private static void validateCaseSentivityForJavascript(LimitsMetadata limitsMetadata) {
49 | // Validate that the attributes are named exactly as expected so that javascript can rely on them
50 | String jsonLimitsMetadata = JSON.serialize(limitsMetadata);
51 | Map untypedLimitsMetadata = (Map)JSON.deserializeUntyped(jsonLimitsMetadata);
52 |
53 | // One negative to confirm that the strings in our map are case sensitive
54 | System.assert(untypedLimitsMetadata.containsKey('AGGREGATEQUERIES') == false);
55 | // Now for the 'real' tests
56 | System.assert(untypedLimitsMetadata.containsKey('AggregateQueries'));
57 | System.assert(untypedLimitsMetadata.containsKey('AsyncCalls'));
58 | System.assert(untypedLimitsMetadata.containsKey('Callouts'));
59 | System.assert(untypedLimitsMetadata.containsKey('CpuTime'));
60 | System.assert(untypedLimitsMetadata.containsKey('DmlRows'));
61 | System.assert(untypedLimitsMetadata.containsKey('DmlStatements'));
62 | System.assert(untypedLimitsMetadata.containsKey('EmailInvocations'));
63 | System.assert(untypedLimitsMetadata.containsKey('FutureCalls'));
64 | System.assert(untypedLimitsMetadata.containsKey('HeapSize'));
65 | System.assert(untypedLimitsMetadata.containsKey('MobilePushApexCalls'));
66 | System.assert(untypedLimitsMetadata.containsKey('QueueableJobs'));
67 | System.assert(untypedLimitsMetadata.containsKey('SoqlQueries'));
68 | System.assert(untypedLimitsMetadata.containsKey('SoqlQueryLocatorRows'));
69 | System.assert(untypedLimitsMetadata.containsKey('SoqlQueryRows'));
70 | System.assert(untypedLimitsMetadata.containsKey('SoslSearches'));
71 | }
72 |
73 | }
--------------------------------------------------------------------------------
/src/classes/LimitsMetadata_Tests.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/QueueMetadata.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | global class QueueMetadata {
6 |
7 | // Stores cached query results
8 | private static final Map QUERIED_QUEUES_BY_ID;
9 | private static final Map QUERIED_QUEUES_BY_DEVELOPER_NAME;
10 |
11 | static {
12 | // Query & cache queues
13 | QUERIED_QUEUES_BY_ID = new Map();
14 | QUERIED_QUEUES_BY_DEVELOPER_NAME = new Map();
15 |
16 | for(Group queue : [
17 | SELECT DeveloperName, DoesIncludeBosses, DoesSendEmailToMembers, Email, Id, Name,
18 | (SELECT SobjectType FROM QueueSobjects),
19 | (SELECT Id, GroupId, UserOrGroupId FROM GroupMembers)
20 | FROM Group
21 | WHERE Type = 'Queue'
22 | ]) {
23 | QUERIED_QUEUES_BY_ID.put(queue.Id, queue);
24 | QUERIED_QUEUES_BY_DEVELOPER_NAME.put(queue.DeveloperName, queue);
25 | }
26 | }
27 |
28 | public static List getQueueApiNames() {
29 | List queueApiNames = new List(QUERIED_QUEUES_BY_DEVELOPER_NAME.keySet());
30 | queueApiNames.sort();
31 | return queueApiNames;
32 | }
33 |
34 | @AuraEnabled global final String ApiName {get; private set;}
35 | @AuraEnabled global final Boolean DoesIncludeBosses {get; private set;}
36 | @AuraEnabled global final Boolean DoesSendEmailToMembers {get; private set;}
37 | @AuraEnabled global final String Email {get; private set;}
38 | @AuraEnabled global final Id Id {get; private set;}
39 | @AuraEnabled global final String Label {get; private set;}
40 | @AuraEnabled global final List QueueMembers {get; private set;}
41 | @AuraEnabled global final List SobjectApiNames {get; private set;}
42 |
43 | global QueueMetadata(String queueApiName) {
44 | this(QUERIED_QUEUES_BY_DEVELOPER_NAME.get(queueApiName).Id);
45 | }
46 |
47 | global QueueMetadata(Id queueId) {
48 | Group queue = QUERIED_QUEUES_BY_ID.get(queueId);
49 |
50 | this.ApiName = queue.DeveloperName;
51 | this.DoesIncludeBosses = queue.DoesIncludeBosses;
52 | this.DoesSendEmailToMembers = queue.DoesSendEmailToMembers;
53 | this.Email = queue.Email;
54 | this.Id = queue.Id;
55 | this.Label = queue.Name;
56 | this.QueueMembers = this.getQueueMembers(queue);
57 | this.SobjectApiNames = this.getSobjectApiNames(queue);
58 | }
59 |
60 | private List getQueueMembers(Group queue) {
61 | List queueMembers = new List();
62 | for(GroupMember queueMember : queue.GroupMembers) {
63 | queueMembers.add(new QueueMemberMetadata(queueMember));
64 | }
65 | queueMembers.sort();
66 | return queueMembers;
67 | }
68 |
69 | private List getSobjectApiNames(Group queue) {
70 | List sobjectApiNames = new List();
71 | for(QueueSobject queueSobject : queue.QueueSobjects) {
72 | sobjectApiNames.add(queueSobject.SobjectType);
73 | }
74 | sobjectApiNames.sort();
75 | return sobjectApiNames;
76 | }
77 |
78 | global class QueueMemberMetadata implements Comparable {
79 |
80 | @AuraEnabled global final Id Id {get; private set;}
81 | @AuraEnabled global final Id QueueId {get; private set;}
82 | @AuraEnabled global final String Type {get; private set;}
83 | @AuraEnabled global final Id UserOrGroupId {get; private set;}
84 |
85 | global Integer compareTo(Object compareTo) {
86 | QueueMemberMetadata compareToQueueMember = (QueueMemberMetadata)compareTo;
87 |
88 | if(this.UserOrGroupId == compareToQueueMember.UserOrGroupId) return 0;
89 | else if(this.UserOrGroupId > compareToQueueMember.UserOrGroupId) return 1;
90 | else return -1;
91 | }
92 |
93 | private QueueMemberMetadata(GroupMember groupMember) {
94 | this.Id = groupMember.Id;
95 | this.QueueId = groupMember.GroupId;
96 | this.Type = String.valueOf(groupMember.UserOrGroupId.getSobjectType());
97 | this.UserOrGroupId = groupMember.UserOrGroupId;
98 | }
99 |
100 | }
101 |
102 | }
--------------------------------------------------------------------------------
/src/classes/QueueMetadata.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/QueueMetadata_Tests.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | @isTest
6 | private class QueueMetadata_Tests {
7 |
8 | private static final String queueDeveloperName = 'queueDeveloperName';
9 |
10 | @testSetup
11 | static void testSetup() {
12 | // Create queue
13 | Group queue = new Group(DeveloperName = queueDeveloperName, Name = queueDeveloperName, Type = 'Queue');
14 | insert queue;
15 |
16 | // Create queue Sobject
17 | QueueSobject queueCaseSobject = new QueueSobject(QueueId = queue.Id, SobjectType = 'Case');
18 | insert queueCaseSobject;
19 |
20 | // Create queue members
21 | List queueMembers = new List();
22 | for(User user : [SELECT Id FROM User WHERE IsActive = true AND Id != :UserInfo.getUserId()]) {
23 | GroupMember queueMember = new GroupMember(
24 | GroupId = queue.Id,
25 | UserOrGroupId = UserInfo.getUserId()
26 | );
27 | queueMembers.add(queueMember);
28 | }
29 | insert queueMembers;
30 | }
31 |
32 | @isTest
33 | static void it_should_return_queue_metadata_for_id() {
34 | Group queue = getQueue();
35 |
36 | Test.startTest();
37 |
38 | QueueMetadata queueMetadata = new QueueMetadata(queue.Id);
39 | validateAttributesAreSet(queue, queueMetadata);
40 | validateCaseSentivityForJavascript(queueMetadata);
41 |
42 | Test.stopTest();
43 | }
44 |
45 | @isTest
46 | static void it_should_return_queue_metadata_for_api_name() {
47 | Group queue = getQueue();
48 |
49 | Test.startTest();
50 |
51 | QueueMetadata queueMetadata = new QueueMetadata(queue.DeveloperName);
52 | validateAttributesAreSet(queue, queueMetadata);
53 | validateCaseSentivityForJavascript(queueMetadata);
54 |
55 | Test.stopTest();
56 | }
57 |
58 | private static Group getQueue() {
59 | Group queue = [
60 | SELECT Id, Name, DeveloperName, DoesIncludeBosses, DoesSendEmailToMembers, Email, OwnerId, Owner.Name
61 | FROM Group
62 | WHERE Type = 'Queue'
63 | AND DeveloperName = :queueDeveloperName
64 | ];
65 | return queue;
66 | }
67 |
68 | private static void validateAttributesAreSet(Group queue, QueueMetadata queueMetadata) {
69 | System.assertEquals(queue.DeveloperName, queueMetadata.ApiName);
70 | System.assertEquals(queue.DoesIncludeBosses, queueMetadata.DoesIncludeBosses);
71 | System.assertEquals(queue.DoesSendEmailToMembers, queueMetadata.DoesSendEmailToMembers);
72 | System.assertEquals(queue.Email, queueMetadata.Email);
73 | System.assertEquals(queue.Id, queueMetadata.Id);
74 | System.assertEquals(queue.Name, queueMetadata.Label);
75 | }
76 |
77 | private static void validateCaseSentivityForJavascript(QueueMetadata queueMetadata) {
78 | // Validate that the attributes are named exactly as expected so that javascript can rely on them
79 | String jsonQueueMetadata = JSON.serialize(queueMetadata);
80 | Map untypedQueueMetadata = (Map)JSON.deserializeUntyped(jsonQueueMetadata);
81 |
82 | // One negative to confirm that the strings in our map are case sensitive
83 | System.assert(untypedQueueMetadata.containsKey('APINAME') == false);
84 | // Now for the 'real' tests
85 | System.assert(untypedQueueMetadata.containsKey('ApiName'));
86 | System.assert(untypedQueueMetadata.containsKey('DoesIncludeBosses'));
87 | System.assert(untypedQueueMetadata.containsKey('DoesSendEmailToMembers'));
88 | System.assert(untypedQueueMetadata.containsKey('Email'));
89 | System.assert(untypedQueueMetadata.containsKey('Id'));
90 | System.assert(untypedQueueMetadata.containsKey('Label'));
91 | System.assert(untypedQueueMetadata.containsKey('QueueMembers'));
92 | System.assert(untypedQueueMetadata.containsKey('SobjectApiNames'));
93 | }
94 |
95 | }
--------------------------------------------------------------------------------
/src/classes/QueueMetadata_Tests.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/RecordTypeMetadata.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | global class RecordTypeMetadata implements Comparable {
6 |
7 | @AuraEnabled global final String ApiName {get; private set;}
8 | @AuraEnabled global final Id Id {get; private set;}
9 | @AuraEnabled global final Boolean IsActive {get; private set;}
10 | @AuraEnabled global final Boolean IsAvailable {get; private set;}
11 | @AuraEnabled global final Boolean IsDefault {get; private set;}
12 | @AuraEnabled global final Boolean IsMaster {get; private set;}
13 | @AuraEnabled global final String Label {get; private set;}
14 | @AuraEnabled global final String LocalApiName {get; private set;}
15 | @AuraEnabled global final String Namespace {get; private set;}
16 | @AuraEnabled global final String SobjectApiName {get; private set;}
17 |
18 | global RecordTypeMetadata(String sobjectApiName, String recordTypeApiName) {
19 | this(
20 | Schema.getGlobalDescribe().get(sobjectApiName),
21 | Schema.getGlobalDescribe().get(sobjectApiName).getDescribe().getRecordTypeInfosByDeveloperName().get(recordTypeApiName)
22 | );
23 | }
24 |
25 | global RecordTypeMetadata(Schema.SobjectType sobjectType, Id recordTypeId) {
26 | this(
27 | sobjectType,
28 | sobjectType.getDescribe().getRecordTypeInfosById().get(recordTypeId)
29 | );
30 | }
31 |
32 | global RecordTypeMetadata(Schema.SobjectType sobjectType, Schema.RecordTypeInfo recordTypeInfo) {
33 | this.ApiName = this.getApiName(recordTypeInfo);
34 | this.Id = recordTypeInfo.getRecordTypeId();
35 | this.IsActive = recordTypeInfo.isActive();
36 | this.IsAvailable = recordTypeInfo.isAvailable();
37 | this.IsDefault = recordTypeInfo.isDefaultRecordTypeMapping();
38 | this.IsMaster = recordTypeInfo.isMaster();
39 | this.Label = recordTypeInfo.getName();
40 | this.LocalApiName = this.getLocalApiName(recordTypeInfo.getDeveloperName());
41 | this.Namespace = this.getNamespace(recordTypeInfo.getDeveloperName());
42 | this.SobjectApiName = String.valueOf(sobjectType);
43 | }
44 |
45 | global Integer compareTo(Object compareTo) {
46 | RecordTypeMetadata compareToRecordTypeMetadata = (RecordTypeMetadata)compareTo;
47 | String key = this.SobjectApiName + this.ApiName;
48 | String compareToKey = compareToRecordTypeMetadata.SobjectApiName + compareToRecordTypeMetadata.ApiName;
49 |
50 | if(key == compareToKey) return 0;
51 | else if(key > compareToKey) return 1;
52 | else return -1;
53 | }
54 |
55 | private String getApiName(Schema.RecordTypeInfo recordTypeInfo) {
56 | String namespacePrefix = String.isEmpty(this.getNamespace(recordTypeInfo.getDeveloperName())) ? '' : this.getNamespace(recordTypeInfo.getDeveloperName()) + '__';
57 | return namespacePrefix + recordTypeInfo.getDeveloperName();
58 | }
59 |
60 | private String getLocalApiName(String apiName) {
61 | return apiName.contains('__') ? apiName.substringAfter('__') : apiName;
62 | }
63 |
64 | private String getNamespace(String apiName) {
65 | return apiName.contains('__') ? apiName.substringBefore('__') : null;
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/src/classes/RecordTypeMetadata.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/RecordTypeMetadata_Tests.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | @isTest
6 | private class RecordTypeMetadata_Tests {
7 |
8 | private static final String ORG_NAMESPACE_PREFIX;
9 |
10 | static {
11 | ORG_NAMESPACE_PREFIX = [SELECT NamespacePrefix FROM Organization].NamespacePrefix;
12 | }
13 |
14 | @isTest
15 | static void it_should_return_record_type_metadata_for_record_type_info() {
16 | // For larger orgs with a lot of record types, we don't need to test every record type
17 | // We'll keep a count and stop after 5 to keep tests quick
18 | Integer count = 0;
19 |
20 | Schema.SobjectType accountSobjectType = Schema.Account.SobjectType;
21 | for(Schema.RecordTypeInfo recordTypeInfo : Schema.SobjectType.Account.getRecordTypeInfos()) {
22 | if(count >= 5) break;
23 |
24 | RecordTypeMetadata recordTypeMetadata = new RecordTypeMetadata(accountSobjectType, recordTypeInfo);
25 | count++;
26 | }
27 | }
28 |
29 | @isTest
30 | static void it_should_return_record_type_metadata_for_sobject_and_record_type_api_names() {
31 | for(RecordType recordType : [SELECT Id, BusinessProcessId, Description, DeveloperName, NamespacePrefix, SobjectType FROM RecordType LIMIT 5]) {
32 | Schema.RecordTypeInfo recordTypeInfo = Schema.getGlobalDescribe().get(recordType.SobjectType).getDescribe().getRecordTypeInfosById().get(recordType.Id);
33 | String namespace = recordType.NamespacePrefix == null || recordType.NamespacePrefix == ORG_NAMESPACE_PREFIX ? '' : recordType.NamespacePrefix + '__';
34 | RecordTypeMetadata recordTypeMetadata = new RecordTypeMetadata(recordType.SobjectType, namespace + recordType.DeveloperName);
35 | validateAttributesAreSet(recordTypeInfo, recordType, recordType.SobjectType, recordTypeMetadata);
36 | validateCaseSentivityForJavascript(recordTypeMetadata);
37 | }
38 | }
39 |
40 | @isTest
41 | static void it_should_return_record_type_metadata_for_record_type_id() {
42 | Schema.RecordTypeInfo queryableRecordTypeInfo;
43 | for(Schema.RecordTypeInfo recordTypeInfo : Schema.SobjectType.Account.getRecordTypeInfos()) {
44 | if(recordTypeInfo.isMaster()) continue;
45 |
46 | queryableRecordTypeInfo = recordTypeInfo;
47 | break;
48 | }
49 |
50 | if(queryableRecordTypeInfo == null) return; // This will be null in orgs with no record types, so the test can't finish
51 |
52 | RecordTypeMetadata recordTypeMetadata = new RecordTypeMetadata(Schema.Account.SobjectType, queryableRecordTypeInfo.getRecordTypeId());
53 | RecordType recordType = [
54 | SELECT Id, DeveloperName, NamespacePrefix, SobjectType
55 | FROM RecordType WHERE Id = :queryableRecordTypeInfo.getRecordTypeId()
56 | ];
57 | validateAttributesAreSet(queryableRecordTypeInfo, recordType, recordType.SobjectType, recordTypeMetadata);
58 | validateCaseSentivityForJavascript(recordTypeMetadata);
59 | }
60 |
61 | private static void validateAttributesAreSet(RecordTypeInfo recordTypeInfo, RecordType recordType, String sobjectApiName, RecordTypeMetadata recordTypeMetadata) {
62 | String namespace;
63 | String namespacePrefix = '';
64 | if(recordType != null && recordType.NamespacePrefix != null && recordType.NamespacePrefix != ORG_NAMESPACE_PREFIX) {
65 | namespace = recordType.NamespacePrefix;
66 | namespacePrefix = recordType.NamespacePrefix + '__';
67 | }
68 | String recordTypeName = recordType == null ? null : namespacePrefix + recordType.DeveloperName;
69 |
70 | System.assertEquals(recordType == null ? null : recordTypeName, recordTypeMetadata.ApiName);
71 | System.assertEquals(recordTypeInfo.getRecordTypeId(), recordTypeMetadata.Id);
72 | System.assertEquals(recordTypeInfo.isActive(), recordTypeMetadata.IsActive);
73 | System.assertEquals(recordTypeInfo.isAvailable(), recordTypeMetadata.IsAvailable);
74 | System.assertEquals(recordTypeInfo.isDefaultRecordTypeMapping(), recordTypeMetadata.IsDefault);
75 | System.assertEquals(recordTypeInfo.isMaster(), recordTypeMetadata.IsMaster);
76 | System.assertEquals(recordTypeInfo.getName(), recordTypeMetadata.Label);
77 | System.assertEquals(recordType == null ? null : recordType.DeveloperName, recordTypeMetadata.LocalApiName);
78 | System.assertEquals(recordType == null ? null : namespace, recordTypeMetadata.Namespace);
79 | System.assertEquals(sobjectApiName, recordTypeMetadata.SobjectApiName);
80 | }
81 |
82 | private static void validateCaseSentivityForJavascript(RecordTypeMetadata recordTypeMetadata) {
83 | // Validate that the attributes are named exactly as expected so that javascript can rely on them
84 | String jsonRecordTypeMetadata = JSON.serialize(recordTypeMetadata);
85 | Map untypedRecordTypeMetadata = (Map)JSON.deserializeUntyped(jsonRecordTypeMetadata);
86 |
87 | // One negative to confirm that the strings in our map are case sensitive
88 | System.assert(untypedRecordTypeMetadata.containsKey('APINAME') == false);
89 | // Now for the 'real' tests
90 | System.assert(untypedRecordTypeMetadata.containsKey('ApiName'));
91 | System.assert(untypedRecordTypeMetadata.containsKey('Id'));
92 | System.assert(untypedRecordTypeMetadata.containsKey('IsActive'));
93 | System.assert(untypedRecordTypeMetadata.containsKey('IsAvailable'));
94 | System.assert(untypedRecordTypeMetadata.containsKey('IsDefault'));
95 | System.assert(untypedRecordTypeMetadata.containsKey('IsMaster'));
96 | System.assert(untypedRecordTypeMetadata.containsKey('Label'));
97 | System.assert(untypedRecordTypeMetadata.containsKey('LocalApiName'));
98 | System.assert(untypedRecordTypeMetadata.containsKey('Namespace'));
99 | System.assert(untypedRecordTypeMetadata.containsKey('SobjectApiName'));
100 | }
101 |
102 | }
--------------------------------------------------------------------------------
/src/classes/RecordTypeMetadata_Tests.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/SobjectMetadata.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | global class SobjectMetadata {
6 |
7 | @AuraEnabled global final String ApiName {get; private set;}
8 | @AuraEnabled global final List ChildRelationships {get; private set;}
9 | @AuraEnabled global final String DisplayFieldApiName {get; private set;}
10 | @AuraEnabled global final List FieldApiNames {get; private set;}
11 | @AuraEnabled global final List FieldSetApiNames {get; private set;}
12 | @AuraEnabled global final Boolean HasMultiCurrency {get; private set;}
13 | @AuraEnabled global final Boolean HasSubtypes {get; private set;}
14 | @AuraEnabled global final Boolean IsAccessible {get; private set;}
15 | @AuraEnabled global final Boolean IsChatterFeedEnabled {get; private set;}
16 | @AuraEnabled global final Boolean IsCreateable {get; private set;}
17 | @AuraEnabled global final Boolean IsCustom {get; private set;}
18 | @AuraEnabled global final Boolean IsCustomSetting {get; private set;}
19 | @AuraEnabled global final Boolean IsDeletable {get; private set;}
20 | @AuraEnabled global final Boolean IsMruEnabled {get; private set;}
21 | @AuraEnabled global final Boolean IsMergeable {get; private set;}
22 | @AuraEnabled global final Boolean IsQueryable {get; private set;}
23 | @AuraEnabled global final Boolean IsSearchable {get; private set;}
24 | @AuraEnabled global final Boolean IsUndeletable {get; private set;}
25 | @AuraEnabled global final Boolean IsUpdateable {get; private set;}
26 | @AuraEnabled global final String KeyPrefix {get; private set;}
27 | @AuraEnabled global final String Label {get; private set;}
28 | @AuraEnabled global final String LabelPlural {get; private set;}
29 | @AuraEnabled global final String LocalApiName {get; private set;}
30 | @AuraEnabled global final String Namespace {get; private set;}
31 | @AuraEnabled global final List RecordTypes {get; private set;}
32 | @AuraEnabled global final String TabIcon {get; private set;}
33 |
34 | global SobjectMetadata(String sobjectApiName) {
35 | this(Schema.getGlobalDescribe().get(sobjectApiName));
36 | }
37 |
38 | global SobjectMetadata(Schema.SobjectType sobjectType) {
39 | DescribeSobjectResult sobjectDescribe = sobjectType.getDescribe();
40 |
41 | this.ApiName = String.valueOf(sobjectType);
42 | this.ChildRelationships = this.getChildRelationships(sobjectDescribe.getChildRelationships());
43 | this.DisplayFieldApiName = this.getDisplayFieldApiName(sobjectDescribe);
44 | this.FieldApiNames = this.getFieldApiNames(sobjectDescribe);
45 | this.FieldSetApiNames = this.getFieldSetApiNames(sobjectDescribe);
46 | this.HasMultiCurrency = sobjectDescribe.fields.getMap().containsKey('CurrencyIsoCode');
47 | this.HasSubtypes = sobjectDescribe.getHasSubtypes();
48 | this.IsAccessible = sobjectDescribe.isAccessible();
49 | this.IsChatterFeedEnabled = sobjectDescribe.isFeedEnabled();
50 | this.IsCreateable = sobjectDescribe.isCreateable();
51 | this.IsCustom = sobjectDescribe.isCustom();
52 | this.IsCustomSetting = sobjectDescribe.isCustomSetting();
53 | this.IsDeletable = sobjectDescribe.isDeletable();
54 | this.IsMergeable = sobjectDescribe.isMergeable();
55 | this.IsMruEnabled = sobjectDescribe.isMruEnabled();
56 | this.IsQueryable = sobjectDescribe.isQueryable();
57 | this.IsSearchable = sobjectDescribe.isSearchable();
58 | this.IsUndeletable = sobjectDescribe.isUndeletable();
59 | this.IsUpdateable = sobjectDescribe.isUpdateable();
60 | this.KeyPrefix = sobjectDescribe.getKeyPrefix();
61 | this.Label = sobjectDescribe.getLabel();
62 | this.LabelPlural = sobjectDescribe.getLabelPlural();
63 | this.LocalApiName = sobjectDescribe.getLocalName();
64 | this.Namespace = this.getNamespace();
65 | this.RecordTypes = this.getRecordTypes(sobjectType, sobjectDescribe.getRecordTypeInfos());
66 | this.TabIcon = this.getTabIcon();
67 | }
68 |
69 | private List getChildRelationships(List relationships) {
70 | List childRelationships = new List();
71 | for(Schema.ChildRelationship relationship : relationships) {
72 | childRelationships.add(new ChildRelationshipMetadata(relationship));
73 | }
74 | childRelationships.sort();
75 | return childRelationships;
76 | }
77 |
78 | private String getDisplayFieldApiName(Schema.DescribeSobjectResult sobjectDescribe) {
79 | // There are several commonly used names for the display field name - typically, Name
80 | // Check the common names first before resorting to looping through all Sobject fields
81 | // The order of the field names has been sorted based on number of objects in a dev org with that field
82 | List educatedGuesses = new List{
83 | 'Name', 'DeveloperName', 'ApiName', 'Title', 'Subject',
84 | 'AssetRelationshipNumber', 'CaseNumber', 'ContractNumber',
85 | 'Domain', 'FriendlyName', 'FunctionName', 'Label', 'LocalPart',
86 | 'OrderItemNumber', 'OrderNumber', 'SolutionName', 'TestSuiteName'
87 | };
88 | for(String fieldName : educatedGuesses) {
89 | Schema.SobjectField field = sobjectDescribe.fields.getMap().get(fieldName);
90 |
91 | if(field == null) continue;
92 |
93 | Schema.DescribeFieldResult fieldDescribe = field.getDescribe();
94 |
95 | if(fieldDescribe.isNameField()) return fieldDescribe.getName();
96 | }
97 |
98 | return null;
99 | }
100 |
101 | private List getFieldApiNames(Schema.DescribeSobjectResult sobjectDescribe) {
102 | List fieldApiNames = new List();
103 | for(Schema.SobjectField field : sobjectDescribe.fields.getMap().values()) {
104 | fieldApiNames.add(String.valueOf(field));
105 | }
106 | fieldApiNames.sort();
107 | return fieldApiNames;
108 | }
109 |
110 | private List getFieldSetApiNames(Schema.DescribeSobjectResult sobjectDescribe) {
111 | List fieldSetApiNames = new List();
112 | for(Schema.FieldSet fieldSet : sobjectDescribe.fieldSets.getMap().values()) {
113 | String namespace = fieldSet.getNameSpace() == null ? '' : FieldSet.getNamespace() + '__';
114 | fieldSetApiNames.add(namespace + fieldSet.getName());
115 | }
116 | fieldSetApiNames.sort();
117 | return fieldSetApiNames;
118 | }
119 |
120 | private String getNamespace() {
121 | Integer localNameIndex = this.ApiName.replace('__c', '').indexOf('__');
122 | return localNameIndex < 0 ? null : this.ApiName.substring(0, localNameIndex);
123 | }
124 |
125 | private List getRecordTypes(Schema.SobjectType sobjectType, List recordTypeInfos) {
126 | List recordTypes = new List();
127 | for(Schema.RecordTypeInfo recordTypeInfo : recordTypeInfos) {
128 | recordTypes.add(new RecordTypeMetadata(sobjectType, recordTypeInfo));
129 | }
130 | recordTypes.sort();
131 | return recordTypes;
132 | }
133 |
134 | private String getTabIcon() {
135 | String tabIcon;
136 | for(Schema.DescribeTabSetResult tabSetResult : Schema.describeTabs()) {
137 | if(tabIcon != null) break;
138 |
139 | for(Schema.DescribeTabResult tabResult : tabSetResult.getTabs()) {
140 | if(tabIcon != null) break;
141 | if(tabResult.getSobjectName() != this.ApiName) continue;
142 |
143 | String iconType = tabResult.isCustom() ? 'custom' : 'standard';
144 | String svgIconName;
145 | for(Schema.DescribeIconResult icon : tabResult.getIcons()) {
146 | if(icon.getContentType() != 'image/svg+xml') continue;
147 |
148 | svgIconName = icon.getUrl().substringAfterLast('/').replace('.svg', '');
149 | tabIcon = iconType + ':' + svgIconName;
150 | break;
151 | }
152 | }
153 | }
154 | // Hardcoded exceptions - Salesforce doesn't return SVGs for these objects, so hardcoding is necessary
155 | if(tabIcon == null && this.ApiName == 'Asset') tabIcon = 'standard:maintenance_asset';
156 | if(tabIcon == null && this.ApiName == 'AssetRelationship') tabIcon = 'standard:asset_relationship';
157 |
158 | return tabIcon;
159 | }
160 |
161 | global class ChildRelationshipMetadata implements Comparable {
162 |
163 | @AuraEnabled global String ChildSobjectApiName {get; private set;}
164 | @AuraEnabled global String FieldApiName {get; private set;}
165 | @AuraEnabled global String FieldRelationshipApiName {get; private set;}
166 | @AuraEnabled global Boolean IsCascadeDelete {get; private set;}
167 | @AuraEnabled global Boolean IsRestrictedDelete {get; private set;}
168 | @AuraEnabled global String RelationshipApiName {get; private set;}
169 |
170 | global ChildRelationshipMetadata(Schema.ChildRelationship childRelationship) {
171 | this.ChildSobjectApiName = String.valueOf(childRelationship.getChildSobject());
172 | this.FieldApiName = String.valueOf(childRelationship.getField());
173 | this.FieldRelationshipApiName = childRelationship.getField().getDescribe().getRelationshipName();
174 | this.IsCascadeDelete = childRelationship.isCascadeDelete();
175 | this.IsRestrictedDelete = childRelationship.isRestrictedDelete();
176 | this.RelationshipApiName = childRelationship.getRelationshipName();
177 | }
178 |
179 | global Integer compareTo(Object compareTo) {
180 | ChildRelationshipMetadata compareToChildRelationship = (ChildRelationshipMetadata)compareTo;
181 | String key = this.ChildSobjectApiName + this.FieldApiName;
182 | String compareToKey = compareToChildRelationship.ChildSobjectApiName + compareToChildRelationship.FieldApiName;
183 |
184 | if(key == compareToKey) return 0;
185 | else if(key > compareToKey) return 1;
186 | else return -1;
187 | }
188 |
189 | }
190 |
191 | }
--------------------------------------------------------------------------------
/src/classes/SobjectMetadata.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/SobjectMetadata_Tests.cls:
--------------------------------------------------------------------------------
1 | /*************************************************************************************************
2 | * This file is part of the SimpleMetadata project, released under the MIT License. *
3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. *
4 | *************************************************************************************************/
5 | @isTest
6 | private class SobjectMetadata_Tests {
7 |
8 | @isTest
9 | static void it_should_return_metadata_for_account_sobject_token() {
10 | SobjectMetadata accountMetadata = new SobjectMetadata(Schema.Account.SobjectType);
11 | validateAttributesAreSet(accountMetadata);
12 | validateCaseSentivityForJavascript(accountMetadata);
13 | }
14 |
15 | @isTest
16 | static void it_should_return_metadata_for_account_sobject_api_name() {
17 | SobjectMetadata accountMetadata = new SobjectMetadata('Account');
18 | validateAttributesAreSet(accountMetadata);
19 | validateCaseSentivityForJavascript(accountMetadata);
20 | }
21 |
22 | private static void validateAttributesAreSet(SobjectMetadata sobjectMetadata) {
23 | Schema.DescribeSobjectResult accountDescribe = Schema.Account.SobjectType.getDescribe();
24 |
25 | System.assertEquals('Account', sobjectMetadata.ApiName);
26 | System.assertEquals('Name', sobjectMetadata.DisplayFieldApiName);
27 | System.assertEquals(accountDescribe.getChildRelationships().size(), sobjectMetadata.ChildRelationships.size());
28 | System.assertEquals(accountDescribe.fields.getMap().size(), sobjectMetadata.FieldApiNames.size());
29 | System.assertEquals(accountDescribe.getHasSubtypes(), sobjectMetadata.HasSubtypes);
30 | System.assertEquals(accountDescribe.isAccessible(), sobjectMetadata.IsAccessible);
31 | System.assertEquals(accountDescribe.isFeedEnabled(), sobjectMetadata.IsChatterFeedEnabled);
32 | System.assertEquals(accountDescribe.isCreateable(), sobjectMetadata.IsCreateable);
33 | System.assertEquals(accountDescribe.isCustom(), sobjectMetadata.IsCustom);
34 | System.assertEquals(accountDescribe.isCustomSetting(), sobjectMetadata.IsCustomSetting);
35 | System.assertEquals(accountDescribe.isDeletable(), sobjectMetadata.IsDeletable);
36 | System.assertEquals(accountDescribe.isMergeable(), sobjectMetadata.IsMergeable);
37 | System.assertEquals(accountDescribe.isMruEnabled(), sobjectMetadata.IsMRUEnabled);
38 | System.assertEquals(accountDescribe.isQueryable(), sobjectMetadata.IsQueryable);
39 | System.assertEquals(accountDescribe.isSearchable(), sobjectMetadata.IsSearchable);
40 | System.assertEquals(accountDescribe.isUndeletable(), sobjectMetadata.IsUndeletable);
41 | System.assertEquals(accountDescribe.isUpdateable(), sobjectMetadata.IsUpdateable);
42 | System.assertEquals(accountDescribe.getKeyPrefix(), sobjectMetadata.KeyPrefix);
43 | System.assertEquals(accountDescribe.getLabel(), sobjectMetadata.Label);
44 | System.assertEquals(accountDescribe.getLabelPlural(), sobjectMetadata.LabelPlural);
45 | System.assertEquals(accountDescribe.getLocalName(), sobjectMetadata.LocalApiName);
46 | System.assertEquals(accountDescribe.getRecordTypeInfos().size(), sobjectMetadata.RecordTypes.size());
47 | System.assertEquals('standard:account', sobjectMetadata.TabIcon);
48 |
49 | System.assertNotEquals(null, sobjectMetadata.ApiName);
50 | System.assertNotEquals(null, sobjectMetadata.ChildRelationships);
51 | System.assertNotEquals(null, sobjectMetadata.DisplayFieldApiName);
52 | System.assertNotEquals(null, sobjectMetadata.HasMultiCurrency);
53 | System.assertNotEquals(null, sobjectMetadata.HasSubtypes);
54 | System.assertNotEquals(null, sobjectMetadata.IsAccessible);
55 | System.assertNotEquals(null, sobjectMetadata.IsChatterFeedEnabled);
56 | System.assertNotEquals(null, sobjectMetadata.IsCreateable);
57 | System.assertNotEquals(null, sobjectMetadata.IsCustom);
58 | System.assertNotEquals(null, sobjectMetadata.IsCustomSetting);
59 | System.assertNotEquals(null, sobjectMetadata.IsDeletable);
60 | System.assertNotEquals(null, sobjectMetadata.IsMruEnabled);
61 | System.assertNotEquals(null, sobjectMetadata.IsMergeable);
62 | System.assertNotEquals(null, sobjectMetadata.IsQueryable);
63 | System.assertNotEquals(null, sobjectMetadata.IsSearchable);
64 | System.assertNotEquals(null, sobjectMetadata.IsUndeletable);
65 | System.assertNotEquals(null, sobjectMetadata.IsUpdateable);
66 | System.assertNotEquals(null, sobjectMetadata.FieldApiNames);
67 | System.assertNotEquals(null, sobjectMetadata.FieldSetApiNames);
68 | System.assertNotEquals(null, sobjectMetadata.KeyPrefix);
69 | System.assertNotEquals(null, sobjectMetadata.Label);
70 | System.assertNotEquals(null, sobjectMetadata.LabelPlural);
71 | System.assertNotEquals(null, sobjectMetadata.LocalApiName);
72 | System.assertNotEquals(null, sobjectMetadata.RecordTypes);
73 | System.assertNotEquals(null, sobjectMetadata.TabIcon);
74 | }
75 |
76 | private static void validateCaseSentivityForJavascript(SobjectMetadata sobjectMetadata) {
77 | // Validate that the attributes are named exactly as expected so that javascript can rely on them
78 | String jsonSobjectMetadata = JSON.serialize(sobjectMetadata);
79 | Map untypedSobjectMetadata = (Map)JSON.deserializeUntyped(jsonSobjectMetadata);
80 |
81 | // One negative to confirm that the strings in our map are case sensitive
82 | System.assert(untypedSobjectMetadata.containsKey('APINAME') == false);
83 | // Now for the 'real' tests
84 | System.assert(untypedSobjectMetadata.containsKey('ApiName'));
85 | System.assert(untypedSobjectMetadata.containsKey('ChildRelationships'));
86 | System.assert(untypedSobjectMetadata.containsKey('DisplayFieldApiName'));
87 | System.assert(untypedSobjectMetadata.containsKey('FieldApiNames'));
88 | System.assert(untypedSobjectMetadata.containsKey('FieldSetApiNames'));
89 | System.assert(untypedSobjectMetadata.containsKey('HasMultiCurrency'));
90 | System.assert(untypedSobjectMetadata.containsKey('HasSubtypes'));
91 | System.assert(untypedSobjectMetadata.containsKey('IsAccessible'));
92 | System.assert(untypedSobjectMetadata.containsKey('IsChatterFeedEnabled'));
93 | System.assert(untypedSobjectMetadata.containsKey('IsCreateable'));
94 | System.assert(untypedSobjectMetadata.containsKey('IsCustom'));
95 | System.assert(untypedSobjectMetadata.containsKey('IsCustomSetting'));
96 | System.assert(untypedSobjectMetadata.containsKey('IsDeletable'));
97 | System.assert(untypedSobjectMetadata.containsKey('IsMruEnabled'));
98 | System.assert(untypedSobjectMetadata.containsKey('IsMergeable'));
99 | System.assert(untypedSobjectMetadata.containsKey('IsQueryable'));
100 | System.assert(untypedSobjectMetadata.containsKey('IsSearchable'));
101 | System.assert(untypedSobjectMetadata.containsKey('IsUndeletable'));
102 | System.assert(untypedSobjectMetadata.containsKey('IsUpdateable'));
103 | System.assert(untypedSobjectMetadata.containsKey('KeyPrefix'));
104 | System.assert(untypedSobjectMetadata.containsKey('Label'));
105 | System.assert(untypedSobjectMetadata.containsKey('LabelPlural'));
106 | System.assert(untypedSobjectMetadata.containsKey('LocalApiName'));
107 | System.assert(untypedSobjectMetadata.containsKey('Namespace'));
108 | System.assert(untypedSobjectMetadata.containsKey('RecordTypes'));
109 | System.assert(untypedSobjectMetadata.containsKey('TabIcon'));
110 | }
111 |
112 | }
--------------------------------------------------------------------------------
/src/classes/SobjectMetadata_Tests.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 43.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | *
5 | ApexClass
6 |
7 | 43.0
8 |
9 |
--------------------------------------------------------------------------------